2010-07-06 2 views
2

Я пишу расширения для программы на C++. Я пишу стандартные C/C++ dlls, и я использую IJW для вызова C# dll. Это всегда работало отлично, пока я не написал и не назвал C# dll, который, в свою очередь, называется OpenFileDialog и SaveFileDialog. Всякий раз, когда вызывался с ShowDialog, приложение замерзало.C++/cli -> вызов C# dll -> вызов проблемы OpenFileDialog

Так делая «Минимальный Рабочий пример» Я получил: Необработанное исключение типа «System.Threading.ThreadStateException» произошло в System.Windows.Forms.dll

Дополнительная информация: Текущий поток должен быть установите режим однопоточной квартиры (STA) до того, как вызовы OLE могут быть сделаны. Убедитесь, что ваша основная функция имеет STAThreadAttribute, отмеченный на нем. Это исключение возникает только в том случае, если к процессу прикреплен отладчик.

Итак, я попытался добавить атрибут STAThread infront основного в моем «Минимальном рабочем примере», и я получил эту ошибку.

ошибка C2337: 'STAThread': атрибут не найден

Итак, два вопроса:

  1. Как d0 я получаю "Минимальный рабочий пример" работает и
  2. Как Я получаю настоящее приложение?

(это даже можно добавить атрибут STAThread в неуправляемый блоке #pragma?)

#pragma unmanaged 
BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved) 
{ 
... 
} 

ответ

2

Когда ты DLL, вы не можете напрямую контролировать квартиру ваш поток работает в - поток может быть только в одной квартире за раз, и если поток, который вызывает в вашу DLL, уже какая-то другая квартира, вы не можете его изменить.

Вы управляете кодом, вызывающим вашу DLL? Если нет, то я думаю, что самое лучшее, что вы можете сделать, это запустить свою собственную нить (в которой вы можете управлять квартирой, в которой она работает, через CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)), а затем позвонить OpenFileDialog/SaveFileDialog оттуда.

+0

Гораздо лучший ответ, чем мой. –

+0

Для меня с WPF вместо WinForms аналогичная проблема была решена путем вызова CoInitialize (NULL) в основной функции. В этом случае начало новой нити не было необходимым (и обычно не желательно), тоже –

0

Все,

Спасибо за помощь. Почему-то начинать новую нить никогда не приходило в голову.

Спасибо всем за этот лакомый кусочек. Поскольку я уже в IJW C++/cli, я решил лучше решить проблему, используя инфраструктуру .net.

Как только я понял, что мне нужна новая нить, все было довольно просто.

я переместил функцию, вызвавшего DLL C# в отдельный класс:

исх класс 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)