0

so i recently got back into VBA and i want to write my code so that it works for both 32- and 64- bit and also for VBA7 and older versions.

The simple Code i came up with is the following:

#If VBA7 Then
     #If Win64 Then
          Private Declare PtrSafe Function GetSystemDirectoryA Lib "kernel32" _
          (ByVal lpBuffer As String, ByVal nSize As LongPtr) As LongPtr
     #Else
          Private Declare Function GetSystemDirectoryA Lib "kernel32" _
          (ByVal lpBuffer As String, ByVal nSize As LongPtr) As LongPtr
     #End If
#Else
     Private Declare Function GetSystemDirectoryA Lib "kernel32" _
     (ByVal lpBuffer As String, ByVal nSize As Long) As Long
#End If

Public Function GetSystemDirectory() As String
     Dim lngLen As LongPtr, lpBuffer As String, nSize As LongPtr
     nSize = 255
     lpBuffer = String(nSize, vbNullChar)
     lngLen = GetSystemDirectoryA(lpBuffer, nSize)
     GetSystemDirectory = Left(lpBuffer, lngLen)
End Function

Sub test()
     Debug.Print GetSystemDirectory()
End Sub

So now i thought i got it, but if i try to run the code it says:

Error while compiling:

Types Incompatible

When i reverse everything back to Long instead of LongPtr, it works but thats not what i want/need.

I read something that i should only replace some Longs with LongPtr, but that it would also work by just replacing all of them.

As you can see i am quite new to this. Anyway, does anyone know what i dont see?

Thanks in Advance.

IRezzet
  • 13
  • 9
  • `I read something that i should only replace some Longs with LongPtr` - [correct](https://stackoverflow.com/a/63801528/11683), and you have overdone it here. The function signature is `(string, long) as long` regardless of bitness. You don't need the `#If Win64` branch [either](https://stackoverflow.com/a/57843773/11683), only the `#If VBA7` one. And even then, than branch provides support for old Offices (prior to Office 2010). If you don't want to support Office 2007 and lower, you don't need any branches at all. – GSerg Jan 18 '23 at 19:59
  • 1
    Apart from the wrong data types in the `Declare`s, your existing code is wrong in that it unconditionally declares `LongPtr` variables in the Sub and passes them to conditionally defined `Long`/`LongPtr` arguments. If you want to support the old Offices and use `#If VBA7`, you must put that `#If VBA7` everywhere where you declare a variable that would be `LongPtr` in the newer offices or `Long` in the older. – GSerg Jan 18 '23 at 20:02
  • I Want to support older versions yes. could you elaborate the second part of the Answer a little? I dont really understand the Difference tho. If everything is declared as a LongPtr on a 64-bit version of VBA7 shouldn´t it just work, because in the Windows documentation it says that LongPtr just refers to the fitting datatype (depending on which version i am using). Given that, should it just all refer to LongLong and if not then atleast all to the same Datatype? – IRezzet Jan 18 '23 at 20:10
  • (yes i should take the whole code and put it in #If VBA7 but this one here is just for testing --> it always takes the same path because i always test it on the same system for now) – IRezzet Jan 18 '23 at 20:11
  • If everything is declared as `LongPtr`, that everything will have different size on 32 bit offices and on 64 bit offices. Which is correct for things that do change size with bitness, i.e. pointers (please click the link in the [first comment](https://stackoverflow.com/questions/75164320/excel-vba-compatibilty-between-32-and-64-bit-code-longptr?noredirect=1#comment132639458_75164320)). For things that do not change size with bitness, such as e.g. Windows' `DWORD` or `UINT`, declaring them as `LongPtr` will unbalance the stack and crash your host program when you attempt to call that function. – GSerg Jan 18 '23 at 20:13
  • @GSerg As i read your comment again, do i get it right that one of the mistakes is that the GetSystemDirectoryA function always need (string, long)? and if yes then it is wrong because LongPtr on my System would refer to LongLong and therefor it can´t work? – IRezzet Jan 18 '23 at 20:14
  • `always need (string, long)` - yes. – GSerg Jan 18 '23 at 20:15
  • @GSerg Ok thank you very much i will see if i can get it running! – IRezzet Jan 18 '23 at 20:17
  • Nice overview here: https://codekabinett.com/rdumps.php?Lang=2&targetDoc=windows-api-declaration-vba-64-bit – Tim Williams Jan 18 '23 at 21:21
  • @Gserg hi again, if the Signatures always have to be filled, why does: --> private declare ptrsafe GetSystemDirectoryA Lib "kernel32" (ByVal lpBuffer As String, ByVal nSize As LongPtr [instead of Long]) As LongPtr Debug.Print GetSystemDirectoryA("SomeString", SomeNumber) work?? – IRezzet Jan 18 '23 at 23:28
  • On 32 bits it works because `LongPtr` resolves to `Long` as it should. On 64 bits it works because Win64 uses a [different ABI](https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#parameter-passing) where the first four integer parameters are passed in registers rather than on the stack. The register is 64 bits anyway and will receive the unexpected `LongLong` correctly without misaligning the stack. – GSerg Jan 19 '23 at 00:27

0 Answers0