How to Use an Unmanaged DLL from C#C# code does not have the luxury of IJW. The only way to access code in an unmanaged DLL from C# is using PInvoke . To demonstrate how it's done, create a C# console application called CSUseLegacyDLL . Although you could set up the custom marshaling in C#, it would be quite a lot of work. Instead, the C# example will pass a SYSTEMTIME to Log() , and use the MakeSystemTimeFromDateTime() helper method. Listing 7.2 shows the code for the C# console application. There are several very significant differences from the equivalent C++ code in the "Using PInvoke to Control Marshaling" section. These include
Listing 7.2 Class1.cs CSUseLegacyDLLusing System; using System.Runtime.InteropServices; namespace CSUseLegacyDLL { struct SYSTEMTIME { public short wYear; public short wMonth; public short wDayOfWeek; public short wDay; public short wHour; public short wMinute; public short wSecond; public short wMilliseconds; } /// <summary> /// Summary description for Class1. /// </summary> class Class1 { static SYSTEMTIME MakeSystemTimeFromDateTime(DateTime dt) { SYSTEMTIME st; st.wYear = (short) dt.Year; st.wMonth = (short) dt.Month; st.wDayOfWeek = (short) dt.DayOfWeek; st.wDay = (short) dt.Day; st.wHour = (short) dt.Hour; st.wMinute = (short) dt.Minute; st.wSecond = (short) dt.Second; st.wMilliseconds = (short) dt.Millisecond; return st; } [DllImport("legacy.dll", CharSet=CharSet.Ansi)] static extern bool Log(String message, ref SYSTEMTIME time); [DllImport("legacy.dll")] static extern double Add(double num1, double num2); /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main(string[] args) { System.Console.Write("1 + 2 is "); System.Console.WriteLine( Add(1,2)); String s = "Testing with a C# string" ; SYSTEMTIME st = MakeSystemTimeFromDateTime(DateTime.Now); Log(s, ref st); System.Console.WriteLine("log succeeded"); } } } After entering the C# code, build the project. Copy legacy.dll into the bin/Debug folder under the CSUseLegacyDLL project folder. Run the application and you should see the usual output. Open log.txt and you should see the current date and time, along with the C# version of the text message. The legacy DLL is available to developers in any managed language. What about the custom marshaling approach? It's quite a bit harder in C# than in C++. A better plan is to create a managed library in C++ that exposes a Log() method, and to have that method use PInvoke and custom marshaling to get to the legacy DLL. That code is out of the scope of this chapter, but would make an interesting exploration for anyone wanting to push a little deeper than usual into legacy DLL interop issues. |