1

How can I correctly typecast to a structure in Delphi? This does not work exactly like in C++ where one would just pass a &Data according to the MSDN documentation.

program Project1;

uses
  System.SysUtils,
  Winapi.Windows,
  Winapi.Winsock2;

function WSAStartup(wVersionRequired: WORD; out lpWSAData: LPWSADATA): Integer; WINAPI; external 'ws2_32.dll';

var
  Data: WSADATA;
begin
  WSAStartup(WINSOCK_VERSION, LPWSADATA(@Data)); // E2197 Constant object cannot be passed as var parameter
  ReadLn;
end.
5
  • 1
    As first, choose to use either functions declared in the Winapi.Winsock2, or declare them all by yourself. Mixing them is a bad idea. If you would use the one declared in the RTL unit, you would declare a TWSAData variable and pass it as it is. Your import is wrong, you are not going to output a pointer. Either you pass a pointer there, or output a structure. Commented May 12, 2015 at 14:30
  • 1
    Nice to see that someone still believes that MSDN is correct :) Headers are correct. But anyway, my point was to stop mixing the imports. Either make your own, or use those from RTL. If you choose the first, then you can either remove that out, or keep that out and let the function return you the structure, not a pointer to the structure (lpWSAData: LPWSADATA, or out lpWSAData: WSADATA). Commented May 12, 2015 at 14:35
  • @TLama Many functions are declared like this in the SDK. Would the first approach (lpWSAData: LPWSADATA) be more universal? Commented May 12, 2015 at 14:41
  • 1
    Yes, that is more universal. So universal, that you'll be able to pass to that parameter pointer to anything you like :) You are losing type safety by doing that. With that out variant, the compiler prevents you to pass there anything other than WSADATA structure. Commented May 12, 2015 at 14:49
  • 2
    @TLama MSDN is correct here, I'm not quite sure what you are driving at. As for LPWSADATA, that is perfectly typesafe so long as you use the typed address option. Commented May 12, 2015 at 15:48

1 Answer 1

4

I guess that you've translated the function from the MSDN documentation which reads:

int WSAStartup(
  _In_  WORD      wVersionRequested,
  _Out_ LPWSADATA lpWSAData
);

The confusion stems from the use of the _Out_ annotation. That is a macro that expands to nothing. It is used to convey intent to tools that, for instance, convert the header file declaration to different languages. More information can be found here:

You've erroneously translated _Out_ to the Delphi out keyword. You could simply remove that keyword and your declaration would be correct:

function WSAStartup(wVersionRequired: WORD; lpWSAData: LPWSADATA): Integer; 
  WINAPI; external 'ws2_32.dll';

Then your call would be:

WSAStartup(WINSOCK_VERSION, @Data);

Alternatively, since this parameter is not optional, you could translate it like this:

function WSAStartup(wVersionRequired: WORD; out lpWSAData: WSADATA): Integer; 
  WINAPI; external 'ws2_32.dll';

You would then call like this:

WSAStartup(WINSOCK_VERSION, Data);

You should however, use the declaration of the function that can be found in Winapi.Winsock2 and so avoid risking making such mistakes. That is, assuming that Embarcadero have not made mistakes in translation, which does sometimes happen.

Finally, it would be remiss of me were I not to chide you, at least mildly, for ignoring the return value of the function call.

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

3 Comments

So these annotations are only used by Visual Studio for code analysis?
I'm not sure that Visual Studio uses them at all to be honest.
These annotations CAN be used by tools. I don't know which tool actually does that. I find it quite helpful when manually translating headers, though.

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.