На моем компьютере с Windows есть две учетные записи: \ A1 и \ SYSTEM.Мой тестовый проект состоит из трех приложений:
- Server.exe - сервер com-of-proc.реализует объект Q
- Service.exe - out of out proc com service.реализует объект T
- Client.exe - клиентские приложения
Мой рабочий процесс показан ниже:
- Я вошел в систему\ A1.Я запускаю «Client.exe».
- Клиент создает экземпляр объекта «T»
- Клиент вызывает некоторый метод, скажем «T.ActivateQ», который создает экземпляр «Q».
Мое намерение - заставить Service.exe создать экземпляр «Q» в учетной записи \ A1, даже если Service.exe находится в учетной записи \ SYSTEM.
Каккак указано в этой статье, Windows имеет встроенную функциональность для выполнения такого рода активации, которая называется «активация сеанса к сеансу».Это реализовано с помощью Session Moniker («Session:! Clsid:»).
Учитывая это, я настроил «Server.exe» для запуска в качестве «Интерактивного пользователя» через dcomcnfg.Затем я реализовал функцию CoGetClassObjectInSession:
void CoGetClassObjectInSession(DWORD sessionId, Guid const& clsid, void *pvReserved, Guid const& riid, void **ppv)
{
ATL::CComQIPtr<IBindCtx> bindCtxInst;
COMCHK(CreateBindCtx(NULL, &bindCtxInst));
CComQIPtr<IMoniker> classMonikerInst;
COMCHK(::CreateClassMoniker(clsid, &classMonikerInst));
std::wstringstream ss;
ss << L"Session:" << std::dec << sessionId;
ULONG parsed;
ATL::CComQIPtr<IMoniker> sessionMonikerInst;
COMCHK(::MkParseDisplayNameEx(bindCtxInst, ss.str().c_str(), &parsed, &sessionMonikerInst));
ATL::CComQIPtr<IMoniker> classObjectMoniker;
COMCHK(sessionMonikerInst->ComposeWith(classMonikerInst, FALSE, &classObjectMoniker));
ATL::CComPtr<IClassFactory> sessionFactoryInst;
COMCHK(classObjectMoniker->BindToObject(bindCtxInst, NULL, riid, ppv));
}
и использую ее в сервисе:
HRESULT CMyActivator::Activate()
{
try
{
// Impersonate the client
CComQIPtr<IServerSecurity> ss;
COMCHK(::CoGetCallContext(__uuidof(IServerSecurity), reinterpret_cast<void**>(&ss)));
callctx_impersonation_handle _handle(ss);
ImpersonationScope _imp_scope(_handle);
CComQIPtr<IClassFactory> ppv;
CoGetClassObjectInSession(/*session id for \\A1*/ 1, Guid(__uuidof(Q)), nullptr, Guid(__uuidof(IClassFactory)), reinterpret_cast<void**>(&ppv));
ENSURE(NULL != ppv, "'ppv' should not be null");
return S_OK;
}
catch(std::exception const& ex)
{
return E_FAIL;
}
catch(...)
{
return E_FAIL;
}
}
Но ничего не происходит.Я имею в виду, что служба всегда запускает сервер в сеансе 0, который соответствует учетной записи \ SYSTEM.
Параметры безопасности клиента:
COMCHK(::CoSetProxyBlanket(
activatorQ
, RPC_C_AUTHN_DEFAULT
, RPC_C_AUTHZ_DEFAULT
, NULL
, RPC_C_AUTHN_LEVEL_DEFAULT
, RPC_C_IMP_LEVEL_DELEGATE
, NULL
, EOAC_DYNAMIC_CLOAKING));
Файл Server.rgs:
HKLM
{
NoRemove Software
{
NoRemove Classes
{
NoRemove AppID
{
ForceRemove '%APPID%' = s 'Test Server'
{
val RunAs = s 'Interactive User'
}
}
}
}
}
Я что-то не так делаю?
ОБНОВЛЕНИЕ Я наконец нашел решение.В сценарии регистрации для класса 'Q' отсутствует поле AppID:
HKCR
{
NoRemove CLSID
{
ForceRemove {6FDE856C-F1B2-4466-8435-20F4AEF2C2E1} = s 'SMonClass Class'
{
ForceRemove Programmable
LocalServer32 = s '%MODULE%'
{
val ServerExecutable = s '%MODULE_RAW%'
}
TypeLib = s '{4FA39B0F-5B24-43C6-A5B1-11D8F34277B7}'
Version = s '1.0'
--> val AppID = s '%APPID%'** <-- This line
}
}
}