In C++ I have defined a class that has this as a member:
static const std::basic_string<TCHAR> MyClass_;
There is also a getter function for this value:
LPCTSTR CClass::GetMyClassName()
{
return MyClass_.c_str();
}
When I create an instance of this class and then try and access it intellisense pops up but the name has been changed depending on whether the project has been compiled for Unicode or Multibyte. If it has been compiled for Unicode the function appears as:
aClass.GetMyClassNameW();
else it is:
aClass.GetMyClassNameA();
What I'd like to know is how is the name getting changed?
Also I would like to know is it possible for intellisense to show the correct name of the function? So that I can access it like this:
aClass.GetMyClassName()
EDIT: The precise member function name I've used in my code is:
WinClass::GetClassName()
Your method name is literally "GetMyClassName" or is it "GetClassName"?
GetClassName is in the SDK (winuser.h) and is redefined based on the UNICODE defines. If you are using "GetClassName" the intellisense is probably getting confused; in fact the compiler is generating the A/W suffix for the actual compiled method as well but that would all work because everyone (Linker/Compiler) agrees on the redefined name (even if its not visible).
Thats the windows way to support in fact 2 versions of the Win32 API:
One for ascii characters of 1 byte with (char)
One for unicode with chars of typically 2 byte width (wchar)
If you look into i.e. winuser.h, you'll see the following:
WINUSERAPI
BOOL
WINAPI
SetWindowTextA(
__in HWND hWnd,
__in_opt LPCSTR lpString);
WINUSERAPI
BOOL
WINAPI
SetWindowTextW(
__in HWND hWnd,
__in_opt LPCWSTR lpString);
#ifdef UNICODE
#define SetWindowText SetWindowTextW
#else
#define SetWindowText SetWindowTextA
#endif // !UNICODE
I cant exactly tell why the same happens to your function GetMyClassName. But it pobably has the same reason.
Related
I use CreateWindowEx which expands to CreateWindowExA. That function uses LPCSTR types. I would like to pass as a second argument MSFTEDIT_CLASS (from Richedit.h):
#define MSFTEDIT_CLASS L"RICHEDIT50W"
The following casting doesn't work:
(LPCSTR)MSFTEDIT_CLASS
CreateWindowEx returns NULL. It works when I pass the second argument this way:
"RICHEDIT50W"
but I don't want to copy a string from the header. How to fix that ?
There is only a single, viable solution here: Call CreateWindowExW, either directly or by defining the UNICODE preprocessor symbol and have the generic-text mapping CreateWindowEx expand to CreateWindowExW.
The window you are creating is a Unicode window, always. The character set used for communicating with a window is set at class registration time. The window class named "RICHEDIT50W" is registered using RegisterClassExW by the system. You don't have control over this.
Since you are eventually going to have to talk to the window using messages, you will need to use the Unicode variants of the message handling functions (GetMessageW, DispatchMessageW, etc.). You cannot use the ANSI versions, unless you are happy with an application, that sometimes doesn't fail.
I use Visual Studio to create programs in C++ for Windows. I wonder what the best method is to write Windows API functions (including macros) as if they were part of a namespace, e.g. WinAPI. I used to define a macro that is empty, so the preprocessor deletes it, and only the :: will stay in the code, which means global scope:
#define WinAPI
BOOL bResult = WinAPI::SetWindowText( hwnd, L"Test Text" );
// After preprocessing:
BOOL bResult = ::SetWindowText( hwnd, L"Test Text" );
However, I ran into problems with macros, like ListBox_AddString; moreover I don't think that my solution was neat.
I would like to see at first glance whether a function call is part of Windows API, or one of my functions with a similar name. Is there a solution which uses namespaces somehow instead of an empty macro?
Update
I tried to implement Richard Hodges' proposal (using Visual Studio 2010):
namespace MyNamespace
{
int APIENTRY wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR szCmdLine, int iShowCmd )
//...
}
First I received LNK1561: entry point must be defined, so I set Project Properties > Linker > Linker > Advanced > Entry Point = MyNamespace::wWinMain
Then I received LNK1221: a subsystem can't be inferred and must be defined, so I set Project Properties > Linker > Linker > System > SubSystem = Windows (/SUBSYSTEM:WINDOWS)
Now it compiles, links and runs, but iShowCmd is 0x7efde000 (a value I cannot interpret) instead of the usual (SW_SHOW = 0x00000001).
What is wrong?
I think you'll find that it's more productive to put all your application's classes and functions in an app namespace, and treat the global namespace as belonging to the 'current system environment'.
The global namespace is always already polluted with c libraries, windows, posix, OSX, etc.
You can't avoid that, since there are no operating systems with only a c++ API.
Does anyone know when we need to use Unicode function rather than ANSI function when we use WinMain or wWinMain? Or can we use the normal generic function? And also with the usage of WinMain or wWinMain, will it affect the type of parameter used in a function?
For example in the two different tutorials of creating empty windoes, one tutorial from MSDN specifies like this:
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
...
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"Learn to Program Windows", // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
While another tutorial specifies like this:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
...
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
Notice in the title of the window, one is using L"Title" while another is using "Title", so I assume that depending of types of WinMain it also affects type of parameters since as far as I know wWinMain is used for Unicode and WinMain is for ANSI.
Also another related question if I am using wWinMain or WinMain and then I use the generic function, such as MessageBox, will it resolve to MessageBoxW or MessageBoxA depending of WinMain type?
Thanks
WinMain() and wWinMain() don't affect whether the program runs as ANSI or Unicode or not; all it determines is how the pCmdLine parameter is encoded. (You should be using GetCommandLine() anyway because pCmdLine doesn't include the program name, and possibly other things but I've forgotten where on MSDN I found the warnings... Combining GetCommandLineW() and CommandLineToArgvW() will let you get an argc/argv pair even in a program that uses WinMain().)
What decides if your APIs are ANSI or Unicode are the _UNICODE and UNICODE macros, but you're probably better off using the W-suffixed functions explicitly (but keep the two defined anyway).
What decides if your windows are Unicode or not is whether you used RegisterClassW()/RegisterClassExW() on the window class or not.
you, like many, full of confusion in terms of a lack of understanding of the fundamental things. first of all we need direct or indirect set the /ENTRY (Entry-Point Symbol) of our exe. if no direct /ENTRY:function option set, linker use defaults - say select wWinMainCRTStartup when UNICODE defined and /SUBSYSTEM:WINDOWS and WinMainCRTStartup when /SUBSYSTEM:WINDOWS but UNICODE not defined. wWinMainCRTStartup internally call wWinMain when WinMainCRTStartup internally call WinMain. so choose entry point is dependent on defined UNICODE or no, but only if /ENTRY:function not direct set. we can for example define UNICODE but set /ENTRY:WinMainCRTStartup and need be implement "ANSI" WinMain. and at all we can not use CRT at all and set as EP any own function
about using A or W version of functions in code - say MessageBox this is only macro which expanded to MessageBoxW or MessageBoxA dependent form are UNICODE is defined in compilation time. however we can not use macro but full functions names. so we can mix in same code MessageBoxA and CreateFileW, CreateProcessA and CreateWindowExW
I have a function that is located in a different cpp file than WinMain is, and when called will create a window. However the windows class for that new window was declared and registered inside of WinMain. Now, when I create the window in the separate function, I am forced to redeclare the 2nd and 3rd variable of the CreateWindowEx function:
_In_opt_ LPCTSTR lpClassName,
_In_opt_ LPCTSTR lpWindowName,
because the location of the function that is actually doing the creating doesn't have access to those variables that were created in WinMain. Now... my doubt is, is my program actually using the window class I registered in WinMain? For all I know, redeclaring these variables, and creating the function far away from the WinMain function could have caused the compiler to adopt some other standard window class. So, is my program actually using the window class I registered in WinMain?
Edited: giving slightly more code
//+++++++++++++++++++++++++++++++++++++cpp file with win main:
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
...//previous code made the main window of the program and so forth
const char g_szClassName2[] = "windowClass2";//name of the window class
WNDCLASSEX winClass2;
HWND invisHWnd;
winClass2.cbSize = sizeof(WNDCLASSEX);
winClass2.style = 0;
winClass2.lpfnWndProc = WndProcedure2;
winClass2.cbClsExtra = 0;
winClass2.cbWndExtra = 0;
winClass2.hInstance = hInstance;
winClass2.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winClass2.hCursor = LoadCursor(NULL, IDC_ARROW);
winClass2.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
winClass2.lpszMenuName = NULL;
winClass2.lpszClassName = g_szClassName2;
winClass2.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&winClass2);
... //other code irrelevant to issue
}
//+++++++++++++++++++++++++++++++++++++other cpp file:
void otherCppFile::creatingWindow()
{
const char g_szClassName2[] = "windowClass2";//name of the window class
const char WndName2[] = "winClass2";//name of the window class
HWND windowHandle = CreateWindowEx(0,
g_szClassName2,
WndName2,
WS_OVERLAPPEDWINDOW,
0,
0,
800,
500,
NULL,
NULL,
NULL,
NULL);
}
Is this last function using the window class registered in WinMain even though it is not located in WinMain and some of the variables are redeclared in the function?
The whole point of registering a window class is so that it is unique and you can use it whenever you need to. When you register a window class using the RegisterClass[Ex] function, you have two options for identifying it:
The window class name (a string) that you passed into the function.
An ATOM (an integer value) that is returned by the function.
In 99.9% of cases, you'll forget about the ATOM and just use the string. You need the string to create the window class, so you might as well just keep up with the string and use it to create windows of that class.
Technically, what you're doing is okay, then. You have multiple variables, but they all contain exactly the same string value, so everything is working properly. But that's a maintenance nightmare, and also violates the DRY (don't repeat yourself) rule. What if you wanted to change the name of your window class? You'd have to find every file that declared it and make sure that you updated it. Then you'd have to wait forever for your entire project to recompile, because you've touched large numbers of files. No good.
Instead, you want to declare this variable at global scope, making it available in every file of your project that creates windows. Put it in a common header file that you're going to include in all of your code files, or make a separate Window.h header or something of that nature and include it where appropriate.
Do make sure that this window class name is declared as a constant. There is no reason it should ever be modified during the execution of your application.
If you're struggling with declaring and/or using global constants in C++, you might check the answers to this question or do a search of your own on Stack Overflow. This part is not unique to Windows programming; it is just basic C++.
Of course, you'll often hear that global variables are bad. That's true enough. The code that you're writing isn't really C++. It is C. The Windows API is a C API, so it naturally leads you into writing C code in C++. If you want to really write C++ code, you'll need to find (or write your own) C++ wrapper around the C-based Windows API. For example, you'd write a class that represents windows, and that class would contain a static class-level constant that holds the name of your window class. The class would be responsible for creating all new windows, so you wouldn't need to scatter that information or those implementation details across multiple code files.
As far as the window name, this is completely different. Windows doesn't use it to identify your window. In fact, it is a completely optional parameter for the CreateWindow[Ex] function. You don't even have to give the window a name. This is actually the name that appears in the window's title bar. It is used by the user to identify the window. As such, it often needs to be localized and should be stored in your project's resources file, not in the source code. Use the LoadString function to load strings from your project's resource file. You can do this dynamically whenever you create a window: just load the string you want to use as the caption for that particular window.
I'm developing a plugin (a dll that is loaded by other app). There's a special function that should return HWND so that app can show a dialog. The problem is that I don't know from where I can get the hInstance (it's not passed as a parameter to the function).
Looks like I'm not understanding something, I'm new to all this stuff, so forgive if the question is silly.
UPD: tried to get hInstance with getModuleHandle:
void* createLoginDialog() {
HINSTANCE hIns = (HINSTANCE) GetModuleHandle(L"comapping");
HWND hWnd = CreateWindow(L"Popup",
L"Enter login",
WS_POPUP,
20,
20,
20,
20,
NULL,
NULL,
hIns,
NULL);
return hWnd;
}
I'm still getting Access Violation.
Several ways to get it:
The first argument passed to your DllMain() entrypoint, cast to HINSTANCE
GetModuleHandle() using your DLL name, cast to HINSTANCE
VirtualQuery(), passing the address of your function. Cast the returned MEMORY_BASIC_INFORMATION.BaseAddress to HINSTANCE. Works on both 32-bit and 64-bit versions of Windows.
According to the documentation of CreateWindow, the hInstance argument is optional. This means that it's valid to pass NULL here. However, as Simon Richter points out in the comments to this answer, the argument may only be NULL the window class is registered globally.
If you're writing a DLL, you may just as well define a DllMain entry point function yourself. This function is called by Windows, passing the handle of your function as the first arugment. You can memorize this handle somewhere to reuse it when creating your window.