Clearly
asked on
.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.CoCreateInst ance( 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.InteropServ ices;
namespace ComSrv
{
[GuidAttribute("5F850215-7 AC2-48b8-A 8CF-A008F7 33D661")]
public class MyClass : IMyInterface2
{
public void doit( byte[] msg, ulong msgLength )
{
}
}
[ComImport]
[GuidAttribute("B55AFAEB-B C7D-4ca9-8 065-F9A45F E378B6")]
[InterfaceTypeAttribute
ComInterfaceType.Interface IsIUnknown )]
public interface IMyInterface2
{
void doit(
[In, MarshalAs( UnmanagedType.LPArray, SizeParamIndex=1, ArraySubType=UnmanagedType .U1 )]byte[] msg, [In]ulong msgLength );
}
}
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.CoCreateInst
);
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.InteropServ
namespace ComSrv
{
[GuidAttribute("5F850215-7
public class MyClass : IMyInterface2
{
public void doit( byte[] msg, ulong msgLength )
{
}
}
[ComImport]
[GuidAttribute("B55AFAEB-B
[InterfaceTypeAttribute
ComInterfaceType.Interface
public interface IMyInterface2
{
void doit(
[In, MarshalAs( UnmanagedType.LPArray, SizeParamIndex=1, ArraySubType=UnmanagedType
}
}
ASKER
THey are both running under the exact same context
ASKER
THey are both running under the exact same context
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
http://www.execpc.com/~gopalan/dotnet/classic_com/com.net_interop.html
You have posted this question twice. You can delete the other question in this topic area.
CJ
CJ
ASKER
I've posted twice because 500 is the limit and I want to award 1000.
Aight. Checked the link?
ASKER
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.
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.
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.
Code for managed service component..
using System;
using System.Runtime.InteropServ ices;
namespace ComSrv
{
[GuidAttribute("B55AFAEB-B C7D-4ca9-8 065-F9A45F E378B6")]
[InterfaceTypeAttribute(Co mInterface Type.Inter faceIsIUnk nown)]
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-7 AC2-48b8-A 8CF-A008F7 33D661")]
public class MyClass : IMyInterface2
{
public MyClass()
{
//
// TODO: Add constructor logic here
//
}
public void doit( byte[] msg, ulong msgLength )
{
}
}
}
using System;
using System.Runtime.InteropServ
namespace ComSrv
{
[GuidAttribute("B55AFAEB-B
[InterfaceTypeAttribute(Co
public interface IMyInterface2
{
void doit(
[In, MarshalAs( UnmanagedType.LPArray, SizeParamIndex=1, ArraySubType=UnmanagedType
[In]ulong msgLength );
}
/// <summary>
/// Summary description for Class1.
/// </summary>
///
[GuidAttribute("5F850215-7
public class MyClass : IMyInterface2
{
public MyClass()
{
//
// TODO: Add constructor logic here
//
}
public void doit( byte[] msg, ulong msgLength )
{
}
}
}
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
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
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.CoCreateInst ance( 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;
}
// 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.CoCreateInst
// );
IMyInterface2Ptr ob(__uuidof(MyClass));
UCHAR* pBytes = (UCHAR*)::CoTaskMemAlloc( 20 );
::ZeroMemory( pBytes, 20 );
ob->doit( pBytes, 20 );
}
::CoUninitialize();
return 0;
}
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
But with your original code, I did get access violation when I called doIt method.
Naveen
ASKER
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.
ASKER
BTW, the memory returned from CoTaskMemAlloc is non NULL and the CoCreateInstance returns S_OK.
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.
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.
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.
ASKER
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.
ASKER
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).
ASKER
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.
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.
ASKER
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
instance void doit([in] int32[] marshal( unsigned int8[ + 1]) msg, [in] unsigned int64 msgLength) cil managed
ASKER
Scratch that...the IL is:
instance void doit([in] unsigned int8[] marshal(unsigned int8[ + 1]) msg,[in] unsigned int64 msgLength) cil managed
instance void doit([in] unsigned int8[] marshal(unsigned int8[ + 1]) msg,[in] unsigned int64 msgLength) cil managed
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
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
ASKER
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-7 AC2-48b8-A 8CF-A008F7 33D661")]
public class MyClass : IMyInterface2
What could be going wrong here?
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-7
public class MyClass : IMyInterface2
What could be going wrong here?
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..
http://dotnet.oreilly.com/news/complus_0801.html
but in C..
I don't quite understand
>>[ComImport]
>>[GuidAttribute("B55AFAEB -BC7D-4ca9 -8065-F9A4 5FE378B6") ]
>>[InterfaceTypeAttribute
>>ComInterfaceType.Interfa ceIsIUnkno wn)]
>>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);
>>[ComImport]
>>[GuidAttribute("B55AFAEB
>>[InterfaceTypeAttribute
>>ComInterfaceType.Interfa
>>public interface IMyInterface2
>>{
>> void doit(
>> [In, MarshalAs( UnmanagedType.LPArray, >>SizeParamIndex=1, ArraySubType=UnmanagedType
>>[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
ASKER
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.
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.
ASKER
The question has been answered by someone else outside of experts-exchange. I will not reward anyone points for an answer.
COuld you please share the answer? This may benefit others.
ASKER
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
void doit( [In, MarshalAs( UnmanagedType.LPArray, SizeParamIndex=1, ArraySubType=UnmanagedType
The change was from :
[In]ulong msgLength
to
[In]uint msgLength
Have you been helped here, or is more needed? This question is still open today.
":0) Asta
":0) Asta
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)
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)
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
...It that .Net applications is pointing to a different memory processes..