Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2004-06

Win32 API Call

10 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Jim Wilson

I'm trying to get a Win32 API call to work, but either I found a bug in FPC (not likely) or I'm doing something wrong (more then likely).

There's an API function called GetCurrentHwProfile that doesn't seem to be recognized by FPC, so I added it myself using external. However, when I try calling the function I don't seem to be getting anything returned. I tried checking the Windows GetLastError function, but that doesn't show me anything either.

I've included some code that shows what I mean. It's a text mode program, compiled under Windows 2000 using FPC version 1.0.6 with the command line of: ppc386 -TWin32 -vehnw -WC -XX -Sd

Since I doubt FPC has a bug I'm assuming it's me. Or is it?

********************************************

Program HWprofile;
uses
   windows;
type
   tProfileInfo = packed record
                    Docked : dword;
                    GUID   : ansistring;
                    Name   : ansistring;
                  end;
   pProfileInfo = ^tProfileInfo;
var
   Profile : pProfileInfo;
   Results : boolean;
(*=======================================================================*)
Function GetCurrentHwProfile (var HWProfile: pProfileInfo): boolean;
external 'advapi32' name 'GetCurrentHwProfileA';
(*=======================================================================*)
BEGIN
   Results := GetCurrentHwProfile (Profile);
   if not (Results) then
   begin
     Profile.GUID := 'Unknown';
     Profile.Name := 'Unknown';
   end;
   writeln ('GUID   : ',Profile.GUID);
   writeln ('Name   : ',Profile.Name);
   writeln ('Results: ',Results,' - ',GetLastError);
END.

Regards,
Jim Wilson

Michalis Kamburelis
to Jim Wilson

Hi

You made a few mistakes translating GetCurrentHwProfile to Pascal:

1. parameter to GetCurrentHwProfile should be TProfileInfo, not PProfileInfo (using "var" parameter already forces passing HWProfile by reference)

2. result of GetCurrentHwProfile should be LongBool (4 bytes), not boolean (1 byte)

3. most important, TProfileInfo.GUID and TProfileInfo.Name are not AnsiStrings. They are just char arrays, see attached code for correct declararions.

4. This is not important for FPC 1.0.x, but for newer FPC remember to declare WinAPI functions as "stdcall" (FPC 1.0.x just used "stdcall" by default).

I'm attaching corrected version of your program. On my Windows 2000 Prof it works fine compiled with FPC 1.0.10.

Regards,

Michalis Jim Wilson wrote: > I'm trying to get a Win32 API call to work, but either I found a bug in > FPC (not likely) or I'm doing something wrong (more then likely). > > There's an API function called GetCurrentHwProfile that doesn't seem to > be recognized by FPC, so I added it myself using external. However, when > I try calling the function I don't seem to be getting anything returned. > I tried checking the Windows GetLastError function, but that doesn't > show me anything either. > > I've included some code that shows what I mean. It's a text mode > program, compiled under Windows 2000 using FPC version 1.0.6 with the > command line of: ppc386 -TWin32 -vehnw -WC -XX -Sd > > Since I doubt FPC has a bug I'm assuming it's me. Or is it? > > ******************************************** > > Program HWprofile; > > uses > windows; > > type > > tProfileInfo = packed record > Docked : dword; > GUID : ansistring; > Name : ansistring; > end; > > pProfileInfo = ^tProfileInfo; > > var > Profile : pProfileInfo; > Results : boolean; > > (*=======================================================================*) > Function GetCurrentHwProfile (var HWProfile: pProfileInfo): boolean; > external 'advapi32' name 'GetCurrentHwProfileA'; > (*=======================================================================*) > > BEGIN > > Results := GetCurrentHwProfile (Profile); > > if not (Results) then > begin > Profile.GUID := 'Unknown'; > Profile.Name := 'Unknown'; > end; > > writeln ('GUID : ',Profile.GUID); > writeln ('Name : ',Profile.Name); > writeln ('Results: ',Results,' - ',GetLastError); > > END. > > Regards, > Jim Wilson > > > _______________________________________________ > fpc-pascal maillist - > http://lists.freepascal.org/mailman/listinfo/fpc-pascal >
Peter Vreman
to Jim Wilson: I'm trying to get a Win32 API call to work, but either I found a bug in FPC (not likely)…
Show quoted text 31 lines
I'm trying to get a Win32 API call to work, but either I found a bug in FPC (not likely) or I'm doing something wrong (more then likely). There's an API function called GetCurrentHwProfile that doesn't seem to be recognized by FPC, so I added it myself using external. However, when I try calling the function I don't seem to be getting anything returned. I tried checking the Windows GetLastError function, but that doesn't show me anything either. I've included some code that shows what I mean. It's a text mode program, compiled under Windows 2000 using FPC version 1.0.6 with the command line of: ppc386 -TWin32 -vehnw -WC -XX -Sd Since I doubt FPC has a bug I'm assuming it's me. Or is it? ******************************************** Program HWprofile; uses windows; type tProfileInfo = packed record Docked : dword; GUID : ansistring; Name : ansistring; end;

