Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

#99 CopyEmf() Causes Cross-Thread call to Control.Handle

open
nobody
5
2014-03-15
2008-07-31
rab38505
No

Using .NET 2.0, there is an error in the CopyEmf() implementation in ZedGraph 5.1.4. It tries to call ZedGraphControl.Handle on a thread other than the event dispatcher, which raises an exception. The call to this.Handle is in the ClipboardCopyThreadEmf() method. Below is an implementation of CopyEmf() and ClipboardCopyThreadEmf() that does not cause the cross-thread call to this.Handle, though someone should probably evaluate whether the handle should be used anywhere outside the event dispatcher in the first place. In general, it's not a good idea. From what I understand from the comments, the reason the copy was on a different thread in the first place was to avoid crashes when uses MTA threads, but you aren't supposed to use Windows Forms with MTA threading anyway, so perhaps the copy should just be moved back to the event dispatcher and a note put in the documentation to not use MTA threads with Windows Forms. Be that as it may, here is a version of the code that does still use a separate thread, but does not call this.Handle on the other thread:


public void CopyEmf(bool isShowMessage)
{
if (_masterPane != null)
{
// Threaded copy mode to avoid crash with MTA
// Contributed by Dave Moor
Thread ct = new Thread(new ParameterizedThreadStart(this.ClipboardCopyThreadEmf));
//ct.ApartmentState = ApartmentState.STA;
ct.SetApartmentState(ApartmentState.STA);
ct.Start(this.Handle);
ct.Join();

if (isShowMessage)
{
  string str = _resourceManager.GetString("copied_to_clip");
  MessageBox.Show(str);
}

}
}

private void ClipboardCopyThreadEmf(object objHWnd)
{
if (!(objHWnd is IntPtr))
return;
IntPtr hWnd = (IntPtr)objHWnd;
using (Graphics g = this.CreateGraphics())
{
IntPtr hdc = g.GetHdc();
Metafile metaFile = new Metafile(hdc, EmfType.EmfPlusOnly);
g.ReleaseHdc(hdc);

using (Graphics gMeta = Graphics.FromImage(metaFile))
{
  this._masterPane.Draw( gMeta );
}

//IntPtr hMeta = metaFile.GetHenhmetafile();
ClipboardMetafileHelper.PutEnhMetafileOnClipboard(hWnd, metaFile);
//System.Windows.Forms.Clipboard.SetDataObject(hMeta, true);

//g.Dispose();

}
}

Discussion