|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionThis article should give you a way to reuse existing code, which is supposed to be bug free ;), without rewriting it to .NET Framework. BackgroundWhen the .NET and managed code appeared, it was clear that is required the interoperability between the legacy code written in some language (like C++ or Delphi, you name it) and the brand new .NET languages. Of course, .NET Team didn't leave out this posibility, and introduced P/Invoke or Platform Invoke. The MSDN documentation is quite good on using Win32 API by using P/Invoke, however it doesn't explain very clearly how to use a custom DLL in your code. Also, I must say that P/Invoke isn't the only way to reuse the existing DLL code. You can use managed C++ to import your DLL, but this is not the scope of this article. System RequirementsTo compile the solution you need Visual Studio .NET and Visual Studio 6.0 to create the DLL. The sample application is written in C# and imports a custom DLL written in Visual C 6.0 to do some complicated stuff that was written before .NET appeared :). Also to run the binaries you will need .NET Framework to be installed on the target machine. The DLL stuffI've written a sample DLL that exports 2 functions char* MyAppend(char* in, char* arg1, char *arg2, char*arg3, BOOL last); void KillBuffer(char* in);
All functions are exported as C (not decorated) and are using The C# partIn C# I used a sample console application that calls three times First of all we need tell the compiler that we will be dealing with legacy application and pointers (only if required). So, in project properties we allow unsafe code (see screenshot). In my example actually unsafe was not required, because I choose to marshal all parameters that involve pointers (strings as
After that, we can start declaring our functions. Usually, it's better to declare them in a separate class, but this is not a requirement. You can add the functions to what class do you want since the functions will be static. Another thing to mention is that you need to reference the using System.Runtime.InteropServices;
Let's start importing the functions: class MyDLL {
[DllImport("legacy",
EntryPoint = "MyAppend",
ExactSpelling = true, // Bypass A or W suffix search
CharSet = CharSet.Ansi, // We want ANSI String
CallingConvention = CallingConvention.Cdecl)]
// Called as Cdecl
public static extern /*unsafe*/ IntPtr Append(
IntPtr ptr,
[MarshalAs(UnmanagedType.LPStr)]
string arg1,
[MarshalAs(UnmanagedType.LPStr)]
string arg2,
[MarshalAs(UnmanagedType.LPStr)]
string arg3, bool isLast);
[DllImport("legacy",
EntryPoint = "KillBuffer",
ExactSpelling = true,
CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.Cdecl)]
public static extern /*unsafe*/ void StringDispose(IntPtr ptr);
}
It looks interesting isn't it?. First of all, not all the fields of the DllImport attribute are required. I choosed to write them because it's better to bypass defaults which can give you a strange behaviour.
CharSet tells the compiler how to expand LPTSTR. Charset.Ansi means that TCHAR is 1 byte variance, Charset.Unicode means 2 byte. By setting this field I could skip the MarshalAs attribute.
As you may noted, the first parameter for The The main function looks like: IntPtr target = IntPtr.Zero;
target = MyDLL.Append(target,"xx","yy","zzz",false);
target = MyDLL.Append(target,"xx","yy","zzz",false);
target = MyDLL.Append(target,"xx","yy","zzz",true);
Console.WriteLine("Returned: {0}",Marshal.PtrToStringAnsi(target));
MyDLL.StringDispose(target);
As you see, first we initialize the target pointer to TroubleshootingIf you fail to call your existing code, or you have strange results, you should check:
Conclusion.NET Framework is a great way to develop new applications. However, for some application it isn't feasible, or we don't have enough time to rewrite old code to .NET. So either we stick to the old application or we try to migrate it per module. By using P/Invoke you can accomplish this task pretty easy.
|
||||||||||||||||||||||