views:

600

answers:

2

Instead of calling regsvr32.exe, one can register a .DLL using the following steps:

HINSTANCE hLib = ::LoadLibraryEx(dllPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
HRESULT (STDAPICALLTYPE* lpDllEntryPoint)(void);
(FARPROC&)lpDllEntryPoint = ::GetProcAddress(hLib, "DllRegisterServer");
const HRESULT hRes = (*lpDllEntryPoint)();

This works fine on Windows XP. Regrettably, it fails on Vista, but only with some specific DLLs. hRes becomes E_ACCESSDENIED. I guess this is a security issue. Does anyone know how to register a .DLL from code on Windows Vista?

Note: I was logged in as administrator when running this code.

+3  A: 

COM registration requires write access to the HKEY_LOCAL_MACHINE part of the registry.

Under UAC, write access to the HKEY_LOCAL_MACHINE requires an elevated administrator.

The easiest way to get an elevated process is to create it with a manifest that specifies 'requireAdministrator' access. - Look under the Project Properties -> Configuration Properties->Linker->Manifest File->UAC Execution Level to set the correct setting.

This means you will probably want to split your EXE into two parts. The 'normal' asInvoker part, and, when self registration is detected as a requirement, an elevated InstallMyself part. When the non elevated part detects a first-run type condition, it needs to use ShellExecute(Ex) to execute the FirstInstall.exe part - using CreateProcess or some other API will simply fail with a insufficient privilege error. ShellExecute will present the UAC prompt.

It is possible to use Application Isolation to load COM dll's without any registration step at all.


Is is unfortunate that the cause cannot be determined. However, if you are interested in doing further research, a tool that will help a lot would be Process Monitor from SysInternals. Process Monitor can log all the File, Registry and other access for a process, including all success and fail codes making it a lot easier to debug problems like this without having to resort to deeper means of reverse engineering.

Chris Becke
Thank you very much for your answer. Regrettably, it doesn't solve my problem, as I wasn't even running in UAC mode.
Dimitri C.
it would/should be a specific issue with the com dll you are trying to register. There is no real reason that a com dll should fail under Vista if registered directly from an elevated administrator account. Perhaps regsvr32.exe initializes the COM apartment before calling DllRegisterServer? (i.e. you need to call CoInitialize ?)If you made your own com dll and debugged the registration code being called directly im sure you wouldnt notice any problem.
Chris Becke
You are right! The problem occurs only with certain DLLs. Apparently, the given piece of code works well for most DLLs.
Dimitri C.
"Perhaps regsvr32.exe initializes the COM apartment before calling DllRegisterServer?" Indeed, I didn't call any initialization function. Therefore I reran my test, first calling CoInitialize() and/or OleInitialize(). Regrettably this did not solve the problem.
Dimitri C.
A: 

Regrettably, I couldn't get this to work for all DLLs, even with Chris Becke's excellent tips. I didn't want to spend too much time solving the problem, so now I simply call regsvr32.exe. I expect this .exe to be present on all Windows machines, so I guess it is a good enough solution.

Dimitri C.