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

我有一个运行服务器端的报告应用程序,它从我的数据库中读取一个存储的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下的debugging模式下运行它似乎工作正常 – 图像被转换,添加到剪贴板,并粘贴到指定的范围没有问题。 在将webapp发布到我的IIS服务器之后,在“Clipboard.SetDataObject”语句中出现以下exception,

 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) 

我是在假设这个错误是与不在单线程公寓。 我已经添加了'AspCompat = true'指令到我的ASPX页面没有任何改变(没有想到这会有所帮助,因为AspCompat是比ASPX更多的ASP)。 由于我不能将[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,而是缺less一个“UI”。 我不知道普通的Win32接口是否会更好,但这是我的下一个方法(除非有其他人有更多的.NET'ish解决scheme)。

更新#2

虽然我还没有能够解决与IIS 6和剪贴板的问题,我已经设法解决这个问题,通过将重build的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); 

不是一个理想的解决scheme,而是一个现在的工作。 这种方法唯一的问题是,我似乎在从byte []重buildBMP,将其保存到temp.bmp文件,然后将其添加回来 – bmp看起来是“模糊的”之间有分辨率损失。 可能不得不寻找一个“有损”的格式来使用。

如果STA确实是这个问题,那么尝试在你设置到STA的新线程中执行操作,然后再启动它,如Skeet(tm)对此问题的回答所示:

在.NET中,当我在一个额外的线程中运行窗体时,如何设置STAThread?

在我的脑海深处,虽然有一点声音是暗示剪贴板可能只适用于具有UI的应用程序(例如开发Web服务器)…希望我错了!