HOWTO: Basic Native/Managed Code Interop
IIS7 core extensibility model supports both native and managed code as first-class citizens. So, I feel it is time for a little refresher on managed/native code interop... starting with the more popular route of how to wrap native code API for use within managed code. I am using the newer syntax introduced with .Net Framework 2.0 instead of the older, kludgy syntax.
Now, I am going to ignore the reciprocal route of calling managed code from native code for a couple of reasons:
- It is just boiler plate COM Interop within native code after generating and registering the CCW (COM Callable Wrapper) of the managed class.
- Why don't you just write a managed code module/handler in IIS7 to directly use that managed API?
The example illustrates how to use Managed Code to:
- Pass a .NET String into Managed C++
- Manipulate a .NET String in Managed C++
- Return a .NET String from Managed C++
- Pass in arbitrary number of args into Managed C++
Remember to use a Class Library Project for Sample.h and Sample.cpp to create a Managed C++ Wrapper around native code API, and you can use the resulting Managed Assembly from Sample.cs managed code.
Enjoy,
//David
Sample.h
#pragma once
#include <windows.h>
#include "SomeNativeAPI.h"
using namespace System;
using namespace System::Runtime::InteropServices;
namespace Sample
{
public ref class ManagedClass
{
public:
ManagedClass( String^ name );
~ManagedClass();
!ManagedClass();
String^ DebugPrint( String^ format, ...array<String^>^ args );
private:
SomeNativeType* m_pType;
};
}
Sample.cpp
#include "Sample.h"
Sample::ManagedClass::ManagedClass( String^ name )
{
//
// Convert .NET String into LPSTR for
// Native code API to use in constructor
//
IntPtr szName;
szName = Marshal::StringToHGlobalAnsi( name );
m_pType = new SomeNativeType( szName );
Marshal::FreeHGlobal( szName );
}
Sample::ManagedClass::~ManagedClass()
{
this->!ManagedClass();
}
Sample::ManagedClass::!ManagedClass()
{
delete m_pType;
}
String^ Sample::ManagedClass::DebugPrint( String^ format, ...array<String^>^ args )
{
//
// Use Managed Code to format variable arguments as .NET String,
// convert the .NET String into Unicode String, and pass
// it to Native API
//
String^ formattedString = System::String::Format( format, args );
IntPtr wszFormattedString;
wszFormattedString = Marshal::StringToHGlobalUni( formattedString );
m_pType->SomeFunctionUnicode( wszFormattedString );
Marshal::FreeHGlobal( wszFormattedString );
return formattedString;
}
Sample.cs
namespace Sample
{
class Program
{
static void Main( string[] args )
{
Sample.ManagedClass cls = new Sample.ManagedClass( "Name?" );
System.Console.WriteLine( cls.DebugPrint( "0:{0},1:{1}", "N", "V" ) );
}
}
}
Comments
- Anonymous
October 03, 2007
The System.Runtime.InteropServices namespace defines methods that work with the CLR so that managed code can call native, raw c DLLs.The DllImport atttrubute has be marked by the namespace and the C# program callling the function uses the name of the function" using System; using System.Runtime.InteropServices; class Program { [DllImport("Kernel32.dll")] public static extern bool Beep( uint iFreq, uint iDuration ); static void Main() { bool b = Beep( 100, 100 ); } } C:.NET> csc.exe /target:exe beep.cs