ITaskHandler::Start
的原型如下:
HRESULT ( STDMETHODCALLTYPE Start )(
__RPC__in ITaskHandler * This,
/* [in] */ __RPC__in_opt IUnknown *pHandlerServices,
/* [in] */ __RPC__in BSTR data)
为什么
pHandlerServices
是可选的-如果我得到一个空值(这是我的情况)-我如何通知任务调度程序我已经完成了任务。好的-这是我实现的
QueryInterface
类的交易,它总是返回相同的对象,并且会立即被查询。但事实并非如此,第一个查询是针对ITaskHandler
的,IClassFactory
的函数签名有第二个参数CreateInstance
NULL,这与我实现pUnkOuter
的第二个参数重叠。不过,奇怪的是ITaskHandler_Start
被标记为可选。这是我当前的处理程序实现,它仍然不工作(上一次运行的结果是不支持这样的接口(0x80004002))-我的接口
pHandlerServices
从未被查询过。我甚至实现了ITaskHandler
但alias没有成功(ICallFactory
永远不会被调用)-下面是代码:#define COBJMACROS
#include <windows.h>
#include <objbase.h>
#include <unknwn.h>
// {179D1704-49C5-4111-B3CF-C528ABB014D0}
DEFINE_GUID(CLSID_IRmouseHandler,
0x179d1704, 0x49c5, 0x4111, 0xb3, 0xcf, 0xc5, 0x28, 0xab, 0xb0, 0x14, 0xd0);
#define wstringCLSID_IRmouseHandler L"{179D1704-49C5-4111-B3CF-C528ABB014D0}"
static const GUID CLSID_IRmouseHandler =
{ 0x179d1704, 0x49c5, 0x4111, { 0xb3, 0xcf, 0xc5, 0x28, 0xab, 0xb0, 0x14, 0xd0 } };
// {D363EF80-5C42-46D8-847B-B3A27A3BD0E3}
DEFINE_GUID(IID_IRmouseHandler,
0xd363ef80, 0x5c42, 0x46d8, 0x84, 0x7b, 0xb3, 0xa2, 0x7a, 0x3b, 0xd0, 0xe3);
static const GUID IID_IRmouseHandler =
{ 0xd363ef80, 0x5c42, 0x46d8, { 0x84, 0x7b, 0xb3, 0xa2, 0x7a, 0x3b, 0xd0, 0xe3 } };
#include <taskschd.h>
#include <ObjIdl.h>
#define stub(x)\
\
STDMETHODCALLTYPE x() {\
MessageBox(\
NULL,\
"ITaskHandler_" #x,\
"Account Details",\
MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2\
);}
extern ITaskHandler tskhandler; extern IClassFactory factory; extern ICallFactory callfactory;
stub(CreateCall)
HRESULT ( STDMETHODCALLTYPE CreateInstance )(
IClassFactory * This,
/* [annotation][unique][in] */
_In_opt_ IUnknown *pUnkOuter,
/* [annotation][in] */
_In_ REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject) { return QueryInterface(This, riid, ppvObject);}
HRESULT STDMETHODCALLTYPE QueryInterface(
__RPC__in ITaskHandler * This,
/* [in] */ __RPC__in REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject) {
if(!ppvObject) return E_POINTER;
if(!memcmp(riid, &IID_ITaskHandler, sizeof *riid) || !memcmp(riid, &IID_IUnknown, sizeof *riid))*ppvObject = &tskhandler;
else if(!memcmp(riid, &IID_ICallFactory, sizeof *riid))*ppvObject = &callfactory;
else if(!memcmp(riid, &IID_IClassFactory, sizeof *riid))*ppvObject = &factory;
else return E_NOINTERFACE;
return S_OK;}
ULONG STDMETHODCALLTYPE AddRef(){}
stub(Release)
HRESULT ( STDMETHODCALLTYPE Start )(
__RPC__in ITaskHandler * This,
/* [in] */ __RPC__in_opt IUnknown *pHandlerServices,
/* [in] */ __RPC__in BSTR data) {ITaskHandlerStatus *pHandlerStatus;
IUnknown_QueryInterface(pHandlerServices,&IID_ITaskHandlerStatus,&pHandlerStatus),
ITaskHandlerStatus_TaskCompleted(pHandlerStatus,S_OK);return S_OK;}
stub(Stop)
stub(Pause)
stub(Resume)
ITaskHandler tskhandler = {.lpVtbl = &(struct ITaskHandlerVtbl){.QueryInterface=QueryInterface,.Resume=Resume,
.AddRef=AddRef,.Release=Release,.Start=Start,.Stop=Stop,.Pause=Pause}};
IClassFactory factory = {.lpVtbl = &(struct IClassFactoryVtbl){.QueryInterface=QueryInterface,
.AddRef=AddRef,.Release=Release,.CreateInstance=CreateInstance}};
ICallFactory callfactory = {.lpVtbl = &(struct ICallFactoryVtbl){.QueryInterface=QueryInterface,
.AddRef=AddRef,.Release=Release,.CreateCall=CreateCall}};
int WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
) { DWORD dwToken; //AddVectoredExceptionHandler(1,PvectoredExceptionHandler);
CoInitializeEx(NULL,0), CoRegisterClassObject(&CLSID_IRmouseHandler,&tskhandler,CLSCTX_LOCAL_SERVER,REGCLS_MULTIPLEUSE,&dwToken),Sleep(INFINITE);}
最佳答案
有三个问题:
1)AddRef和stub必须有1个参数,如IUnknown*This(或LPVOID This)。如果您的函数是cdecl,这无关紧要,但COM只与stdcall函数一起工作。
系统要求函数自己清理堆栈中的参数。
2)AddRef至少不能返回0,stub函数必须返回S\u OK或0。也许这不是什么大问题。。
3)调查显示系统查询IUnknown的类工厂,可能它执行的是QueryInterface而不是AddRef。但是无论如何,为每个IUnknown查询返回taskhandler是不正确的。还“工厂”更好。不过,最好在IUnknown上返回这个,不管怎样,每个接口都是IUnknown的后代。
另外一个问题是,如果在Unicode消息框下编译,会显示奇怪的中文文本,因为需要将文本参数设置为Unicode,或者显式使用MessageBoxA
#define COBJMACROS
#include <windows.h>
#include <objbase.h>
#include <unknwn.h>
// {179D1704-49C5-4111-B3CF-C528ABB014D0}
DEFINE_GUID(CLSID_IRmouseHandler,
0x179d1704, 0x49c5, 0x4111, 0xb3, 0xcf, 0xc5, 0x28, 0xab, 0xb0, 0x14, 0xd0);
#define wstringCLSID_IRmouseHandler L"{179D1704-49C5-4111-B3CF-C528ABB014D0}"
static const GUID CLSID_IRmouseHandler =
{ 0x179d1704, 0x49c5, 0x4111,{ 0xb3, 0xcf, 0xc5, 0x28, 0xab, 0xb0, 0x14, 0xd0 } };
// {D363EF80-5C42-46D8-847B-B3A27A3BD0E3}
DEFINE_GUID(IID_IRmouseHandler,
0xd363ef80, 0x5c42, 0x46d8, 0x84, 0x7b, 0xb3, 0xa2, 0x7a, 0x3b, 0xd0, 0xe3);
static const GUID IID_IRmouseHandler =
{ 0xd363ef80, 0x5c42, 0x46d8,{ 0x84, 0x7b, 0xb3, 0xa2, 0x7a, 0x3b, 0xd0, 0xe3 } };
#include <taskschd.h>
#include <ObjIdl.h>
// Vano101: Make This parameter, Return S_OK, Use MessageBoxA or L before text
#define stub(x)\
\
STDMETHODCALLTYPE x(IUnknown* This) {\
MessageBoxA(\
NULL,\
"ITaskHandler_" #x,\
"Account Details",\
MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2\
); \
return S_OK; \
}
extern ITaskHandler tskhandler;
extern IClassFactory factory;
extern ICallFactory callfactory;
stub(CreateCall)
HRESULT(STDMETHODCALLTYPE CreateInstance)(
IClassFactory * This,
/* [annotation][unique][in] */
_In_opt_ IUnknown *pUnkOuter,
/* [annotation][in] */
_In_ REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject) {
return QueryInterface(This, riid, ppvObject);
}
HRESULT STDMETHODCALLTYPE QueryInterface(
__RPC__in ITaskHandler * This,
/* [in] */ __RPC__in REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject) {
if (!ppvObject) return E_POINTER;
if (!memcmp(riid, &IID_ITaskHandler, sizeof *riid)) *ppvObject = &tskhandler;
else if (!memcmp(riid, &IID_IUnknown, sizeof *riid)) *ppvObject = &factory; // Vano101: Return factory on IUnknown
else if (!memcmp(riid, &IID_ICallFactory, sizeof *riid))*ppvObject = &callfactory;
else if (!memcmp(riid, &IID_IClassFactory, sizeof *riid))*ppvObject = &factory;
else return E_NOINTERFACE;
return S_OK;
}
// Vano101: Return 1 on AddRef!, Make This parameter
ULONG STDMETHODCALLTYPE AddRef(IUnknown* This) { return 1; }
stub(Release)
HRESULT(STDMETHODCALLTYPE Start)(
__RPC__in ITaskHandler * This,
/* [in] */ __RPC__in_opt IUnknown *pHandlerServices,
/* [in] */ __RPC__in BSTR data) {
ITaskHandlerStatus *pHandlerStatus;
IUnknown_QueryInterface(pHandlerServices, &IID_ITaskHandlerStatus, &pHandlerStatus),
ITaskHandlerStatus_TaskCompleted(pHandlerStatus, S_OK); return S_OK;
}
stub(Stop)
stub(Pause)
stub(Resume)
ITaskHandler tskhandler = { .lpVtbl = &(struct ITaskHandlerVtbl) {
.QueryInterface = QueryInterface,.Resume = Resume,
.AddRef = AddRef,.Release = Release,.Start = Start,.Stop = Stop,.Pause = Pause
} };
IClassFactory factory = { .lpVtbl = &(struct IClassFactoryVtbl) {
.QueryInterface = QueryInterface,
.AddRef = AddRef,.Release = Release,.CreateInstance = CreateInstance
} };
ICallFactory callfactory = { .lpVtbl = &(struct ICallFactoryVtbl) {
.QueryInterface = QueryInterface,
.AddRef = AddRef,.Release = Release,.CreateCall = CreateCall
} };
int WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
) {
DWORD dwToken; //AddVectoredExceptionHandler(1,PvectoredExceptionHandler);
CoInitializeEx(NULL, 0), CoRegisterClassObject(&CLSID_IRmouseHandler, &tskhandler, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwToken), Sleep(INFINITE);
}