在ASPX webapp中使用服务器端剪贴板的问题

时间:2010-11-16 15:45:21

标签: c# asp.net excel interop clipboard

我有一个运行服务器端的报告应用程序,它从我的数据库中读取存储的BMP(作为byte []),将其转换回图像,然后将其放入构成基础的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下以调试模式运行它似乎工作正常 - 图像被转换,添加到剪贴板,并且没有任何问题地粘贴到指定的范围内。将webapp发布到我的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)

我假设这个错误与NOT不在SingleThreadApartment中有关。我已经将'AspCompat = true'指令添加到我的ASPX页面而没有任何变化(不认为它会有所帮助,因为AspCompat更适合ASP而不是ASPX)。由于我无法将[STAThread]添加到我的'main'(即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,而是缺少'UI'。我不知道正常的Win32接口是否会更好,但这是我的下一个方法(除非其他人有更多的.NET'解决方案。)

更新#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);

不是理想的解决方案,但现在可以使用。这种方法的唯一问题是,我似乎在从byte []重建BMP之间失去了分辨率,将其保存到temp.bmp文件,然后将其重新添加 - bmp看起来“模糊”。可能需要寻找一种不那么“有损”的格式来使用。

1 个答案:

答案 0 :(得分:0)

如果STA确实是问题,那么尝试在启动之前在您设置为STA的新线程中执行操作,如Skeet(tm)对此问题的回答所示:

in .NET, How do I set STAThread when I'm running a form in an additional thread?

在我脑海深处的某个地方虽然有一个小小的声音表明剪贴板可能仅适用于具有UI的应用程序(例如开发网站服务器 )...希望我我错了!