.Net Interop Problem with LPArray : COM Client throws Exception

I need to know how to properly marshal the data from my legacy app to a .Net component. The integrity of the data must be kept. No memory leaks must occur in the solution. The solution should never fault. My legacy app uses the following IDL interface definition:
 
interface IMyInterface2 : IUnknown
{
 HRESULT doit( [in, size_is(msgLength)]UCHAR* msg, [in] ULONG msgLength );
};
 
When my legacy COM Client calls my .Net component that implements this interface, an access violation (0xC0000005) exception is thrown. I've tried everything and can not figure out why the exception is thrown in
the COM Client.
 
Here is the COM Client:
 
#include "stdafx.h"
#include "IMyInterface2_h.h"
#include "IMyInterface2_i.c"
 
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = S_OK;
hr = ::CoInitialize( NULL );
CLSID rcid = { 0x5F850215, 0x7AC2, 0x48b8, { 0xA8, 0xCF, 0xA0, 0x08, 0xF7, 0x33, 0xD6, 0x61 } };
 
{
CComPtr<IMyInterface2> iMyInterface2;
hr = iMyInterface2.CoCreateInstance( rcid, NULL, CLSCTX_INPROC_SERVER
);
UCHAR* pBytes = (UCHAR*)::CoTaskMemAlloc( 20 );
::ZeroMemory( pBytes, 20 );
iMyInterface2->doit( pBytes, 20 );
}
::CoUninitialize();
 
return 0;
}
 
The exception is thrown on the statement:
iMyInterface2->doit( pBytes, 20 );
The call never gets to the .Net component's method
 
And here is the .Net service component. The .Net component must be copied in the same directory as the COM client.
 
using System;
using System.Runtime.InteropServices;
 
namespace ComSrv
{
 [GuidAttribute("5F850215-7AC2-48b8-A8CF-A008F733D661")]
 public class MyClass : IMyInterface2
 {
  public void doit( byte[] msg, ulong msgLength )
  {
  }
 }
 
 [ComImport]
 [GuidAttribute("B55AFAEB-BC7D-4ca9-8065-F9A45FE378B6")]
 [InterfaceTypeAttribute  
ComInterfaceType.InterfaceIsIUnknown)]
 public interface IMyInterface2
 {
  void doit(
   [In, MarshalAs( UnmanagedType.LPArray, SizeParamIndex=1, ArraySubType=UnmanagedType.U1 )]byte[] msg, [In]ulong msgLength );
 }
}

ClearlyAsked:
Who is Participating?
 
moduloConnect With a Mentor Commented:
Finalized as proposed

modulo

Community Support Moderator
Experts Exchange
0
 
Michel SakrCommented:
does the com client calls your .net application using a user context that has enough permissions to do it? try to run the client as an administrator..
...It that .Net applications is pointing to a different memory processes..
0
 
ClearlyAuthor Commented:
THey are both running under the exact same context
0
Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

 
ClearlyAuthor Commented:
THey are both running under the exact same context
0
 
CJ_SCommented:
Isn't as easy as it sounds. This article is pretty good, just read through it:

http://www.execpc.com/~gopalan/dotnet/classic_com/com.net_interop.html
0
 
CJ_SCommented:
You have posted this question twice. You can delete the other question in this topic area.

CJ
0
 
ClearlyAuthor Commented:
I've posted twice because 500 is the limit and I want to award 1000.
0
 
CJ_SCommented:
Aight. Checked the link?
0
 
ClearlyAuthor Commented:
Let me be clear that I am not having a problem in general with .Net/COM interop. In fact, I've got many other interfaces working. The problem I am having is with this particular example which uses LPArray.
0
 
naveenkohliCommented:
0xC0000005 as you have seen is an access violation, usually thrown when trying to access an invalid or NULL pointer.
Could ypu check if iMyInterface2 poiner is NULL after CoCreateInstance. There is a very chance that this interface never got created. I have tried to replicate your problem and I am getting the same problem. Only reason that COM interface was never created.