ansistring is a fpc/delphi specific type. WinAPI uses pchar

Show quoted text 11 lines
pProfileInfo = ^tProfileInfo; var Profile : pProfileInfo; Results : boolean; (*=======================================================================*) Function GetCurrentHwProfile (var HWProfile: pProfileInfo): boolean; external 'advapi32' name 'GetCurrentHwProfileA';

You are missing stdcall calling directive

Jim Wilson
to Michalis Kamburelis: Hi You made a few mistakes translating GetCurrentHwProfile to Pascal: 1. parameter to…
you wrote
You made a few mistakes translating GetCurrentHwProfile to Pascal:

Figures it was me... :-)

1. parameter to GetCurrentHwProfile should be TProfileInfo, not PProfileInfo (using "var" parameter already forces passing HWProfile by reference)

That's awfully odd, because according to the Win32 API reference the function GetCurrentHwProfile requires a pointer, which pProfileInfo is (tProfileInfo is just the type definition). Guess I have some more reading to do.

2. result of GetCurrentHwProfile should be LongBool (4 bytes), not boolean (1 byte)

But in your code it's still a boolean, but it now works (it returns TRUE). And, when I change "Results : longbool" in the var declaration I get "Hint: Type size mismatch, possible loss of data / range check error" at the "writeln ('Results: ',Results,' - ',GetLastError);" statement (and with either declaration the function returns TRUE, so I assume it's working with both). Does that mean longbool isn't really necessary?

Guess I have even more reading to do then I thought!

3. most important, TProfileInfo.GUID and TProfileInfo.Name are not AnsiStrings. They are just char arrays, see attached code for correct declararions.

Another oddity, because the API reference says they're null-terminated strings. So shouldn't an ansistring work for that too?

And where did you get those length numbers from, the ones you used for those const definitions? I can't seem to find them anywhere, and it appears that in order to get the info to display properly you need to assign specific lengths to those char strings.

4. This is not important for FPC 1.0.x, but for newer FPC remember to declare WinAPI functions as "stdcall" (FPC 1.0.x just used "stdcall" by default).

I'll make note of that.

I'm attaching corrected version of your program.

Thanks for that -- you were a big help!

Regards,
Jim Wilson

Michalis Kamburelis
to Jim Wilson
Jim Wilson wrote 17 lines
At 12:00 AM 6/22/2004, you wrote: > You made a few mistakes translating GetCurrentHwProfile to Pascal: Figures it was me... :-) > 1. parameter to GetCurrentHwProfile should be TProfileInfo, not > PProfileInfo (using "var" parameter already forces passing HWProfile > by reference) That's awfully odd, because according to the Win32 API reference the function GetCurrentHwProfile requires a pointer, which pProfileInfo is (tProfileInfo is just the type definition). Guess I have some more reading to do.

It's true that GetCurrentHwProfile requires a pointer to TProfileInfo. But when you declare GetCurrentHwProfile parameter as "var HWProfile: TProfileInfo" then compiler understands that "GetCurrentHwProfile (Profile);" should pass a *pointer* to Profile variable as GetCurrentHwProfile parameter. That's what "var" in "var HWProfile: TProfileInfo" means : to pass HWProfile by reference, i.e. by pointer. That's why HWProfile should be of type TProfileInfo, not PProfileInfo : it will already be passed by pointer, thanks to "var" keyword.

