JAL Computing

C++COMProgramming .NET Mac Palm CPP/CLI Hobbies

 

Home
Up

Win32 Interop

bulletMixing C++/cli and C# into a single assembly
bulletInterior pointers for fast array iteration (non-verifiable)
bullet__clrcall improves efficiency of CLS calling virtual functions in native code

The System::Marshal class provides methods from converting data between unmanaged and managed types. The following code demonstrates some of the aspects of interop programming in C++/cli.

// TestInterop.cpp : main project file.
#include "stdafx.h"
#include "string.h"
#include <vector>
#include <list>
using namespace std;
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Diagnostics;
typedef void (*CALLBACK)();
public class NativeServer {
private:
		list<CALLBACK> lPointers;
public:
		void Register(CALLBACK cb){
			lPointers.push_back(cb);
		}
		void UnRegister(CALLBACK cb) {
			lPointers.remove(cb);
		}
		void Broadcast() {
			std::list<CALLBACK>::iterator iter;
			iter= lPointers.begin();
			while (iter != lPointers.end()) {
				(static_cast<CALLBACK>(*iter))();
				iter++;
			}
		}
		void Clear() {
			lPointers.clear();
		}
};
public class  Native {
public:
		virtual int __clrcall Neg(int* pi) {
			return -(*pi);
		}
		bool Copy(char* out,int size,const char * in) {
			strcpy_s(out,size,in);
			bool isNullTerminated= false;
			if (in[size-1] == '\0')
				isNullTerminated= true;
			return isNullTerminated;
		}
};
public class TestNotify {
public:
		static void Notify() {
			Console::WriteLine("Notify");
		}
};
public ref class Interop {
	public:
		void Notify() {
			Console::WriteLine("Notify");
			}
		int SumManaged(array<int>^ ai) {
			int sum=0;
			for(int i=0; i<ai->Length; i++) {
				sum+= ai[i];
			}
			return sum;
		}
		int InteropClrCall(int i) {
			pin_ptr<int> ppi= &i;
			Native n;
			return n.Neg(ppi);
		}
		int SumInteriorPointer(array<int>^ ai) {
			interior_ptr<int> ipi= &ai[0];
			int sum=0;
			for(int i=0; i<ai->Length; i++) {
				sum+= ipi[i];
			}
			return sum;
		}
		// exercise String to Ansi Ansi to String
		String^ Echo(String^ in) {
			Native n;
			IntPtr ip(0);
			String^ out=L"";
			char* str= 0;
			try {
				str= new char[in->Length+1]; // null terminator
				ip = Marshal::StringToHGlobalAnsi(in); // create char[] on unmanaged heap
				n.Copy(str,in->Length+1,static_cast<const char*>(ip.ToPointer()));
				out= Marshal::PtrToStringAnsi(static_cast<IntPtr>(str));
			}
			catch(...) {
				out= L"exception thrown";
			}
			finally {
				if (ip != IntPtr(0)) {
					Marshal::FreeHGlobal(ip);  // release char[] on unmanaged heap
				}
				if(str) {
					delete [] str;  // release char[] on unmanaged heap
				}
			}
			return out;
		}
		// exercise marshal unmanaged array int to managed array int
		// where pIn is from native dll
		// ASSERT int [] of length size
		array<int>^ IntArrayToManagedArray(const int* pIn, const int size) {
			Debug::Assert(size>0,"Invalid size");
			Debug::Assert(pIn != 0,"Invalid pointer");
			array<int>^ pOut= nullptr;
			if (pIn) {
				IntPtr ipIn(const_cast<int*>(pIn));
				pOut= gcnew array<int>(size);
				Marshal::Copy(ipIn,pOut,0,size);
			}
			return pOut;
		}
		// exercise marshal managed array int to unmanaged array int
		// ASSERT length pOut == size
		// ASSERT managed array length same as unmanaged array length
		void ManagedArrayToIntArray(array<int>^ pIn, const int size, int* pOut) {
			Debug::Assert(size>0,"Invalid size");
			Debug::Assert(pIn != nullptr,"Invalid pointer");
			Debug::Assert(pOut != 0, "Invalid pointer");
			Debug::Assert(pIn->Length == size, "Invalid size");
			if ((pIn!= nullptr) &&(pIn->Length == size)){
				IntPtr ipOut(pOut);
				Marshal::Copy(pIn,0,ipOut,size);
			}
		}
};
public delegate void CallbackDelegate();
int main(array<System::String ^> ^args)
{	
	Interop^ interop= gcnew Interop();
	array<int>^ ai= gcnew array<int>(10){1,2,3,4,5,6,7,8,9,10};
	Console::WriteLine(interop->SumManaged(ai));
	Console::WriteLine(interop->SumInteriorPointer(ai));
	Console::WriteLine(interop->InteropClrCall(1));
	Console::WriteLine(interop->Echo(L"Hello"));
	int unManagedArrayInt[2]= {1,2};
	array<int>^ managedArrayInt= interop->IntArrayToManagedArray(&unManagedArrayInt[0],2);
	for each(int i in managedArrayInt) {
		Console::Write(i+" ");
	}
	unManagedArrayInt[0]= 0;
	unManagedArrayInt[1]= 0;
	interop->ManagedArrayToIntArray(managedArrayInt,2,unManagedArrayInt);
	for (int i=0; i<2; i++){
		Console::Write(unManagedArrayInt[i]+" ");
	}
	// C style callback
	NativeServer ns;
	CALLBACK cb1= &TestNotify::Notify;
	ns.Register(cb1);
	ns.Broadcast();
	ns.UnRegister(cb1);
	// managed C style callback
	CallbackDelegate^ cd= nullptr;
	GCHandle gch;
	CALLBACK cb2= 0;
	try {
		cd = gcnew CallbackDelegate(interop,&Interop::Notify);
		gch = GCHandle::Alloc(cd);
		IntPtr ip = Marshal::GetFunctionPointerForDelegate(cd);
		cb2 = static_cast<CALLBACK>(ip.ToPointer());
		ns.Register(cb2);
		//GC::Collect();  // delegate cannot be collected
		ns.Broadcast();
	}
	finally {
		ns.UnRegister(cb2);  // transaction safe
		if (gch.IsAllocated) {
			gch.Free();  // delegate can now be collected
		}
	}
	
	ns.Broadcast();  // may be invalid if delegate garbage collected
	
	Console::ReadLine();
    return 0;
}
Send mail to [email protected] with questions or comments about this web site. Copyright © 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 © 
Last modified: 08/04/09
Hosted by www.Geocities.ws

1