1. Aart Onkenhout
  2. PowerBuilder
  3. Friday, 13 October 2023 10:06 AM UTC

Hi,

I'm trying to migrate my application to 64 bit. Unfortunately, it crashes when starting it (unless I start in debug mode and set a breakpoint before the main window really shows up). So I turned on tracing. But if I try to open the pbp-file I get an error message. Isn't it possible to open a pbp file when running in 64-bit mode?

I attached a screenshot of the error I'm getting.

If it isn't possible, is there another way to find out on what piece of code it crashes (the event viewer didn't have usefull information).

Regards,

Aart

Attachments (1)
Miguel Leeuwe Accepted Answer Pending Moderation
  1. Friday, 13 October 2023 11:06 AM UTC
  2. PowerBuilder
  3. # 1

Hi,

Appeon still has to make this work as far as I know.

I requested it here; https://www.appeon.com/standardsupport/track/view?id=9794

Comment
  1. Miguel Leeuwe
  2. Friday, 13 October 2023 11:42 AM UTC
  1. Helpful
  1. Aart Onkenhout
  2. Friday, 13 October 2023 11:44 AM UTC
Thanks Miguel. The fact you asked for it in february doesn't sound very hopeful. In the meantime I found one problem with an external function, up to the next one :-).
  1. Helpful 1
  1. Miguel Leeuwe
  2. Friday, 13 October 2023 11:48 AM UTC
Yw, it's all about Appeon's priorities I guess.

Check out the link that I posted above, John has given some useful links there.

Good luck!

