COM Interop allows COM developers to access managed code as easily as they access other COM objects. This tutorial demonstrates using a C# server with a C++ COM client. It also explains the following activities:
The tutorial also briefly demonstrates the marshaling that is automatically applied between managed and unmanaged components.
COM Interop Part 1: C# Client Tutorial shows the fundamentals of using C# to interoperate with COM objects and is a prerequisite for this tutorial. For an overview of both tutorials, see COM Interop Tutorials.
See
This tutorial demonstrates the following activities to create the C# server:
The tutorial also demonstrates the following activities to create the COM client:
Note To create a GUID for interfaces and coclasses that you export to COM clients, use the tool Guidgen.exe, shipped as part of Visual Studio. Guidgen allows you to choose the format in which the GUID is expressed so you don't have to retype it. For more information on Guidgen, see the Knowledge Base article Q168318 "XADM: Guidgen.exe Available Only for Intel Platforms." KB articles are available in the MSDN Library and on the Web at http://support.microsoft.com.
This example consists of two files:
// CSharpServer.cs
// compile with: /target:library
// post-build command: regasm CSharpServer.dll /tlb:CSharpServer.tlb
using System;
using System.Runtime.InteropServices;
namespace CSharpServer
{
// Since the .NET Framework interface and coclass have to behave as
// COM objects, we have to give them guids.
[Guid("DBE0E8C4-1C61-41f3-B6A4-4E2F353D3D05")]
public interface IManagedInterface
{
int PrintHi(string name);
}
[Guid("C6659361-1625-4746-931C-36014B146679")]
public class InterfaceImplementation : IManagedInterface
{
public int PrintHi(string name)
{
Console.WriteLine("Hello, {0}!", name);
return 33;
}
}
}
// COMClient.cpp
// Build with "cl COMClient.cpp"
// arguments: friend
#include <windows.h>
#include <stdio.h>
#pragma warning (disable: 4278)
// To use managed-code servers like the C# server,
// we have to import the common language runtime:
#import <mscorlib.tlb> raw_interfaces_only
// For simplicity, we ignore the server namespace and use named guids:
#if defined (USINGPROJECTSYSTEM)
#import "..\RegisterCSharpServerAndExportTLB\CSharpServer.tlb" no_namespace named_guids
#else // Compiling from the command line, all files in the same directory
#import "CSharpServer.tlb" no_namespace named_guids
#endif
int main(int argc, char* argv[])
{
IManagedInterface *cpi = NULL;
int retval = 1;
// Initialize COM and create an instance of the InterfaceImplementation class:
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(CLSID_InterfaceImplementation,
NULL, CLSCTX_INPROC_SERVER,
IID_IManagedInterface, reinterpret_cast<void**>(&cpi));
if (FAILED(hr))
{
printf("Couldn't create the instance!... 0x%x\n", hr);
}
else
{
if (argc > 1)
{
printf("Calling function.\n");
fflush(stdout);
// The variable cpi now holds an interface pointer
// to the managed interface.
// If you are on an OS that uses ASCII characters at the
// command prompt, notice that the ASCII characters are
// automatically marshaled to Unicode for the C# code.
if (cpi->PrintHi(argv[1]) == 33)
retval = 0;
printf("Returned from function.\n");
}
else
printf ("Usage: COMClient <name>\n");
cpi->Release();
cpi = NULL;
}
// Be a good citizen and clean up COM:
CoUninitialize();
return retval;
}
The executable client can be invoked with the command line: COMClient <name>, where <name> is any string you want to use, for example, COMClient friend.
Calling function. Hello, friend! Returned from function.
In the sample IDE project, set the Command Line Arguments property in the project's Property Pages to the desired string (for example, "friend").