2

I'm having trouble translating from some C declarations to Delphi XE2 for calling functions in a DLL. I translated all the function declarations from a Visual Basic source file, but in testing them I ran in to problems. Some functions returned Long values, but debugging my code I observed that the functions involved returned values that weren't right. Then I turned to the original code in C, and there I found the root of my troubles: At some point in the original C code there is this declaration:

typedef struct { } __RSI_CHANNEL;       
typedef __RSI_CHANNEL FAR* RSI_CHANNEL;

Now, some functions return RSI_CHANNEL; those functions return values like this:

return (RSI_CHANNEL)ws;

And ws is declared as:

rsiChannel FAR* ws = new FAR rsiChannel;

rsiChannel is a typedef struct. So far, so good...by now I guess some of you may have recognized this as PIMPL idiom. Ok, according to the source code comments, I should have to save that return value (RSI_CHANNEL) and test against NULL, and pass it through function calls untouched...nothing more...so my take is it should be implemented in Delphi as Pointer. But it doesn't work. Something like this:

Type 
  RSI_CHANNEL = Pointer;

...{ later in implementation block }...

Function rsiInitWsock(HostName : PAnsiChar; port : Long) : RSI_CHANNEL; stdcall; external 'rsidll32';

No compile errors, no runtime errors. If I call this function, I get Nil.

¿Any idea how this could be implemented in Delphi XE2? and, ¿what I'm doing wrong? thanks in advance.

Additional details:

  • Delphi XE2 (target: Win32)
  • Windows 7 x64

I found the problem; it didn't had to do with my code, it was right since the beginning; it has to do with a ping function in the DLL, it worked on a laptop but it doesn't want to work with a desktop PC (both Win7), and when it doesn't work it breaks subsequent function calls to the DLL (why, I don't know...yet). Anyway, it wasn't a full solution, but @DavidHeffernan was the first to come up with the idea that the problem was someplace else, so I'm accepting his answer mainly because it pointed me in the right direction. Thanks to everyone!

8
  • What does the C declaration of rsiInitWsock look like? Commented Aug 14, 2014 at 20:21
  • It is declared as: RSI_DLL RSI_CHANNEL RSI_API rsiInitWsock(char* hostname, WORD port); RSI_DLL is a macro used for the exported functions in the DLL, RSI_API = stdcall. Commented Aug 14, 2014 at 20:23
  • I think WORD -> UInt16, No? You're declaring long, which is a signed 64-bit integer. Commented Aug 14, 2014 at 20:28
  • 1
    @J... Only in C# is long 64 bits wide Commented Aug 14, 2014 at 20:33
  • @DavidHeffernan I was actually just wondering if I'd crossed wires, that it was maybe 32-bit... I always use Int64 in delphi - the myriad of aliases trip me up! In any case, it's not unsigned and it's not a 16-bit word. Commented Aug 14, 2014 at 20:35

2 Answers 2

3

As described, your handling of RSI_CHANNEL is correct. Declaring it as Pointer is the appropriate action. To make type safety stronger you could define a distinct type rather than an alias:

Type 
  RSI_CHANNEL = type Pointer;

If the port parameter is really WORD then that maps to Word in Delphi.

As to your problem, it lies elsewhere. The translation of RSI_CHANNEL is accurate.

Sign up to request clarification or add additional context in comments.

3 Comments

I should add that I tried several options...all that were pointer-based returned Nil. Since the VB implementation used Long as return type, I used integer-based types until I saw the C declaration. Interestingly, when I use Int64 (and UInt64) as return type I get something (a big number), everything else gets 0 or Nil.
Int64 is wrong because your pointers are 32 bit. Your problem lies elsewhere.
If you use an Int64, the compiler will expect the function to return a 64bit value using the EDX and EAX registers, and then will combine them together to create the Int64 value. But a pointer in a 32bit environment would be returned using the EAX register only, leaving the EDX register unused or random at worse. That would account for large Int64 values being "returned".
2

Since RSI_CHANNEL is a typed pointer in the C code, I would declare a similar typed pointer in Delphi to match, instead of using an untyped Pointer (this is also inline with modern Delphi versions using STRICT to avoid untyped pointers in Win32 API handle types like HWND, etc):

type
  RSI_CHANNEL = ^__RSI_CHANNEL;
  __RSI_CHANNEL = record
  end;       

Function rsiInitWsock(HostName : PAnsiChar; port : WORD) : RSI_CHANNEL; stdcall; external 'rsidll32';

3 Comments

Then your problem lies elsewhere, not related to the pointer itself. You are going to have to debug into the DLL function call and find out EXACTLY what it is really returning and how it is returning it. Something fishy is going on.
The code you have shown should not be behaving the way you have described.
@Remy those comments are the focus of the question and should appear in the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.