How To Call A Managed Dll From Unmanaged Code

January 2, 2009

I here illustrate how a dll written in C# is called in C++ (without CLR).

Make a DLL in C#

Let’s make a small dll (MathLibrary.dll) in C# which provides a public API for adding two numbers. Start Visual Studio, start a new project in Visual C# and select the type of the project as class library. This is how my code for DLL looks like.


using System;
using System.Collections.Generic;
using System.Text;

namespace MathLibrary
{
   public interface IAddClass
   {
      int Add(int a, int b);
   }
   public class CAddClass : IAddClass
   {
      public int Add(int a, int b)
      {
         return a+b;
      }
   }
}

It has a namespace MathLibrary which contains an interface IAddClass and its implementation CAddClass. The public API Add(int a, int b) is provided which can add two numbers supplied.

We have to attach a key file to our DLLl. To generate the key file, go to Visual Studio command prompt (From Start menu –> Programs –> Microsoft Visual Studio 2005 –> Visual Studio Tools). n the command prompt, type

sn.exe -k MyKeyFile.SNK

You can see that MyKeyFile.SNK is generated in the visual studio directory (the command prompt will display where it has been generated). Copy it to the source directory of the dll.  Now edit the AssemblyInfo.cs in visual studio and add/edit the following lines.

[assembly: ComVisible(true)]
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("MyKeyFile.SNK")]

Make sure that MyKeyFile.SNK is in the correct path specified.

Now you can build the DLL (or press Ctrl + Shift + B).

Copy the dll to the directory of the source (C++ program withour CLR option) from where it is to be called.

Register the DLL

Now you have to register the managed dll for using in the unmanaged C++ code. Again take the visual studio command prompt and enter the following command.

RegAsm.exe [including full path] MathLibrary.dll /tlb:MathLibrary.tlb /codebase

We have generated a TLB file, which  contains the type library of different types used in the DLL. The dll is now registered and ready for use in unmanaged code.

Call the DLL from Unmanaged code

The .NET component (dll) can be used as a COM in unmanaged code. So a sample code is provided below which uses the managed DLL as COM.


#include “stdafx.h”
#include

// Import the type library in DLL
#import “MathLibrary.tlb” raw_interfaces_only

using namespace MathLibrary;
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
   // Initialize the COM interface
   HRESULT hr = CoInitialize(NULL);
   // Make a smart pointer to the IAddClass interface in DLL
   IAddClassPtr pIAddClass(__uuidof(CAddClass));   
   // Add two numbers using the ADD API
   long result = 0;
   hr = pIAddClass->Add(10, 20, &result);
   // Release the COM interface
   CoUninitialize();
   // Display the results
   cout << result << '\n';      return 0; } [/sourcecode]


Advertisements

How to Increment/Decrement A Variable In A Thread Safe Manner

December 31, 2008

Sometimes it will be necessary to increment or decrement a variable in a atomic manner so that no other thread can affect it while being incremented/decremented. The complex mutexes and critical sections can do the trick. Still, there is a single line API which does the same and it is

LONG InterlockedIncrement(LONG volatile* Addend)

(InterlockedDecrement for decrementing the value).

For example,

LONG myNo = 10;
LONG returnValue = InterlockedIncrement(&myNo);

will make

myNO = 11 and returnValue = 11.


How To Get The Time Elapsed Since The System Was Started

December 30, 2008

The function GetTickCount() (defined in WinBase.h) returns the no. of milliseconds elapsed since the computer was started.

The returned value is DWORD. So the above call may malfunction if the system has been up continuously for 49.7 days (as DWORD is only 32 bit). You can use the function GetTickCount64(), which returns ULONGLONG,  to overcome this problem.


How To Get the Processor Speed

December 19, 2008

The processor speed in MHz can be read directly from the registry location HARDWARE\DESCRIPTION\System\CentralProcessor. The following sample code illustrates this.

DWORD GetProcessorSpeed()
{
   HKEY hKey;
   // Read the speed from registry
   const long error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                      "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
                      0,
                      KEY_READ,
                      &hKey);

   DWORD dwMHz = 0;
   DWORD BufSize = MAX_PATH;
   if (ERROR_SUCCESS == error)
   {
      RegQueryValueEx(hKey, "~MHz", 0, 0, (LPBYTE)&dwMHz, &BufSize);
   }
   return dwMHz;
}

How To Get The Current CPU Cycle Count

December 18, 2008

