Sunday, June 17, 2007

I implemented the StrConcat() fn in a VC++(unmanaged) DLL..


VC++ DLL code contains :



void StrConcat( char *pszSource, char* pszDest )

{

strcat(pszDest, pszSource); //copy the string

}



here is my new code ...we think it looks silly programming...


ok ...


pszSource and pszDest are arguments to the StrConcat( ) fn( Great Invention).


Important Points :

1.pszSource acts as a input parameter to StrConcat() fn.

2.pszDest acts as both input and output parameter to StrConcat() fn.


I need to call this method from C# application. we can make use of the .NET's platform invocation services to call the DLL fn in C#.


Platform Invocation Services :

-------------------------------------

1.Platform Invocation Services (PInvoke) allows managed code to call unmanaged functions that are implemented in a DLL.


Unmanaged code called in managed code through marshalling.


Calling a DLL Export Directly from C#

To declare a method as having an implementation from a DLL export, do the following:

1.Declare the method with the static and extern C# keywords

2.Attach the DllImport attribute to the method. The DllImport attribute allows you to specify the name of the DLL that contains the method. The common practice is to name the C# method the same as the exported method, but you can also use a different name for the C# method.

3.Optionally, specify custom marshaling information for the method's parameters and return value, which will override the .NET Framework default marshaling.

C# application :



class PlatformInvokeTest

{

[DllImport("CustomDLL.dll")]

public static extern void StrConcat(string source, string dest); // this is the C++ function //exposed by the dll

}

Did u think the above will concatenate the string ... I am sure we will not get the concatenated string in dest.



The reason is as follows :

I already told the Unmanaged code DLL is called through the marshalling mechanism.

for Marshalling, we have to specify whether In or Out parameter passed to the fn. if we are not specifying anything in dest string. we have to declare it as

follows :

[DllImport("CustomDLL.dll")]

public static extern void StrConcat(string source, ref string dest); // this is the C++ function exposed by the dll

we can specify the input parameter using In attribute.

we can specify the output parameter usign Out attribute.



if the parameter is both in and out parameter, At that time we have to use ref keyword to indicate the pass by reference.

Instead of it, we can use

[DllImport("CustomDLL.dll")]

public static extern void StrConcat(string source, StringBuilder dest); // this is the C++ function exposed by the dll

//StringBuilder class has both In and out attribute by default .

two types of Marshalling :

1.Default Marshalling

2.Custom marshalling

Default Marshaling and Specifying Custom Marshaling for Parameters to Unmanaged Methods

When calling an unmanaged function from C# code, the common language runtime must marshal the parameters and return values.

For every .NET Framework type there is a default unmanaged type, which the common language runtime will use to marshal data across a managed to unmanaged function call. For example, the default marshaling for C# string values is to the type LPTSTR (pointer to TCHAR char buffer). You can override the default marshaling using the MarshalAs attribute in the C# declaration of the unmanaged function.





About Example :

Next we have to call the VC++ function puts() from msvcrt.dll. this will displays the characters on screen .

Example for custom marshalling :

// Marshal.cs

using System;

using System.Runtime.InteropServices;



class PlatformInvokeTest

{

[DllImport("msvcrt.dll")]

public static extern int puts(

[MarshalAs(UnmanagedType.LPStr)]

string m);

[DllImport("msvcrt.dll")]

internal static extern int _flushall();





public static void Main()

{

puts("Hello World!");

_flushall();

}

}

string is marshalled as LPSTR data type in VC++. // [MarshalAs(UnmanagedType.LPStr)]

Specifying Custom Marshaling for User-Defined Structs

You can specify custom marshaling attributes for fields of structs and classes passed to or from unmanaged functions. You do this by adding MarshalAs attributes to the fields of the struct or class. or we can use the StructLayout Attribute.

[StructLayout(LayoutKind.Sequential)]

public class LOGFONT

{

public const int LF_FACESIZE = 32;

public int lfHeight;

}

Callback function in VC++ DLL is converted as delegate in C# :



if the VC++ DLL have the Call back fn in a DLL as follows :

typedef void (__stdcall *PFN_MYCALLBACK)();

int __stdcall MyFunction(PFN_ MYCALLBACK callback);

we can call it through the delegate keyword.

How can we call the above fn in C# ?

To call MyFunction from managed code, declare the delegate, attach DllImport to the function declaration, and optionally marshal any parameters or the return value:

public delegate void MyCallback();

[DllImport("MYDLL.DLL")]

public static extern void MyFunction(MyCallback callback);





Summary :

1.we can call the Unmanaged DLL fn using DllImport attribute.

2.For every .NET Framework type there is a default unmanaged type, which the common language runtime will use to marshal data across a managed to unmanaged function call.

3.the default marshaling for C# string values is to the type LPTSTR (pointer to TCHAR char buffer). You can override the default marshaling using the MarshalAs attribute in the C# declaration of the unmanaged function.

4.we can do Custom Marshaling for User-Defined Structs using MarshalAs or StructLayout attribute.

5. Callback fn in unmanaged code(VC++ DLL) called with delegate in C#.( Managed code )










No comments: