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 (1)

  1. David Richter says:

    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