Registering Window Class - winapi

I guess my question is relatively easy for those of you who spent time dealing with Win32 API.
So my question is:
After initializing a WNDCLASSEX instance we need to "register" it using the "RegisterClassEx" function, why? Why do we do that? What's the meaning of this registration and in what cases I need to register things?

The ATOM returned by RegisterClassEx uniquely identifies your "window class" which can then be referred to in other windows APIs. [MSDN]
Effectively it is a hash so as to reduce the amount of data processed each time a window is created or looked for. It does also mean that multiple windows with same features can be easily created and identified.
I was addressing the practical reasons above. Hans Passant's answer correctly explains this is the OO class concept provided for C. Further MSDN example.

The word Class in the function name is significant. When you write code in an object oriented language, like C++, Delphi, Java or C# etcetera, then you use the class keyword to create objects that have behavior. But the winapi was designed to be used from C, a language that doesn't have such functionality. The RegisterClassEx() function is an emulation of that, it lets you create a window that "derives" its behavior from a named class, behavior that you can override. With every window that you create using that class name behaving identically.
The WNDCLASSEX structure you pass gives a window its default behavior. The most significant members of this structure are:
lpszClassName. That's the equivalent of the C++ class name. You can later call CreateWindowEx() and pass that name to get a window that behaves a certain way. Windows itself calls RegisterClassEx() to register several of its built-in window classes that you then can readily re-use in your own code. "EDIT", "BUTTON" and "LISTBOX" are good examples of that.
lpfnWndProc. This is what gives a window class its specific default behavior. The address of its window procedure that implement message handlers for specific messages. You can further customize the default behavior, in other words "derive" your own class from the base class, by specifying another window procedure in the CreateWindowEx() call. Such a window procedure must always call DefWindowProc(), the equivalent of calling the base class method. Or in other words, a window has one virtual method.
hIcon, etcetera. These are the equivalent of properties of the base class, they set default values that affect the default message handlers. Helping you to keep your window procedure simple. It is for example rarely necessary to write a message handler for WM_ERASEBKGND, the hbrBackground member sets the default background for a window.
Windows requires you to call RegisterClassEx() even if you don't plan on re-using a window. Which is by far the most common usage of the function in your own code. You don't start to really take advantage of it until you write a library that implements controls, windows that other code can use. Like "EDIT".

Related

Calling FindWindowEx with program WIndowClass

I'm trying to use FindWindowEx to determine whether a certain program is running or not.
FindWindow(NULL, "Mozilla Firefox");
This works fine as long as I'm on firefox's start page. A workaround I found was:
FindWindow(NULL, "MozillaWindowClass");
But that left me wondering if that was specifically crafted for firefox, but it turns that it appeareantly works for other applications:
FindWindow(NULL, "OllyDbgWindowClass");
So my question is can I just use FindWindow with an argument like "programXWindowClass" for any program? Are there any exceptions to this?
Is "programXWindowClass" guaranteed to exist?
There is no requirement for a caller to RegisterClassEx to follow any particular pattern, that maps a window class name to any other information (like the application name). Any caller can pick any valid window class name they like.
Keep in mind two notable consequences of this:
A window class name need not be unique to any given application. All UWP applications use the window class "Windows.UI.Core.CoreWindow" by default, for example.
A window class name can change across different versions of an application, or even different invocations of an application.
Is "programXWindowClass" guaranteed to exist?
No. What you observed is merely a coincidence in naming.

MSDN terminology - Window procedure for the predefined control vs the control procedure

