ITaskHandler::Start的原型如下:

HRESULT ( STDMETHODCALLTYPE Start )(
            __RPC__in ITaskHandler * This,
            /* [in] */ __RPC__in_opt IUnknown *pHandlerServices,
            /* [in] */ __RPC__in BSTR data)

为什么pHandlerServices是可选的-如果我得到一个空值(这是我的情况)-我如何通知任务调度程序我已经完成了任务。
好的-这是我实现的QueryInterface类的交易,它总是返回相同的对象,并且会立即被查询。但事实并非如此,第一个查询是针对ITaskHandler的,IClassFactory的函数签名有第二个参数CreateInstanceNULL,这与我实现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);
}

08-17 04:49