How to iterate the vtable of COM coclass? - com

How can I iterate/access the vtable of COM coclass which will implement the methods of its exposed interfaces?
I need to access the part of the vtable where all addresses of exposed methods of its interfaces are stored.
e.g. Math is COM object, its exposed interface is "Operations" and "Sum" is the method of this interface, how do I get the address of "Sum"?

I'm not going to ask why are you doing it this way, but perhaps this could help...
Every COM object must implement at least the IUnknown interface. Hence, the first four bytes of the COM object instance is the pointer to IUnknown object. The first four bytes of the IUnknown object (and any other object with virtual functions) is the pointer to vtbl.
(There is no error checking in this example, so please don't split hair on that subject.)
I used an instance of IReferenceClock for demonstration.
int main()
{
CoInitialize( NULL );
IReferenceClock* pRefClock;
HRESULT hr = CoCreateInstance( CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, IID_IReferenceClock, (void**)&pRefClock );
DWORD* pIUnknownAddress = (DWORD*)pRefClock;
DWORD* pVTBLaddress = (DWORD*)*pIUnknownAddress;
// for example, the next interface could be accessed like this
DWORD* pNextInterfaceAddress = ( (DWORD*)pRefClock ) + 1;
DWORD* pNextVTBLaddress = (DWORD*)*pNextInterfaceAddress;
// and you would access virtual functions in the same way as QueryInterface, AddRef and Release below in this example
HRESULT (__stdcall *pQueryInterfaceFunction)(void*, REFIID, void**);
ULONG (__stdcall *pAddRef)( void* );
ULONG (__stdcall *pRelease)( void* );
// IUnknown looks like this:
//
// virtual HRESULT QueryInterface( REFIID riid, void** ppvObject);
// virtual ULONG AddRef( void );
// virtual ULONG Release( void );
//
// So, the first function in vtbl is QueryInterface, the second is AddRef...
pQueryInterfaceFunction = (HRESULT (__stdcall*)(void*, REFIID, void**))*pVTBLaddress;
pAddRef = (ULONG (__stdcall *)( void* ))*( pVTBLaddress + 1 );
pRelease = (ULONG (__stdcall *)( void* ))*( pVTBLaddress + 2 );
// Note: extra void* is actually this pointer.. see below that we pass pRefClock to every call
IUnknown* pUnknown;
UINT nRefCount;
hr = pQueryInterfaceFunction( pRefClock, IID_IUnknown, (void**)&pUnknown );
if( SUCCEEDED( hr ) )
{
nRefCount = pUnknown->Release();
ATLTRACE( TEXT( "nRefCount = %d\n" ), nRefCount );
}
nRefCount = pAddRef( pRefClock );
ATLTRACE( TEXT( "nRefCount after AddRef() call = %d\n" ), nRefCount );
nRefCount = pRelease( pRefClock );
ATLTRACE( TEXT( "nRefCount after Release() call = %d\n" ), nRefCount );
nRefCount = pRefClock->Release();
CoUninitialize();
return 0;
}

Sorry to answer with a question, but I have to ask "from where?"
If you mean, how can you iterate through the vtable from a COM client, I don't think you can. On the client side, all you have is a proxy that knows how to communicate (maybe cross-apartment or cross-process) with the COM server. You could maybe probe the vtable of that proxy, but it can never tell you the addresses of the functions inside the COM server.
Of course, if the server is actually running in a different process, the address of the functions might be of little use to you. Even if the server is in the same process, but in a different apartment, getting function addresses might be dangerous: you could call the functions directly, circumventing COM's interception, and break the server class's assumptions around calling thread, etc.
I guess that iterating the vtable is a means-to-an-end...? Maybe post what you're actually trying to do and I think COM probably has a way to do it.

Related

COM interface (MIDL): size_is for an optional [out] parameter

In short, in the following definition:
HRESULT GetStuff([in] long count,
[out, size_is(count)] long * a,
[out, size_is(count)] long * b);
which fills a and b with count elements, is it legal for the caller to set a and / or b to null?
I want to allow the caller to query only one set of results, so the method may be called with
long only_a_s[10];
itf->GetStuff(10, a, 0);
Do I need to modify the MIDL declaration? I'm unsertain how the pointer/pointer_default attributes play into this.
Notes: There's overhead in acquiring them separately, but so is acquiring values the caller doesn't need, so separate getters or always having to get both is sub-par. I know it does work for inproc / in-apartment calls, but would the MIDL-generated proxy/stub deal with that correctly?
You cannot pass a null pointer as an argument (a.k.a. top-level pointer), as they're [ref] by default.
But you may pass a null pointer, in or out, for non-top-level pointers.
The IDL method definition goes like this:
HRESULT GetStuffAB([in] long countA,
[in] long countB,
[out, size_is(, *pItemsA)] long **pA,
[out, size_is(, *pItemsB)] long **pB,
[out] long *pItemsA,
[out] long *pItemsB);
The C++ implementation:
HRESULT CMyClass::GetStuffAB(long countA,
long countB,
long **pA,
long **pB,
long *pItemsA,
long *pItemsB)
{
// COM stubs will check this for you
// However, you should (must?) manually check in same apartment calls
if (!pA) return E_POINTER;
if (!pB) return E_POINTER;
if (!pItemsA) return E_POINTER;
if (!pitemsB) return E_POINTER;
*pA = nullptr;
*pB = nullptr;
*pItemsA = 0L;
*pItemsB = 0L;
if (countA < 0) return E_INVALIDARG;
if (countB < 0) return E_INVALIDARG;
// Get amount of As into *pItemsA if countA > 0
// Get amount of Bs into *pItemsB if countB > 0
if (*pItemsA < 0) return E_FAIL;
if (*pItemsB < 0) return E_FAIL;
if (*pItemsA > 0)
{
*pA = CoTaskMemAlloc(sizeof(long) * *pItemsA);
if (!*pA) return E_OUTOFMEMORY;
}
if (*pItemsB > 0)
{
*pB = CoTaskMemAlloc(sizeof(long) * *pItemsB);
if (!*pB)
{
if (*pA)
{
// You should not assume the memory will be freed by the caller
// in such drastic situations, so free and clear *pA here before returning
CoTaskMemFree(*pA);
*pA = nullptr;
}
return E_OUTOFMEMORY;
}
}
// Get As into *pA and Bs into *pB
// Or just copy them if getting the amounts implied getting the items
// You could just as well always return S_OK
return (*pItemsA > 0 || *pItemsB > 0) ? S_OK : S_FALSE;
}
Not shown is whatever other code you must implement yourself to get the amount of As and the amount of Bs, and the As and Bs themselves.
If you must get the items to know the amounts, and you're not using RAII, you should free those resources manually before returning.
As an alternative to using CoTaskMemAlloc and CoTaskMemFree, you may want to use ATL's CComHeapPtr, which will automatically free memory RAII-style, thus simplifying your code. Just make sure you call Detach into *pA and *pB before returning successfully.

how to assign pointer in a managed array of pointers c++/cli?

I am new to managed code and i need to pass array of pointers to different structures to windows form using C++/CLI , but it didn`t work !
My problem is in the managed array, how can i correctly access its elements .
The code sequence :
array<void*> ^ ptr;//here ptr value is undefined , type array<void*> ^
ptr = gcnew array<void*> (2);// length 0x2 , 0x0 and 0x1 values are undefined of type void
class1::struct1 structObj1;
class2::struct2 structObj2;
ptr[0] = &structObj1;// value is empty of type void!!
ptr[1] = &structObj2;//value is empty of type void!!
When i watched ptr , i found the above comments.
Notice that repeating code but using unmanaged array works probably
void* ptr[2];//here ptr value is undefined , type void*[]
class1::struct1 structObj1;
class2::struct2 structObj2;
ptr[0] = &structObj1;// value is address1 of type void*
ptr[1] = &structObj2;//value is address2 of type void*
Can anyone see where is the problem??
Do I need to use unmanaged array then convert to managed? If yes, how can I do it ??
Passing unmanaged pointers in a managed array may be valid C++/CLI, but it's definitely not the ideal way to do things. Do consider creating a custom managed class (ref class in C++/CLI) to hold the structures, instead of passing around pointers.
For this, I'm assuming that struct1 and struct2 are unmanged structs. This answer only applies if that is the case.
Your existing code works for me. Here's my version, with some debugging added in.
public struct struct1 { int foo; };
public struct struct2 { float bar; };
int main(array<System::String ^> ^args)
{
array<void*> ^ ptr;
ptr = gcnew array<void*> (2);
for(int i = 0; i < ptr->Length; i++)
Debug::WriteLine("ptr[{0}] = {1:X8}", i, reinterpret_cast<int>(ptr[i]));
struct1 structObj1;
struct2 structObj2;
ptr[0] = &structObj1;
ptr[1] = &structObj2;
for(int i = 0; i < ptr->Length; i++)
Debug::WriteLine("ptr[{0}] = {1:X8}", i, reinterpret_cast<int>(ptr[i]));
struct1* pointerToStructObj1 = reinterpret_cast<struct1*>(ptr[0]);
structObj1.foo = 4;
Debug::WriteLine("pointerToStructObj1->foo = {0}", pointerToStructObj1->foo);
}
Output:
ptr[0] = 00000000
ptr[1] = 00000000
ptr[0] = 0013F390
ptr[1] = 0013F394
pointerToStructObj1->foo = 4
Edit
To use Debug::WriteLine, add using namespace System::Diagnostics.
The debugger doesn't know how to display the contents of a void*, so it just displays blank. It does display a null pointer differently, though: null shows up as <undefined value>, non-null shows up as just blank.
My philosophy on C++/CLI is: If you're going to write managed code, write managed code. Consider replacing your vector with a managed List. If you still need unmanaged objects, I strongly urge you to consider writing a managed class with properly typed pointers, rather than a void* array.
To implement such a class, create whatever fields you need, just be sure that they're pointers, not direct. (vector<foo>* instead of vector<foo>.) Create the objects with new in the constructor, and delete them in the destructor (which is called on Dispose) & finalizer.

Debugging unmanaged callback problems

Apologies in advance here for the length of the question.
I have a closed source and undocumented COM object - an unmanaged DLL - that I'm attempting to integrate into a Windows service written in C#. The COM object wraps access to some hardware that the service needs to interact with.
I'm not able to get interface documentation or source for the object. All I have to go on is the object itself, three [closed source undocumented] clients that interact with the COM object, and a fair amount of domain specific knowledge.
So far this has been a very tough nut to crack - one week and counting.
I was able to obtain the object's CLSID from the registry - this allowed me to instantiate it in the service.
The next step was to find the IIDs for the interface(s) that I need to use. The particular methods that I was looking for are not exported. I don't have PDBs. There doesn't appear to be any typelib info and the OLE-COM Object Viewer refuses to open the COM object. IDispatch is not implemented either, so it has been a matter of digging. I eventually succeeded in identifying two IIDs by manually searching the binaries for GUIDs and eliminating unique and/or known GUIDs. At this point I'm confident that the IIDs are correct.
The IIDs are obviously useless without corresponding method info. For that I was forced to resort to reversing with IDA. Correlating references to the GUIDs with my knowledge of the hardware functions and the rough disassembly allowed me to make some educated guesses about the structure and purpose of the interfaces.
Now I'm at the point where I need to attempt to use the interfaces to interact with the hardware... and this is where I'm stuck.
From the disassembly, I know that the first method I have to call looks like this:
HRESULT __stdcall SetStateChangeCallback(LPVOID callback);
The callback signature looks something like this:
HRESULT (__stdcall *callbackType)(LPVOID data1, LPVOID data2)
Here is my service code:
[ComImport, System.Security.SuppressUnmanagedCodeSecurity,
Guid(...),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface AccessInterface
{
[PreserveSig]
int SetStateChangeCallback(IntPtr callbackPtr);
...
}
[UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)]
private delegate int OnStateChangeDelegate(IntPtr a, IntPtr b);
private int OnStateChange(IntPtr a, IntPtr b)
{
Debug("***** State change triggered! *****");
}
private Guid _typeClsid = new Guid(...);
private Guid _interfaceIid = new Guid(...);
private object _comObj = null;
private AccessInterface _interface = null;
private OnStateChangeDelegate _stateChangeDelegate = null;
private IntPtr _functionPtr = IntPtr.Zero;
private void InitHardware()
{
Type t = Type.GetTypeFromCLSID(_typeClsid);
_comObj = Activator.CreateInstance(t);
if (_comObj == null)
{
throw new NullReferenceException();
}
_interface = _comObj as AccessInterface;
if (_interface == null)
{
throw new NullReferenceException();
}
_stateChangeDelegate = new OnStateChangeDelegate(OnStateChange);
_functionPtr = Marshal.GetFunctionPointerForDelegate(_stateChangeDelegate);
int hr = _interface.SetStateChangeCallBack(_functionPtr);
// hr (HRESULT) == 0, indicating success
}
Now, I can run this code successfully but only if I pass IntPtr.Zero to SetStateChangeCallBack(). If I pass a real reference, the service crashes within a matter of seconds after calling SetStateChangeCallBack() - presumably when the COM object tries to invoke the callback for the first time - with exception code 0xc0000005.
The fault offset is consistent. With the aid of IDA and the previously generated disassembly I was able to identify the area where the problem occurs:
06B04EF7 loc_6B04EF7: ; CODE XREF: 06B04F49j
06B04EF7 lea eax, [esp+0Ch]
06B04EFB push eax
06B04EFC mov ecx, ebx
06B04EFE call near ptr unk_6B06660
06B04F03 test eax, eax
06B04F05 jl short loc_6B04F4B
06B04F07 mov esi, [esp+0Ch]
06B04F0B test esi, esi
06B04F0D jz short loc_6B04F45
06B04F0F push 36h
06B04F11 lea ecx, [esp+18h]
06B04F15 push 0
06B04F17 push ecx
06B04F18 call near ptr unk_6B0F960
06B04F1D mov edx, [esp+1Ch]
06B04F21 push edx
06B04F22 lea eax, [esp+24h]
06B04F26 push esi
06B04F27 push eax
06B04F28 call near ptr unk_6B0F9E0
06B04F2D push esi
06B04F2E call near ptr unk_6B0C8D2
06B04F33 mov eax, [edi+4]
06B04F36 mov ecx, [eax]
06B04F38 add esp, 1Ch
06B04F3B lea edx, [esp+14h]
06B04F3F push edx
06B04F40 push eax
06B04F41 mov eax, [ecx] ; Crash here!
06B04F43 call eax
06B04F45
06B04F45 loc_6B04F45: ; CODE XREF: 06B04F0Dj
06B04F45 cmp dword ptr [edi+28h], 0
06B04F49 jnz short loc_6B04EF7
06B04F4B
06B04F4B loc_6B04F4B: ; CODE XREF: 06B04F05j
06B04F4B pop esi
06B04F4C pop ebx
06B04F4D pop edi
06B04F4E add esp, 40h
06B04F51 retn
The crash is at offset 0x06B04F41 (ie. "mov eax, [ecx]").
Corresponding pseudo code function from the disassembly (note assembler above starts at the do loop):
void __thiscall sub_10004EE0(int this)
{
int v1; // edi#1
void *v2; // esi#4
void *v3; // [sp+4h] [bp-40h]#3
int v4; // [sp+8h] [bp-3Ch]#5
char v5; // [sp+Ch] [bp-38h]#5
v1 = this;
if ( *(_DWORD *)(this + 4) )
{
if ( *(_DWORD *)(this + 40) )
{
do
{
if ( sub_10006660(v1 + 12, (int)&v3) < 0 )
break;
v2 = v3;
if ( v3 )
{
memset(&v5, 0, 0x36u);
unknown_libname_44(&v5, v2, v4);
j_j__free(v2);
// Crash on this statement!
(*(void (__stdcall **)(_DWORD, char *))**(void (__stdcall ****)(_DWORD, _DWORD))(v1 + 4))(
*(_DWORD *)(v1 + 4),
&v5);
}
}
while ( *(_DWORD *)(v1 + 40) );
}
}
}
I'm convinced that I am not passing the function pointer to the COM object correctly, but I'm stuffed if I can figure out how to do it properly. I've tried [in order of desperation!]:
_functionPtr
_functionPtr.ToPointer() [as void* param]
_functionPtr.ToInt32() [as int param]
_stateChangeDelegate [as OnStateChangeDelegate param]
OnStateChange [as OnStateChangeDelegate param]
using CallingConvention.Cdecl for the delegate
adding static qualifier to variables and functions
changing signature of the callback (including removing the return value, changing the parameters to ints, modifying the number of parameters)
adding a level of indirection [by storing _functionPtr.ToInt32() in a block of memory allocated with Marshal.AllocCoTaskMem()]
In some cases the changes triggered different crash locations... like crashes in ntdll, or at 06B04F36. In most cases the crash is as described above - at 06B04F41.
When I attach IDA Pro to the process it looks like the address of my callback is going into EAX at 06B04F40, and the address that the COM object attempts to use has a fixed offset from that. For example:
EAX (correct address) = 000A1392
ECX (used address) = 0A1378B8
The last 4 digits of ECX are always 78B8.
So again, I think I'm not passing the delegate or function pointer correctly but I'm not sure how to do it. I guess the fact that the service is running in a WOW64 environment could also be having an impact.
My question: what would you suggest I do to (1) get more information about the problem and/or (2) solve the problem?
Keep in mind I don't have access to any source code except the full code for the C# service. I'm using the free version of IDA Pro so I don't seem to be able to do anything more useful than reverse to pseudo code or attach to the process and catch the crash exception. It is not possible to run the service from VS in debug mode so I really only have logging on that side... not that I think it would be much good as the problem is triggering in the unmanaged code where I don't have compilable/easily-readable source. Maybe I'm wrong?
Thank you sincerely for your advice!
Edit:
Well, after another day bashing my head against the problem I figured if I couldn't succeed from C# I would try and create a minimal C++ test application to do what the service has to do... and I was successful!
IAccessInterface : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE SetCallback(
/* [in] */ LPVOID pCallBack) = 0;
virtual HRESULT STDMETHODCALLTYPE SetDevice(
/* [in] */ char* context1,
/* [in] */ LPVOID context2,
/* [in] */ LPVOID context3) = 0;
virtual HRESULT STDMETHODCALLTYPE CloseDevice() = 0;
};
IAccessInterface* pInterface;
int __stdcall CallbackImpl(char* context, char* data)
{
printf("Callback succeeded!\r\n");
return 0;
}
void CleanUp(bool deviceOpen)
{
if (pInterface != NULL)
{
if (deviceOpen)
{
pInterface->SetCallback(NULL);
pInterface->CloseDevice();
}
pInterface->Release();
pInterface = NULL;
}
CoUninitialize();
}
int _tmain(int argc, _TCHAR* argv[])
{
GUID objClsid = GUID();
GUID interfaceIid = GUID();
CoInitialize(NULL);
int hr = CoCreateInstance(objClsid, 0, 1, interfaceIid, (void**)&pInterface);
if (!pInterface || !SUCCEEDED(hr))
{
CleanUp(false);
return 1;
}
LPVOID ptr = &callbackImpl;
LPVOID ptr2 = &ptr;
hr = pInterface->SetCallback(&ptr2);
if (!SUCCEEDED(hr))
{
CleanUp(false);
return 1;
}
char* context1 = "a_device_identifier";
hr = pInterface->SetDevice(context1, NULL, NULL);
if (!SUCCEEDED(hr))
{
CleanUp(false);
}
Sleep(30000); // give time for device to initialise and trigger callbacks (testing only)
// clean up
CleanUp(true);
return 0;
}
So now I just need to find a way to replicate the following three lines with equivalent C#:
LPVOID ptr = &CallbackImpl;
LPVOID ptr2 = &ptr;
hr = pInterface->SetCallback(&ptr2);
It seems unnecessary (even suspicious) that so many levels of indirection would be required. Maybe I haven't fully understood the disassembly. At this point the most important thing is that it works.
So any comments about how to achieve this from C# would be welcome!

Usage of Minidump within a COM Object

I'm developing a COM dll which is an add-in to MSoffice. Since I'm not creating any logs within add-in I would like to add a crash report generator into my add-in.
Hopefully 'Minidump' would be the best choice, but I have never use Minidump inside a COM object.
I appreciate if somebody can point out possibilities of creating such crash dump with minidump
inside a COM object.
Thank You
I suspect you should be able to use the technique described here, create a minidump.
The actual implementation is
straightforward. The following is a
simple example of how to use
MiniDumpWriteDump.
#include <dbghelp.h>
#include <shellapi.h>
#include <shlobj.h>
int GenerateDump(EXCEPTION_POINTERS* pExceptionPointers)
{
BOOL bMiniDumpSuccessful;
WCHAR szPath[MAX_PATH];
WCHAR szFileName[MAX_PATH];
WCHAR* szAppName = L"AppName";
WCHAR* szVersion = L"v1.0";
DWORD dwBufferSize = MAX_PATH;
HANDLE hDumpFile;
SYSTEMTIME stLocalTime;
MINIDUMP_EXCEPTION_INFORMATION ExpParam;
GetLocalTime( &stLocalTime );
GetTempPath( dwBufferSize, szPath );
StringCchPrintf( szFileName, MAX_PATH, L"%s%s", szPath, szAppName );
CreateDirectory( szFileName, NULL );
StringCchPrintf( szFileName, MAX_PATH, L"%s%s\\%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",
szPath, szAppName, szVersion,
stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
GetCurrentProcessId(), GetCurrentThreadId());
hDumpFile = CreateFile(szFileName, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
ExpParam.ThreadId = GetCurrentThreadId();
ExpParam.ExceptionPointers = pExceptionPointers;
ExpParam.ClientPointers = TRUE;
bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL);
return EXCEPTION_EXECUTE_HANDLER;
}
void SomeFunction()
{
__try
{
int *pBadPtr = NULL;
*pBadPtr = 0;
}
__except(GenerateDump(GetExceptionInformation()))
{
}
}

What is the correct way to cast when using ATL and IUnknownPtr?

During the modification of an existing ATL COM object I came across an article from the "The Old New Thing" blog called "The ways people mess up IUnknown::QueryInterface" and there was a discussion in the comments section that started when one of the respondents (Norman Diamond) pointed out that that in one of the article's examples that the cast to void** was incorrect.
However when I try and correct my code to do the casting properly I end up with a memory leak.
The example was as follows:
IShellFolder *psf = some object;
IUnknown *punk = NULL;
psf->QueryInterface(IID_IUnknown, (void**)&punk);
Norman said
punk is not a void*. punk is an IUnknown*.
void** is not a universal pointer type. void* is a universal pointer type, and char* and relatives are grandparented in to be equivalent in that way, but void** is not.
If you want to obey the calling convention and avoid horrible deaths, you have to do this:
IUnknown *punk;
void *punkvoid;
psf->QueryInterface(IID_IUnknown, &punkvoid);
punk = (IUnknown *)punkvoid;
Lots of other MSDN contributors made the same identical mistake.... some people might say that it works in all VC++ implementations to date, but that doesn't make it correct code, and it's still violating the calling convention.
In light of this I went to change my old code - which was as follows:
#include <comdef.h>
...
HRESULT FinalConstruct()
{
if (m_dwROTCookie != 0)
return E_FAIL;
//Check whether there already is an instance of the Object
IUnknownPtr pUnk = NULL;
if (GetActiveObject(CLSID_Object, NULL, &pUnk) == S_OK)
{
TRACE_WARNING("An instance of Object already exists in the current context");
return S_OK;
}
HRESULT hr = QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&pUnk));
hr = RegisterActiveObject(pUnk, CLSID_Object, ACTIVEOBJECT_WEAK, m_dwROTCookie);
if (FAILED(hr))
return hr;
hr = CoLockObjectExternal(pUnk, TRUE, TRUE);
pUnk = NULL;
ATLASSERT(m_dwRef == 2);
return hr;
}
I then changed it as follows:
HRESULT FinalConstruct()
{
if (m_dwROTCookie != 0)
return E_FAIL;
//Check whether there already is an instance of the Object
IUnknownPtr pUnk = NULL;
if (GetActiveObject(CLSID_Object, NULL, &pUnk) == S_OK)
{
TRACE_WARNING("An instance of Object already exists in the current context");
return S_OK;
}
void* pUnkVoid = NULL;
HRESULT hr = QueryInterface(IID_IUnknown, &pUnkVoid);
if (SUCCEEDED(hr)
{
pUnk = reinterpret_cast<IUnknown*>(pUnkVoid);
hr = RegisterActiveObject(pUnk, CLSID_Object, ACTIVEOBJECT_WEAK, m_dwROTCookie);
if (FAILED(hr))
return hr;
hr = CoLockObjectExternal(pUnk, TRUE, TRUE);
pUnk = NULL;
}
ATLASSERT(m_dwRef == 2);
return hr;
However now my application has a memory leak from this the COM Object
You likely have a memory leak because you call GetActiveObject() and QueryInterface() which upon success increment the reference count on the object, but don't call Release() later to decrement the reference count.
Mmm, I think that rather than assigning the void* to pUnk I should be using:
pUnk.Attach(reinterpret_cast<IUnknown*>(pUnkVoid));