In a nutshell
Confused between the term "The window procedure for the predefined edit control window class" and "the edit control procedure".
In detail
I feel silly to ask this, but am I missing something from what is mentioned below?
from: MSDN
The window procedure for the predefined edit control window class
carries out default processing for all messages that the edit control
procedure does not process. When the edit control procedure returns
FALSE for any message, the predefined window procedure checks the
messages and carries out the following default actions.
*bold formatting by me
Let me specify my interpretation of above:
The window procedure for the predefined edit control window class: I believe this is the internal implementation of edit control's logic inside Windows (similar to any custom control we create).
The edit control procedure: Well this is something which I'm not able to interpret accurately. My wild guesses are:
Likely: It's our custom WndProc that we may subclass from edit control if we need to modify edit control default behaviour (say tab/carriage return processing etc.)
My self debate: In this case MSDN would have mentioned word "subclass" explicitly at least somewhere in article.
Unlikely: It's some abstracted/specialized internal Wndproc for windows that is class specific.
My self debate: If this was the case, there would be some mention of this somewhere.
What further adds to the confusion is the "When the edit control procedure returns FALSE for any message, the predefined window procedure checks the messages and carries out the following default actions" mentioned above. I believe the return value from a WndProc is always LRESULT and is message specific, and this TRUE/FALSE thing applies generally to DialogProcs. So what's the piece I am missing? Also even if I believe its a WndProc, return value does not decide the default processing, our explicitly calling DefWindowProc()/CallWindowProc() decides the default processing. So what is the return based processing above page talks about?
From the comments and research, it looks like this is to do with slightly inaccurate documentation on MSDN. Though I am sure folks at Microsoft can add some sense to it, maybe something related to internal implementation.

Who is owner of GWLP_USERDATA cell?

good known that GWLP_USERDATA can be used to associate some pointer size data with the specified window. but who has the right do it ? obviously if two piece of code independently do this - one piece is overwrite data of another - so there must only be one owner. but it must be clear determined a general rule - who is owner of GWLP_USERDATA cell ? whom it belong ?
can be two internally consistent agreements:
code that created the window is owner. belong to the creator of the
window
code which implement window class. belong to the window class
implementer
what of this two solutions must be used ?
1. from MSDN:
GWLP_USERDATA:
Sets the user data associated with the window. This data is intended
for use by the application that created the window. Its value is
initially zero.
how need understand This data is intended for use by the application that created the window ?
so code which call CreateWindowEx, CreateDialogParam, DialogBoxParam, etc - and only this code can use GWLP_USERDATA. from this also follows that window class implementer can not use GWLP_USERDATA. so huge number of examples where GWLP_USERDATA used for bind instance of class to the specified window is incorrect. Managing Application State - official MSDN example, where GWLP_USERDATA used for bind data structure to window is incorrect ?!
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
is error under this rule.
what can be said in favor of this version ?
i check different windows versions (from xp to win10) - how i can see all windows built-in window classes ( WC_* and others) use
SetWindowLongPtr(hwnd, 0, (LONG_PTR)pThis);
for bind instance of class to the specified window. always index 0 used instead GWLP_USERDATA
many can say - so what ? even if now this is true, what about future windows versions ?
but if think, what sense migrate from index 0 (really private implementer index in all senses) to GWLP_USERDATA ?
change existing SetWindowLongPtr(hwnd, 0, (LONG_PTR)pThis); to SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis); what prize ? or additional begin use GWLP_USERDATA with index 0 too ? this already absolute senseless - one pointer is enough for bind window to data structure, all additional pointers must be (and in case windows code will be) in this structure already. so i personally can assume that this is not changed
also can note an error in the documentation for SetWindowLongPtr and GetWindowLongPtr here:
The zero-based offset to the value to be set. Valid values are in the
range zero through the number of bytes of extra window memory, minus
the size of an integer
really minus the size of an pointer which 8 bytes on x64, when size of an integer always 4.
2. look at a reputable blog - The bonus window bytes at GWLP_USERDATA:
Note that this value, ..., belongs to the window class and not to the
code that creates the window... only the window class implementer may
read or write the values.
but exist also next two author remarks:
Interesting. I’m checking into that. But even if it does belong to the
creator of the window, enough window class implementations use it that
you still should stay away for safety’s sake.
and
I asked around and guidance is "unclear", though leaning slightly
towards "it belongs to the person who called CreateWindow". For
safety’s sake, then, you should just avoid it unless you can establish
clear ownership
again look for Managing Application State MSDN example - window class implementer used GWLP_USERDATA !
look for ATL atlhost.h - AtlAxWindowProc used GWLP_USERDATA
//case WM_CREATE:
::SetWindowLongPtr(hWnd, GWLP_USERDATA, (DWORD_PTR)pAxWindow);
again class implementer used GWLP_USERDATA
but under this agreement we can not use GWLP_USERDATA with CreateDialogParam, DialogBoxParam because here we not implementer (The DialogProc function is an application-defined callback function called from DefDlgProc - real class implementation code for dialogs - so only DefDlgProc can potential use GWLP_USERDATA cell)
so application that created the window or window class implementer is owner ?
if think - the variant application that created the window is more logical. window class implementer have two choice: can set cbWndExtra to sizeof(PVOID) and use index 0 or use GWLP_USERDATA index. when application that created the window - have no choice - only GWLP_USERDATA index or use another (less effective and more complex) way like SetProp, SetWindowSubclass, etc. so be logical if window class implementer use index 0 for bind self data to window and leave free GWLP_USERDATA for code that created the window. again how about CreateDialogParam, DialogBoxParam - most native way here for use data structure binds to dialog use GWLP_USERDATA index, but here we window creator, not dialog class implementer ! so can use GWLP_USERDATA or not ?
in all case need take to account that enough existing custom window class implementations use GWLP_USERDATA
my assumptions:
if we call CreateWindowEx for non windows core built-in
class - we must not use GWLP_USERDATA here
if we call CreateDialogParam, DialogBoxParam - i assume
that we can here use GWLP_USERDATA
if we call CreateWindowEx for windows built-in class (WC_*
named) we also can use GWLP_USERDATA
if we window class implementer - the best choice - set cbWndExtra
to sizeof(PVOID) and use index 0

