Share This!

Sunday, July 28, 2013

Executing an Unmanaged (COM) DLL from an ASP.NET web page.

 I had a regular old DLL that needed to accept parameters, and spit out a string as an answer.  It is a 64 bit DLL running on a 64 bit server under .NET Framework 4.5.

Here is a quick tutorial on how I got it to work.

First, I had to add this to my main <Configuration> section of my web.config


 <system.codedom>
  <compilers>
   <compiler
     language="c#;cs;csharp"
     extension=".cs"
     compilerOptions="/unsafe"
     type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  </compilers>
 </system.codedom>



The /unsafe option is the big thing we needed here, as any call from managed code (.NET is all managed code) to unmanaged code, is considered unsafe.

Next, the dll must be wrapped in its own class.  So add a class to your web site.  Mine looks like this.
using System;
using System.Runtime.InteropServices;

namespace CodeGenerator
{

 internal class NativeMethods
 {
  [DllImport("kernel32.dll", SetLastError = true)]
  public static extern IntPtr LoadLibrary(string dllToLoad);

  [DllImport("kernel32.dll", SetLastError = true)]
  public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

  [DllImport("kernel32.dll")]
  public static extern bool FreeLibrary(IntPtr hModule);
 }

 public class unlocker
 {
  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  private delegate IntPtr CreateCode2A(
   int level,
   string name,
   string encrypt_template,
   UInt32 hardwareID,
   UInt16 otherinfo1,
   UInt16 otherinfo2,
   UInt16 otherinfo3,
   UInt16 otherinfo4,
   UInt16 otherinfo5
   );


  public static unsafe string CreateUnlockingCode(string regname, string encrypt_template, string HardwareID, string pathtoDLL)
  {
   string unlockingcode = "";
   string sfp = HardwareID.Remove(4, 1);
   UInt32 lfingerprint = Convert.ToUInt32(sfp, 16);

   IntPtr pDll = NativeMethods.LoadLibrary(pathtoDLL);  //attempt to load the library
   int err1 = Marshal.GetLastWin32Error();
   try
   {
    IntPtr pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "CreateCode2A");
    int err2 = Marshal.GetLastWin32Error();
    CreateCode2A createCode2 = (CreateCode2A)Marshal.GetDelegateForFunctionPointer(
      pAddressOfFunctionToCall,
      typeof(CreateCode2A));

    if (err1 == 0 && err2 == 0)
    {
     IntPtr unlockingcodeptr = createCode2(1, regname, encrypt_template, lfingerprint, 0, 0, 0, 0, 0);
     unlockingcode = Marshal.PtrToStringAnsi(unlockingcodeptr);
    }
    else
    {
     unlockingcode = string.Format("Error Codes: {0} and {1}", err1, err2);
    }
   }
   finally
   {
    bool result = NativeMethods.FreeLibrary(pDll);
   }
   return unlockingcode.ToString();
  }

 }
}

Now all we need is to call our CreateUnlockingCode function from the main page, which calls the DLL function, and marshals the result back to a C# string for us.


unlockingcode = CodeGenerator.unlocker.CreateUnlockingCode(regname, encrypt_template, fingerprint, pathtoDLL);

...

Bryan Valencia is a contributing editor and founder of Visual Studio Journey.  He owns and operates Software Services, a web design and hosting company in Manteca, California.

No comments:

Post a Comment

Contact Us

Name

Email *

Message *