У меня есть приложение для составления отчетов, которое работает на стороне сервера, которое считывает сохраненный BMP из моей базы данных (в виде байта []), преобразует его обратно в изображение, а затем помещает его в электронную таблицу Excel, которая образует основудля этого отчета (этот отчет в конечном итоге доставляется клиенту для загрузки.) Для этого я пытаюсь использовать буфер обмена на стороне сервера для обработки «вставки» изображения в определенный диапазон на листе.Вот фрагмент кода -
System.Drawing.Image image;
Bitmap bm;
Graphics g;
Excel.Range range;
MemoryStream ms = new MemoryStream(graphRecs.ElementAt(0).Graph, 0,
graphRecs.ElementAt(0).Graph.Length);
ms.Write(graphRecs.ElementAt(0).Graph, 0, graphRecs.ElementAt(0).Graph.Length);
image = System.Drawing.Image.FromStream(ms, true);
bm = new Bitmap(413, 130);
g = Graphics.FromImage(bm);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.DrawImage(image, 0, 1, 413, 130);
Clipboard.SetDataObject(bm, false, 4, 250);
range = ws.get_Range(cBlkPtr[6, 2], cBlkPtr[6, 2]);
ws.Paste(range, bm);
Clipboard.Clear();
Запуск в режиме отладки под VS2008, кажется, работает нормально - изображение преобразуется, добавляется в буфер обмена и вставляется в указанный диапазон без проблем.После публикации веб-приложения на моем сервере IIS происходит сбой в операторе Clipboard.SetDataObject со следующим исключением:
Requested Clipboard operation did not succeed.
at System.Windows.Forms.Clipboard.ThrowIfFailed(Int32 hr)
at System.Windows.Forms.Clipboard.SetDataObject(Object data, Boolean copy, Int32
retryTimes, Int32 retryDelay)
at ReportGenerate.buildPvsClinicSections(Worksheet ws, Object j, patientRecord p, String
patientStatus, String programType)
Я предполагаю, что эта ошибка связана с тем, что НЕ находится вSingleThreadApartment.Я добавил директиву AspCompat = true на свою страницу ASPX без изменений (не думал, что это поможет, поскольку AspCompat больше подходит для ASP, чем для ASPX).Поскольку я не могу добавить [STAThread] к своему «основному» (это будет IIS), я не знаю, как действовать дальше.Я также готов изменить подход, который я использую при добавлении изображения в электронную таблицу, при условии, что я могу явно указать (через диапазон), где его разместить.Например, использование Shape.AddPicture не позволяет мне сделать это.
Есть идеи?
Спасибо.
Обновление
Я обновилфрагмент кода для запуска второго потока с правильным ApartmentState -
range = ws.get_Range(cBlkPtr[6, 2], cBlkPtr[6, 2]);
ClipboardModel cbm = new ClipboardModel(bm, range, ws);
System.Threading.Thread cbThread = new System.Threading.Thread(new
System.Threading.ParameterizedThreadStart(DoClipboardStuff));
cbThread.SetApartmentState(System.Threading.ApartmentState.STA);
cbThread.Start(cbm);
cbThread.Join();
Метод 'DoClipboardStuff' выглядит следующим образом -
[STAThread]
protected void DoClipboardStuff(object o)
{
try
{
ClipboardModel cbm = (ClipboardModel)o;
Clipboard.SetDataObject(cbm.bm, false, 4, 250);
cbm.ws.Paste(cbm.range, cbm.bm);
Clipboard.Clear();
}
catch (Exception e)
{
StreamWriter sw = new StreamWriter(@"C:\Myopia\Log.txt");
sw.WriteLine(e.Message);
sw.WriteLine(e.StackTrace);
sw.Flush();
sw.Close();
throw e;
}
}
Теперь я получаю точно такую же ошибку, как и раньшеТолько сейчас в этом методе.Я начинаю подозревать, что это не ApartmentState, а скорее отсутствие «пользовательского интерфейса».Я не знаю, будет ли нормальный интерфейс Win32 лучше, но это мой следующий подход (если только у кого-то нет более, .NET'ish решения.)
Update # 2
Хотя мне не удалось решить проблему с IIS 6 и буфером обмена, мне удалось обойти эту проблему, записав восстановленный BMP во временный файл, а затем с помощью Shapes.AddPicture разместил его там, где он мне нуженбыть -
g.DrawImage(image, 0, 1, 400, 75);
bm.Save(@"c:\Myopia\temp.bmp");
Excel.Shape xlShape = ws.Shapes.Item("Rectangle 2");
float left = xlShape.Left;
float top = Convert.ToSingle(ws.get_Range("A1", cBlkPtr[5, 2]).Height);
float width = xlShape.Width;
float height = xlShape.Height;
xlShape = ws.Shapes.AddPicture(@"c:\Myopia\temp.bmp",
Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue,
left, top, width, height);
Не идеальное решение, но то, которое работает на данный момент.Единственная проблема с этим подходом заключается в том, что у меня, кажется, есть потеря разрешения между восстановлением BMP из байта [], сохранением его в файл temp.bmp и последующим добавлением его обратно - bmp выглядит «нечетким».Возможно, придется искать менее «потерянный» формат для использования.