This is one mean function! I've tried everything I can think of. I registered a type library with LoadTypeLibEx() which is a really easy function to use. I mistakingly thought UnregisterTypeLib() would be routine. Its most decidedly not! The error I keep getting with FormatMessage() is...
Error accessing the OLE registry.
Here is my entire Debug output file from a program run...
Output.txt Opened In WinMain()
Entering ExeUnregisterServer()
Error accessing the OLE registry.
Leaving ExeRegisterServer()
Exiting WinMain()!
Here is my call to UnregisterTypeLib()...
hr=UnRegisterTypeLib
(
LIBID_CFLibrary,
1,
0,
LOCALE_USER_DEFAULT,
SYS_WIN32
);
Here is the function description from msdn...
UnRegisterTypeLib
HRESULT UnRegisterTypeLib
(
REFGUID libID,
unsigned short wVerMajor,
unsigned short wVerMinor,
LCID lcid,
SYSKIND syskind
);
Removes type library information from the system registry. Use this API to allow applications to properly
uninstall themselves. In-process objects typically call this API from DllUnregisterServer.
Parameters
libID Globally unique identifier.
wVerMajor Major version number of the type library being removed.
wVerMinor Minor version number of the type library being removed.
lcid Locale identifier. There are two predefined LCID values.
The system default locale is LOCALE_SYSTEM_DEFAULT, and
the current user's locale is LOCALE_USER_DEFAULT.
syskind The target operating system (SYSKIND).
(SYS_WIN16, SYS_WIN32, SYS_MAC)
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not write to the file.
TYPE_E_REGISTRYACCESS The system registration database could not be opened.
TYPE_E_INVALIDSTATE The type library could not be opened.
Comments
In-process objects typically call this API from DllUnregisterServer.
The first parameter libID is a const from an midl generated file, so I don't see where that could be the problem. The typelib exists; I've checked it out with RegEdit and OleView.
The 2nd and 3rd parameters are the major and minor library version numbers, which I believe default to 1 and 0. I didn't set them, and 1.0 shows up in RegEdit & OleView. Maybe this is the problem. I just don't know???
The 4th parameter is a BIG TIME PROBLEM!!! Its where I think things might be falling apart, but everything I've tried so far hasn't worked. The docs say there are two built in enums for this and I've tried them both. They are...
LOCALE_SYSTEM_DEFAULT
and
LOCALE_USER_DEFAULT
Having failed at that I tried the unbelievably nasty double nested macro route of MAKELCID and MAKELANGID, which resolves to this...
MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT)
But that doesn't work either. By the way, I'm calling CoInitialize(NULL); first.
Here is Main.cpp that shows the whole function (its not too long)
//Main.cpp C:\Code\VStudio\VC++6\Projects\COM\CF\CFExe\Release\CFExe.exe
#include <Windows.h>
#include <stdio.h>
#include <string.h>
#include "CFInterfaces_i.c"
#include "CF.h"
#include "CFFactory.h"
#include "Registry.h"
DWORD g_allLocks;
const char g_szFriendlyName[] = "Com Object CF";
const char g_szVerIndProgID[] = "ComObject.CF";
const char g_szProgID[] = "ComObject.CF.1";
FILE* fp;
HRESULT ExeRegisterServer(HINSTANCE hInstance)
{
OLECHAR wcDllPath[256];
char szDllPath[256];
ITypeLib* pTypeLib;
HRESULT hr;
fprintf(fp,"Entering ExeRegisterServer()\n");
if(GetModuleFileName(hInstance, szDllPath, sizeof(szDllPath)/sizeof(char)))
{
mbstowcs(wcDllPath, szDllPath, 256);
hr=LoadTypeLibEx(wcDllPath, REGKIND_REGISTER, &pTypeLib);
if(FAILED(hr))
return hr;
else
fprintf(fp," LoadTypeLibEx() Apparently Succeeded!\n");
pTypeLib->Release();
fprintf(fp," szDllPath = %s\n", szDllPath);
fwprintf(fp,L" wcDllPath = %s\n", wcDllPath);
}
fprintf(fp,"Leaving ExeRegisterServer()\n\n");
return RegisterServer(szDllPath, &CLSID_CF,&LIBID_CFLibrary, g_szFriendlyName, g_szVerIndProgID, g_szProgID);
}
HRESULT ExeUnregisterServer(HINSTANCE hInstance) //LOCALE_USER_DEFAULT
{
OLECHAR wcDllPath[256];
char szDllPath[256];
void* pMsgBuf=NULL;
HRESULT hr;
fprintf(fp,"Entering ExeUnregisterServer()\n");
if(GetModuleFileName(hInstance, szDllPath, sizeof(szDllPath)/sizeof(char)))
{
mbstowcs(wcDllPath, szDllPath, 256);
hr=UnRegisterTypeLib
(
LIBID_CFLibrary,
1,
0,
LOCALE_USER_DEFAULT,
SYS_WIN32
);
}
if(FAILED(hr))
{
FormatMessage
(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
hr,
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
(LPTSTR)&pMsgBuf,0,NULL
);
fprintf(fp," %s",pMsgBuf);
LocalFree(pMsgBuf);
}
fprintf(fp,"Leaving ExeRegisterServer()\n\n");
return hr;
}
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
CFFactory Factory;
DWORD regID = 0;
MSG ms;
fp=fopen("Output.txt","w");
fprintf(fp,"Output.txt Opened In WinMain()\n\n");
CoInitialize(NULL);
if(strstr(lpCmdLine, "/r"))
ExeRegisterServer(hInstance);
if(strstr(lpCmdLine, "/u"))
ExeUnregisterServer(hInstance);
if(strstr(lpCmdLine, "/Embedding") || strstr(lpCmdLine, "-Embedding"))
{
fprintf(fp,"Got In Where We Were Loaded By SCM!\n");
CoRegisterClassObject(CLSID_CF, (IClassFactory*)&Factory, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, ®ID);
while(GetMessage(&ms, 0, 0, 0))
{
TranslateMessage(&ms);
DispatchMessage(&ms);
}
CoRevokeClassObject(regID);
}
CoUninitialize();
fprintf(fp,"Exiting WinMain()!\n");
fclose(fp);
return 0;
}
If you look at the Winmain() you'll see I set it up to register/unregister the local server exe with a program run like so (the name of the program is CFExe.exe)...
>CFExe.exe [/r] [/u]
Any ideas as to why I can't get this to work. I'm running under administrator privledges.