Show quoted text 13 lines
> 2. result of GetCurrentHwProfile should be LongBool (4 bytes), not > boolean (1 byte) But in your code it's still a boolean, but it now works (it returns TRUE). And, when I change "Results : longbool" in the var declaration I get "Hint: Type size mismatch, possible loss of data / range check error" at the "writeln ('Results: ',Results,' - ',GetLastError);" statement (and with either declaration the function returns TRUE, so I assume it's working with both). Does that mean longbool isn't really necessary? Guess I have even more reading to do then I thought!

In my code I changed Boolean to LongBool only in declaration of GetCurrentHwProfile. It's not needed to change type of "Results" variable because FPC will implicitly convert between LongBool and Boolean types.

SizeOf(LongBool) = 4, SizeOf(Boolean) = 1. This means that Boolean and LongBool have really different representation inside computer memory. So GetCurrentHwProfile should really return LongBool, not Boolean. If such code runs correctly with "Boolean" instead of "LongBool", you can consider it an accident.

Show quoted text 9 lines
> 3. most important, TProfileInfo.GUID and TProfileInfo.Name are not > AnsiStrings. They are just char arrays, see attached code for correct > declararions. Another oddity, because the API reference says they're null-terminated strings. So shouldn't an ansistring work for that too?

They *are* null-terminated strings. But they are not pointers to some char arrays. Instead they are just char arrays. msdn calls them "pointer to a null-terminated string" because in C pointer to a char can be usually considered the same thing as an array of chars.

AnsiString is something completely different: AnsiString is a pointer to some null-terminated char array with some additional internal data (positioned right before the pointed memory place). As Peter said, AnsiString is something that is known only in FPC and Delphi. It's completely different than simple "pointer to null-terminated char array" that is usually used in C. Such "pointer to null-terminated char array" is called PChar in Pascal. *But* TProfileInfo.Name and GUID fields are not PChar, they are simply char arrays.

And where did you get those length numbers from, the ones you used for those const definitions?

I discovered HW_PROFILE_GUIDLEN and MAX_PROFILE_LEN values by looking at C headers distributed with DevCpp. You can use any C compiler distributed for Windows to do such thing. Just find a directory inside your C compiler with header files for WinAPI (typically this should be a directory with "windows.h" file) and there you will find C declarations for all WinAPI constants, types, functions, macros...

I can't seem to find them anywhere, and it appears that in order to get the info to display properly you need to assign specific lengths to those char strings.

I'm sorry but I don't understand this statement. In Pascal you can usually use "array[0..<const>]of char" just like it was a "PChar", i.e. compiler understands that it's a char array terminated with null character.

Regards,

Michalis
Matt Emson
to Jim Wilson: Figures it was me... :-) That's awfully odd, because according to the Win32 API…
That's awfully odd, because according to the Win32 API reference the function GetCurrentHwProfile requires a pointer, which pProfileInfo is (tProfileInfo is just the type definition). Guess I have some more reading to do.

No, it makes a lot of sense. You could use:

....(var value: TProfileInfo, ...) *or* ....(pvalue: PProfileInfo, ...)

Passing as "var" passes the value as a pointer behind the scenes, but gives you the chance not to mess about with casting etc. You can't do this is C really (winapi written in C..) Not back when the Win32API was written. Back then every C app passed by value or as a pointer to simualte by reference.

But in your code it's still a boolean, but it now works (it returns

TRUE).

And, when I change "Results : longbool" in the var declaration I get

"Hint:

Type size mismatch, possible loss of data / range check error" at the "writeln ('Results: ',Results,' - ',GetLastError);" statement (and with either declaration the function returns TRUE, so I assume it's working

with

both). Does that mean longbool isn't really necessary?

It should be boolean. All Win32API return values which are BOOL translate as Boolean.

Another oddity, because the API reference says they're null-terminated strings. So shouldn't an ansistring work for that too?

