ITaskHandler::Start
的原型如下:
HRESULT ( STDMETHODCALLTYPE Start )(
__RPC__in ITaskHandler * This,
/* [in] */ __RPC__in_opt IUnknown *pHandlerServices,
/* [in] */ __RPC__in BSTR data)
pHandlerServices
是可选的-如果我得到NULL(这是我的情况)-如何通知任务调度程序我已经完成任务。
好-这是我实现的类QueryInterface
的处理,以始终返回相同的对象思维-ITaskHandler
将立即被查询。但是,情况并非如此-第一个查询是针对IClassFactory
的,并且CreateInstance
的函数签名具有第二个参数pUnkOuter
NULL,它与我的{{ 1}}。不过,ITaskHandler_Start
被标记为可选是很奇怪的。
这是我当前对处理程序的实现,该实现仍不起作用(上次运行结果是不支持此类接口(0x80004002))-从未查询过我的接口pHandlerServices
。我什至到目前为止都实现了ITaskHandler
,但是没有运气的别名(从未调用过ICallFactory
)-这是代码:
CreateCall
答案 0 :(得分:1)
@HansPassant指出的关键是,任务计划程序将仅在进程外运行COM对象。为此,您需要注册COM对象才能使用系统提供的DllSurrogate。
这是我的示例的COM注册键
HKEY_CLASSES_ROOT\AppID\{6B9279D0-D220-4288-AFDF-E424F558FEF2}
DllSurrogate REG_SZ ""
Computer\HKEY_CLASSES_ROOT\CLSID\{36A976F4-698B-4B50-BE2C-83F815575199}
Default REG_SZ Path\To\your_com.dll
AppID REG_SZ {6B9279D0-D220-4288-AFDF-E424F558FEF2}
ThreadingModel REG_SZ Both
有效的示例代码(对不起的C ++)-它基本上只是默认的COM实现,并带有ITaskHandler。它至少调用Start。如果要使用自己的代码,建议您在担心任务计划程序之前,先在简单的测试程序中测试COM对象的加载。
// {36A976F4-698B-4B50-BE2C-83F815575199}
DEFINE_GUID(CLSID_TestObject,
0x36a976f4, 0x698b, 0x4b50, 0xbe, 0x2c, 0x83, 0xf8, 0x15, 0x57, 0x51, 0x99);
int main()
{
CoInitialize(nullptr);
ITaskHandler* handler = nullptr;
HRESULT hr = CoCreateInstance(CLSID_TestObject, nullptr, CLSCTX_LOCAL_SERVER, IID_ITaskHandler, (LPVOID*)&handler);
fprintf(stderr, "CoCreateInstance %08x\r\n", hr);
return 0;
}
DllMain.cpp
extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}
// {36A976F4-698B-4B50-BE2C-83F815575199}
DEFINE_GUID(CLSID_TestObj,
0x36a976f4, 0x698b, 0x4b50, 0xbe, 0x2c, 0x83, 0xf8, 0x15, 0x57, 0x51, 0x99);
long g_nComObjsInUse;
STDAPI DllGetClassObject(const CLSID& clsid,
const IID& iid,
void** ppv)
{
OutputDebugStringW(L"DllGetClassObject");
if (IsEqualGUID(clsid, CLSID_TestObj))
{
TestClassFactory *pAddFact = new TestClassFactory();
if (pAddFact == NULL)
return E_OUTOFMEMORY;
else
{
return pAddFact->QueryInterface(iid, ppv);
}
}
return CLASS_E_CLASSNOTAVAILABLE;
}
STDAPI DllCanUnloadNow()
{
OutputDebugStringW(L"DllCanUnloadNow");
if (g_nComObjsInUse == 0)
{
return S_OK;
}
else
{
return S_FALSE;
}
}
TestObj.h
extern long g_nComObjsInUse;
class CTestObj :
public ITaskHandler
{
public:
CTestObj();
virtual ~CTestObj();
//IUnknown interface
HRESULT __stdcall QueryInterface( REFIID riid,void **ppObj) override;
ULONG __stdcall AddRef() override;
ULONG __stdcall Release() override;
//IAdd interface
HRESULT __stdcall Start(IUnknown* handler, BSTR data) override;
HRESULT __stdcall Stop(HRESULT* retCode) override;
HRESULT __stdcall Pause() override;
HRESULT __stdcall Resume() override;
private:
long m_nRefCount; //for managing the reference count
};
TestObj.cpp
HRESULT __stdcall CTestObj::Start(IUnknown* handler, BSTR data)
{
OutputDebugStringW(L"Start");
return S_OK;
}
HRESULT __stdcall CTestObj::Stop(HRESULT* retCode)
{
OutputDebugStringW(L"Stop");
return S_OK;
}
HRESULT __stdcall CTestObj::Pause()
{
OutputDebugStringW(L"Pause");
return S_OK;
}
HRESULT __stdcall CTestObj::Resume()
{
OutputDebugStringW(L"Resume");
return S_OK;
}
CTestObj::CTestObj()
{
InterlockedIncrement(&g_nComObjsInUse);
}
CTestObj::~CTestObj()
{
InterlockedDecrement(&g_nComObjsInUse);
}
HRESULT __stdcall CTestObj::QueryInterface(REFIID riid, void **ppObj)
{
OutputDebugStringW(L"QueryInterface");
if (IsEqualGUID(riid,IID_IUnknown))
{
*ppObj = static_cast<IUnknown*>(this);
AddRef();
return S_OK;
}
if (IsEqualGUID(riid,IID_ITaskHandler))
{
*ppObj = static_cast<ITaskHandler*>(this);
AddRef();
return S_OK;
}
*ppObj = NULL;
return E_NOINTERFACE;
}
ULONG __stdcall CTestObj::AddRef()
{
OutputDebugStringW(L"AddRef");
return InterlockedIncrement(&m_nRefCount);
}
ULONG __stdcall CTestObj::Release()
{
OutputDebugStringW(L"Release");
long nRefCount = 0;
nRefCount = InterlockedDecrement(&m_nRefCount);
if (nRefCount == 0) delete this;
return nRefCount;
}
TestClassFactory.h
class TestClassFactory : IClassFactory
{
public:
TestClassFactory();
~TestClassFactory();
HRESULT __stdcall QueryInterface(
REFIID riid,
void **ppObj) override;
ULONG __stdcall AddRef() override;
ULONG __stdcall Release() override;
HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,
const IID& iid,
void** ppv) override;
HRESULT __stdcall LockServer(BOOL bLock) override;
private:
long m_nRefCount;
};
TestClassFactory.cpp
extern long g_nComObjsInUse;
TestClassFactory::TestClassFactory()
{
InterlockedIncrement(&g_nComObjsInUse);
}
TestClassFactory::~TestClassFactory()
{
InterlockedDecrement(&g_nComObjsInUse);
}
HRESULT __stdcall TestClassFactory::CreateInstance(IUnknown* pUnknownOuter,
const IID& iid,
void** ppv)
{
OutputDebugStringW(L"CreateInstance");
if (pUnknownOuter != NULL)
{
return CLASS_E_NOAGGREGATION;
}
CTestObj* pObject = new CTestObj();
if (pObject == NULL)
{
return E_OUTOFMEMORY;
}
return pObject->QueryInterface(iid, ppv);
}
HRESULT __stdcall TestClassFactory::LockServer(BOOL bLock)
{
OutputDebugStringW(L"LockServer");
return E_NOTIMPL;
}
HRESULT __stdcall TestClassFactory::QueryInterface(
REFIID riid,
void **ppObj)
{
OutputDebugStringW(L"QueryInterface");
if (IsEqualGUID(riid, IID_IUnknown))
{
*ppObj = static_cast<IUnknown*>(this);
AddRef();
return S_OK;
}
if (IsEqualGUID(riid, IID_IClassFactory))
{
*ppObj = static_cast<IClassFactory*>(this);
AddRef();
return S_OK;
}
*ppObj = NULL;
return E_NOINTERFACE;
}
ULONG __stdcall TestClassFactory::AddRef()
{
OutputDebugStringW(L"AddRef");
return InterlockedIncrement(&m_nRefCount);
}
ULONG __stdcall TestClassFactory::Release()
{
OutputDebugStringW(L"Release");
long nRefCount = 0;
nRefCount = InterlockedDecrement(&m_nRefCount);
if (nRefCount == 0) delete this;
return nRefCount;
}
任务注册XML
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.6" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>2006-11-10T14:29:55.5851926</Date>
<Author>a</Author>
<URI>\b</URI>
<SecurityDescriptor>D:(A;;FA;;;BA)(A;;FA;;;SY)(A;;FRFX;;;WD)</SecurityDescriptor>
</RegistrationInfo>
<Triggers>
<LogonTrigger id="06b3f632-87ad-4ac0-9737-48ea5ddbaf11">
<Enabled>false</Enabled>
<Delay>PT1H</Delay>
</LogonTrigger>
</Triggers>
<Principals>
<Principal id="AllUsers">
<GroupId>S-1-1-0</GroupId>
<RunLevel>LeastPrivilege</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>Parallel</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>false</AllowHardTerminate>
<StartWhenAvailable>true</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>true</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession>
<UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT1H</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="AllUsers">
<ComHandler>
<ClassId>{36A976F4-698B-4B50-BE2C-83F815575199}</ClassId>
</ComHandler>
</Actions>
</Task>
答案 1 :(得分:1)
有3个问题:
1)AddRef和stub必须具有1个参数,例如IUnknown * This(或LPVOID This)。函数是否为__cdecl无关紧要,但COM仅与__stdcall函数一起使用。 系统期望函数从堆栈中自己清除参数。
2)AddRef必须至少不返回0,并且存根函数必须返回S_OK或0。也许这不是大问题。
3)调查显示针对类工厂的系统查询IUnknown,也许它执行QueryInterface而不是AddRef。但是无论如何,为每个IUnknown查询返回taskhandler都是不正确的。最好返回“工厂”。但是最好在IUnknown上返回This,无论如何,每个接口都是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);
}