Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
CreateFile library error
#1
I have been using this code for awhile. It is a CreateFile library function call.
Problem it work in Qb64pe-32 bit but in 64-bit throws a GNU C++ compilation error and I wanted to know why!?

Erik.

Code: (Select All)
Rem $Dynamic
DefLng A-Z
Declare Dynamic Library "kernel32"
    Function CloseHandle& (ByVal hfile As _Offset)
End Declare

Rem hfind = CreateFileA(ASCIIZ, &H180, &H3, 0, 3, 0, 0)
' parameters:
'  (1) pointer to filename
'  (2) access:
'    x80(128)  - read
'    x100(256) - write
'  (3) sharing
'  (4) security attributes
'  (5) create file flag
'  (6) flags (standard OSHA)
'  (7) pointer to template file

' paramater 5
'  0 DEFAULT_OPEN_EXISTING = open only if exists
'  1 CREATE_NEW    = create only if not exist
'  2 CREATE_ALWAYS = always create new file
'  3 OPEN_EXISTING = open only if exists
'  4 OPEN_ALWAYS  = open file always
'  5 TRUNCATE_EXISTING = open/truncate to 0 only if exists
'  6 OPEN_DIRECTORY    = open if directory exists

Declare Library
    Function CreateFileA& (filename$, Byval access&, Byval sharing&, Byval sec_attr%&, Byval create&, Byval flags&, Byval template%&)
End Declare
Dim hfind As _Offset

' detect file
Print "Enter filename";
Input f$
If Len(f$) Then
    f$ = f$ + Chr$(0)
    hfind = CreateFileA(f$, &H180, 0, 0, 3, 0, 0)
    If hfind Then
        Print "File exists."
        r = CloseHandle(hfind)
    End If
End If
End
Reply
#2
'CreateFileA' returns a HANDLE, which should be treated as an `_Offset`, but you wrote it as `CreateFileA&`, so the return value is treated as a 32-bit `LONG`.

The C++ compiler isn't allowing you to make the mistake of casting the HANDLE value to a LONG (which is what QB64 will do to make your function definition work) because that's always a bug on 64-bit systems and chops-off the top-half of the 64-bit HANDLE value, making it useless.
Reply
#3
So if I modify the handle to:

Code: (Select All)
Dim hfind As _Unsigned Long
it should work on 64-bit qb64?

Erik.
Reply
#4
(06-05-2023, 10:35 PM)eoredson Wrote: So if I modify the handle to:

Code: (Select All)
Dim hfind As _Unsigned Long
it should work on 64-bit qb64?

Erik.

You got it backwards. You correctly declared `hfind` as an `_Offset` type, but you incorrectly declared the return type of `CreateFileA` to be a `Long` instead of an `_Offset`. You need to declare it as `CreateFileA%&` so that QB64 knows it returns an _Offset type.
Reply
#5
Can you tell me if this is correct..

Code: (Select All)
Rem $Dynamic
DefLng A-Z
Declare Dynamic Library "kernel32"
    Function CloseHandle& (ByVal hfile As _Offset)
End Declare

Rem hfind = CreateFileA(ASCIIZ, &H180, &H3, 0, 3, 0, 0)
' parameters:
'  (1) pointer to filename
'  (2) access:
'    x80(128)  - read
'    x100(256) - write
'  (3) sharing
'  (4) security attributes
'  (5) create file flag
'  (6) flags (standard OSHA)
'  (7) pointer to template file

' paramater 5
'  0 DEFAULT_OPEN_EXISTING = open only if exists
'  1 CREATE_NEW    = create only if not exist
'  2 CREATE_ALWAYS = always create new file
'  3 OPEN_EXISTING = open only if exists
'  4 OPEN_ALWAYS  = open file always
'  5 TRUNCATE_EXISTING = open/truncate to 0 only if exists
'  6 OPEN_DIRECTORY    = open if directory exists

Declare Library
    Function CreateFileA%& (filename$, Byval access&, Byval sharing&, Byval sec_attr%&, Byval create&, Byval flags&, Byval template%&)
End Declare
Dim hfind As _Offset

' detect file
Print "Enter filename";
Input f$
If Len(f$) Then
    f$ = f$ + Chr$(0)
    hfind = CreateFileA(f$, &H180, 0, 0, 3, 0, 0)
    If hfind Then
        Print "File exists."
        Print "Handle: "; Hex$(hfind)
        r = CloseHandle(hfind)
    End If
End If
End
If the entire problem is with the function declaration then I have got it wrong the whole time. Huh
Reply
#6
In 64-bit _UNSIGNED LONG sometimes won't be good enough, and it won't be toward a parameter that expects a pointer. It's because LONG in QB64 is always 32-bit. It needs to be _INTEGER64 or better yet, _OFFSET.

When converting 32-bit code to 64-bit be prepared to turn any LONG or _UNSIGNED LONG into _OFFSET, or less frequently _INTEGER64. But it depends on the context, such as that "size_t" that seems to be declared as different type in each C/C++ header file.

Pointers are really a PITA which is why I gave up soon with C programming. Was repeatedly crashing my computer trying to program a cheap window manager out of the equivalent of SCREEN 0 limited to MS-DOS, many many years ago.
Reply
#7
(06-05-2023, 11:58 PM)eoredson Wrote: If the entire problem is with the function declaration then I have got it wrong the whole time. Huh
The code looks good to me, and seems to work Smile

Yes it was technically wrong the whole time. The catch is that because `_Offset` is 32-bits wide in 32-bit QB64, and a `Long` is also 32-bits wide, using `CreateFileA&` happens to work anyway when using 32-bit QB64. It's only when using 64-bit QB64 that the `_Offset` vs `Long` distinction matters.

To make your code portable between 32-bit and 64-bit you should ensure you use `_Offset` for any value that needs to vary in size depending on the platform (That goes for all pointer types, such as `HANDLE` in Win32).
Reply
#8
That helps and is a real pita because:

  32-bit = Long/_Unsigned Long
  64-bit = _Integer64/_Offset

never seemed clear to me because of the function declaration is CreateFile%& as well..

Erik.
Reply
#9
My ultimate goal was to make sure my projects are cross-platform compatible between 32-bit and 64-bit.

I can't test this fact since I have no 64-bit version of Qb64pe that ever worked very well..

If I can get around the compilation errors then I can test the code.
Reply
#10
(06-06-2023, 01:34 AM)eoredson Wrote: That helps and is a real pita because:

  32-bit = Long/_Unsigned Long
  64-bit = _Integer64/_Offset

never seemed clear to me because of the function declaration is CreateFile%& as well..

Erik.
That's note quite right, `_Offset` is not the same thing as `_Integer64`.

`_Offset` is special, it is 32-bits wide on 32-bit QB64, and 64-bits wide on 64-bit QB64. It is a different size depending on the version used, which is also why you need to use it to represent types like `HANDLE` which also differ in size in C++ depending on the platform. To make cross-platform programs you have to use `_Offset` to represent C++ types like pointers which are a different size on different platforms.
Reply




Users browsing this thread: 3 Guest(s)