I didn't understand what is IntPtr, could someone explain this?
thanks
It is an integer that is the same size as a pointer. 32 bits wide in 32 bit images, 64 wide in 64 bit images.
It is the managed counterpart of void*.
You can cast to and from void* for usage in managed code without having to resort to unsafe code in managed layers, eg C#.
It's a .NET platform-specific type that is used to represent a pointer or a handle.
The IntPtr type is designed to be an integer whose size is platform-specific. That is, an instance of this type is expected to be 32-bits on 32-bit hardware and operating systems, and 64-bits on 64-bit hardware and operating systems.
The IntPtr type can be used by languages that support pointers, and as a common means of referring to data between languages that do and do not support pointers.
IntPtr objects can also be used to hold handles. For example, instances of IntPtr are used extensively in the System.IO.FileStream class to hold file handles.
(from MSDSN)
This is about the c and c++ type intptr_t but the principle is the same.
What is uintptr_t data type
http://msdn.microsoft.com/en-us/library/system.intptr(v=VS.100).aspx#Y69
A pointer sized blackbox. Sometimes you have languages that don't support unsafe code/pointers, and thus need to use IntPtr in the API.
I think its use has been reduced since .net 2 since many of its use-cases are better fit for safe-handles.
Related
In C# I am declaring an interface, which will be exposed to COM for use by C++. Our spec says one integer parameter should be [in]UINT uiVal. I'm using int in C# and it is being exposed as long.
It's not a big deal, but how can I force it to marshall to UINT rather than long? Some specific .Net type, or do I need to add attributes to the C# parameter somehow?
UINT is a type alias from the Windows SDK, you will never get it out of a type library. Tooling that translates type libraries, like the #import directive you are using, pick native C types. History plays a role, COM was originally designed for the 16-bit version of Windows. When long was important to declare a 32-bit integer.
Closest you can get is uint in the C# declaration, it will be translated to unsigned long in your C++ code. Which is fine, it is still a 32-bit type, Microsoft chose the LLP64 data model for 64-bit code. They did not have much of a choice. Unlike the LP64 model chosen in *nix. They did not have much of a choice either, the Y2K38 disaster is approaching fast :)
I'm new to COM. According to http://msdn.microsoft.com/en-us/library/windows/desktop/ms221069(v=vs.85).aspx
BSTR is a string with prefix. I am wondering what it the purpose for BSTR. In which case we have to use BSTR instead of string type? If someone could have an example please?
Thanks
First of all, sometimes you have to use BSTR. For example, if you call a COM method and the callee expects a BSTR you'd rather not pass any other string type - otherwise they could call SysStringLen() and run into undefined behavior. Use BSTR when an API descriptions says you should use BSTR.
Also BSTR has these useful features:
(the most important thing) It is allocated on a separate heap managed by COM and so if your application consists of different modules using different runtime heaps any module can allocate a BSTR and any module can then free it easily which is not the case with other dynamically allocated stuff. This is very useful for cases when for example you pass an existing string, the callee has to either preserve or reallocate it - without the single heap and the single set of allocation functions you'd have a hard time doing that.
(the less important thing) it's supported by Automation marshaller so you can easily use it in COM interfaces that must be marshalled and not bother crafting and registering the proxy-stubs stuff
(the least important IMO) it can contain embedded null characters unlike other typical string types
BSTR is standard string type in wide family of APIs:
A BSTR (Basic string or binary string) is a string data type that is used by COM, Automation, and Interop functions. Use the BSTR data type in all interfaces that will be accessed from script.
You use BSTR when you have to, esp. when API you are using expects that you pass BSTR; e.g. when certain COM interface method requires BSTR argument. You use BSTR or anything else at your discretion when you have choices.
I have a module A in Managed C++, it depends on module B in native C++ which wrapped as COM plus.
In module B, I read bytes from a file. Now I am trying to call the file reading functionality from A. But failed.
Dependency detail: I used tlbimp.exe and generated the interop according to Module B. A referrs to the interop.
I tried to pass an "array^" but only one char was received, which is understandable because marshaling doesn't know the array length and could NOT handle the whole array.
I searched out some recommendation about safe array, but could NOT use it successfully in my projects.
Could somebody help me on this?
Thanks a lot.
If you are going to be talking to your native object via COM, you're going to have to pass the array the COM way.
SAFEARRAY would definitely work, but you don't have to use it. It is a fair amount of work to set up anyway. If neither component is a scripting language or VB6, there is little value to using a SAFEARAY.
COM can marshal the array just fine, you just have to tell it how big it is. The two most common mechanisms in COM to pass (native) arrays are "fixed-sized arrays" and "conformant arrays".
Fixed-size array:
If you know at compile time the size of the array, this is the way to go. Declare your COM method as follows in your IDL:
...
const long ARRAY_SIZE = 1024;
...
HRESULTS MethodAbc(MyClass array[ARRAY_SIZE]);
Marshalling will take care of passing the whole array.
Conformant Arrays:
You declare them as follows in IDL:
HRESULT MethodAbc([size_is(arraySize)] MyClass array[], long arraySize);
This tells COM that the arraySize parameter holds the count of elements.
My experience with CLI is minimal, but I don't think you can just pass a CLI handle. Among other things, I believe you need to pin the pointer so that GC doesn't move the array during the COM call. Others please correct me here if I'm wrong.
In my VB6 application I make several calls to a COM server my team created from a Ada project (using GNATCOM). There are basically 2 methods available on the COM server. Their prototypes in VB are:
Sub PutParam(Param As Parameter_Type, Value)
Function GetParam(Param As Parameter_Type)
where Parameter_Type is an enumerated type which distinguishes the many parameters I can put to/get from the COM server and 'Value' is a Variant type variable. PutParam() receives a variant and GetParam() returns a variant. (I don't really know why in the VB6 Object Browser there's no reference to the Variant type on the COM server interface...).
The product of this project has been used continuously this way for years without any problems in this interface on computers with Windows XP with SP2. On computers with WinXP SP3 we get the error 0x800706F7 "The stub received bad data" when trying to put parameters with the 'Long' type.
Does anybody have any clue on what could be causing this? The COM server is still being built in a system with SP2. Should make any difference building it on a system with SP3? (like when we build for X64 in X64 systems).
One of the calls that are causing the problem is the following (changed some var names):
Dim StructData As StructData_Type
StructData.FirstLong = 1234567
StructData.SecondLong = 8901234
StructData.Status = True
ComServer.PutParam(StructDataParamType, StructData)
Where the definition of StructData_Type is:
Type StructData_Type
FirstLong As Long
SecondLong As Long
Status As Boolean
End Type
(the following has been added after the question was first posted)
The definition of the primitive calls on the interface of the COM server in IDL are presented below:
// Service to receive data
HRESULT PutParam([in] Parameter_Type Param, [in] VARIANT *Value);
//Service to send requested data
HRESULT GetParam([in] Parameter_Type Param, [out, retval] VARIANT *Value);
The definition of the structure I'm trying to pass is:
struct StructData_Type
{
int FirstLong;
int SecondLong;
VARIANT_BOOL Status;
} StructData_Type;
I found it strange that this definition here is using 'int' as the type of FirstLong and SeconLong and when I check the VB6 object explorer they are typed 'Long'. Btw, when I do extract the IDL from the COM server (using a specific utility) those parameters are defined as Long.
Update:
I have tested the same code with a version of my COM server compiled for Windows 7 (different version of GNAT, same GNATCOM version) and it works! I don't really know what happened here. I'll keep trying to identify the problem on WinXP SP3 but It is good to know that it works on Win7. If you have a similar problem it may be good to try to migrate to Win7.
I'll focus on explaining what the error means, there are too few hints in the question to provide a simple answer.
A "stub" is used in COM when you make calls across an execution boundary. It wasn't stated explicitly in the question but your Ada program is probably an EXE and implements an out-of-process COM server. Crossing the boundary between processes in Windows is difficult due to their strong isolation. This is done in Windows by RPC, Remote Procedure Call, a protocol for making calls across such boundaries, a network being the typical case.
To make an RPC call, the arguments of a function must be serialized into a network packet. COM doesn't know how to do this because it doesn't know enough about the actual arguments to a function, it needs the help of a proxy. A piece of code that does know what the argument types are. On the receiving end is a very similar piece of code that does the exact opposite of what the proxy does. It deserializes the arguments and makes the internal call. This is the stub.
One way this can fail is when the stub receives a network packet and it contains more or less data than required for the function argument values. Clearly it won't know what to do with that packet, there is no sensible way to turn that into a StructData_Type value, and it will fail with "The stub received bad data" error.
So the very first explanation for this error to consider is a DLL Hell problem. A mismatch between the proxy and the stub. If this app has been stable for a long time then this is not a happy explanation.
There's another aspect about your code snippet that is likely to induce this problem. Structures are very troublesome beasts in software, their members are aligned to their natural storage boundary and the alignment rules are subject to interpretation by the respective compilers. This can certainly be the case for the structure you quoted. It needs 10 bytes to store the fields, 4 + 4 + 2 and they align naturally. But the structure is actually 12 bytes long. Two bytes are padded at the end to ensure that the ints still align when the structure is stored in an array. It also makes COM's job very difficult, since COM hides implementation detail and structure alignment is a massive detail. It needs help to copy a structure, the job of the IRecordInfo interface. The stub will also fail when it cannot find an implementation of that interface.
I'll talk a bit about the proxy, stub and IRecordInfo. There are two basic ways a proxy/stub pair are generated. One way is by describing the interfaces in a language called IDL, Interface Description Language, and compile that with MIDL. That compiler is capable of auto-generating the proxy/stub code, since it knows the function argument types. You'll get a DLL that needs to be registered on both the client and the server. Your server might be using that, I don't know.
The second way is what VB6 uses, it takes advantage of a universal proxy that's built into Windows. Called FactoryBuffer, its CLSID is {00000320-0000-0000-C000-000000000046}. It works by using a type library. A type library is a machine readable description of the functions in a COM server, good enough for FactoryBuffer to figure out how to serialize the function arguments. This type library is also the one that provides the info that IRecordInfo needs to figure out how the members of a structure are aligned. I don't know how it is done on the server side, never heard of GNATCOM before.
So a strong explanation for this problem is that you are having a problem with the type library. Especially tricky in VB6 because you cannot directly control the guids that it uses. It likes to generate new ones when you make trivial changes, the only way to avoid it is by selecting the binary compatibility option. Which uses an old copy of the type library and tries to keep the new one as compatible as possible. If you don't have that option turned on then do expect trouble, especially for the guid of the structure. Kaboom if it changed and the other end is still using the old guid.
Just some hints on where to start looking. Do not assume it is a problem caused by SP3, this COM infrastructure hasn't changed for a very long time. But certainly expect this kind of problem due to a new operating system version being installed and having to re-register everything. SysInternals' ProcMon is a good utility to see the programs use the registry to find the proxy, stub and type library. And you'd certainly get help from a COM Spy kind of utility, albeit that they are very hard to find these days.
If it suddenly stopped working happily on XP, the first culprit I'd look for is type mismatches. It is possible that "long" on such systems is now 64-bits, while your Ada COM code (and/or perhaps your C ints) are exepecting 32-bits. With a traditionally-compiled system this would have been checked for you by your compiler, but the extra indirection you have with COM makes that difficult.
The bit you wrote in there about "when we compile for 64-bit systems" makes me particularly leery. 64-bit compiles may change the size of many C types, you know.
This Related Post suggests you need padding in your struct, as marshalling code may expect more data than you actually send (which is a bug, of course). Your struct contains 9 bytes (assuming 4 bytes for each of the ints/longs and one for the boolean). Try to add padding so that your struct contains a multiple of 4 bytes (or, failing that, multiple of 8, as the post isn't clear on the expected size)
I am also suggesting that the problem is due to a padding issue in your structure. I don't know whether you can control this using a #pragma, but it might be worth looking at your documentation.
I think it would be a good idea to try and patch your struct so that the resulting type library struct is a multiple of four (or eight). Your Status member takes up 2 bytes, so maybe you should insert a dummy value of the same type either before or after Status - which should bring it up to 12 bytes (if packing to eight bytes, this would have to be three dummy variables).
Is WCHAR in COM interfaces a good thing ?
I've been searching the internet for an answer to this question with no results.
Basically should char* / wchar* be used in COM or should i use BSTR instead ?
Is it safe or does it depend ?
In this code example its strings (code grabbed from a random source):
STDMETHOD(SetAudioLanguageOrder(WCHAR *nValue)) = 0;
STDMETHOD_(WCHAR *, GetAudioLanguageOrder()) = 0;
I'm confused over when to use what with all marshaling, memory boundaries, etc. that comes up when talking about COM.
What about data buffers (byte*) ?
It depends on the context in which the caller will call you. First, if you use a non-automation type, marshaling will not be automatically performed for you. Therefore, you'll end up having to write your own marshaler to move a wchar_t* across process boundaries.
That said, there's no rule that says you can't pass a wchar_t* in a COM interface. There are many COM interfaces that pass custom types (structs, pointers to structs, callbacks, etc), and it's all just about your needs.
In your interface, if you do use WCHAR strings, I'd declare SetAudioLanguageOrder this way:
STDMETHOD(SetAudioLanguageOrder(const WCHAR *nValue)) = 0;
This makes it clearer who is (not) supposed to free the string, and provides more context as how to treat the string (the caller is discouraged from modifying the string, though the caller can certainly force that behavior if they want to write bad code).
The GetAudioLanguageOrder call is OK, but now the question is: who frees the returned string, and how should it be freed? Via free(...)? Or C++ delete[]? If you use a BSTR, then you know - use SysFreeString. That's part of the reason to use BSTR's instead of WCHAR strings.
If you are going to support dual interfaces and clients other than C++, use BSTR. If all callers are C++, then WCHAR* is fine.
You will have to be able to know the length of that array in one way or another. In C or C++ it's typical to use null-terminated strings and you often use them within one process - the callee accesses the very same data as the caller prepared and null-terminated.
Not the same with COM - you might want to create an out-proc server or use your in-proc server in a surrogate process and then you'll need marshalling - a middleware mechanism that transmits that data between processes or threads - to work. That mechanism will not know about the size of the string unless you one of MIDL attributes such as size_is to specify the right array size. Using those attributes will require an extra parameter for each array - that complicates the interface and requires extra care while dealing with data.
That said, in most cases you get a more fluent interface by just using BSTRs.