(for now, I'm not migrating to 64 bit for this exact reason, sadly).
  1. Helpful
There are no comments made yet.
Arnd Schmidt Accepted Answer Pending Moderation
  1. Friday, 13 October 2023 13:52 PM UTC
  2. PowerBuilder
  3. # 2

AFAIK you always get a corrupted trace file when the applications crashes during the trace.

Correct me if am wrong! That would be great!

regards

Arnd

Comment
There are no comments made yet.
Chris Pollach @Appeon Accepted Answer Pending Moderation
  1. Friday, 13 October 2023 14:19 PM UTC
  2. PowerBuilder
  3. # 3

Hi Aart;

  FWIW: I spent a lot of time in the early PB 2021 & 2022 GA releases tweaking many of the STD framework's external MS-Windows API calls to be 64 bit compliant ....

   As a reference, the key would be to open the STD_FC_Base.pbl and introspect the "nc_app_controller_master" object's external function declarations and compare them to what your App is using. Also, various structures need to be tweaked as well. You can find all the referenced structures that these external API's use in the STD_FC_Base.pbl  library as well. The framework does not use local structures - only global ones - enabling 100% re-usability.

   Also, you can check out the latest STD Framework for PB 2022 R2 here that I just released ...

http://chrispollach.blogspot.com/2023/10/2023r2.html

Hopefully, that might help speed up your refactoring efforts.

Note: I also pinged Engineering for an update on ticket # 9794.  ;-)

Regards ... Chris

Comment
  1. Arnd Schmidt
  2. Friday, 13 October 2023 16:50 PM UTC
... and because PowerBuilder does not do type checking on your code, you also have to maintain/test your code.

It is possible to call a function with int or long that has a longptr as function argument.

Even more if a function returns longptr there is no warning that you have a type clash when you assign it to a long or ulong.

@Chris, I am not sure if you should also better use longptr for HWND (your screenshot seems to use ulong for HWND).



  1. Helpful
  1. Chris Pollach @Appeon
  2. Friday, 13 October 2023 17:30 PM UTC
Hi Arndt;

Yes, you certainly can. I still have many external calls that pass a pointer as uLong and did not need to change this to LongPtr and they still work in the 32 & 64 bit world. So it seems to me that the requirement for using LongPtr is based on how the external method has been written. HTH

Regards ... Chris
  1. Helpful
  1. Arnd Schmidt
  2. Friday, 13 October 2023 23:28 PM UTC
Ah, Ok! Your coding technique relies on this fact:

https://learn.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication

Declaring GetFocus() and GetForegroundWindow() returning "different" types (ulong vs. LongPtr) is doable. But I don't like it:-(

Regards .. Arnd
  1. Helpful
There are no comments made yet.
Aart Onkenhout Accepted Answer Pending Moderation
  1. Saturday, 14 October 2023 07:16 AM UTC
  2. PowerBuilder
  3. # 4

Thank you Chris. I will have a look at your declarations.

Comment
There are no comments made yet.
John Fauss Accepted Answer Pending Moderation
  1. Saturday, 14 October 2023 21:21 PM UTC
  2. PowerBuilder
  3. # 5

Although the use of the UnsignedLong (ULong) data type in external function declarations for Windows handles in WinAPI functions may work in many cases, I think it is a terrible idea for several reasons.

1. It is not how the WinAPI functions are documented, so for all intent and purposes, it's incorrect.

The only reason it works at all is because of the interprocess communcation between 32-bit and 64-bit applications that the Windows O/S facilitates (refer to the link that Arnd posted in a comment elsewhere in this thread [Thank you for posting that link, Arnd!] ). From my perspective, using ULong for a Windows handle is well, sloppy programming.

2. In only works for function argument parameters and not in structures.

Several API functions require the use of structures, and a structure member that holds a Windows handle must be a 64-bit integer in a 64-bit process/application, or else the API function will not be able to extract all of the structure member values correctly. Using the wrong data type not only affects the relative offset of any following structure members from the beginning of the structure, it can and often does change the alignment of structure members and the alignment of the structure itself in memory... as well as the overall length of the structure.

Some WinAPI structures contain a member that specifies the structure length, so specifying the correct structure length can be critical to ensure it works correctly.

Here's a simple example. The FlashWindowEx API function gets passed the address of a FLASHWINFO structure. That structure is defined as follows in C/C++:

typedef struct {
   UINT  cbSize;
   HWND  hwnd;
   DWORD dwFlags;
   UINT  uCount;
   DWORD dwTimeout;
} FLASHWINFO, *PFLASHWINFO;

Here's the PB external function declaration:

FUNCTION Boolean FlashWindowEx ( REF s_flashwinfo pfwi ) LIBRARY "user32.dll"

Note: The structure argument is passed by reference because the API function requires that the memory address of the structure be passed as the argument value.

In 32-bit, each of the three typedef'd data types in the structure declaration (UINT, HWND and DWORD) are equivalent to ULongs in PB, so the members are laid out in memory as five consecutive four-byte unsigned integers. Since the largest size of any structure member is four bytes, the structure gets aligned on a four-type boundary and its length must be a multiple of four. Its length is therefore 20 bytes, so the caller must set the value of the first member (the size of the structure, in memory, in bytes) to 20.

The structure becomes dramatically different in 64-bit. The first member is still a four-byte integer, but the type definition HWND used by second argument (the handle to the window that is to be "flashed") becomes an eight-byte integer in 64-bit. Because it is now an eight-byte integer, the second structure member must now be aligned on a memory address that is evenly divisible by eight instead of four... so four bytes of "padding" are needed in memory between the first and second structure members. This brings the structure length at this point to 16 bytes. The remaining three members are still four-byte integers as they were in 32-bit, so they can immediately follow the second member in memory. The structure length is 16 + 12 = 28 bytes, right?

Unfortunately, no.

You see, the length and starting memory address of a structure must be evenly divisible by the size of the largest data element, which was four in 32-bit but is now eight in 64-bit because the second structure member (the handle) is now an eight-byte integer instead of four. Therefore, another four bytes of padding are required after the last structure member. The correct structure length is 32 bytes and this is value that is needed in the first structure member in order for the API function to be called successfully in 64-bit.

This reinforces my next reason for not using ULong for Windows handles:

3. Consistency. If you always use the proper data type, you won't have to try and remember these arcane rules and recognize when you should use an eight-byte integer instead of a four-byte integer. Other developers looking at your code won't be confused (or at least maybe they will not be AS confused wink).

4. The Longptr data type is the proper and perfect data type for this use, because the PB compiler changes the length allocated for this data type, based on the target bitness.

5. The PowerScript Handle() function was recently changed to now return a Longptr data type, so Appeon Engineering recognizes that Longptr is the correct and proper data type to be used with Windows handles.

My final reason to use Longptr for Windows handles is the simplest and I think the best reason:

6. It provides a good example for other developers to follow.

So, Chris, a lot of PB developers look to the STD framework that you've developed for guidance on the proper way to do things in PB, as well they should... you've done a terrific job in designing it, providing the framework to all, and in keeping it updated. For this reason, I think it would be best for everyone if you made the change to use Longptr everywhere a Windows handle is being utilized.

John

P.S.: For all, here's a link to Microsoft documentation that I use frequently to help me translate WinAPI typedef'd data types to PB data types:

    https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types

Some type definitions are nested, so in those cases you have to work your way through multiple layers. For example HWND becomes HANDLE, which becomes PVOID, which becomes a pointer (memory address) to any data type (or you can also think of it as a pointer to anything). A memory address in 32-bit is 32 bits (four bytes) long, and in 64-bit is 64-bits (eight bytes) long. This is why/how the length of a Windows handle is dependent on the app's bitness.

Comment
  1. John Fauss
  2. Tuesday, 17 October 2023 00:52 AM UTC
Public ticket 11040 has been opened as a documentation bug. I have three other documentation-related tickets in the system, and they have all been classified as "Enhancement Request".
  1. Helpful 1
  1. John Fauss
  2. Tuesday, 17 October 2023 01:02 AM UTC
@Miguel - Believe me, I understand how confusing and/or difficult it can be to ferret out the actual datatypes in WinAPI functions, since Microsoft seems addicted to using nested type definitions. The general rule I follow is that any datatype which begins with the letter "h" (upper or lowercase) is nearly always some kind of a Windows handle (there are very few exceptions that I have come across). If the link listing WinAPI data types I provided earlier does not include the datatype in question, I use Notepad++ to search through all of the WinAPI header (.h) files, to find the type definition, then continue digging from there.
  1. Helpful
  1. Arnd Schmidt
  2. Tuesday, 17 October 2023 11:05 AM UTC
I remember "someone" wrote a lot of good stuff some years ago...

https://community.appeon.com/index.php/component/tags/tag/winapi

;-)
  1. Helpful 1
There are no comments made yet.
Julie Jiang @Appeon Accepted Answer Pending Moderation
  1. Monday, 16 October 2023 02:08 AM UTC
  2. PowerBuilder
  3. # 6

Hi Miguel, 

The bug 9794 shall have been fixed a while ago (https://www.appeon.com/standardsupport/bugfixes?contents=9794&product=PowerBuilder&category=&version=&build=_).  Please double check.   

Best regards,

Julie

Comment
  1. Miguel Leeuwe
  2. Monday, 16 October 2023 09:16 AM UTC
Hi Julie,

Thanks! I didn't see any kind of notification on the bug site, but great news!

regards
  1. Helpful
  1. Aart Onkenhout
  2. Monday, 16 October 2023 15:10 PM UTC
Unfortunately, you can't open it when your application crashes, so you still don't have a clue where it crashes if it does.
  1. Helpful
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.