delphi winapi windows-7 com windows-vista

delphi - COM Elevation Moniker no puede elevar el servidor en Vista/Windows 7



winapi windows-7 (1)

Un error que está cometiendo es que está pasando la variable HInstance global de HInstance donde CoGetObject() espera un HWND lugar. Un identificador de HINSTANCE no es un identificador de HWND válido. Necesita utilizar un HWND real, como la propiedad Handle de un TForm , o bien, especifique 0 para que el Moniker de elevación elija una ventana adecuada para usted.

En cuanto al valor de retorno ERROR_ELEVATION_REQUIRED , todo lo que puedo decir es que su registro COM probablemente esté incompleto en alguna parte. Por favor, muestre los detalles de registro completos que en realidad están siendo almacenados en el Registro (no lo que su código cree que está almacenando, lo que el Registro en realidad está almacenando).

Se debe llamar a CoInitializeSecurity() cuando el proceso del servidor comienza a ejecutarse.

Creé un servidor COM local que requiere elevación y debería crearse una instancia desde un proceso no elevado.

Utilizando el artículo de MSDN sobre el moniker de elevación COM , configuré la clase del servidor siguiendo los requisitos especificados. El servidor se registró correctamente en la colmena HKLM.

El ejemplo de código:

procedure CoCreateInstanceAsAdmin(const Handle: HWND; const ClassID, IID: TGuid; PInterface: PPointer); var rBindOpts: TBindOpts3; sMonikerName: WideString; iRes: HRESULT; begin ZeroMemory(@rBindOpts, Sizeof(TBindOpts3)); rBindOpts.cbStruct := Sizeof(TBindOpts3); rBindOpts.hwnd := Handle; rBindOpts.dwClassContext := CLSCTX_LOCAL_SERVER; sMonikerName := ''Elevation:Administrator!new:'' + GUIDToString(ClassID); iRes := CoGetObject(PWideChar(sMonikerName), @rBindOpts, IID, PInterface); OleCheck(iRes); end; class function CoIMyServer.Create: IMyServer; begin CoCreateInstanceAsAdmin(HInstance, CLASS_IMyServer, IMyServer, @Result); end;

Cuando se trata de CoGetObject(PWideChar(sMonikerName), @rBindOpts, IID, PInterface) obtengo la pantalla UAC y confirmo que CoGetObject(PWideChar(sMonikerName), @rBindOpts, IID, PInterface) el servidor como administrador. Sin embargo, OleCheck(iRes) devuelve: "La operación solicitada requiere elevación" error.

De ese artículo que he leído sobre "elevación sobre el hombro (OTS)".

¿Es esta la única forma de que mi instancia de servidor esté disponible para el proceso no elevado? Si es así, ¿cuándo debe CoInitializeSecurity en el servidor?

Complete los detalles de registro

HKLM/SOFTWARE/Wow6432Node/Classes/CLSID {MyServer CLSID} (Default) = IMyServer Object LocalizedString = @C:/Program Files (x86)/MyServer/MyServer.exe,-15500 Elevation Enabled = 0x000001 (1) LocalServer32 (Default) = C:/PROGRA~2/MyServer/MYSERVER.EXE ProgID (Default) = uMyServer.IMyServer TypeLib (Default) = {TypeLib GUID} Version (Default) = 1.0 HKLM/SOFTWARE/Wow6432Node/Classes/Interface {GUID of IID_IMyServer} (Default) = IMyServer ProxyStubClsid32 (Default) = {Some GUID} TypeLib (Default) = {TypeLib GUID} Version = 1.0

Arriba están las únicas entradas que existen en mi registro después de registrar el servidor.

Detalles adicionales

Intenté sin éxito llamar a CoInitializeSecurity() implícitamente + estableciendo permisos de almuerzo según lo recomendado usando el siguiente código:

function GetSecurityDescriptor(const lpszSDDL: LPWSTR; out pSD: PSecurityDescriptor): Boolean; begin Result := ConvertStringSecurityDescriptorToSecurityDescriptorW(lpszSDDL, SDDL_REVISION_1, pSD, nil); end; function GetLaunchActPermissionsWithIL(out pSD: PSecurityDescriptor): Boolean; var lpszSDDL: LPWSTR; begin // Allow World Local Launch/Activation permissions. Label the SD for LOW IL Execute UP lpszSDDL := ''O:BAG:BAD:(A;;0xb;;;WD)S:(ML;;NX;;;LW)''; Result := GetSecurityDescriptor(lpszSDDL, pSD); end; function GetAccessPermissionsForLUAServer(out pSD: PSecurityDescriptor): Boolean; var lpszSDDL: LPWSTR; begin // Local call permissions to IU, SY lpszSDDL := ''O:BAG:BAD:(A;;0x3;;;IU)(A;;0x3;;;SY)''; Result := GetSecurityDescriptor(lpszSDDL, pSD); end; function SetAccessPermissions(hAppKey: HKEY; pSD: PSECURITY_DESCRIPTOR): Boolean; var dwLen: DWORD; iRes: LONG; begin dwLen := GetSecurityDescriptorLength(pSD); iRes := RegSetValueExA(hAppKey, ''AccessPermission'', 0, REG_BINARY, pSD, dwLen); Result := iRes = ERROR_SUCCESS; end; function SetLaunchActPermissions(hAppKey: HKEY; pSD: PSECURITY_DESCRIPTOR): Boolean; var dwLen: DWORD; iRes: LONG; begin dwLen := GetSecurityDescriptorLength(pSD); iRes := RegSetValueExA(hAppKey, ''LaunchPermission'', 0, REG_BINARY, pSD, dwLen); Result := iRes = ERROR_SUCCESS; end; procedure Initialize; var pSD: PSecurityDescriptor; sSubKey: WideString; hAppKey: HKEY; begin sSubKey := ''AppID/{GUID}''; RegOpenKeyW(HKEY_CLASSES_ROOT, PWideChar(sSubKey), hAppKey); if GetAccessPermissionsForLUAServer(pSD) then if not SetAccessPermissions(hAppKey, pSD) then raise Exception.Create(Format(''Access permissions aren''''t set. System error: %d'', [GetLastError()])); pSD := nil; if GetLaunchActPermissionsWithIL(pSD) then if not SetLaunchActPermissions(hAppKey, pSD) then raise Exception.Create(Format(''Launch permissions aren''''t set. System error: %d'', [GetLastError()])); end; initialization TAutoObjectFactory.Create(ComServer, TMyServer, Class_IMyServer, ciMultiInstance, tmApartment); Initialize;

Como un GUID de AppID intenté usar el mismo GUID de CLSID de mi interfaz de servidor y un nuevo GUID generado: el resultado era el mismo. AccessPermission valores de AccessPermission y LaunchPermission aparecieron en el lugar especificado después del registro del servidor.

También probado:

  • Especificación de ROTFlags = 1 en la clave AppId
  • Construyendo el servidor como una aplicación de 64 bits

Claves / valores de registro adicionales que creé manualmente:

[HKEY_LOCAL_MACHINE/SOFTWARE/Classes/AppID/MyServer.exe] @="MyServer" "AppID"="{My GUID}" [HKEY_LOCAL_MACHINE/SOFTWARE/Classes/AppID/{My GUID}] @="MyServer" "ROTFlags"=dword:00000001 [HKEY_LOCAL_MACHINE/SOFTWARE/Classes/CLSID/{My GUID}] @="MyServer Object" "AppID"="{My GUID}"