User Tools

Site Tools


software:interfacing_c_code

[edin]Migrate interfacing page here.

Using C/C++ code in C# programs

This is the most basic method for wrapping C/C++ code. It gives you absolute control, but you have to do everything manually. It may have some limitations…

Wrapping C/C++ in unmanaged DLLs

Writing a simple DLL in C

- load-time dynamic linking - distributing: .h and .lib for building, .dll for running

Using the DLL code in a C++ program

Using the DLL code in a C# program

For the C# client, under Project properties→Build→Platform target you must specify x86 if your DLL is 32-bit, and x64 if it is 64-bit, otherwise you will be getting the very unpleasant “System BadImageFormatException”.

Wrapping C/C++ in managed DLLs

Wrapping C/C++ with SWIG

Using C# code in C/C++ programs

A step-by-step tutorial for wrapping C# code in a Component Object Model (COM) Library and using it from C/C++ (and C#). A sample solution for Visual Studio 9 containing all the code mentioned below can be found here.

Further tutorials can be found in the Resources section.

Creating a COM Class Library in C#

First, we need to build our C# code for COM interoperability.

1. Create a new C# Class Library project:

 New->Project->Visual C# Projects ->Class Library

2. Write the code. Sample code with one interface function is provided below

 /*! \brief A simple C# Class Library, visible through COM.
  * 
  */
 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Runtime.InteropServices;   // Required for COM interoperability.
 
 namespace CsharpLibrary
 {
     // Class interface.
     [Guid("7DB79628-A473-4ea3-BCD6-B55324883DC5")]
     public interface CsharpClassInterface
     {
         [DispId(1)]
         double MultiplyWithMagicNumber( double x );
     }
 
     // Class events (not used in this example).
     [Guid("D2FE50FB-B75E-4c60-9C34-0FE98385BFB0"),
         InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
     public interface CsharpClassEvents
     { 
 
     }
 
     // Class implementation.
     [Guid("7A2C4083-824C-4555-BD8B-E72C11E5F4C3"),
         ClassInterface(ClassInterfaceType.None),
         ComSourceInterfaces(typeof(CsharpClassEvents))]
     public class CsharpClass : CsharpClassInterface
     {
         private double magicNumber_ = 5.0; 
 
         // A dummy function, shows passing of elementary data types.
         public double MultiplyWithMagicNumber(double x)
         {
             return ( x * magicNumber_ );
         }
     }
 }

3. Adjust project properties to make the library available through COM. Check the box

 Project properties -> Build -> Output -> Register for COM interop

This will create a .tlb file (used by C++ clients) and register the assembly as a COM library.

4. Create a strong name/key pair with the sn utility. Open the command prompt and add Visual Studio tools to the environment %PATH% variable by running<

 $<Visual Studio Installation Path>\Common7\Tools\vsvars32.bat

Position yourself in the project folder and create the key file

 $cd <path to your project folder>
 $sn -k LibraryNameKey.snk

add the key file to the project by selecting the generated .snk file in:

Project Properties -> Signing -> Choose a strong name key file

5. In the AssemblyInfo.cs set the line:

 ComVisible(true)

6. Build the project. If the build succeded without errors, open the OLE-COM Object Viewer application (part of the Microsoft Windows SDK) and you should see an entry for CsharpLibrary under “Type Libraries”. Your COM object is now ready to use.

Accessing the class library from C++ (through COM)

Once you have created and registered your COM component, using it from a C++ program is relatively straightforward. Create an empty console project, add a new .cpp source file, with the following code:

 /*!	\brief A C++ COM client demo.
 */
 
 #include <iostream>
 
 #include <comutil.h>
 // Import the type library to make COM classes accessible.
 #import "..\..\CsharpLibrary\bin\Debug\CsharpLibrary.tlb" named_guids 
 
 int main( void )
 {
 	// Initialize the COM library.
 	CoInitialize( NULL );
 
 	// Declare smart pointer to our COM object interface.
 	// This type is generated automagically when building the COM library.
 	CsharpLibrary::CsharpClassInterfacePtr pCsharp;
 
 	// Create an instance of the COM object.
 	HRESULT hRes = pCsharp.CreateInstance( __uuidof( CsharpLibrary::CsharpClass) );
 	if ( FAILED( hRes ) )
 	{
 		std::cout << "CSharpClassInterfacePtr::CreateInstance failed "
 			<< "with error " << std::hex << hRes << std::endl;
 	}
 	else
 	{
 		// If the instance is successfully created, use the object.
 		double a = 2.4;
 		std::cout << a << " times magic number = " 
 			<< pCsharp->MultiplyWithMagicNumber( a )
 			<< "\nCOM is working :)"
 			<< "\npress any key to end the program..." << std::endl;
 	}
 	char c;
 	std::cin >> c;
 
 	// Release the COM library.
 	CoUninitialize();
 
 	return 0;
 }

Of course, you need to make sure that you #import statement specifies the actual path to the .tlb file. Build the project and run it, if all goes well, voila, you have created your first C++ COM client.

Accessing the class library from C#

Since the class library is written in C#, we can use it directly, as a regular C# library (in fact, we can't use it through COM).

1. Create a new C# console application.

2. Import the Class Library: Right-click on the newly created project in the Solution explorer window, choose Add Reference, go to the Browse tab (don't go to the COM tab, because the library is not accessible through COM in C#), find the CsharpLibrary.dll and click OK. The library will show up under the References section of your project (in the Solution Explorer window).

3. You can now use the classes defined in the library in the same way as from the C++ program. Sample code is shown below.

 /*! \brief  Sample code for using a C# class library.
  * 
  */
 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 
 // Use our fancy Class Library. It must be added to the project references.
 using CsharpLibrary;
 
 namespace CsharpClient
 {
     class Program
     {
         static void Main(string[] args)
         {
             /* Create a reference to the class defined in the Class Library.
              * Use only what's availabl through the class interface (because
              * that's what is visible to COM.
              */
             CsharpClassInterface pCsharp = new CsharpClass();
             double a = 3.14;
 
             // Call a function implemented in the Class Library.
             Console.WriteLine( "{0} multiplied by the magic number equals {1}",
                 a, pCsharp.MultiplyWithMagicNumber(a) );
 
             // Print info and return from the program.
             Console.WriteLine("Our Class Library is working :)");
             Console.WriteLine("press any key to continue...");
             Console.ReadKey(true);
         }
     }
 }

Resources

C++ DLLs

C# COM Server

software/interfacing_c_code.txt · Last modified: 2017/05/12 09:29 (external edit)