No, no, no!! AnsiString (just use "String", it's the same difference unless you change the RTL to use WideStrings) is an array of char 1...N, with an extra hidden 0 element. This is a hangover from shortstrings which used element 0 to hold their length. A PChar is an array 0...N-1 or char. In my experiance you *can* pass Strings to API calls if you pass something like @(s[1]) or in Delphi pchar(string), but if you use them in this Record/struct, you'll quickly find that String PChar.

And where did you get those length numbers from, the ones you used for those const definitions? I can't seem to find them anywhere, and it

appears

that in order to get the info to display properly you need to assign specific lengths to those char strings.

Generally, with a Win32API call set your PChars to point to a buffer and tell the API call how long it is. In some structures (records) the seze is set, or is of a specific fixed sized type.

Show quoted text 5 lines
>4. This is not important for FPC 1.0.x, but for newer FPC remember to >declare WinAPI functions as "stdcall" (FPC 1.0.x just used "stdcall" by >default). I'll make note of that.

To be fair to you, FPC should have always used StdCall for Win32API calls. It would be less confusing now, anyway.

Matt

Marco van de Voort
to Matt Emson
Show quoted text 8 lines
> >4. This is not important for FPC 1.0.x, but for newer FPC remember to > >declare WinAPI functions as "stdcall" (FPC 1.0.x just used "stdcall" by > >default). > > I'll make note of that. To be fair to you, FPC should have always used StdCall for Win32API calls. It would be less confusing now, anyway.

FPC always did add stdcall, since FPC didn't use stdcall by default, but what now is "oldfpccall" in 1.9.x. The two are similar though, and sometimes forgetting stdcall isn't noticed. (good example was the main reason why threading didn't work for win32 in 1.9.2. A callback missed stdcall, and with 1.9.2 the calling convention was register for the first time)

However policy was and is to flag them as stdcall. Anything else was an exception, not the rule.

Matt Emson
to Marco van de Voort
> To be fair to you, FPC should have always used StdCall for Win32API

calls.

Show quoted text 7 lines
> It would be less confusing now, anyway. FPC always did add stdcall, since FPC didn't use stdcall by default, but what now is "oldfpccall" in 1.9.x. .... However policy was and is to flag them as stdcall. Anything else was an exception, not the rule.

Okay, change "used" to "enforced"...

Michalis Kamburelis
to Matt Emson: No, it makes a lot of sense. You could use: ....(var value: TProfileInfo, ...) *or*…

Matt Emson wrote:
...

It should be boolean. All Win32API return values which are BOOL translate as Boolean.
That's not true. WinAPI uses BOOL type, it's defined in WinAPI headers as
   typedef int WINBOOL,*PWINBOOL,*LPWINBOOL;
   ...
   typedef WINBOOL BOOL;

So BOOL is int. So it's 32-bit value on 32-bit systems. Compile this simplistic program with any compiler under windows to see that BOOL really takes 4 bytes.

   #include <windows.h>
   int main(int argc, char *argv[])
   {
     printf("%d\n", sizeof(BOOL));
     return 0;
   }
   /* output is 4 */

Then, another simplistic program in FPC confirms that LongBool takes 4 bytes of space and Boolean 1 byte:

   begin
    Writeln(SizeOf(LongBool), ' ', SizeOf(Boolean));
   end.
   { output is 4 1 }
In FPC Windows unit BOOL type is correctly defined as
   WINBOOL = longbool;
   BOOL = WINBOOL;

Summing it up: you have to use LongBool (or Windows.Bool) when translating WinAPI functions that take or return BOOL type. Boolean is not correct, even if it sometimes works.

Michalis
Matt Emson
to Michalis Kamburelis
Summing it up: you have to use LongBool (or Windows.Bool) when translating WinAPI functions that take or return BOOL type. Boolean is not correct, even if it sometimes works.

Actually, you're right up to a point. You should return BOOL, but a Boolean value will auto convert when assigned a BOOL, hence:

function SwitchToThread: BOOL; stdcall;

but

var
  res: Boolean;
begin
  res := SwitchToThread;
  if res then
   ...;
end;