3

Some of the methods of a COM interface, which I have imported from a type library (part of a hardware SDK), return or receive a value of type IUnknown. As an example, the SDK documentation specifies the methods as follows:

bool SetInput1Selection(InputSelection inputSelection)
InputSelection GetInput1Selection()

But Delphi imported those methods like this:

function SetInput1Selection(const inputSelection: IUnknown): WordBool; safecall;
function GetInput1Selection: IUnknown; safecall;

The type InputSelection seems to be a simple integer or enum type, but is not specified anywhere. The documentation only gives a table of the 14 different possible values, as well as their meaning.

Ideally, I would like to declare my own type:

TInputSelection = (isCustom, isStartReset, ...)

Here is how the type library defines these functions:

virtual HRESULT __stdcall SetInput1Selection (/*[in]*/ IUnknown * inputSelection, /*[out,retval]*/ VARIANT_BOOL * pRetVal ) = 0;
virtual HRESULT __stdcall GetInput1Selection (/*[out,retval]*/ IUnknown * * pRetVal ) = 0;

But how can I make this work?

TLama
  • 75,147
  • 17
  • 214
  • 392
  • If you know that `InputSelection` type in your type library is the enumeration and you know its members, just correct it in the Delphi import (in the way you've shown). It might be just wrong import. – TLama Dec 16 '12 at 12:00
  • @TLama I tried substituting _Integer_ for _IUnknown_ in the TLB unit. But the values returned by `GetInput#Selection` do not seem to correspond to any allowed values. They don't even map 1:1, meaning the same value is returned for input channels that have different values set (the SDK includes a test application, with which I can read/write input channel settings). Something more seems to be going on here. Is there a 'proper' way of doing this? – Gerald Menzel Dec 16 '12 at 12:39
  • Since we don't know the SDK you have to look at it for yourself, what type is meant by SDK. If it is not clear from doc you should ask the SDK developer – Sir Rufo Dec 16 '12 at 13:46
  • I have. Apparently, they had the sdk development outsourced and are now unable to provide ANY developer support. Not what I expected when I bought their hardware. But now I have to make the best of it. Is there perhaps some forensic way to find out what to do with such an IUnknown parameter? – Gerald Menzel Dec 16 '12 at 14:06
  • What I've tried to say in my first comment (or better to say guess, without seeing your type library) is that Delphi importer probably failed in importing of that parameter and that you should modify your Delphi import manually (if you know that the parameter is enumeration instead of interface). – TLama Dec 16 '12 at 14:24
  • Here is how the type library defines these function: `virtual HRESULT __stdcall SetInput1Selection (/*[in]*/ IUnknown * inputSelection, /*[out,retval]*/ VARIANT_BOOL * pRetVal ) = 0;` and `virtual HRESULT __stdcall GetInput1Selection (/*[out,retval]*/ IUnknown * * pRetVal ) = 0;`. So I think the delphi importer did everything it could. The documentation seems to imply that `InputSelection' is an enum. But apart from that, I have no idea how to approach a solution. – Gerald Menzel Dec 16 '12 at 14:42

1 Answers1

3

Integers/Enums and Interfaces are described differently in a TypeLibrary, so it is very unlikely that the TypeLibrary importer is getting them confused. My guess is that InputSelection really is an interface type that wraps some other data, and likely has properties/methods of its own to access that data. If ithat interface does not appear in the TypeLibrary then it might be a private interface.

One thing you could try is call QueryInterface() on the IUnknown that GetInput1Selection() returns, asking it for an IDispatch interface. If that crashes, then the IUnknown is not a valid interface pointer, which would go back to a possible bad import. But if it does not crash, it likely is a real interface, especially if QueryInterface() succeeds. If it does, call IDispatch.GetTypeInfo() to see if it describes itself. If so, you can discover all of the properties and methods, including parameters, that the interface implements. In some environments, if an IDispatch-based object is just a wrapper around a POD value, like an integer, it usually has a Value property, and there is even a special DISPID for accessing such a property IDispatch.Invoke() (I don't recall the actual DISPID number, I will have to look it up).

Update: any chance you are programming a Nanotec stepper motor? I found documentation online that resembles the functions you mention:

GetInput1Selection
    Definition:
        InputSelection GetInput1Selection()

This function outputs the function for digital input 1.
The function corresponds to serial command ':port_in_a'.

SetInput2Selection
    Definition:
        bool SetInput2Selection(InputSelection inputSelection)

This function sets the function for digital input 2.
The value returned by the function can be used to check that the command was correctly recognized by the controller.
The function corresponds to serial command ':port_in_b'.

Unfortunately, it does not describe what InputSelection actually is.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks for taking the time, Remy! Calling QueryInterface for IDispatch doesn't crash, but also does not succeed. I also tried `Supports(GetInput1Selection,TDispatch)`, which returns FALSE. It seems IDispatch is not supported. What options do I have left? – Gerald Menzel Dec 17 '12 at 14:26
  • To be more precise, `QueryInterface(GetInput1Selection,IDispatch)` returns `E_NOINTERFACE`. – Gerald Menzel Dec 17 '12 at 14:36
  • Then you need to contact the SDK vendor and ask about it. The fact that `QueryInterface()` returns `E_NOINTERFACE` without crashing means that `GetInput1Selection()` is actually returning a valid `IUknown` interface, which means the documentation is wrong, or at least misleading. Are you SURE there are no other interface types being declared in the imported TypeLibrary? – Remy Lebeau Dec 17 '12 at 18:55
  • Sadly, the vendor is of no help here (see my comment above). But I followed a brute-force approch and found one compatible interface: `IProvideClassInfo`, which provides access to a `ITypeInfo` interface. Could that be useful, perhaps? I'm out of my depth here. Any further help on this would be very much appreciated! – Gerald Menzel Dec 17 '12 at 19:09
  • Yes, controlling a NanoTec stepper motor interface is exactly what I'm doing. And you're right, the documentation is poor. But concerning `IProvideClassInfo`, I don't know what to do. I messed around a little with its `ITypeInfo` interface, which lead me to the type library of `mscorlib.dll`. Here, an `_Object` interface is declared, which my mysterious `IUnknown` also supports. I don't know if that is of any significance, though. – Gerald Menzel Dec 17 '12 at 20:33
  • Have a look at [this article](http://spec.winprog.org/typeinf2/) for how to work with `ITypeInfo` and obtain information from it. It explains how to extract detailed information and reconstruct interface and method declarations. You will be able to use that information to determine what your mystery `IUnknown` actually implements, then you can write a declaration for a corresponding interface that you can query the `IUnknown` for to access that functionality in your code. – Remy Lebeau Dec 17 '12 at 21:28