Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
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