-
Aug 7th, 2020, 04:31 AM
#1
Thread Starter
Hyperactive Member
Why is there SetWindowLongA and SetWindowLongW in Windows API?
I generally program in VBA and hooking is not a big thing there. Lately I have been playing with hooking in VB6 and I noticed in the Windows API there is a SetWindowLongA and SetWindowLongW. I try to do everything I do in Unicode so I want to use the W version. When I look at Microsoft's documentation for each, it shows 3 parameters which are all passed ByVal and none of them relates to a string so the two calls look identical. Does anyone know why there is an "A" version and a "W" version?
BTW, the same question is for functions SetWindowsHookExA and SetWindowsHookW.
Thanks
-
Aug 7th, 2020, 07:27 AM
#2
Re: Why is there SetWindowLongA and SetWindowLongW in Windows API?
Originally Posted by MountainMan
I generally program in VBA and hooking is not a big thing there. Lately I have been playing with hooking in VB6 and I noticed in the Windows API there is a SetWindowLongA and SetWindowLongW. I try to do everything I do in Unicode so I want to use the W version. When I look at Microsoft's documentation for each, it shows 3 parameters which are all passed ByVal and none of them relates to a string so the two calls look identical. Does anyone know why there is an "A" version and a "W" version?
BTW, the same question is for functions SetWindowsHookExA and SetWindowsHookW.
Thanks
If a window handle is ANSI, then use SetWindowLongA. If a window is Unicode (e.g. from a CreateWindowExW call) then use SetWindowLongW.
It's certainly also possible to unicodify a window proc by using GetWindowLongA and GWL_WNDPROC and then re-apply with SetWindowLongW.
You can use the IsWindowUnicode API to know if a window is ANSI or Unicode.
But it's not so inconvinient/complicated as it sounds. You can use SendMessageW on an ANSI window without an issue. Windows will take care of the conversions.
Last edited by Krool; Aug 7th, 2020 at 07:33 AM.
-
Aug 7th, 2020, 08:52 AM
#3
Re: Why is there SetWindowLongA and SetWindowLongW in Windows API?
Originally Posted by Krool
It's certainly also possible to unicodify a window proc by using GetWindowLongA and GWL_WNDPROC and then re-apply with SetWindowLongW.
. . . and this changes the way keyboard messages for this specific window are "translated" by the OS, along with probably other internal changes needed to retrofit unicode support (long time ago).
cheers,
</wqw>
-
Aug 7th, 2020, 09:31 AM
#4
Re: Why is there SetWindowLongA and SetWindowLongW in Windows API?
And, from VB6 (or VBA), when using the ...W version of API calls, you must always wrap your passed in strings (and string buffers) with the StrPtr() function to prevent conversion to ANSI (and the API String arguments must be declared as Long in the declaration). But it sounds like you're probably already aware of that one.
EDIT: And just further commenting on what's already been said: Basically, I just always try and use the ...W version of the API functions, and let Windows worry about whether the window is ANSI or Unicode.
EDIT2: For grins, here's an example:
Code:
Private Declare Function LoadLibraryExW Lib "kernel32" (ByVal lpLibFileName As Long, ByVal hFile As Long, ByVal dwFlags As Long) As Long
[in a procedure]
hHandle = LoadLibraryExW(StrPtr(sModule), 0&, 0&)
----------- versus ----------
Private Declare Function LoadLibraryExA Lib "kernel32" (ByVal lpLibFileName As String, ByVal hFile As Long, ByVal dwFlags As Long) As Long
[in a procedure]
hHandle = LoadLibraryExA(sModule, 0&, 0&)
Last edited by Elroy; Aug 7th, 2020 at 09:45 AM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Aug 7th, 2020, 09:58 AM
#5
Re: Why is there SetWindowLongA and SetWindowLongW in Windows API?
A long time ago there was SetWindowLong(). Later on when NT came along it was split into SetWindowLongA() and SetWindowLongW() while Win9x only had SetWindowLongA().
In C programs you normally defined the one you wanted as SetWindowLong() in a macro, so old programs needed minimal rewriting.
Later in Win9x's life cycle it got the unicows.dll add-on library, which added W entrypoints for many calls. Eventually unicows.dll started shipping with Win9x (98SE maybe?) but before that later versions of IE installed it (maybe 4.1 or so?). The unicows adapter library had to translate text to ANSI then call the old A entrypoints in Win9x and then translate back to Unicode so there was some performance cost.
NT was native Unicode, so the A entrypoints are slower, translating from then back to ANSI.
Worse yet, in VB5 and 6 calling A entrypoints with any ByVal String argument involves two more translations to/from ANSI. That's a total of 4 for each String for each call on NT.
Win2K was NT 5.0, XP was NT 5.1, Vista was NT 6.0, etc.
-
Aug 7th, 2020, 10:54 AM
#6
Thread Starter
Hyperactive Member
Re: Why is there SetWindowLongA and SetWindowLongW in Windows API?
I use the W functions all the time too. I was just wondering why those particular functions had an A and a W version since the parameters did not involve strings.
-
Aug 7th, 2020, 11:11 AM
#7
Re: Why is there SetWindowLongA and SetWindowLongW in Windows API?
The ones without any text arguments might do something else under the covers, for example call text-encoding sensitive procedures themselves or send different message values since those often come in both ANSI and Unicode forms.
On Win9x it didn't matter, it was all ANSI. NT OSs can be a different story. To get the actual details you have to ask somebody like Raymond Chen.
-
Aug 7th, 2020, 12:41 PM
#8
Re: Why is there SetWindowLongA and SetWindowLongW in Windows API?
Lots of "and... " posts, so I'll add another. I grouped Strings & UDTs below; even though Strings were talked about earlier.
When using W type APIs, be very careful with any strings and UDTs (user-defined types) you pass to those APIs. Typically, strings are passed via StrPtr() and the API string parameters are "As Long" not "As String". Likewise, UDTs that contain strings are typically passed via VarPtr(UDT) and the API UDT parameters are "As Long" not "As [theUDTname]"
You need to protect strings from being converted to ANSI when they are passed to W type APIs.
Some UDTs can have members that are predefined for ANSI or unicode, i.e., array(0 to 31) when ANSI vs array(0 to 63) for unicode.
I use the W functions all the time too. I was just wondering why those particular functions had an A and a W version since the parameters did not involve strings.
As mentioned earlier, the structures returned by the API may be using strings or ANSI/Unicode specific values. For example, listview/treeviews return Long values in many WM_NOTIFY structures. The value of those Longs may be different when unicode is used vs ANSI.
edited: Another thing to keep in mind is what an API call does. It calls a function inside a DLL. If the API has both a W and A version, likely two different functions. One function may be expecting 2-byte characters while the other isn't, maybe one is expecting a larger UDT than the other. Windows may be able to redirect/fix some improper calls to the wrong version, but maybe it's only smart enough for its own DLLs?
Last edited by LaVolpe; Aug 7th, 2020 at 01:09 PM.
-
Aug 7th, 2020, 01:22 PM
#9
Re: Why is there SetWindowLongA and SetWindowLongW in Windows API?
Part of the complication comes from the hacks VB6 implements to try to make the transition to Unicode transparent.
A "Declare" compiles to a bunch of code that tries to deal with the mismatch between old A entrypoints and VB's Unicode text. That's where the extra conversion-copying on the way in and back out comes from.
Typelibs can often be used instead of Declares to bypass that and simplify things. They can often make some calls possible that might otherwise require gymnastics in your VB code.
A lot of this might have eventually been washed away if VB had not been frozen at VB6.
-
Aug 7th, 2020, 01:57 PM
#10
Re: Why is there SetWindowLongA and SetWindowLongW in Windows API?
Originally Posted by dilettante
A lot of this might have eventually been washed away if VB had not been frozen at VB6.
Yes, it would be nice if we had AsAnsi and AsUnicode keywords for these API declarations, much like the PtrSafe keyword in the VBA. For instance, something like:
Code:
Private Declare AsUnicode Function LoadLibraryExW Lib "kernel32" (ByVal lpLibFileName As String, ByVal hFile As Long, ByVal dwFlags As Long) As Long
And then, we could make the calls without any conversion or worrying about StrPtr().
But hey ho, that's just wishful thinking.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Aug 7th, 2020, 02:18 PM
#11
Re: Why is there SetWindowLongA and SetWindowLongW in Windows API?
@Elroy, you could pass ANSI string parameters As Long.
But who would want to make that their standard, As Long vs As String, for ANSI?
Notice, parameters in both APIs are As Long
Code:
Private Declare Function SetWindowText Lib "user32.dll" Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal lpString As Long) As Long
Private Declare Function GetWindowText Lib "user32.dll" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As Long, ByVal cch As Long) As Long
Private Sub Command1_Click()
SetWindowText Me.hwnd, StrPtr(StrConv("Hello World", vbFromUnicode))
Dim sCaption As String, lSize As Long
sCaption = Space$(128) ' half of what's required/desired
lSize = GetWindowText(hwnd, StrPtr(sCaption), LenB(sCaption))
MsgBox Left$(StrConv(sCaption, vbUnicode), lSize)
End Sub
oops, convert then get Left$ -- patched above.
Last edited by LaVolpe; Aug 7th, 2020 at 02:40 PM.
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|