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, &regID);
    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.

I found the solution to this in my "Inside Distributed COM" book by Guy and Henry Eddon. The LCID parameter needs to be LANG_NEUTRAL. That works!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.