"Native" COM development

Started by
2 comments, last by Plerion 14 years, 1 month ago
Hello everybody! Maybe some of you know ATL and COM. ATL helps a lot developping COM-Servers by providing millions of makros, thousands of templates and a cryptic logic behind all that. Actually i know that pretty good and making a COM-server isnt a hard job for me using ATL so i decided to step up and try to provide all the neccessary functions by myself without any ATL or whatever. I came pretty far till yet but now im stuck. Im trying to write a shell-extension for the tooltips. Or: Overloading/Overwriting IQueryInfo::GetInfoTip. I dont do any checks yet in my code to keep it clear and readable, the checks will follow when the basic concept works. 1. Registering is already done in the registry, so DllRegisterServer does nothing. 2. DllCanUnloadNow doesnt work yet, i need to kill explorer.exe when i want to unload my dll, but that doesnt matter, ill cover that later. 3. My factory-class works, it gets called and returns a new factory for creating instances of my class 4. ShellExt::QueryInterface gets called. Here is the code:

#pragma comment (linker, "/EXPORT:DllRegisterServer=_DllRegisterServer@0,PRIVATE")
#pragma comment (linker, "/EXPORT:DllGetClassObject=_DllGetClassObject@12,PRIVATE")
#pragma comment (linker, "/EXPORT:DllUnregisterServer=_DllUnregisterServer@0,PRIVATE")
#pragma comment (linker, "/EXPORT:DllCanUnloadNow=_DllCanUnloadNow@0,PRIVATE")

static int gRefCount = 0;

STDAPI DllRegisterServer()
{
	return S_OK;
}

STDAPI DllUnregisterServer()
{
	return S_OK;
}

STDAPI DllCanUnloadNow()
{
	MessageBoxA(0, "CanUnload", "", MB_OK);
	return gRefCount ? S_FALSE : S_OK;
}

STDAPI DllGetClassObject(const IID& rclsid, const IID& iid, LPVOID* ppv)
{
	CClassFactory<ShellExt>* pCf = new CClassFactory<ShellExt>();
	pCf->QueryInterface(iid, ppv);
	pCf->Release();
	return S_OK;
}

STDMETHODIMP ShellExt::GetInfoTip(DWORD, LPWSTR* ppOut)
{
	MessageBoxA(0, "Test", "", MB_OK);
	IMalloc* pMalloc;
	SHGetMalloc(&pMalloc);
	
	wchar_t wszText[] = L"This a part of the tooltip!";
	*ppOut = (LPWSTR)pMalloc->Alloc((wcslen(wszText) + 1) * sizeof(wchar_t));
	wcscpy(*ppOut, wszText);
	pMalloc->Release();
	return S_OK;
}

STDMETHODIMP ShellExt::Load(LPCOLESTR wszFile, DWORD)
{
	return S_OK;
}

ULONG ShellExt::AddRef()
{
	++gRefCount;
	return gRefCount;
}

ULONG ShellExt::Release()
{
	--gRefCount;
	return gRefCount;
}

HRESULT __stdcall ShellExt::QueryInterface(const IID& rrid, void** ppvObject)
{
	*ppvObject = this;
	AddRef();
	return S_OK;
}
After QueryInterface sadly nothing happens anymore. From what i could see it calls my derivated versions of IPersistFile::IsDirty and IPersistFile::GetClassID. They both return E_NOTIMPL. This is no problem, in the ATL-counterpart im doing it exactly the same way and there it works. So i guess my problem is in QueryInterface. Does anyone have some experience in COM and can help me? Or does anyone know a forum or place where COM-people are? Thanks in advance Plerion
Advertisement
I'm sure you know this, but QueryInterface is only supposed to return a pointer if your class actually supports that interface...

If you want to make your life a little easier with QI, you can use QISearch.
QISearch sounds really interesting, im trying to implement that at the moment but sadly it didnt had any effect in my program. Still there is no call to my IQueryInfo-functions:
#define VTABLE_OFFSET(cls, iface)    ((PCHAR)(iface*)(cls*) 1 - (PCHAR)1)HRESULT __stdcall ShellExt::QueryInterface(const IID& riid, void** ppvObject){	static const QITAB qit[] = 	{		{&IID_IPersistFile, VTABLE_OFFSET(ShellExt, IPersistFile)},		{&IID_IQueryInfo, VTABLE_OFFSET(ShellExt, IQueryInfo)},		{NULL, 0}	};    return QISearch(this, qit, riid, ppvObject);}


Tested QISearchs returnvalue and it doesnt fail for 3 calls, and it fails for the rest.
Argh, never mind, stupid plerion forgot to set the ThreadingModel-key in the registry. So it spammed QueryInterface for all that marshalling-stuff.

This topic is closed to new replies.

Advertisement