我有一个相当复杂的要求。我的STA COM对象在DLL中实现(不能将其移动到进程外EXE)。通过DllSurrogate
我在dllhost.exe
进程中托管我的对象。我的对象有一个附加到它的UI(一个简单的无模式对话框),但我需要PreTranslateAccelerator
机制,以便一些快捷方式工作,等等。因为COM激活我的对象并将其托管在默认的dllhost.com
,我显然没有控制消息泵。
在这种情况下,是否还有预先翻译邮件的方法?我怀疑COM已经预见到了这样一个特定的场景,但也许我错过了一些东西。
答案 0 :(得分:1)
我需要将所有内容打包在一个DLL中。
在这种情况下,DllSurrogate
不是执行此操作的唯一方法。还有Rundll32
:
INFO: Windows Rundll and Rundll32 Interface
这将允许您在DLL的EntryPoint
内运行自己的消息循环,并完全控制消息处理,包括PreTranslateMessage
。您可以从ATL EXE服务器复制消息循环逻辑。
请记住,还有32位和64位版本的" RunDll32.exe"在每个64位Windows操作系统中。使用与您的DLL的位相匹配的那个。
答案 1 :(得分:1)
好的,这是。我希望我没有遗漏任何重要的东西。基本上,我创建了一个自定义CMyComCreator
而不是默认值。我不是只创建一个COM对象并返回一个接口指针,而是旋转一个worker UiThread
。我使用MyData
结构来跨线程传递数据。工作线程完成设置后,我使用CComGITPtr
将编组接口指针从UiThread
传回主节点。消费者(进程外)最终得到的接口指针直接与绕过主线程的UiThread
对话。您可能会认为CMyDialog
是一个无模式对话框,它会在销毁时发送PostQuitMessage
以终止消息循环。这就是全部。可能看起来很麻烦,但效果很好。
struct MyData
{
ATL::CComGITPtr<IUnknown> Unk;
ATL::CEvent Event;
HRESULT hr;
MyData() : hr(E_OUTOFMEMORY), Event(FALSE, FALSE) { }
};
static CMessageLoop * MessageLoop;
class CMyComCreator
{
public:
static HRESULT WINAPI CreateInstance(
_In_opt_ void* pv,
_In_ REFIID riid,
_COM_Outptr_ LPVOID* ppv)
{
ATLASSERT(ppv != NULL);
if (ppv == NULL)
return E_POINTER;
*ppv = NULL;
HRESULT hRes = E_OUTOFMEMORY;
MyData* data = NULL;
ATLPREFAST_SUPPRESS(6014 28197)
/* prefast noise VSW 489981 */
ATLTRY(data = _ATL_NEW MyData)
ATLPREFAST_UNSUPPRESS()
if (data != NULL)
{
HANDLE thread = (HANDLE)_beginthreadex(NULL, 0, UiThread, (void *)data, 0, NULL);
if (thread)
{
WaitForSingleObject(data->Event, INFINITE);
CloseHandle(thread);
hRes = data->hr;
if (SUCCEEDED(hRes))
{
ATL::CComPtr<IUnknown> unk;
hRes = data->Unk.CopyTo(&unk);
if (SUCCEEDED(hRes))
{
hRes = unk->QueryInterface(riid, ppv);
}
}
}
delete data;
}
return hRes;
}
};
typedef CMyComCreator _CreatorClass;
static unsigned __stdcall UiThread(void * param)
{
CoInitializeEx(0, COINIT_APARTMENTTHREADED);
MyData * data = (MyData *)param;
ATL::CComObject<CMyDialog> * bb;
data->hr = ATL::CComObject<CMyDialog>::CreateInstance(&bb);
ATL::CComPtr<IUnknown> unk((IDispatch *) bb);
data->Unk = unk;
unk.Release();
data->Event.Set();
if (SUCCEEDED(data->hr))
{
CMessageLoop theLoop;
MessageLoop = &theLoop;
int nRet = theLoop.Run();
MessageLoop = NULL;
}
CoUninitialize();
return 0;
}