Threading using the ref statement? Wha Happen?
-
My COM object is not implemented as an STA. so if it's marshalling, what can I do? (I know there probably isn't a short answer) thanks.
Instead of importing the typelib automatically, you may have to define your own interface in .NET (that which reflects the class interface of your OCX), putting the appropriate marshaling attributes (
MarshalAsAttribute
). See that class (and theSystem.Runtime.InteropServices
namespace for more details (and it'd be good to take a quick glance before proceding). Question, though. Are you trying to pass the first byte array element as a reference, or do you want to pass the entire array. The way you're doing it means that you're passing the address of the first element and this will definitely requiring marshaling. If you want to pass the whole array as a ref, useref myByteArray
as a parameter instead. .NET will take care of a lot of things for you, including stuff like this.-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
-
Instead of importing the typelib automatically, you may have to define your own interface in .NET (that which reflects the class interface of your OCX), putting the appropriate marshaling attributes (
MarshalAsAttribute
). See that class (and theSystem.Runtime.InteropServices
namespace for more details (and it'd be good to take a quick glance before proceding). Question, though. Are you trying to pass the first byte array element as a reference, or do you want to pass the entire array. The way you're doing it means that you're passing the address of the first element and this will definitely requiring marshaling. If you want to pass the whole array as a ref, useref myByteArray
as a parameter instead. .NET will take care of a lot of things for you, including stuff like this.-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
I want to pass the entire array, but what data type will my COM object be expecting if I pass
ref bytearray
? right now, the prototype for my COM method is:STDMETHODIMP CUSB::WriteSPI(unsigned char* datain, int size)
so, when C# gets a hold of that, it takes the pointer as aref byte
in other words, what is the C++/COM equivalent of a ref to an array? -
I want to pass the entire array, but what data type will my COM object be expecting if I pass
ref bytearray
? right now, the prototype for my COM method is:STDMETHODIMP CUSB::WriteSPI(unsigned char* datain, int size)
so, when C# gets a hold of that, it takes the pointer as aref byte
in other words, what is the C++/COM equivalent of a ref to an array?First, an array is always a reference type. While some examples use
ref
with arrays, it's really only necessary for value types (int
,long
,byte
, etc.) Passing a reference type results in the address passed to the native function. For your interface, though, you'd want to write your method to that functions like so:[Guid("...")]
public interface IUSB
{
void WriteSPI(
[MarshalAs(UnmanagedType.LPArray,SizeParamIndex=1)]byte[] array,
int size);
// ...
}This will marshal the array as the address to the first element, which is what you're wanting to do.
-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
-
First, an array is always a reference type. While some examples use
ref
with arrays, it's really only necessary for value types (int
,long
,byte
, etc.) Passing a reference type results in the address passed to the native function. For your interface, though, you'd want to write your method to that functions like so:[Guid("...")]
public interface IUSB
{
void WriteSPI(
[MarshalAs(UnmanagedType.LPArray,SizeParamIndex=1)]byte[] array,
int size);
// ...
}This will marshal the array as the address to the first element, which is what you're wanting to do.
-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
I understand, but C# still sees the
unsigned char*
from my COM method as aref byte
so how can I get around that? sorry to keep bugging you. -
I understand, but C# still sees the
unsigned char*
from my COM method as aref byte
so how can I get around that? sorry to keep bugging you.Hmm, it's usually right...but not always the easiest to implement. It would make sense, since ref'ing the first element would return the address of the array, but as you can see...it's not working. :(( What I was referring to was actually defining the interface yourself and not using the interop assembly that's generated automatically. Especially for small typelibs or for typelibs which you only need a couple of things (like many do for mshtml's typelib), it's just easier defining the interface with the right attributes and method placements (for IUnknown interfaces, order of the methods is important; for IDispatch interfaces, using the DispIdAttribute with the correct ID is important). You can still instantiate the COM object through the interop, or derive a class from AxHost and override the necessary things, also implementing your interface, or using various methods in the Marshal class or Type class, and set the reference to a variable defined as your class interface. Access the methods from the interface (as in all COM you should, anyway). Still, though, that method signature should be right. When you say jibberish, what exactly do you mean?
-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
-
Hmm, it's usually right...but not always the easiest to implement. It would make sense, since ref'ing the first element would return the address of the array, but as you can see...it's not working. :(( What I was referring to was actually defining the interface yourself and not using the interop assembly that's generated automatically. Especially for small typelibs or for typelibs which you only need a couple of things (like many do for mshtml's typelib), it's just easier defining the interface with the right attributes and method placements (for IUnknown interfaces, order of the methods is important; for IDispatch interfaces, using the DispIdAttribute with the correct ID is important). You can still instantiate the COM object through the interop, or derive a class from AxHost and override the necessary things, also implementing your interface, or using various methods in the Marshal class or Type class, and set the reference to a variable defined as your class interface. Access the methods from the interface (as in all COM you should, anyway). Still, though, that method signature should be right. When you say jibberish, what exactly do you mean?
-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
When I said it was putting out garbage data, when I call
WriteSPI(dataarray, size)
I was looking at the output in bytes and I would get: 00 00 AA 00 size 00 ... so the size value was being sent in the part that was supposed to be the data, the first three bytes of data was always the same though, no matter what I sent. Are you saying that I can write a separate interface for my COM object in C#, that will override the one that was automatically generated when I compiled the C++ code for the COM object? If so, I didn't realize you can do that. If I specify the GUID as an attribute for the object, it will be able to find it? hmmmm... -
When I said it was putting out garbage data, when I call
WriteSPI(dataarray, size)
I was looking at the output in bytes and I would get: 00 00 AA 00 size 00 ... so the size value was being sent in the part that was supposed to be the data, the first three bytes of data was always the same though, no matter what I sent. Are you saying that I can write a separate interface for my COM object in C#, that will override the one that was automatically generated when I compiled the C++ code for the COM object? If so, I didn't realize you can do that. If I specify the GUID as an attribute for the object, it will be able to find it? hmmmm...This definitely sounds like a marshaling problem. Seems like data about the array is being sent when you want the array data since the bytes should be the same on both. You shoud read Advanced COM Interop in the MSDN Library. Basically, you're interface is just a way to access the class. In COM, you treat every object through it's interface by QI'ing (QueryInterface) for the interface that the class implements. In .NET this is acheived by merely casting. You can define the interface in your project regardless of what is in the interop assembly, yes. As long as the method signatures are marshalable and similar (proper number of params) and use the same return types (should all be void unless
PreserveSignature
istrue
, which then you useint
to represent an HRESULT). Just instantiate your COM class and cast it to the interface you redefined (remember, use the same GUID for the interface in theGuidAttribute
and keep all that stuff the same I said in the previous post) and you should have a valid reference to your object through that interface (again, it's like calling QI, which doesn't care about qualified names like .NET does). I'm not sure I'm explaining this as easily as possible, but read that section in MSDN (or perhaps start with the more basic stuff that comes before it). COM interop is powerful but is also is a beast to tame.-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
-
This definitely sounds like a marshaling problem. Seems like data about the array is being sent when you want the array data since the bytes should be the same on both. You shoud read Advanced COM Interop in the MSDN Library. Basically, you're interface is just a way to access the class. In COM, you treat every object through it's interface by QI'ing (QueryInterface) for the interface that the class implements. In .NET this is acheived by merely casting. You can define the interface in your project regardless of what is in the interop assembly, yes. As long as the method signatures are marshalable and similar (proper number of params) and use the same return types (should all be void unless
PreserveSignature
istrue
, which then you useint
to represent an HRESULT). Just instantiate your COM class and cast it to the interface you redefined (remember, use the same GUID for the interface in theGuidAttribute
and keep all that stuff the same I said in the previous post) and you should have a valid reference to your object through that interface (again, it's like calling QI, which doesn't care about qualified names like .NET does). I'm not sure I'm explaining this as easily as possible, but read that section in MSDN (or perhaps start with the more basic stuff that comes before it). COM interop is powerful but is also is a beast to tame.-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
okay, I get it... Thanks a lot for your help. just one last question, for my new interface, do I use the GUID from the COM interface or from the COM class itself? that's it, I swear. thanks again. Jesse
-
okay, I get it... Thanks a lot for your help. just one last question, for my new interface, do I use the GUID from the COM interface or from the COM class itself? that's it, I swear. thanks again. Jesse
The interface.
-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
-
The interface.
-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
arrrrrgggggghh... Using the interface works fine, except when it is in my new thread. damn.