System::Runtime::InteropServices

Chapter 22/23 of the ‘Pro Visual C++/CLI and the .NET 3.5 Platform’ book is an excellent resource for understanding P/Invoke (and an excellent VC++ book generally).

Used when making calls out of the .NET managed environment to unmanaged .DLLs. P/Invoke finds the DLL, loads it into memory, marshals its arguments (converts from managed to native) so the DLL can understand the call, makes the call to the DLL function and than marshals the return value (converting from native to managed).

Good Resources

http://pinvoke.net/

http://msdn.microsoft.com/en-us/library/aa719104%28VS.71%29.aspx

http://msdn.microsoft.com/en-us/library/eyzhw3s8.aspx

DllImport

(Same as DllImportAttribute)
DllImport provides a simple way to make calls to native code from a managed application. Copy the .dll file into your project exe directory.


	DllImport(L"MyDllName.dll")]
	//Create the function prototype here

Reference Values

Some functions might take arguments that return a value. Just use the ‘%’ as you normally would, but make sure you are not passing a handle (e.g. int %value is fine, but String ^%text is not).

Keywords such as ‘out’ don’t work for managed C – the % character is how you tell the compiler a value is coming returned.

When porting VB code look for ByRef. Usually values are passed as ByVal, but if ByRef is used then it means this is a returned variable.

Data Marshalling

Usually when using P/Invoke you don’t have to worry about marshalling as in most cases the managed and unmanaged formats of data types are the same. However there is nothing stopping you specifically defining how parameters are to be marshalled using MarshalAsAttribute in the function prototype you create for the DLL import.

Variables

bool – Bool (Win32 BOOL type)

char – Char (1 byte signed integer)

short – Int16 (2 byte signed integer)

long – Int32 (4 byte signed integer)

__int64 – Int64 (8 byte signed integer)

unsigned char – Byte (1 byte unsigned integer)

unsigned short – UInt16 (2 byte unsigned integer)

unsigned int or unsigned long – UInt32 (4 byte unsigned integer)

unsigned __int64 – UInt64 (8 byte unsigned integer)

Strings

If you use String^ when defining the function prototype then this correctly maps to null terminated wchar_t arrays – i.e. you can use String^. However as an example here’s how you would do it if you used System::String in the function prototype, effectively doing the data marshalling yourself:


	String ^MyString = L"Hello";
	pin_ptrmy_string = &(MyString->ToCharArray()[0]);
	SomeDllFunction(my_string);

Some Examples

Forcing our application form to the foreground

Outside of function / in header file:


	[System::Runtime::InteropServices::DllImport(L"user32.dll")]
	static System::IntPtr SetForegroundWindow(System::IntPtr  hWnd);

In function:


	SetForegroundWindow(this->Handle);		//Can test return bool value if we want
Misc

	[System::Runtime::InteropServices::DllImport(L"ivbind.dll")]
	//int IvBindRegisterEvents (const char *pszIpAddress);
	static System::Int32 IvBindRegisterEvents (String ^pszIpAddress); 

	[System::Runtime::InteropServices::DllImport(L"ivbind.dll")]
	//int IvBindSendEvent (const char *pszIpAddress, int nPort, const FILETIME *pTime, int nEventNum, const char *pData, int nSize);
	static System::Int32 IvBindSendEvent (String ^pszIpAddress, System::Int32 nPort, System::DateTime ^pTime,
		System::Int32 nEventNum, String ^pData, System::Int32 nSize);
MSDN C++ Examples

public:
	[DllImport(S"KERNEL32.DLL", EntryPoint=S"MoveFileW",  SetLastError=true,
	CharSet=CharSet::Unicode, ExactSpelling=true,
	CallingConvention=CallingConvention::StdCall)]
	static bool MoveFile(String* src, String* dst);

	[DllImport(L"winspool.Drv", EntryPoint="StartDocPrinterW", SetLastError=true, CharSet=CharSet::Unicode, ExactSpelling=true, CallingConvention=CallingConvention::StdCall)]
	System::Boolean StartDocPrinter(
					System::IntPtr hPrinter,
					int level,
					[MarshalAs(UnmanagedType::LPWStr)] String ^pDocName,
					[MarshalAs(UnmanagedType::LPWStr)] String ^pOutputFile,
					[MarshalAs(UnmanagedType::LPWStr)] String ^pDataType);

	[DllImport(L"winmm.dll")]
	static System::IntPtr timeSetEvent(
		UInt32			uDelay,
		UInt32			uResolution,
		[MarshalAs(UnmanagedType::FunctionPtr)] MMTimerProc ^lpTimeProc,
		UInt32			dwUser,
		Int32				fuEvent
		);
Feel free to comment if you can add help to this page or point out issues and solutions you have found. I do not provide support on this site, if you need help with a problem head over to stack overflow.

Comments

Your email address will not be published. Required fields are marked *