Have you tried using #import direcive with the TLB created from your managed .Net service component. I am sure that you must have doine it, but could you check if you REGASM the managed asembly so that gets registered with COM.

I have made some modification your code and after that i did not get any acces violation.
0
 
naveenkohliCommented:
Code for managed service component..

using System;
using System.Runtime.InteropServices;

namespace ComSrv
{
     [GuidAttribute("B55AFAEB-BC7D-4ca9-8065-F9A45FE378B6")]
     [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
     public interface IMyInterface2
     {
          void doit(
               [In, MarshalAs( UnmanagedType.LPArray, SizeParamIndex=1, ArraySubType=UnmanagedType.U1 )]byte[] msg,
               [In]ulong msgLength );
     }

     /// <summary>
     /// Summary description for Class1.
     /// </summary>
     ///
     [GuidAttribute("5F850215-7AC2-48b8-A8CF-A008F733D661")]
     public class MyClass : IMyInterface2
     {
          public MyClass()
          {
               //
               // TODO: Add constructor logic here
               //
          }

          public void doit( byte[] msg, ulong msgLength )
          {
          }

     }
}
0
 
naveenkohliCommented:
1.I compiled it...
2.used REGASM on this assembly to register with COM
3. Then i used TLBEXP to create TLB file
4. Copied TLB file to client folder.
5. Copied assembly to testclient folder

0
 
naveenkohliCommented:
Code for client application...You will notice that i have commented out some lines from your code. And replaced #include directives with #import directive

// TestApp.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
//#include "TestIdl_h.h"
//#include "TestIdl_i.c"
#import "MyNetService.tlb" raw_interfaces_only
using namespace MyNetService;


int _tmain(int argc, _TCHAR* argv[])
{
     HRESULT hr = S_OK;
     hr = ::CoInitialize( NULL );
     //CLSID rcid = { 0x5F850215, 0x7AC2, 0x48b8, { 0xA8, 0xCF, 0xA0, 0x08, 0xF7, 0x33, 0xD6, 0x61 } };

     {
          //CComPtr<IMyInterface2> iMyInterface2;
          //hr = iMyInterface2.CoCreateInstance( IID_IMyInterface2, NULL, CLSCTX_INPROC_SERVER
          //     );

          IMyInterface2Ptr ob(__uuidof(MyClass));
          UCHAR* pBytes = (UCHAR*)::CoTaskMemAlloc( 20 );
          ::ZeroMemory( pBytes, 20 );
          ob->doit( pBytes, 20 );
     }
     ::CoUninitialize();

     return 0;

}
0
 
naveenkohliCommented:
Then I ran this test app.... I did not get any exceptions thrown at me.
But with your original code, I did get access violation when I called doIt method.

Naveen
0
 
ClearlyAuthor Commented:
As I stated in my original post, I am attempting to load the .Net component into a legacy application. I do not have the luxury of modifying the legacy apllication. Using the #import would require changing my legacy apllication. I was able to reduce the interface problem to my legacy application in the example I posted. Thus, figuring out how to solve the problem in my example application should solve my legacy application problem. The solution I need is some change in the .Net component.
0
 
ClearlyAuthor Commented:
BTW, the memory returned from CoTaskMemAlloc is non NULL and the CoCreateInstance returns S_OK.
0
 
naveenkohliCommented:
Do you have luxury of debugging through the legacy application or not? ?Because that can make things little simple if you have because right now you are not even sure of the COM object got created or not.
Can you verify if the object was created at all? Access violation has to come from NULL pointer. Most likely its your COM object pointer.
0
 
naveenkohliCommented:
If you could really verify that interface is getting created and is not NULL, it will really help because it will eliminate one cause of this trouble.
0
 
ClearlyAuthor Commented:
Verified that the interface is created. Before the call to CoCreateInstance, the value of iMyInterface2 is 0x00000000. After the call to CoCreateInstance, the value of iMyInterface2 is 0x0111002c.
0
 
ClearlyAuthor Commented:
BTW, I've actually got 19,000 additional points that I am happy to reward if in fact I am satisfied with the solution and the solution comes quickly (24 hours).
0
 
ClearlyAuthor Commented:
Here is more detail of the error emssage:

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
0
 
ClearlyAuthor Commented:
Here is the ILDasm signature for the .Net IMyInterface2:

instance void  doit([in] int32[]  marshal( unsigned int8[ + 1]) msg, [in] unsigned int64 msgLength) cil managed
0
 
ClearlyAuthor Commented:
Scratch that...the IL is:

instance void  doit([in] unsigned int8[]  marshal(unsigned int8[ + 1]) msg,[in] unsigned int64 msgLength) cil managed
0
 
naveenkohliCommented:
Clearly,
Now I am also getting the same "Run time Check Failure" errors. I have done some reasearch on this. COuple of other people have run into this issue too. But the problem turned out to be wrong GUIDs used for CoCreateInstance. It seems that this is not the problem in your case. Could you check into this?

Naveen
0
 
ClearlyAuthor Commented:
What should I check? The code is in the original post.

The COM Client instantiates:

CLSID rcid = { 0x5F850215, 0x7AC2, 0x48b8, { 0xA8, 0xCF, 0xA0, 0x08, 0xF7, 0x33, 0xD6, 0x61 } };

and the GuidAttribute set for my .Net component is:

[GuidAttribute("5F850215-7AC2-48b8-A8CF-A008F733D661")]
public class MyClass : IMyInterface2

What could be going wrong here?
0
 
Michel SakrCommented:
something similar was known in vb6 where I had to recompile the client component to conform to the server component..
http://dotnet.oreilly.com/news/complus_0801.html
but in C..
0
 
EDDYKTCommented:
I don't quite understand

>>[ComImport]
>>[GuidAttribute("B55AFAEB-BC7D-4ca9-8065-F9A45FE378B6")]
>>[InterfaceTypeAttribute  
>>ComInterfaceType.InterfaceIsIUnknown)]
>>public interface IMyInterface2
>>{
>> void doit(
>>  [In, MarshalAs( UnmanagedType.LPArray, >>SizeParamIndex=1, ArraySubType=UnmanagedType.U1 )]byte[] >>msg,
>>[In]ulong msgLength );
>>}
>>}

