tags:

views:

335

answers:

2

This is a continuation of Register implementation of a com interface ; only now I've got actual code that needs debugging.

I've got two COM objects, one that implements IAudioSessionEvents and one that implements IClassFactory and produces the first object.

The following code registers those objects (in accordance with my understanding of COM registration):

BOOL RegisterClassManually(WCHAR* szGuid, WCHAR* szDllPath)
{
WCHAR szKeyName[1024];
wsprintf(szKeyName, TEXT("Software\\Classes\\CLSID\\%s"), szGuid);

if(!RegisterKeyValue(HKEY_CURRENT_USER, szKeyName, NULL, TEXT(DESCRIPTION_CONST))) return false;

wsprintf(szKeyName, TEXT("Software\\Classes\\CLSID\\%s\\InprocServer32"), szGuid);

if(!RegisterKeyValue(HKEY_CURRENT_USER, szKeyName, NULL, szDllPath)) return false;
if(!RegisterKeyValue(HKEY_CURRENT_USER, szKeyName, TEXT("ThreadingModel"), TEXT("Apartment"))) return false;

return true;
}

STDAPI DllRegisterServer()
{
//Write data to HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\{GUID}
// Also ""\\InProcServer32
// Also "".ThreadingModel = "Apartment"

WCHAR* szGuid;
WCHAR szDllPath[512];
StringFromCLSID(CLSID_AudioEventsFactory, &szGuid);

if(g_dllModule == NULL) return SELFREG_E_CLASS;

GetModuleFileName(g_dllModule, szDllPath, 512);

if(!RegisterClassManually(szGuid, szDllPath)) return SELFREG_E_CLASS;

StringFromCLSID(CLSID_AudioEvents, &szGuid);

if(!RegisterClassManually(szGuid, szDllPath)) return SELFREG_E_CLASS;

return S_OK;
}

I've omitted RegisterKeyValue(...), its simple registry code that I've confirmed works as intended.

This code attempts to use these COM objects:

IAudioSessionEvents* listener = NULL;

IClassFactory* factory = NULL;

//Fails on this call
hr = CoGetClassObject(CLSID_AudioEventsFactory, CLSCTX_ALL, NULL, __uuidof(IClassFactory), (void**)&factory);

if(hr != S_OK)
{
 ... Report Error ...
}

hr = factory->CreateInstance(NULL, __uuidof(IAudioSessionEvents), (void**)&listener);

The call to CoGetClassObject(...) returns hr = 0x80040111 (ClassFactory cannot supply requested class).

Implementation of DllGetClassObject (per 1800 INFORMATION pointing out the ommision):

STDAPI DllGetClassObject(const CLSID& clsid,
                     const IID& iid,
                     void** ppv)
{

if (clsid == __uuidof(IClassFactory))
{
    AudioEventsFactory *pFact = new AudioEventsFactory;
    if (pFact == NULL)
        return E_OUTOFMEMORY;
    else
    {
        return pFact->QueryInterface(iid , ppv);
    }
}

return CLASS_E_CLASSNOTAVAILABLE;
}

What am I doing wrong here? I suspect its in the COM registration, but can't find anything that actually lays out exactly what is required in the registry. I've sort of reverse-engineered what I store at the moment.

+1  A: 

What is the content of your DllGetClassObject function? It is this that is eventually called in response to the CoGetClassObject call.

1800 INFORMATION
Woops, I've added it.
Kevin Montrose
Oh geez, I'm an idiot. I should be checking clsid against CLSID_AudioEventsFactory, not IID_IClassFactory in DllGetClassObject(...).
Kevin Montrose
+1  A: 

This article COM in plain C has a pretty good description how you have to implement a COM dll without using ATL. As pointed by 1800 DllGetClassObject will be called to create a COM object. Also The COM Programmer's Cookbook is nice reference about COM.

Ismael