Click here to Skip to main content
15,894,539 members
Articles / Programming Languages / C#
Article

Editing the Interop Assembly to Pass Array from COM DLL to C# App and Vice Versa

Rate me:
Please Sign up or sign in to vote.
2.25/5 (6 votes)
1 Jul 2006CPOL1 min read 54.6K   330   12   6
This article shows how to change the COM method signature by editing the Interop assembly

Please review the demo code before you read the article.

Introduction

The first step to connect between .NET components and COM components is to create an RCW, by:

  1. Using the references dialog box of Visual Studio .NET, or
  2. Using the TLBIMP command-line tool

The type library importer converts most COM method signatures into managed signatures, but it might not always be appropriate for the COM component. Here I describe how to modify the metadata inside the interop assembly.

Specify Marshaling Changes in Microsoft Intermediate Language (MSIL)

  1. Generate the initial interop assembly using Visual Studio .NET. For example, add reference to MarshallingTest.dll and you will note that MARSHALLINGTEST reference has been added to your solution. You can use tlbimp.exe tool:

    tlbimp MarshallingTest.tlb /out:MarshallingTest.dll
  2. At the command prompt, type the following command to produce Microsoft intermediate language (MSIL) for the assembly:

    ildasm MarshallingTest.dll /out:MarshallingTest.il
  3. Edit the MSIL (MarshallingTest.il) :

    Here you should make your correction, search for...

    MSIL
    .method public hidebysig newslot virtual instance 
       void SetSurface(int32 size, native int pSurface) 
       runtime managed internalcall

    ... and make the following change:

    MSIL
    .method public hidebysig newslot virtual instance 
       void SetSurface(int32 size, native int & pSurface) 
       runtime managed internalcall

    Then, search for:

    MSIL
    .method public hidebysig newslot virtual instance 
       void GetSurface([out] int32& size, [out] native int pSurface) 
       runtime managed internalcall

    Change to:

    MSIL
    .method public hidebysig newslot virtual instance 
       void GetSurface([out] int32& size, [out] native int & pSurface) 
       runtime managed internalcall
  4. At the command prompt, type the following command to produce a new MarshallingTest.dll defining the proper syntax:

    ilasm /DLL MarshallingTest.il
  5. Delete the old reference to the MARSHALLINGTEST and add a new reference for the new DLL that was generated using ilasm.exe (step 4).

Inside the Code

This code shows how to connect to a COM object from a C# application and how to allocate the Marshalling memory before the get/set call:

Sample screenshot

Note that the StructureToPtr member function converts an array of structures to block of memory using the Marshal.AllocCoTaskMem method.

Also note that during the GetSurface call, the memory allocation is done on the COM side. So, the C# side is responsible for freeing this memory.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Israel Israel
- Experience over 10 years in OOD/OOP, Working with Microsoft technologies VB, VC++, MFC, COM, C#, VB.NET, SQL Server, (Managed & Unmanaged code) etc... for developing solutions used in Optical industry and Semi-conductor industry.
- Team Leader: Leading & Management group of developers, Fixing software problems, Build Installation & QA.
- Individual efforts and learning : WEB Sites, ASP .Net,Encryption Protocols & MORE

Comments and Discussions

 
GeneralWorking with a COM server Pin
Dave_Sullivan3313-Apr-07 5:24
Dave_Sullivan3313-Apr-07 5:24 
GeneralRe: Working with a COM server Pin
Dave_Sullivan3316-Apr-07 4:34
Dave_Sullivan3316-Apr-07 4:34 
GeneralGeneric version Pin
Husayt7-Nov-06 23:03
Husayt7-Nov-06 23:03 
Thanks for great routine.
I have actually changed it a little bit to make it generic.

private static IntPtr StructureToPtr<t>(T[] MyArray)
{
return StructureToPtr<t>(MyArray,0);
}

private static IntPtr StructureToPtr<t>(T[] MyArray,int iStructSize)
{
if (iStructSize ==0) iStructSize=Marshal.SizeOf(typeof(T));
//Compute our size and allocate memory
IntPtr Buf = IntPtr.Zero;
Buf = Marshal.AllocCoTaskMem(
MyArray.Length * iStructSize
);

//Copy each structure into our allocated block
//iCurOffset tracks how deep into
//the block we need to copy
int iCurOffset = 0;
foreach (T item in MyArray)
{
Marshal.StructureToPtr(
item,
(IntPtr)(Buf.ToInt32() + iCurOffset),
false);
iCurOffset += iStructSize;
} return Buf;
}

Thanks

Regards,
Huseyn
GeneralRe: Generic version Pin
Rabia Kl.9-Nov-06 0:37
Rabia Kl.9-Nov-06 0:37 
Generalerror 8007007e Pin
mega_john24-May-06 2:49
mega_john24-May-06 2:49 
GeneralRe: error 8007007e Pin
Rabia Kl.31-May-06 3:11
Rabia Kl.31-May-06 3:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.