create vbscript vbdataobject

I am using a program which makes it possible to customize dialogues via vbscript. Now, the form has an attribute which seems to be a vbDataObject (VarType returns 13).
How can I read the content and create a new vbDataObject to assign it to the attribute?
Don't know if this is exactly the answer, but it seems that vbDataObject's are indeed COM objects, but they just do not expose an IDispatch interface (so they're not true automation objects). As such, VBScript just isn't capable of accessing their content, since it needs an IDispatch interface for it. It just has an IUnknown interface which it doesn't know what to do with.
Passing them around should be possible, though, so if another true automation COM object can manipulate them for you (maybe there is such an object in the app designed to do this?), you could use that to make an object with the correct settings and pass that to the form.
Another option is to contact the authors of the app and ask them if they're willing to give this one object an IDispatch interface as well. Since they presumably went the length to put IDispatch interfaces on most of their objects, this omission might just be an oversight on their part.

Using Printer.Print in VB6

I come from a Java and .NET background.
In VB6 it appears that you do not always have to create an instance of a class when using it. For example, when using the Printer class you can simply say Printer.print instead of having to create an instance first i.e. Dim printer As New Printer and then running printer.Print. I know that Printer is a system object in VB6, but why don't you have to create an instance?
Visual Basic traditionally had a large number of pre-defined identifiers that are directly recognized by the compiler. The Printer object is one of those. Under the hood, this is implemented with the [appobject] attribute but that's carefully hidden in the language. The runtime creates an instance of the COM coclass automatically, much like the As New syntax. The DAO DBEngine object would be an example of one that isn't predefined in the language parser.
This is over and done with in VB.NET, a truly object oriented language with a large class library, much like Java. There is no Printer object anymore, you're supposed to use the PrintDocument class. The Printer object is still supported for legacy code, available in the Microsoft.VisualBasic.PowerPacks.Printing.Compatibility.VB6 namespace. It however requires the New keyword to create an instance of it.
Be careful investing a lot of time and energy in VB6, it is in all respects a badly outdated language.
VB6 isn't an object oriented language in the same way as you would expect if you are used to newer languages. VB6 will do implicit instantiation and you can treat certain things as if it were static. For example, you can declare a variable of a form, but you don't have to. You can directly call a form and manipulate it without declaring it. In the case of the printer, it can't be explicitly declared and instantiated, but VB6 already has one available.

Resources