I mentioned earlier that I decided to write a DLL in C++ to invoke from my C# app for Windows Mobile. I’d not done this before, so thought I’d jot down a few quick notes about it.
I found a few detailed articles about this on MSDN that made for a good introduction to the topic:
- An Introduction to P/Invoke and Marshaling on the Microsoft .NET Compact Framework
- Advanced P/Invoke on the Microsoft .NET Compact Framework
- Marshalling Types During Platform Invoke (P/Invoke) on the Microsoft .NET Compact Framework
- Writing Unmanaged Functions for Microsoft .NET Compact Framework-based Applications
There is a ton of information in these articles, so there isn’t much to add. Instead, I’ll give a quick, high-level overview.
If the C++ code just needs to return variables with basic types, it’s pretty straightforward:
C++
extern "C" __declspec(dllimport) int getninetynine(void) { return 99; }
C#
[DllImport("MyLib.dll", EntryPoint = "getninetynine", SetLastError = true)] private static extern int GetMyIntFromDLL(); public void InvokeMyDLL() { int ThisWillBe99 = GetMyIntFromDLL(); }
For my purposes, I wanted to return a string. This is more fiddly.
In short, I needed to pre-create the string in the C# code, then pass it to the DLL to modify it.
The problem is that the C# code is having to define the size of a string that the C++ code will be constructing. Which means either creating a massive buffer that is definitely going to be enough, or breaking this down into two C++ functions – one of which can return the size of the buffer, the second to actually construct it.
In hindsight, this limitation shouldn’t have surprised me – it’s how many Windows API functions which return strings work.
C++
extern "C" __declspec(dllimport) int changefirstletter(WCHAR* teststring) { teststring[0] = 'X'; return 0; }
C#
[DllImport("bLADEBluetoothLib.dll", EntryPoint = "changefirstletter", CharSet = CharSet.Unicode, SetLastError = true)] private static extern int ModifyStringInDLL(String teststring); public void InvokeMyDLL() { string testString = "Hello World"; ModifyStringInDLL(testString); // testString now = "Xello World" }
If you look at the example usage code for the DLL I wrote, I’ve gone for the allocate-a-massive-buffer-and-hope-it’s-enough approach.
String myBuffer = new String(' ', 500);
Not very elegant, but it’s a start.
Tags: .net, compact framework, dotnet, p/invoke, windows mobile, windowsmobile
[…] I’m getting quite into the whole p/invoking thing, I thought I’d have a go at wrapping it up in a C# class for a .NET application. It’s […]
[…] […]
Great artical. Well done. This is exactly what I needed. Cheers!