.NET runtime or more precisely Common Language Runtime (CLR) runs the code
written for .NET platform. .NET compilers target the .NET runtime and
generate intermediate binary code. The code generated by .NET compilers
cannot be run directly on the processor because the generated code is not in
machine language. The code is generated in Microsoft Intermediate Language
(IL) and is called Managed Code. During runtime, .NET JIT (Just in Time)
compilers convert this intermediate code to native machine code and that
machine code is eventually run on the processor. Apart from the IL code,
.NET compilers also produce the metadata that describes your code. Every
type and member defined and referenced in your code is described within
metadata. .NET runtime loads metadata information for performing different
tasks like resolving method calls, loading different dependent modules,
marshaling data from one component to another, etc.
Legacy code (COM/COM+ components, Win32 DLLs, etc.) does not have to go
through all these steps and is already in native machine code. We don't need
any special JIT compilers and services in order to run legacy code. This
kind of code is also called Unmanaged Code.
CLR is the replacement of existing COM, Microsoft Transaction Server (MTS or
Viper), and COM+ layers., and Microsoft is encouraging developers and
companies to switch to the new .NET platform. You might be wondering what
will happen to the large code base of COM, MTS, and COM+ after companies
have invested so much in these technologies. Will the code have to be
rewritten for .NET? Can companies use their old code base and also use new
platform services? My answer is, yes I agree with you. There has been a lot
of investment in COM/MTS/COM+/Win32 DLLs, and it will not be feasible to
migrate that entire code base to .NET. But you don't have to worry about it
because you can access your legacy code from .NET code and vice versa. This
is possible because of the interoperation services provided by .NET
platform. In this way, you can write new code in .NET languages (VB .NET,
C#, Managed Extensions for C++, and others) and can still use your old
code. This article will not cover using .NET components from legacy code. I
will save that for a future article.
Topics Covered
This article addresses the following:
Using COM components from managed applications
Using Win32 DLL functions from managed applications
Software Required
The following software is required for testing the code of this article:
For demonstration purposes, I have created a COM DLL (UnmanagedServer.dll)
in Visual Basic 6.0 and a client application (ManagedClient.exe) in C#.
The COM DLL contains a component named CTest in which there is a method
named SayHello. This method takes a string as input and prefix that string
with the word "Hello" and returns that string. The managed client
application uses this method and displays the returned string in the console
window.
Step 1
Download and extract this article's ZIP file into a directory. Register
UnmanagedComponent.dll with regsvr32.exe.
Step 2
Since .NET runtime requires metadata in order to execute the code and our
COM component does not have any metadata, we will generate metadata for our
COM component. For this task, we will use the utility tlbimp.exe that is
found in the Bin directory of the .NET SDK installation directory. This
utility generates the metadata information by reading a COM-type library.
The output of this utility is a binary file that contains the metadata of
our COM component.
Now open a DOS box and go to the directory where you have extracted the COM
component, and type the following command:
This will create the metadata file in the same directory.
To view the contents of this file, use Intermediate Language Disassembler
(IL Disassembler). This tool is also installed with .NET SDK. The following
figure shows UnmanagedServer_net_wrapper.dll in IL Disassembler.
This tool puts all the components of the COM DLL in a namespace. The
namespace has the same name as the type library. In our case, the name of
the namespace is UnmanagedServer because the name of the type library file
is UnmanagedServer.dll.
Step 3
Now we will create the client application. The following is the code of the
ManagedClient.cs file.
1 using System;
2 using UnmanagedServer ;
3
4 class ManagedClient
5 {
6 public static void Main()
7 {
8 CTest objTest ;
9 objTest = new CTest() ;
10 string strMessage = "15Seconds reader" ;
11 strMessage = objTest.SayHello(strMessage) ;
12 Console.WriteLine(strMessage) ;
13 Console.WriteLine("\nPress any key to exit") ;
14 Console.Read() ;
15 }
16 }
The code is very simple.
Line 1 and Line 2 tell the compiler to use System and UnmanagedServer
namespaces, respectively, for type definitions that we are using in our
program.
Line 4 is starting a class. In C#, creating a class is required, even to
write a simple method.
Line 6 starts the Main method of the application.
Line 8 and Line 9 are declaring and initializing the CTest object.
Line 11 is invoking the SayHello Method.
Line 12 and Line 13 are used to output strings to the console.
Line 14 is used for taking key press input from the keyboard.
Use the following command in the DOS box or use BuildManagedClient.bat file
for compiling the ManagedClient.cs file.
In this command, the /reference option tells the C# compiler that we want to
include the types from UnmanagedServer_net_wrapper.dll, and the /out option
tells the compiler to output the executable of the name ManagedClient.exe.
The name of the source file to compile is given in the end.
Running this command will create the ManagedClient.exe file and running that
file would produce the following output:
Did you see how easy it is to use legacy COM components from managed code?
Now you can tell your manager, "We can move to .NET platform, and you don't
have to worry about our legacy COM code. I will take care of it."
Some Considerations
Are you asking, "What if one does not have access to the type library of a
COM server? Can we use such a COM server from managed code?" Yes, you can
access those components, too. .NET has services for accessing such
components. (I may cover that in a future article.)
I have tested accessing COM components installed in COM+ applications, and
it works fine. I could not test accessing components installed in MTS
packages, but I hope it will work.
Using Win32 DLL Functions from Managed Applications
Calling Win32 DLL functions from managed code is possible. .NET Platform
Invocation Service (PInvoke) is used for this task. There is a namespace
named System.Runtime.InteropServices that allows us to access the PInvoke
service.
For demonstration purposes I have created a simple client application named
ManagedClient2.exe.
That application displays the name of the computer. It uses a Win32
application programming interface (API) function named GetComputerName to
obtain the name of the computer.
The code is shown below:
1 using System;
2 using System.Text ;
3 using System.Runtime.InteropServices;
4
5 class ManagedClient2
6 {
7 [DllImport("kernel32.dll")]
8 public static extern bool GetComputerNameA(
9 [MarshalAs(UnmanagedType.LPStr)] StringBuilder
r_strComputerName,
10 ref int r_iLength) ;
11 public static int Main()
12 {
13 int iLength = 255 ;
14 bool bReturnValue = false ;
15 StringBuilder strComputerName = new
StringBuilder(iLength) ;
16 bReturnValue = GetComputerNameA(strComputerName, ref
iLength) ;
17 Console.WriteLine("Your computer name is " +
strComputerName) ;
18 Console.WriteLine("\nPress any key to exit") ;
19 Console.Read() ;
20 return 0 ;
21 }
22 }
Use the following command in the DOS box or use BuildManagedClient2.bat file
for compiling the ManagedClient2.cs file.
Running this command will create the ManagedClient2.exe file and running
that file would produce the following output (Your machine name will be
displayed in your output):
To use DLL exported functions from the managed environment one must declare
DLL functions, just like I did on Lines 7, 8, 9, and 10. I have broken the
declaration to multiple lines just for readability purposes, but they can be
merged into a single line.
The DlImport attribute is used to specify the location of the DLL that
contains the implementation of the external method. Similarly, the static
and external keywords are used to tell the compiler that this method is not
in the current module, rather it is in some external module.
Note that I have used some special attribute with method parameters. These
instructions are for the .NET marshaller so that it could convert .NET types
to the types expected by the DLL function and vice versa. For example, the
[MarshalAs(UnmanagedType.LPStr)] attribute tells the marshaller to convert
the parameter to a pointer to ANSI string and pass that pointer to the DLL
function. You must use correct attributes depending on the types expected by
the DLL functions, otherwise runtime exceptions might occur. In the same
way, the ref attribute with r_Ilength parameter tells the marshaller to pass
a pointer to the passed parameter to DLL function.
After declaring the functions that you want to call, you are all set. Go and
call those functions as if they belong to the current module.
Conclusion
I have just touched the scratch of using DLLs from managed code. I hope this
will get you started. Now you should explore it in more depth, especially
with respect to the marshaling and parameter-passing attributes.
About the Author
Mansoor Ahmed Siddiqui is a software consultant and technical writer working in the United States. He is in the field of Software Development since 1997. His areas of expertise include designing and
development of Web-based applications, client-server applications, and three-tier applications with a special focus on middle-tier and Win32 programming. He has expertise in UML, Visual C++, MFC, ATL, Visual Basic 6.0, Rational Rose, SQL Server 7.0, ASP, JavaScript, XML, ADO, COM/DCOM/COM+, MTS, MSMQ, Java, JSP, Servlets, EJBs, J2EE, VB .NET and C#. Currently he is working with Visual Studio 7.0 and .NET Platform. Apart from this, he is also an MCSD and brainbench certified in different languages.
Other interests are listening to music, swimming, playing cricket, and hanging out with friends. He can be reached at mansoorasiddiqui@hotmail.com
Tool Parts provide an interface for Web Part properties well beyond the capabilities of the default property pane. In this article Gayan Peiris shows how to customize Web Parts with custom Tool Parts. [Read This Article][Top]
This article demonstrates how to create a reusable component in ASP.NET 2.0 and then consume it from an ASP.NET page. Also learn how the ObjectDataSource control can be used to directly bind the output of an object to the controls in an ASP.NET page and how precompilation can be used to increase the performance of the Web application and catch compilation errors. [Read This Article][Top]
Browser Helper Objects (BHOs) are COM components that communicate with Internet Explorer to enrich the browsing experience. Michele Leroux Bustamante returns to the world of COM to show you how to build a managed BHO with the help of the .NET Framework's COM interoperability features. [Read This Article][Top]
In addition to creating custom Web Parts for SharePoint Portal Server, developers can actually create their own custom properties to further enhance Web Part appearance and behavior. Gayan Peiris explains the process and provides all the necessary code. [Read This Article][Top]
Accessing shared resources is a challenge for many ASP.NET developers. Tony Arslan explains how a simple serviced component can solve this infamous problem. [Read This Article][Top]
Using callbacks and function pointers in VB can be risky and complicated. Ben Garcia explains his work-around for the function pointer issue he encountered while creating the VB version of his SNMP component. [Read This Article][Top]
In part two of this intriguing article series, Ben Garcia shows how to build an updated and improved SNMP component in VC++ AND VB, and he briefly explains why limitations in VB make VC++ a better language for developing this type of application. [Read This Article][Top]
Ben Garcia sheds some light on the Simple Network Management Protocol
(SNMP). First he provides a history of SNMP, then he dives right into its
architecture. Finally, he shows how to build a COM component that
communicates with SNMP-enabled devices. [Read This Article][Top]
Paul Apostolos begins his series on using Web services and the MSComm32.OCX
component to access caller id information from a Web page. In part 1, learn how to write the Visual Basic program that runs on the server and updates a database with incoming callers.
[Read This Article][Top]
Doug Dean explains different methods of retrieving and manipulating data from a database in a VB DLL so that it is ready to be rendered in a browser. [Read This Article][Top]
Mailing List
Want to receive email when the next article is published? Just Click Here to sign up.