Click here to Skip to main content
15,892,161 members
Articles / Programming Languages / C++

COM in plain C, Part 5

Rate me:
Please Sign up or sign in to vote.
4.94/5 (35 votes)
21 May 2006CPOL18 min read 120.4K   2.3K   101  
Add a connectable object (source/sink).
// This is a C example that tests the IExample4 COM component (in IExample4.dll).

#include <windows.h>
#include <objbase.h>
#include <stdio.h>
#include "../IExample4/IExample4.h"

int main(int argc, char **argv)
{
	IExample4		*exampleObj;
	IClassFactory	*classFactory;
	HRESULT			hr;

	// We must initialize OLE before we do anything with COM objects. NOTE:
	// some COM components, such as the IE browser engine, require that you
	// use OleInitialize() instead. But our COM component doesn't require this
	if (!CoInitialize(0))
	{
		// Get IExample4.DLL's IClassFactory
		if ((hr = CoGetClassObject(&CLSID_IExample4, CLSCTX_INPROC_SERVER, 0, &IID_IClassFactory, &classFactory)))
			MessageBox(0, "Can't get IClassFactory", "CoGetClassObject error", MB_OK|MB_ICONEXCLAMATION);
		else
		{
			// Create an IExample4 object
			if ((hr = classFactory->lpVtbl->CreateInstance(classFactory, 0, &IID_IExample4, &exampleObj)))
			{
				classFactory->lpVtbl->Release(classFactory);
				MessageBox(0, "Can't create IExample4 object", "CreateInstance error", MB_OK|MB_ICONEXCLAMATION);
			}
			else
			{
				// Release the IClassFactory. We don't need it now that we have the one
				// IExample4 we want
				classFactory->lpVtbl->Release(classFactory);






				//==========================================================================
				// STUDY THIS
				//==========================================================================
				{
				// Get the IDispatch object for the Ports collection, and stuff it into our variable "portsObj".
				// NOTE: What our DLL is really returning is a MyRealICollection object. But this app doesn't
				// know that. All we know here is that this object is an IDispatch. So its VTable has the 3
				// IUnknown functions (QueryInterface, AddRef, and Release) and the 4 IDispatch functions
				// (GetTypeInfoCount, GetTypeInfo, GetIDsOfNames, and Invoke). And that's all as far as we're
				// concerned. If the object has any other functions, we can't call them directly by referencing
				// lpVtbl. We have to call those extra functions indirectly via the Invoke function, as we'll
				// see below
				IDispatch			*portsObj;

				if ((hr = exampleObj->lpVtbl->GetPorts(exampleObj, &portsObj)))
					MessageBox(0, "Can't get the Ports collection (IDispatch) object", "GetPorts error", MB_OK|MB_ICONEXCLAMATION);
				else
				{
					IEnumVARIANT	*enumObj;
					VARIANT			ret;
					ULONG			count;
					DISPPARAMS		dspp;

					// Get the IEnumVARIANT for the Ports IDispatch object. We do this by calling our collection's
					// _NewEnum() function. We have to do that indirectly by calling our collection's Invoke function.
					// Fortunately, the _NewEnum function is passed no args, so we can simply zero out the DISPPARAMS
					// we pass to invoke
					ZeroMemory(&dspp, sizeof(DISPPARAMS));

					// We know that _NewEnum has a DISPID of DISPID_NEWENUM, so we don't need to call GetIDsOfNames
					// to look that up. We do have to pass a VARIANT where a pointer to an IUnknown object will be
					// returned to us. And we initialize it first too (just in case _NewEnum doesn't do that)
					VariantInit(&ret);
					if (!(hr = portsObj->lpVtbl->Invoke(portsObj, DISPID_NEWENUM, &IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD|DISPATCH_PROPERTYGET, &dspp, &ret, 0, 0))

						// Make sure _NewEnum returned an IUnknown pointer in our VARIANT's punkVal
						&& ret.vt == VT_UNKNOWN)
					{
						// Call the IUnknown's QueryInterface function, and ask it to return a pointer to the
						// IEnumVARIANT object
						hr = ret.punkVal->lpVtbl->QueryInterface(ret.punkVal, &IID_IEnumVARIANT, (void **)&enumObj);
					}

					// We don't need the IUnknown object now that we've got the IEnumVARIANT. By calling
					// VariantClear(), it will do the Release on our VARIANT's punkVal member. (And if an
					// error occurred, our VARIANT's vt member is still VT_NOTHING so VariantClear does nothing
					VariantClear(&ret);

					// We also don't need the Ports collection object anymore. Release it. Good riddance
					portsObj->lpVtbl->Release(portsObj);

					// Did we get that IEnumVARIANT?
					if (hr)
						MessageBox(0, "Can't get the IEnumVARIANT object", "Invoke error", MB_OK|MB_ICONEXCLAMATION);
					else
					{
						// Call the IEnumVARIANT's Next(), and display the VARIANT value it returns each time.
						// NOTE: We expect the VARIANT it returns to have a type of VT_BSTR, so we can display it
						// as is. We break out of the loop when Next() finally returns no more items (ie, it
						// sets our count variable to 0)
						for (;;)
						{
							enumObj->lpVtbl->Next(enumObj, 1, &ret, &count);
							if (!count) break;
							printf("%S\n", ret.bstrVal);

							// We need to SysFreeString the BSTR when we're done with it. By calling
							// VariantClear(), it will do that on our VARIANT's bstrVal member
							VariantClear(&ret);
						}

						// Release the IEnumVARIANT now that we're done with it
						enumObj->lpVtbl->Release(enumObj);
					}
				}
				}

				//==========================================================================




				
				// Release the IExample4 now that we're done with it
				exampleObj->lpVtbl->Release(exampleObj);
			}
		}

		// When finally done with OLE, free it
		CoUninitialize();
	}
	else
		MessageBox(0, "Can't initialize COM", "CoInitialize error", MB_OK|MB_ICONEXCLAMATION);

	return(0);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions