Author Topic: Compliant 64-bit compiling  (Read 6135 times)

0 Members and 1 Guest are viewing this topic.

Arnold

  • Hero Member
  • *****
  • Posts: 932
Compliant 64-bit compiling
« on: February 18, 2018, 02:46:06 AM »
Hi Charles,

as Oxygen is able to create 64-bit executable code, it seems that for the data types, there are some rules to follow. I wondered when it makes sense to dispense with the int type and prefer to use sys, therefore I took a look at Windows Dev Center:

https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx
https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/the-new-data-types

and I am quite sure that I did not understand everything. But would it be safe to treat all handles (starting with H...) and all kind of pointers to treat as sys? I am also not sure about long, longlong, long32, long64 etc.

How does Oxygen treat GetWindowLong, SetWindowLong in 64-bit Windows? Is there a need for using GetWindowLongPtr, SetWindowLongPtr?

Roland

Charles Pegge

  • Admin Support Member
  • *****
  • Posts: 4268
    • Oxygen Basic
Re: Compliant 64-bit compiling
« Reply #1 on: February 18, 2018, 06:11:17 AM »
Hi Roland,

I would use Get/SetWindowLongPtr, since they are compatible with 32/64 bit values on 32/64 bit platforms.

When passing 32bit values to functions expecting 64bit values:

int is sign extended to sys
dword is zero extended to sys

But when passing variables byref, the types should match.


Arnold

  • Hero Member
  • *****
  • Posts: 932
Re: Compliant 64-bit compiling
« Reply #2 on: February 19, 2018, 12:41:46 AM »
Hi Charles,

it seems that using Get/SetWindowLong and Get/SetWindowLongPtr is a little bit tricky. I learned these functions are used to set and get e.g. certain window styles (GWL_STYLE, GWL_EXSTYLE), for subclassing (GWL_WNDPOC), or as a pointer to data with a given window (GWL_USERDATA). The GWLP_ parameters seem to have the same values.

Set/GetWindowLongPtr can only be used for 64-bit compiling, using these functions for 32-bit will fail. Since some time I have been looking for a simple solution which covers this case. In examples\WinGui\ChildWin.o2bas I tried this:

Code: [Select]
...
! GetWindowLongPtr lib "user32.dll" alias "GetWindowLongPtrA" (sys hWnd, sys nIndex) as sys
'% Win_64

  '-------------------------------------------------------------
  function EnumChildProc(sys hwndChild, lParam) as bool callback
  '=============================================================
  {
    RECT * rcParent;
    sys i, idChild;
    sys v,w,info
 
    // Retrieve the child-window identifier. Use it to set the
    // position of the child window.
    info=GWL_ID
#ifdef Win_64
    idChild = GetWindowLongPtr(hwndChild, info)
#else
    idChild = GetWindowLong(hwndChild, info)
#endif
...

I also tried this way:

Code: [Select]
...
! GetWindowLongPtrA lib "user32.dll" alias "GetWindowLongPtrA" (sys hWnd, sys nIndex) as sys
'% Win_64

function GetWindowLongPtr(sys h, sys i) as sys
#ifdef Win_64
    return GetWindowLongPtrA(h,i)
#else
    return GetWindowLong(h,i)
#endif
end function
 
  '-------------------------------------------------------------
  function EnumChildProc(sys hwndChild, lParam) as bool callback
  '=============================================================
  {
    RECT * rcParent;
    sys i, idChild;
    sys v,w,info
 
    // Retrieve the child-window identifier. Use it to set the
    // position of the child window.
    info=GWL_ID
    idChild = GetWindowLongPtr(hwndChild, info)
...

Both of my solutions are not really satisfying. The first one needs a workaround for every Get/SetWindowLong/Ptr. In the second case I need to define Win_64 before the function GetWindowLongPtr. Defining Win_64 after the function does not work. Perhaps with the new macro system there is a better way? Two other examples which use GetWindowLong / SetWindowlong are \tools\FindEd.o2bas and \examples\WinDynDialogs\FullScreen.o2bas.

I suspect for really 64-bit compliant compiling Get/SetWindowLongPtr should be considered. And perhaps these functions should also be added to minwin.inc
 
Roland

Charles Pegge

  • Admin Support Member
  • *****
  • Posts: 4268
    • Oxygen Basic
Re: Compliant 64-bit compiling
« Reply #3 on: February 19, 2018, 05:38:20 AM »
Hi Roland,

Inserted into the user32.dll section of minwin.inc:

Code: [Select]
  #ifdef mode64bit
  ! GetWindowLongPtr "GetWindowLongPtrA"          '2
  ! SetWindowLongPtr "GetWindowLongPtrA"          '3
  #else
  ! GetWindowLongPtr "GetWindowLongA"             '2
  ! SetWindowLongPtr "SetWindowLongA"             '3
  #endif


my test:
Code: [Select]
extern lib "user32.dll"
...
#ifdef mode64bit
  ! GetWindowLongPtr "GetWindowLongPtrA"
#else
  ! GetWindowLongPtr "GetWindowLongA"
#endif
...
end extern

print @GetWindowLongPtr

Are there any other incompatible functions you know of?
« Last Edit: February 19, 2018, 06:14:03 AM by Charles Pegge »

Arnold

  • Hero Member
  • *****
  • Posts: 932
Re: Compliant 64-bit compiling
« Reply #4 on: February 19, 2018, 08:26:05 AM »
Hi Charles,

the feature to use mode64bit is brilliant. I made some tests with Oxygen in progress, and running in JIT mode, compiling to 32-bit and 64-bit worked without problems.

The only difference I am aware of is the different use of cdecl for some libraries like msvcrt.dll or iup.dll. If I understood MSDN correctly then in 64-bit mode the cdecl modifier is ignored. I assume I could #undef cdecl in the beginning of a program for 64-bit compiling?

But to be honest at the moment I am quite happy to run 32-bit applications. I have progressed much further with my studies than I had dreamed.

Roland

Charles Pegge

  • Admin Support Member
  • *****
  • Posts: 4268
    • Oxygen Basic
Re: Compliant 64-bit compiling
« Reply #5 on: February 19, 2018, 09:26:48 AM »
It's soft-coded. RTL32 and RTL64 have equates mode32bit and mode64bit.

Perhaps we should also have a W version of minwin for the unicode apis: modeWideChar

Arnold

  • Hero Member
  • *****
  • Posts: 932
Re: Compliant 64-bit compiling
« Reply #6 on: April 04, 2018, 11:14:33 PM »
Hi Charles,

exploring the WinApi functions I found that for Win64 there is also a SetClassLongPtr / GetClassLongPtr function which in 32-bit will be used as SetClassLong / GetClassLong. Set/GetClassLong is not declared in minwin.inc, but it is in user.inc.

I have not yet fully understood the connection between user.inc and minwin.inc. In minwin.inc you distinguish between 32/64-bit with Set/GetWindowLong/Ptr but not in user.inc. In user.inc there is also no Set/GetWindowLongPtr function. Is this done internally?

Roland

Charles Pegge

  • Admin Support Member
  • *****
  • Posts: 4268
    • Oxygen Basic
Re: Compliant 64-bit compiling
« Reply #7 on: April 05, 2018, 05:23:54 AM »
Hi Roland,

My solution is to place these macro definitions in WinData.inc
Code: [Select]
  #ifndef mode64bit
    def GetClassLongPtr   GetClassLong
    def SetClassLongPtr   SetClassLong
    def GetWindowLongPtr  GetWindowLong
    def SetWindowLongPtr  SetWindowLong
    def GetClassLongPtrW  GetClassLongW
    def SetClassLongPtrW  SetClassLongW
    def GetWindowLongPtrW GetWindowLongW
    def SetWindowLongPtrW SetWindowLongW
  #endif

Then change this user section in MinWin.inc
Code: [Select]
  #ifdef mode64bit
  ! GetWindowLongPtr "GetWindowLongPtrA"          '2
  ! SetWindowLongPtr "SetWindowLongPtrA"          '3
  #endif

Then add this to User.inc
Code: [Select]
#ifdef mode64bit
  ! GetClassLongPtr   "GetClassLongPtrA"
  ! SetClassLongPtr   "SetClassLongPtrA"
  ! GetWindowLongPtr  "GetWindowLongPtrA"
  ! SetWindowLongPtr  "SetWindowLongPtrA"
  ! GetClassLongPtrW
  ! SetClassLongPtrW
  ! GetWindowLongPtrW
  ! SetWindowLongPtrW
#endif

If this is satisfactory, I'll include these changes  in the next update.


Arnold

  • Hero Member
  • *****
  • Posts: 932
Re: Compliant 64-bit compiling
« Reply #8 on: April 05, 2018, 10:17:36 AM »
Hi Charles,

I replaced the modified include files and everything looks very good. Until now I had no problems.

This is a small example using SetClassLongPtr and SetWindowLongPtr (Double-clicks and Opacity):

Code: (o2) [Select]
'SetClassLongPtr / SetWindowLongPtr

$ filename "window_click2.exe"

'uses rtl32
'uses rtl64

uses WinUtil

% GCL_STYLE = -26


MainWindow 310,250,WS_OVERLAPPEDWINDOW


function WndProc(sys hwnd, Msg, wParam, lParam) as sys callback

    select Msg
   
        case WM_CREATE
            'Replaces the window-class style bits   
            SetClassLongPtr(hwnd, GCL_STYLE, GetClassLongPtr(hwnd, GCL_STYLE) | CS_DBLCLKS)

            'Change attributes of window
            SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED)
            int WindowOpacity = (255 * 70) / 100
            SetLayeredWindowAttributes(hwnd, 0, WindowOpacity, LWA_ALPHA)


        case WM_LBUTTONDOWN
            SetWindowText(hwnd, "Left Button Down")
        case WM_LBUTTONUP
            SetWindowText(hwnd, "Left Button Up")
        case WM_LBUTTONDBLCLK
            SetWindowText(hwnd, "Left Button Double Click")

        case WM_RBUTTONDOWN
            SetWindowText(hwnd, "Right Button Down")
        case WM_RBUTTONUP
            SetWindowText(hwnd, "Right Button Up")
        case WM_RBUTTONDBLCLK
            SetWindowText(hwnd, "Right Button Double Click")
   
        case WM_CLOSE
            DestroyWindow(hwnd)
       
        case WM_DESTROY
            PostQuitMessage(0)
       
        case else
            return DefWindowProc(hwnd, Msg, wParam, lParam)
           
    end select
   
    return 0
end function


Arnold

  • Hero Member
  • *****
  • Posts: 932
Re: Compliant 64-bit compiling
« Reply #9 on: April 28, 2018, 03:42:38 AM »
Hi Charles,

the contribution of Chris about existing files caused me to play with the function GetFileAttributes. The following code works fine with 32 bit, but fails if compiled to 64-bit executable, no matter what I try. I searched in internet but I did not find sufficient information until now.

Is GetFileAttributes not used any more this way with Win64 or must 0xffffffff treated differently? These negative constants start to worry me.

Roland

Code: [Select]
$ filename "ExistFilePath.exe"

'uses rtl32
'uses rtl64

uses corewin
uses console

% INVALID_FILE_ATTRIBUTES = (dword -1) '0xffffffff

function existFP(string szFilePath) as bool
  'path, filename?
  dword attrib = GetFileAttributes(szFilePath)
printl attrib
  'if attrib != 0xffffffff then return true
  if attrib != INVALID_FILE_ATTRIBUTES then return true
  return false
end function

sub checkFP(string fp)
  if existFP(fp) then
    printl fp " exists"
  else
    printl fp " does not exist" 
  end if
end sub

'check folder
checkFP("c:\temp")
checkFP("C:\temp\Get Start\Tgh")
checkFP("c:\oxygenbasic\examples")
checkFP("c:\program files")

'check file
checkFP("C:\OxygenBasic\Oxygen.dll")
checkFP("C:\OxygenBasic\Oxygen.?ll")
checkFP("C:\OxygenBasic\Oxygen.*")
checkFP("c:\oxygenbasic\projectsA\Controls\CtrlSliders.o2bas")

printl "Enter ... " : waitkey

chrisc

  • Guest
Re: Compliant 64-bit compiling
« Reply #10 on: April 28, 2018, 05:36:50 AM »
Hi Roland

according to https://www.pinvoke.net/default.aspx/Constants.INVALID_FILE_ATTRIBUTES

the  INVALID_FILE_ATTRIBUTES =  -1   and it is an int

so i place these into code

% INVALID_FILE_ATTRIBUTES =  -1
 int attrib = GetFileAttributes(szFilePath)

and it works now when compile to 64bits

Code: [Select]
' ExistFilePath.o2bas
' http://www.oxygenbasic.org/forum/index.php?topic=1544.msg18057;topicseen#msg18057
$ filename "ExistFilePath.exe"

'uses rtl32
uses rtl64

uses corewin
uses console

% INVALID_FILE_ATTRIBUTES =  -1  ' 0xffffffff   ' (dword -1) '0xffffffff

function existFP(string szFilePath) as bool
  'path, filename?
 ' dword attrib = GetFileAttributes(szFilePath)
   int attrib = GetFileAttributes(szFilePath)
printl   "  attrib " attrib
  'if attrib != 0xffffffff then return true
 ' if attrib != INVALID_FILE_ATTRIBUTES then return true
   if attrib <> INVALID_FILE_ATTRIBUTES then
      return true
   end if
  return false
end function

sub checkFP(string fp)
  if existFP(fp) then
    printl fp " exists"
  else
    printl fp " does not exist"
  end if
end sub

'check folder
checkFP("c:\temp")
checkFP("C:\temp\Get Start\Tgh")
checkFP("c:\oxygenbasic\examples")
checkFP("c:\program files")

'check file
checkFP("C:\OxygenBasic\Oxygen.dll")
checkFP("C:\OxygenBasic\Oxygen.?ll")
checkFP("C:\OxygenBasic\Oxygen.*")
checkFP("c:\oxygenbasic\projectsA\Controls\CtrlSliders.o2bas")

printl "Enter ... " : waitkey

Arnold

  • Hero Member
  • *****
  • Posts: 932
Re: Compliant 64-bit compiling
« Reply #11 on: April 29, 2018, 12:54:19 AM »
Hi Chris,

thank you for the link. Unfortunately the function does still not work correctly in Win64. You can check this if you use some correct / incorrect paths / filenames. In Win32 I will get the value -1, in Win64 I will get 4294967295. Only the value for c:\program files is correct.

I tried some more combinations. Perhaps Charles will find out what goes wrong. And maybe GetFileAttributes must not be used any more for this purpose in Win64 (checking for existing files/folders). I am not sure.

Roland

Charles Pegge

  • Admin Support Member
  • *****
  • Posts: 4268
    • Oxygen Basic
Re: Compliant 64-bit compiling
« Reply #12 on: April 29, 2018, 01:24:26 AM »
Hi Roland,

GetFileAttributes, according to MSDN, definitely returns a dword like most other flag carrying values. Perhaps you could monitor its hex return value using a sys variable, and see what comes out for different folders/files.

Arnold

  • Hero Member
  • *****
  • Posts: 932
Re: Compliant 64-bit compiling
« Reply #13 on: April 29, 2018, 08:49:23 AM »
Hi Charles,

I am getting old. (Hopefully I will get older). It is the second time this month that I do not follow my own advice. I use two different computers for 32 and 64 bit with a different folder for Oxygenbasic. The results must of course be different. Sorry if I caused inconvenience.

And as far as I can see Chris has found the only working solution until now. It seems that in Win64 there is the type Int64 which can be used as int in O2. For me the code now works in 32-bit and 64-bit. As I think it is important for similar cases I add the code below. And perhaps there is another solution nevertheless.

Probably negative constants must be checked a little bit more. They are problematic with notification messages and some special cases like this one.

Roland

Code: [Select]
$ filename "ExistFilePath.exe"

'uses rtl32
'uses rtl64

uses corewin
uses console

% INVALID_FILE_ATTRIBUTES = -1 '(dword -1) '0xffffffff

function existFP(string szFilePath) as bool
  'path, filename?
  int attrib = GetFileAttributes(szFilePath)
  if attrib != INVALID_FILE_ATTRIBUTES then return true
  return false
end function

sub checkFP(string fp)
  if existFP(fp) then
    printl fp " exists"
  else
    printl fp " does not exist" 
  end if
end sub

'check folder
...

'check file
...

printl "Enter ... " : waitkey

chrisc

  • Guest
Re: Compliant 64-bit compiling
« Reply #14 on: April 29, 2018, 09:17:20 AM »
Hello Roland

my pc is a win10 64bits and i don't have a 32bit machine so that explain why the
program when i first compile works as it is all 64bits