With a little bit of help from assembler, we can find the exact CPU cycle count. This can be very much helpful to find the execution time of a program or function. The code to find the cpu cycle count is given below.

 
__int64 GetCpuCycle()
{
   unsigned int LowWord = 0;
   unsigned int HighWord = 0;
   _asm
   {
      // Insert Real Time Stamp Counter opcodes
      _emit 0x0F
      _emit 0x31
      mov HighWord, edx
      mov LowWord, eax
   }
   return ((__int64)(HighWord) << 32) + LowWord; } [/sourcecode] We can use the above function at the beginning and end of a program to get the no. of clock cycles it needed.


Shortcut keys in Visual studio 2005

December 5, 2008

The folowing is a description of some of the shortcut keys in Visual Studio 2005 (generously contributed by friend Premraj).

Ctrl-Alt-V, A
Displays the Auto window to view the values of variables currently in the scope of the current line of execution within the current procedure
Ctrl-Alt-C
Displays the Call Stack window to display a list of all active procedures or stack frames for the current thread of execution. Available only in break mode
Ctrl-Alt-D
Displays the Disassembly window
Ctrl-Alt-I
Displays the Immediate window, where you can evaluate expressions and execute individual commands
Ctrl-Alt-V, L
Displays the Locals window to view the variables and their values for the currently selected procedure in the stack frame
Ctrl-Alt-M, 1
Displays the Memory 1 window to view memory in the process being debugged. This is particularly useful when you do not have debugging symbols available for the code you are looking at. It is also helpful for looking at large buffers, strings, and other data that does not display clearly in the Watch or Variables window
Ctrl-Alt-M, 2
Displays the Memory 2 window
Ctrl-Alt-M, 3
Displays the Memory 3 window
Ctrl-Alt-M, 4
Displays the Memory 4 window
Ctrl-Alt-U
Displays the Modules window, which allows you to view the .dll or .exe files loaded by the program. In multiprocess debugging, you can right-click and select Show Modules for all programs
Ctrl-Alt-G
Displays the Registers window, which displays CPU register contents
Ctrl-Alt-N
Displays the Running Documents window that displays the set of HTML documents that you are in the process of debugging. Available in break and run modes
Ctrl-Alt-V, T
Displays the This window, which allows you to view the data members of the object associated with the current method
Ctrl-Alt-H
Displays the Threads window to view all of the threads for the current process
Ctrl-F11
Displays the disassembly information for the current source file. Available only in break mode
Ctrl-Alt-W, 1
Displays the Watch 1 window to view the values of variables or watch expressions
Ctrl-Alt-W, 2
Displays the Watch 2 window
Ctrl-Alt-W, 3
Displays the Watch 3 window
Ctrl-Alt-W, 4
Displays the Watch 4 window


How To Get All CD Drives

November 19, 2008

In the last post, I described how to open/close cd tray. Some of you might have raised your eye brows as there is no description how to find the drive letter of cd drive. Here is a sample program which prints all cd drive letters in a system.

#include
#include
#include “wtypes.h”
#include “basetsd.h”
#include “winbase.h”
using namespace std;

int main()

   // Iterate through all the 26 drives possible  
   for (char Drive = ‘a’; Drive <= 'z'; ++Drive)    {       // Format drive like "c:\"       string StrDrive = "";       StrDrive.push_back(Drive);       StrDrive.append(":\\");       // Print the drive letter if it is a cd drive       if (DRIVE_CDROM == GetDriveType(StrDrive.c_str()))       {          cout << Drive << '\n';       }    }    return 0; } [/sourcecode]

Some Background Info

The GetDriveType() function can give the type of a drive. The possible values are given below.

  • DRIVE_UNKNOWN = 0 : The drive type can not be determined.
  • DRIVE_NO_ROOT_DIR = 1 :The root path is invalid; for example, there is no volume is mounted at the path.
  • DRIVE_REMOVABLE = 2 : The drive has removable media; for example, a floppy drive, thumb drive, or flash card reader.
  • DRIVE_FIXED = 3 : The drive has fixed media; for example, a hard drive or flash drive.
  • DRIVE_REMOTE = 4 : The drive is a remote (network) drive.
  • DRIVE_CDROM = 5 : The drive is a CD-ROM drive.
  • DRIVE_RAMDISK = 6 : The drive is a RAM disk.

The GetDriveType() function expects an argument of type LPCTSTR, which can specify the root path of the drive with a trailing slash (as in c:\). if the argument is NULL, it will take the root of the current directory.

GetDriveType() will be expanded to GetDriveTypeW (for UNIODE) and GetDriveTypeA (for ANSI). The macro _T() can automatically expand the argument to multibyte character string if unicode is defined.