我编写了C ++程序的扩展。我编写标准的C / C ++ dll,我使用IJW来调用C#dll。这一直很有效,直到我编写并调用了一个C#dll,后者又称为OpenFileDialog和SaveFileDialog。无论何时使用ShowDialog调用,应用程序都会冻结。
因此,在制作“最低工作范例”时,我得到了: System.Windows.Forms.dll中发生未处理的“System.Threading.ThreadStateException”类型异常
附加信息:在进行OLE调用之前,必须将当前线程设置为单线程单元(STA)模式。确保您的Main函数标记了STAThreadAttribute。仅当调试器附加到进程时才会引发此异常。
所以,我尝试在我的“最小工作示例”中添加main的STAThread属性,我收到了这个错误。
错误C2337:'STAThread':找不到属性
所以,有两个问题:
(甚至可以在#pragma非托管块中添加STAThread属性吗?)
#pragma unmanaged
BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
{
...
}
答案 0 :(得分:2)
当你是一个DLL时,你不能直接控制你的线程运行的公寓 - 一个线程一次只能在一个公寓里,所以如果调用你的DLL的线程已经是其他公寓,那么你就无法改变它。
您是否控制调用DLL的代码?如果没有,那么我认为你能做的最好的事情就是启动自己的线程(你可以通过CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) 控制它运行的公寓),然后调用{{1从那里开始/ OpenFileDialog
。
答案 1 :(得分:0)
每个人,
感谢您的帮助。出于某种原因,我从未想过开始新的线程。
感谢大家的那一点。由于我已经在IJW C ++ / cli土地,我认为使用.net框架解决问题会更好。
一旦我意识到我需要一个新线程,这很简单。
我将调用C#dll的函数移动到一个单独的类中:
ref class StaClass { 公共:
System::String^ strFile;
System::String^ strNote;
void CallWiki()
{
WikiNotes::FrmWiki fw;
fw.File = strFile;
fw.Note = strNote;
fw.ShowDialog();
}
};
然后从主线程我使用此代码来启动STA线程。
wiki->strFile = gcnew System::String(File);
wiki->strNote = gcnew System::String(Note);
ThreadStart^ threadDelegate = gcnew ThreadStart(wiki, &StaClass::CallWiki);
Thread^ newThread = gcnew Thread(threadDelegate, 0);
newThread->SetApartmentState(ApartmentState::STA);
newThread->Start();
简单易读和理解(至少对我来说 - 我是.Net程序员,我从未深入研究过COM,MFC和ATL)