Since UnmanagedType.U1 is known type by .NET. Do you really need to pass msgLength?

ie [In, MarshalAs( UnmanagedType.LPArray, >>SizeParamIndex=0, ArraySubType=UnmanagedType.U1 )]byte[] >>msg);
0
 
ClearlyAuthor Commented:
EDDYKT :
How does .Net know how long the byte array is? It is not a string and does not have a NULL terminator. It is literally a chunk of memory.
0
 
ClearlyAuthor Commented:
The question has been answered by someone else outside of experts-exchange. I will not reward anyone points for an answer.
0
 
naveenkohliCommented:
COuld you please share the answer? This may benefit others.
0
 
ClearlyAuthor Commented:
The problem was with the ulong marshalled parameter. The correct signature is listed below.

void doit( [In, MarshalAs( UnmanagedType.LPArray, SizeParamIndex=1, ArraySubType=UnmanagedType.U1 )]byte[] msg, [In]uint msgLength );

The change was from :
    [In]ulong msgLength
    to
    [In]uint msgLength
0
 
Asta CuCommented:
Have you been helped here, or is more needed?  This question is still open today.
":0) Asta
0
 
Zlatin ZlatevTechnical ArchitectCommented:
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

-  PAQ and points removed


Please leave any comments here within the next seven days.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER !

Zlatin Zlatev
_____________
P.S. @Clearly, I do not suggest delete for the question because there are comments from experts that may be useful to other EE members with similar problem. You will loose your question points assigned in this question, unless you provide a starting point or a solution for the question within 7 days.

In that case my suggestion will be to redeem the points to you (PAQ and points not removed)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.