JAL Computing

C++COMProgramming .NET Mac Palm CPP/CLI Hobbies

 

Home
Up

COM Interop

C# supports calling unmanaged code. In this very short tutorial we will build a C++ unmanaged ATL COM dll and call it from C# using COM Interop. If you want to call a Win32 function, use PInvoke.

Creating the C++ COM dll

1) First create a C++ ATL project using Visual Studio 2003. File --> New --> Project --> Visual C++ --> ATL Project called TestATLCOM.

2) Add a simple COM class to the project. Project --> Add Class --> C++ --> ATL Simple Object and name it Test.

3) In the Class View right right click over ITest --> Add --> Add Method. Name the new method GetNumTokens. Add an in parameter of type BSTR called newValue. Add an in parameter of type long* called pValue. Click finish.

4) Modify the code in Test.h by changing the [in] parameter pValue to an [out, retval] parameter. The modified IDL should look like this:

__interface ITest : IDispatch
{
[id(1), helpstring("method GetNumTokens")] HRESULT GetNumTokens([in] BSTR newValue,
[out,retval] LONG* pValue);
};

Add the stl string library by adding an #include <string> directive like this:

// Test.h : Declaration of the CTest
#pragma once
#include "resource.h" // main symbols

#include <string>

5) Modify the Test.cpp code by adding a using namespace std statement like this:

// Test.cpp : Implementation of CTest

#include "stdafx.h"
#include "Test.h"
#include ".\test.h"

using namespace std;

You can now add the following implementation of GetNumTokens:

// CTest
STDMETHODIMP CTest::GetNumTokens(BSTR newValue, LONG* pValue)
{
    // TODO: Add your implementation code here
    CComBSTR bStr(""); // default empty string, remember NULL --> empty string
    if (newValue != NULL) {
        bStr= newValue;  // you must copy a BSTR passed by value as  [in} BSTR newValue
    }
    long lTokens= 0;
    char cDelim= ',';
	wstring strToken;
    wstring inString(bStr);
    wstring::size_type iPos;
    iPos= inString.find(cDelim,0);
    if (iPos == wstring::npos && inString.length() <= 0) { // no tokens
        lTokens= 0;
        strToken= L"";
    }
    else if (iPos== wstring::npos && inString.length() > 0) { // one token
        lTokens = 1;
        strToken= inString;
    }
    else { // more than one token
        while (iPos != wstring::npos ) {
            lTokens+= 1;
            strToken= inString.substr(0,iPos);
            inString= inString.substr(iPos+1);
            iPos= inString.find(cDelim,0);
        }
        strToken= inString; // last token
        lTokens+= 1;
    } 
    *pValue= lTokens;
    return S_OK;
}

6) Compile the project and Visual Studio will register the dll as TestCOMInterop 1.0 Type Library. Thats it.

Calling COM dll

To call our COM dll, just create a C# console application and add a reference to our TestCOMInterop dll.

1) Create a new C# console application called CallATLCOM.

2) Add a reference to our TestCOMInterop dll. Project --> Add Reference... --> COM --> TestCOMInterop 1.0 Type Lib... --> Select --> OK. This auto magically wraps the unmanaged C++ code into a managed class. You can also do this from the command line using TlbImp.exe, the Type Library Importer. Here is the assembler code that calls the unmanaged code:

.method public hidebysig newslot virtual 
        instance int32  GetNumTokens([in] string  
			marshal( bstr) newValue) runtime 
			managed internalcall
{
  .custom instance void [mscorlib]System.Runtime.InteropServices.DispIdAttribute::.ctor(int32) = 
			( 01 00 01 00 00 00 00 00 ) 
  .override TestCOMInterop.ITest::GetNumTokens
} // end of method CTestClass::GetNumTokens

3) Now just call our Test method by passing a comma delimited string. The Test method simply returns the number of tokens in the string. Here is the CallATLCOM source code:

namespace CallATLCOM
{
	/// <summary>
	/// Summary description for Class1.
	/// </summary>
	class Class1
	{
		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main(string[] args)
		{
			//
			// TODO: Add code to start application here
			//
			TestCOMInterop.CTestClass o= new TestCOMInterop.CTestClass();
			System.Console.WriteLine(o.GetNumTokens("Hello,World"));
			System.Console.ReadLine();
		}
	}
}

Output: 2

Learn More

Here are some links that may be helpful:

bulletMicrosoft COM Interop Tutorial Part 1
bulletMicrosoft COM Interop Tutorial Part 2
bulletC++ COM Programming

Have fun.

 
Send mail to [email protected] with questions or comments about this web site. Copyright © 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 © 
Last modified: 08/04/09
Hosted by www.Geocities.ws

1