-
1 Attachment(s)
Typelib to add LongPtr type to VB6 for universal codebases
VB6LongPtr.tlb - Add LongPtr to VB6
This is just a dead simple typedef but I didn't see anything like it readily available, so thought I'd post the one I made.
While you can (and must) use compiler constants to declare APIs differently, it gets to be unwieldy fast when you want to have the rest of your code be compatible when you have variables and Type members that also must be LongPtr. So to create universal codebases, I made a simple typelib that adds a LongPtr alias for Long in VB6. You can declare variables, Type members, arguments, etc, as LongPtr, and VB6 will treat them identically to a Long, with which they're also interchangeable- you can pass a LongPtr variable to a function expecting a Long, and a Long to a function expecting a LongPtr.
Add this only to your VB6 projects, not to VBA or twinBASIC projects.
UPDATE (06 Mar 2026) - Added LongPtr64 and LongLong aliased to Currency.
Code:
//VB6LongPtr by fafalone
//Simply uses an alias to make LongPtr a usable type in VB6 in order
//to create universal codebases for VB6/VBA/twinBASIC. Include this
//typelib **only** with VB6 projects, as VBA/tB have a native LongPtr.
//(Since VB6 is 32bit only, LongPtr *always* would resolve to Long)
[
uuid(D8EE61B0-8778-4A43-8F98-E7E1C2C08AD4),
version(2.00),
helpstring("VB6 LongPtr Support"),
lcid(0x0)
]
library VB6LongPtr {
importlib("stdole2.tlb");
typedef [public] long LongPtr;
typedef [public] CURRENCY LongPtr64;
typedef [public] CURRENCY LongLong;
};
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
I've been using a similar hack with an empty enum for some time now
Code:
#Const HasPtrSafe = (VBA7 <> 0) Or (TWINBASIC <> 0)
#If HasPtrSafe Then
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
#Else
Private Enum LongPtr
[_]
End Enum
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
#End if
Notice CopyMemory's last parameter is LongPtr in both declares in both x86 and x64 targets (i.e. bitness agnostic declare).
This also allows declaring bitness agnostic UDTs (no conditional compilation) like this
Code:
Private Type SAFEARRAY1D
cDims As Integer
fFeatures As Integer
cbElements As Long
cLocks As Long
pvData As LongPtr
cElements As Long
lLbound As Long
End Type
cheers,
</wqw>
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
The last param of CopyMemory is a SIZE_T, which like pointers is 4 bytes on 32bit, 8 on 64... it comes up in a few other places too; like the GlobalAlloc/LocalAlloc/HeapAlloc functions and their related calls.
Btw twinBASIC has the VBA7 constant set, so I don't know if you need both just for PtrSafe. I use it for DeclareWide sometimes.
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
This is a fantastic idea. I do like the TypeLib approach better though, as it allows for the actual declaration of variables as LongPtr, which I have done before (which the Enum won't let you do). Anytime I have a memory pointer I'm declaring in the VBA, I use LongPtr. Now, I can make that code interchangeable between VB6 and VBA.
Nice work, Fafalone. :)
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
Quote:
Originally Posted by
Elroy
I do like the TypeLib approach better though, as it allows for the actual declaration of variables as LongPtr, which I have done before (which the Enum won't let you do)
When is enum failing? Can you give some sample code?
Quote:
Originally Posted by
fafalone
Btw twinBASIC has the VBA7 constant set, so I don't know if you need both just for PtrSafe. I use it for DeclareWide sometimes.
Good to know, thanks!
cheers,
</wqw>
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
Quote:
Originally Posted by
wqweto
When is enum failing? Can you give some sample code?
I guess I just didn't think it through. I use all the time to declare function returns and also procedure arguments. I've just never used it to declare a stand-alone variable, but it obviously works fine.
Code:
Option Explicit
Private Enum LongPtr
[_]
End Enum
Private Sub Form_Load()
Dim p As LongPtr
End Sub
I should have realized that it'd work, given that you can use it to declare arguments. My bad. :blush:
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
Hi wqweto and fafalone,
Of course we know, VB is capable of using Aliases through tlbs since "M.C.s-PowerVB". And moreover we can "kind of" use an Alias for Long by doing an empty Enum, and this is well known practice for decades now.
I do not claim to be the only one who ever had the idea for using an empty enum as an Alias for LongPtr, however I posted the idea in 2021 in ActiveVB-forum:
http://foren.activevb.de/forum/vba/t...C-als-a/#forum
Also have a look at the english translation in my github:
https://github.com/OlimilO1402/XL_VBanywhere
I very much like to see this idea is used by many developers out there suddenly today
instead of using a tlb I tend to use a Module named MPtr in which I collected all Ptr-related stuff in it
https://github.com/OlimilO1402/Ptr_P...dules/MPtr.bas
besides UDTPtr, of course also the empty LongPtr Enum
As for now, all I want to say, LongPtr is not enough, if you want to make a code running everywhere in VBC and all VBA. Unfortunately we need to declare all our API-functions twice
for VBA7(x64) with the keyword Ptrsafe and for VB6(x86) without the keyword Ptrsafe
RtlMoveMemory:
the last parameter (ByteLength) in x64 is a 64bit LongLong and in x86 it is a 32-bit Long
even If we could use the same thing here, imho it would be a "crime" to use LongPtr if the variable is not a pointer
all we need is a second Alias for this as well, even if LongLong is not 64-bit in x86
a little example from MPtr:
Code:
#If VBA7 = 0 Then
Public Enum LongPtr
[_]
End Enum
#End If
#If Win64 = 0 Then
Public Enum LongLong
[_]
End Enum
#End If
#If Win64 Then
Public Const SizeOf_LongPtr As Long = 8
#Else
Public Const SizeOf_LongPtr As Long = 4
#End If
#If VBA7 Then
Public Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (ByRef pDst As Any, ByRef pSrc As Any, ByVal BytLen As LongLong)
Public Declare PtrSafe Sub RtlZeroMemory Lib "kernel32" (ByRef pDst As Any, ByVal BytLen As LongLong)
#Else
Public Declare Sub RtlMoveMemory Lib "kernel32" (ByRef pDst As Any, ByRef pSrc As Any, ByVal BytLen As LongLong)
Public Declare Sub RtlZeroMemory Lib "kernel32" (ByRef pDst As Any, ByVal BytLen As LongLong)
#End If
Public Function StrArrPtr(ByRef strArr As Variant) As LongPtr
'Attention, here 32bit-64bit-trap, so use only RtlMoveMemory to be variable in size of ptr
RtlMoveMemory StrArrPtr, ByVal VarPtr(strArr) + 8, MPtr.SizeOf_LongPtr
End Function
using:
Code:
Private Sub BtnTestSAPtr_Click()
ReDim sa(0 To 10) As String
sa(0) = "one"
sa(1) = "two"
Dim saX() As String
SAPtr(StrArrPtr(saX)) = SAPtr(StrArrPtr(sa))
Debug.Print saX(0)
MPtr.ZeroSAPtr StrArrPtr(saX)
End Sub
Cheers
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
Personally, when coding in VBA, I'd never use LongPtr to declare a non-pointer LongLong. The reason why is simple. I might be in 32-bit, but I'm still doing some operations that are expecting a 64-bit variable, which isn't terribly unusual.
So OlimilO, your point is well taken. Just an FYI, we actually do have the LongLong in VB6. We just have to use a Variant to do it, and there are some caveats to it.
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
I used the following aliases here:
Code:
typedef [public] long PTR;
typedef [public] long HANDLE;
typedef [public] long SIZE_T;
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
I've thought about making all the internal aliases in oleexp public... it currently has LongPtr, LONG_PTR, BOOL, CHAR, KNOWNFOLDERID and REFERENCE_TIME/HNSTIME public... but I decided it might get confusing with dozens of types... might be too much for most VB people lol
Code:
typedef long ULONG;
typedef long UINT;
typedef long UINT32;
typedef long HWND;
typedef long DWORD;
typedef long HKEY;
typedef long HMENU;
typedef long HICON;
typedef long HBITMAP;
typedef long HIMAGELIST;
typedef long HMODULE;
typedef long HDC;
typedef long HACCEL;
typedef long HTASK;
typedef long HPALETTE;
typedef long HANDLE;
typedef long COLORREF;
typedef double REFTIME;
typedef long HSEMAPHORE;
typedef long HEVENT;
typedef long DWORD_PTR;
typedef long ULONG_PTR;
typedef long LCID;
typedef CURRENCY ULONGLONG;
typedef CURRENCY UINT64;
typedef UUID *REFKNOWNFOLDERID;
typedef UUID FOLDERTYPEID;
typedef UUID CLSID;
typedef short WORD;
typedef short VARIANT_BOOL;
typedef CURRENCY DWORDLONG;
I'd agree with Elroy about LongLong... probably not a good idea since most usage isn't SIZE_T (maybe most if you count handles, which technically aren't pointers, but still there's a lot of platform-independent places where it's always an 8-byte type.
What do you mean about LongLong in a Variant though? It's not like Decimal where there's half implemented support via CDec()... do you just mean the various ways of messing around with the Variant in memory where you can use *any* type, or there something I'm missing?
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
Quote:
Originally Posted by
fafalone
What do you mean about LongLong in a Variant though? It's not like Decimal where there's half implemented support via CDec()... do you just mean the various ways of messing around with the Variant in memory where you can use *any* type, or there something I'm missing?
I've got to run to a party in about 5 minutes, and I'll find links when I get back. But yeah, there's no C...() for it like there is CDec(). But, if you force a Variant to be a LongLong, it works fairly well. You just can't use it as a Variant-byref (the pointer in the variant). If the LongLong is in the Variant as byval, it works in VB6. If I remember correctly, you can even add, subtract, multiply, and divide the things ... but I'd need to review to make sure.
GTG
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
Handles are "like" Pointers, 32bit in x68 and 64bit in x64, so using the LongPtr Alias for all kinds of handles, imho would be OK, and should be considered as the way to go.
Yes calculations with the datatype Decimal inside the Variant is slow, but so are all int64-operations in x86.
Yes Decimal is an underrated datatype. It has in total 96bits and it can be an unsigned In64 and also act like a signed Int64, either way is possible.
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
i always use Currency for 64 bit operations. It's faster than one wrapped into a Variant variable.
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
Quote:
Originally Posted by
OlimilO
Of course we know, VB is capable of using Aliases through tlbs since "M.C.s-PowerVB". And moreover we can "kind of" use an Alias for Long by doing an empty Enum, and this is well known practice for decades now.
Yes, it was one of your github projects I first saw this hack some time this year.
We don't do x64 in VB6 land that often and only recently our interest has peaked in connection with TwinBASIC's imminent general availability (kind of but you get the point) so we are getting ready to port some major building blocks in VB6 land to x64 (i.e. becoming bitness agnostic) which will cross-pollinate VBA7 world as well with some quality efforts IMO.
Who knows we might see x64 version of RC6 too :-))
cheers,
</wqw>
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
Quote:
Originally Posted by
The trick
i always use Currency for 64 bit operations. It's faster than one wrapped into a Variant variable.
I actually do too. You can even do addition and subtraction with Currency, thinking of them as LongLong. But you can't do multiplication nor division, as that will work out differently.
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
Quote:
Originally Posted by
Elroy
I actually do too. You can even do addition and subtraction with Currency, thinking of them as LongLong. But you can't do multiplication nor division, as that will work out differently.
You could use apis:
Code:
Option Explicit
Private Declare Function allmul Lib "ntdll" _
Alias "_allmul" ( _
ByVal cMultiplicand As Currency, _
ByVal cMultiplier As Currency) As Currency
Private Declare Function alldiv Lib "ntdll" _
Alias "_alldiv" ( _
ByVal cDivident As Currency, _
ByVal cDivisor As Currency) As Currency
Private Sub Form_Load()
Debug.Print alldiv(5, 0.08) ' // 50000 / 800 = 62
Debug.Print allmul(500, 8) ' // 5000000 * 80000 = 400000000000
End Sub
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
Quote:
Originally Posted by
wqweto
Yes, it was one of your github projects I first saw this hack some time this year.
OlimilO showed me this tip in this year too. I never saw this before and i often use it (for example)
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
Quote:
Originally Posted by
The trick
You could use apis:
Code:
Option Explicit
Private Declare Function allmul Lib "ntdll" _
Alias "_allmul" ( _
ByVal cMultiplicand As Currency, _
ByVal cMultiplier As Currency) As Currency
Private Declare Function alldiv Lib "ntdll" _
Alias "_alldiv" ( _
ByVal cDivident As Currency, _
ByVal cDivisor As Currency) As Currency
Private Sub Form_Load()
Debug.Print alldiv(5, 0.08) ' // 50000 / 800 = 62
Debug.Print allmul(500, 8) ' // 5000000 * 80000 = 400000000000
End Sub
Very nice! That's good information. :) I've already saved the API declarations.
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
just asking: it can be the same for create the Pointers types?
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
You can use them internally within a typelib where it will resolve to a ByRef when compiled, but no, VB has no true pointer type support. You can see this with oleexp; I accidentally left in the last time I tried it:
typedef [public] long *vbLongPtr;
You'll get an automation type not supported error if you try to actually use it in VB6.
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
What "I accidentally left in the last time I tried it?
You have very accidenentally done so typedef [public] long *vbLongPtr
WILL not be work with VB7 (Office 10) and Office 10 (VB7) Long_PTR
This is very accidenentally because you WANT people to STICK to your TypeLib.
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
oleexp.tlb and vblongptr.tlb are 32-bit only typelibs. They do not work, at all, with 64bit hosts. I do not want people to use oleexp in those, because it's not intended for them. For 64bit twinBASIC, I offer WinDevLib (formerly tbShellLib), which is basically oleexp+thousands of additional APIs. When tB supports exporting .tlb from packages, I'll release it for 64bit VBA, and oleexp will be deprecated in favor of it. Frankly I don't care if people use it or not, and frequently point out alternatives, and instructions to convert things for use outside those libraries.
Office doesn't have LONG_PTR, or vbLongPtr. Both of those are user-defined only. The only one built in is LongPtr. These typelibs *would* work with 32bit VBA7 though (and plenty of people use oleexp for it), since the built-in version will take precedence and you can implicitly convert between them.
It's an accident in that I wanted to see what happened if I made such a def pubic, and intended to remove it from the public release when the answer was 'nothing good', but forgot. But again, now that this has been brought to my attention, the bug will be fixed in the next release. I fix my bugs, I don't dismiss people who point them out and defend blatantly wrong mistakes. Since I don't know everything like you, I appreciate any help someone is willing to offer me.
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
here you speak:
- Currency, but VB6 don't have it;
- fafalone you give us the LongPtr.... thanks, even i don't understand how can i get it... i just download the lib;
- using 'Long' and the 'TypeDef', we can do 'HDC' and others handles.
- fafalone if you can get the 'LongPtr', we can get, too, pointers(even change the name) for numbers, floats and strings.
thanks for all
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
-VB6 does have Currency
-Add either this typelib or oleexp.tlb under Project->References
-Yes you could add others like that but you'd have to modify the typelib.
-In VB6 it's just a name change; it's not adding true pointer types. You could create aliases for those other types too, but again you have to modify the typelib; e.g. typedef [public] short ATOM; would add 'ATOM' as another name for 'Integer'.
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
fafalone: "-In VB6 it's just a name change; it's not adding true pointer types. You could create aliases for those other types too, but again you have to modify the typelib; e.g. typedef [public] short ATOM; would add 'ATOM' as another name for 'Integer'."
Code:
typedef [public] long PTR;
typedef [public] long HANDLE;
typedef [public] long SIZE_T;
ok.. i can do:
Code:
typedef [public] long PTR;
typedef [public] long HANDLE;
typedef [public] long SIZE_T;
typedef [public] long STRPointer;
typedef [public] long LongPTR;
but like you see nothing happens... only change the name.... why not like:
Code:
typedef [public] varptr(varname) LongPTR;
???
ok..i'ts an error, but you get the point ;)
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
You can see the consequences in the current oleexp version; it has
typedef [public] long *vbLongPtr;
which would make it a true pointer.
When you try to use it in VB6, you get an error 'Automation type not supported'.
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
UPDATE (06 Mar 2026) - Added LongPtr64 and LongLong aliased to Currency.
-
Re: Typelib to add LongPtr type to VB6 for universal codebases
Code:
Private Declare Function VarCyMulI8 Lib "oleaut32" (ByVal cyLeft As Currency, ByVal llRight As Currency, ByRef pcyResult As Currency) As Long
Declare Function DivLL Lib "ntdll" Alias "_alldiv" (ByVal Left As Currency, ByVal Right As Currency) As Currency
Declare Function ModLL Lib "ntdll" Alias "_allrem" (ByVal Left As Currency, ByVal Right As Currency) As Currency
Declare Function MulLLUnsafe Lib "ntdll" Alias "_allmul" (ByVal Left As Currency, ByVal Right As Currency) As Currency
Property Get MulLL(ByVal Left As Currency, ByVal Right As Currency) As Currency
Dim hr As Long
hr = VarCyMulI8(Left, Right, MulLL)
If hr < 0 Then Err.Raise hr
End Property