Why winmain parameters doesn't match to each other? - visual-studio

Why QApp constructor fails with WinMain parameters?
int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPTSTR _lpCmdLine, int _nShowCmd) {
QApplication app(_nShowCmd, & _lpCmdLine);
And here it fail with exception:
Exception at adress 0x0F3621DC (Qt5Guid.dll) in updater_app.exe: 0xC0000005
Whats wrong? how to fix it?
UPD:
And it works in such way:
int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPTSTR _lpCmdLine, int _nShowCmd) {
int nShowCmd(0);
QApplication app(nShowCmd, & _lpCmdLine);
_lpCmdLine is 10 and _nShowCmd is empty string - so it doesn't match. Why?

The Qt application QApplication main object supposed to be created in the standard main function:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// more app objects initialization
return app.exec();
}
and you do:
int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPTSTR _lpCmdLine, int _nShowCmd)
{
QApplication app(nShowCmd, & _lpCmdLine);
return app.exec();
}
Which implies that &_lpCdLine being equivalent to argv but:
LPTSTR _lpCmdLine which is an equivalent to char* and you take an address of it so &_lpCmdLine matches char** when _lpCmdLine is pointing to a contiguous buffer of characters and not an array of character strings as argv.
It makes sense to consider how main() function is implemented on Windows. There is a good discussion: WINMAIN and main() in C++ (Extended) Mind that the C runtime must be initialized before main() function runs and that may depend on compiler/linker. And also find an example of Qt application main function.
I guess that the case when you make your code not to crash by introducingn nShowCmd == 0 makes QApplication object not to read the command line which prevents an incorrect access via random content interpreted as addresses in _lpCmdLine. But that is still wrong and an incomplete intitialization of QApplication object.
The authors fails to see the window and sees the console instead and that relates to incomplete code of main function not launching any window. Also, QML application main.cpp might help.

Since this problem becomes relevant again with Qt6, here is a very simple solution for VisualStudio with using WinMain as entry point:
QApplication app(__argc, __argv);
__argc and __argv are populated by the microsoft compiler
(found this suggestion here: https://codingmisadventures.wordpress.com/2009/03/10/retrieving-command-line-parameters-from-winmain-in-win32/)
Short explanation of the problem: using main() with VC requires to use Subsystem:Console, but this always opens a console window, which you wanna avoid usually. You cannot get rid of this console, except with some very dirty hacks. So you need to switch to Subsystem:Windows to have a "silent" application launch, but this requires to use WinMain() as application entry point. Up to Qt5 there was an own implementation of WinMain() in qtmain.lib, which you simply linked in, and which forwards to the main()-function, but this has been kicked out in Qt6. The problem exists afaik only for MSVC users, because with mingw you can disable the console window and continue using main(), as shown in the Qt-examples.

Related

How to get args from WinMain or wWinMain in Rust?

I am trying to learn how to work with raw Win32 API's and am following the tutorial here, but cannot, for the life of me, figure out how to pass int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) function signature to work. I do understand the int WINAPI isn't needed...but how do I get all of those parameters to pass to WinAPI calls? Especially hInstance and nCmdShow?
My Goal
Get hInstance and nShowCmd from
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {}
into a Rust program, perhaps something like:
fn main(/* args, such as hInstance, nShowCmd here /*) {
}
or, the more likely way:
fn main() {
std::env::/* hopefully something like args() /*;
}
What I've tried
I've tried getting the args, but this just passes the command-line arguments that I used to spawn the program, just as args[0] being the name of the program, which is the expected behavior. Also, calling args_os() gives the same result.
I've also tried to set the windows subsystem, but the previous behavior is the same, not the desired behavior...
#![windows_subsystem = "windows"]
I am able to get the hInstance handle by manually calling GetModuleHandle() and passing in a null pointer, but have no idea how to get the nShowCmd manually.
Important Note
I am using the windows crate, which is what I would like to use.
Any help to this eluding mystery would be much appreciated!
P.S. My window does open, and everything works fine, as expected, including working with FFI, and all the crazies involved there, lol. But I just would like to understand how this is done. One can get by without the nShowCmd, but I would really like to be able to understand how this is done in rust. I also cannot overwrite the fn main() function signature, so not sure how to go about it.
WinMain is the user-provided entry point of a Windows application. The raw application entry point as seen by the OS is far simpler:
DWORD CALLBACK RawEntryPoint(void);
It is now up to language support libraries to recover the startup information and call into the user-provided entry point (see WinMain is just the conventional name for the Win32 process entry point for details):
GetModuleHandle(NULL) for hInstance
hPrevInstance is always NULL in 32-bit and 64-bit Windows
GetCommandLine for the unparsed command line passed to the program
GetStartupInfo for lots of state information, including the wShowWindow that corresponds to nCmdShow
If you have Visual Studio installed you can have a look inside exe_common.inl to see how the C and C++ support libraries go about this.
With Rust things are unfortunately more complex. Even though the compiler and linker repurpose MSVC's CRT implementation responsible for extracting the information that would be passed into WinMain, I'm not aware of a way to get a hold of this from Rust.
You're going to have to recover that information manually. Getting to the nCmdShow parameter is a bit more involved, so let's illustrate that here:
// build.rs
// Using windows-rs 0.17.2; version 0.10.0 and later should be just fine
fn main() {
windows::build!(Windows::Win32::System::Threading::GetStartupInfoW,)
}
// src/main.rs
mod bindings {
windows::include_bindings!();
}
use bindings::Windows::Win32::System::Threading::{GetStartupInfoW, STARTUPINFOW};
fn main() {
let mut si = STARTUPINFOW {
cb: std::mem::size_of::<STARTUPINFOW>() as u32,
..Default::default()
};
unsafe { GetStartupInfoW(&mut si) };
let cmd_show = si.wShowWindow as i32;
println!("nCmdShow: {:?}", cmd_show);
}
With that you now have access to a value that corresponds to the nCmdShow parameter passed into WinMain when compiling for C or C++ (roughly, anyway). Ideally you would need to see whether dwFlags contains the STARTF_USESHOWWINDOW bit, and fabricate a reasonable default when it doesn't.
That said, I'm not even sure what purpose the nCmdShow argument passed into WinMain serves. As explained under ShowWindow, using that value doesn't have any effect when it is populated from caller-provided information.
Update 2021-10-28
Starting with version 0.22.1 the windows crate comes with pre-built bindings, making it a lot easier to consume the Windows API. The following implements the same program using the pre-built bindings in place of compile-time code generation.
Cargo.toml
[package]
name = "startup_info"
version = "0.0.0"
edition = "2021"
[dependencies.windows]
version = "0.22.1"
features = ["Win32_Foundation", "Win32_System_Threading"]
main.rs
use windows::Win32::System::Threading::{GetStartupInfoW, STARTUPINFOW};
fn main() {
let mut si = STARTUPINFOW {
cb: std::mem::size_of::<STARTUPINFOW>() as u32,
..Default::default()
};
unsafe { GetStartupInfoW(&mut si) };
let cmd_show = si.wShowWindow as i32;
println!("nCmdShow: {:?}", cmd_show);
}
There is this function in Kernel32: GetStartupInfo() that in windows-rs seems to be mapped to bindings::Windows::Win32::System::Threading::GetStartupInfoW.
This function fills a STARTUPINFOW structure that has, between a lot of useful fields, WORD wShowWindow that has the same value as the last argument in WinMain().
The funny thing about WinMain is that there is nothing magic in it, it is just the function that the real entry point function, WinMainCRTStartup calls from the CRT initialization code. You can get an idea of how it does its thing by looking at the equivalent Wine source code. There you can see that your idea of calling GetModuleHandle(NULL) to get the hInstance is the right one.

MFC - Display message

I'm trying to display a simple message within my first MFC application.
Strangely, the first sample doesn't work, instead the second one works correctly.
auto text = std::to_wstring(1).c_str();
MessageBox(text, NULL, 0); // Not ok, the message is empty
auto temp = std::to_wstring(1);
MessageBox(temp.c_str(), NULL, 0); // Ok, display 1
Can you explain why of this behavior?
Yes, in the first example, the wstring created by the call to std::to_wstring only has the scope of the line. After the line executes, it is out of scope and its value is dubious.
In the second example, the wstring is still in scope and valid and so the call to .c_str() works.
No, the other answer is wrong. Look at the implementation of c_str(). c_str() returns basically a LPCWSTR... call it a const WCHAR* or const wchar_t* or whatever. However, the return of c_str() is to an internal pointer of wstring. The problem is that after the line of code executes, the wstring returned from to_wstring() is not valid and so the the pointer returned by c_str() is garbage. For fun, try the following code:
//cstr_.cpp
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv)
{
auto temp = to_wstring(1).c_str();
wprintf(L"%s\n", temp);
auto temp2 = to_wstring(1);
wprintf(L"%s\n", temp2.c_str());
wstring ws = to_wstring(1);
auto temp3 = ws.c_str();
wprintf(L"%s\n", temp3);
}
I compiled the above from a VC++ shell prompt with: cl.exe cstr.cpp
If the other answer is correct, then the last line should have garbage or nothing output because according to the other answer, c_str() is a temp. But, if my answer is correct, then it should output 1 (which it does). If all else fails, look at the implementation source code.

Make a exported function ansi and unicode aware in win32 dll with the use of TCHAR

I'm trying to make a win32 dll that are able to handle ansi and unicode depending what specify in the character set on properties. Unicode or Not Set. ANSI when building in Visual Studio.
The dll has the definition
extern "C" int __stdcall calc(TCHAR *foo)
The definition file is as follow
typedef int (CALLBACK* LPFNDLLCALC)( TCHAR *foo)
Inside the MFC Calling app i load the dll as this
HINSTANCE DllFoo = LoadLibrary(L"foo.dll");
LPFNDLLCALC lpfnDllcalc = (LPFNDLLCALC)GetProcAddress(DllFoo ,"calc");
CString C_SerialNumber;
mvSerialNumber.GetWindowText(C_SerialNumber);
TCHAR* SerialNumber = C_SerialNumber.GetBuffer(0);
LPFNDLLCALC(SerialNumber);
I understand that i make something wrong in the C_SerialNumber.GetBuffer(0) to the TCHAR* pointer. Because in the debugger in the dll only show the first char is passed to the dll. Not the complete string.
How do i get CString to pointer that work in both ansi and unicode.
If change all my code to wchar_t or char in stead of TCHAR i get it to work. Put not with this nativ TCHAR macro.
As I see it you have two options:
Write the code entirely using TCHAR. Then compile the code into two separate DLLs, one narrow and one wide.
Have a single DLL that exports two variants of each function that operates on text. This is how the Windows API is implemented.
If you choose the second option, you don't need to implement each function twice. The primary function is the wide variant. For the narrow variant you convert the input from narrow to wide and then call the wide version. Vice versa for output text. In other words, you use the adapter pattern.
I suppose that you are imagining a third option where you have a single function that can operate on either form of text. Don't go this way. This way abandons type safety and will give you no end of pain. It will also be counter to user's expectations.
As David said, you need to export two separate functions, one for Ansi and one for Unicode, just like the Win32 API does, eg:
#ifdef __cplusplus
extern "C" {
#endif
int WINAPI calcA(LPCSTR foo);
int WINAPI calcW(LPCWSTR foo);
#ifdef __cplusplus
}
#endif
typedef int (WINAPI *LPFNDLLCALC)(LPCTSTR foo);
Then you can do the following:
int WINAPI calcA(LPCSTR foo)
{
return calcW(CStringW(foo));
}
int WINAPI calcW(LPCWSTR foo)
{
//...
}
HINSTANCE DllFoo = LoadLibrary(L"foo.dll");
LPFNDLLCALC lpfnDllcalc = (LPFNDLLCALC) GetProcAddress(DllFoo,
#ifdef UNICODE
"calcW"
#else
"calcA"
#endif
);
CString C_SerialNumber;
mvSerialNumber.GetWindowText(C_SerialNumber);
lpfnDllcalc(C_SerialNumber);

Command-Line arguments not working (char, TCHAR) VS2010

I have following code:
int _tmain(int argc, char** argv) {
bool g_graphics = true;
palPhysics * pp = 0;
#ifndef PAL_STATIC
PF -> LoadPALfromDLL();
#endif
char a[] = "Bullet";
std::string aa;
aa = std::string(argv[1]);
//PF->SelectEngine("Bullet");
DebugBreak();
PF -> SelectEngine(argv[1]);
//PF->SelectEngine(aa);
//debug
// assert(false);
pp = PF -> CreatePhysics();
}
I am trying to read in the command line argument no. 1 in this line:
PF->SelectEngine(argv[1]);
However, I only get the first letter of the argument. I have also tried changing
int _tmain(int argc, char** argv)
to
int _tmain(int argc, TCHAR** argv), but then I get
error:
error C2664: 'palFactory::SelectEngine' : cannot convert parameter 1 from 'TCHAR *' to 'const PAL_STRING &'
PAL_STRING is just a std::string.
This might be a simple one, but I am not sure how to convert TCHAR to std::string, especially since TCHAR is something else depending on compiler /environment settings. Is anyone aware of an easy way to get the command-line arguments to work, such that I don't need to convert anything myself, i..e maybe by changing the tmain function?
Thanks!
C
Update: example of invoking on command line:
Yep. so the way I invoke this on command line is:
progname.exe arg1 arg2,
where arg1 is a physics engine I am trying to load, and arg2 is a dae(physics file with physics info), so I go, specifically:
progname.exe Bullet E:/a.dae
Stepping into the line "PF->SelectEngine(argv[1]);" gives the following code:
bool palFactory::SelectEngine(const PAL_STRING& name) {
#ifdef INTERNAL_DEBUG
printf("palFactory::SelectEngine: this = %p\n", this);
#endif
SetActiveGroup(name); // also calls RebuildRegistry
return isClassRegistered("palPhysics");
}
, in this case, when debugging, I can see that const PAL_STRING& name, i.e. the string, is just "B", instead of what I would expect it to be, which is "Bullet", my command line argument I have passed in the command line.
I've been plauged by this problem for years. The only solution I've been able to find is to NOT USE Visual Studio. I've had to fall back to using other compilers when I must be able to process command-line args. Specifically, I've been using the Digital Mars compiler successfully. It handles the command-line args correctly. I use the VS environment for intellisense and debugging, then compile with DMC to deploy.
---edit below---
Turns out, I just wasn't asking the right question. I finally asked the right question, and got the right answer! See link below.
What is the difference between _tmain() and main() in C++?

WinMain exported from a DLL

I am trying to hide the WinMain function inside a DLL in order to avoid typing again much of the code over and over again.
I exported wWinMain from the DLL by declaring it as
extern "C" int WINAPI wWinMain( ... )
{
// repetitive code here
}
and used the linker option /EXPORT:wWinMain, but when I try to use the import library in another project I get the error
LIBCMTD.lib(wincrt0.obj) : error LNK2019: unresolved external symbol _WinMain#16 referenced in function __tmainCRTStartup
Remark I do want to use the GUI interface and I know this is common error when you define a main instead of a WinMain function. Also, I enabled the UNICODE support in both projects. What should I do?
This is not possible as-is, the linker can only set the entrypoint for an EXE to a function that's inside the EXE. Rename the wWinMain() in the DLL to something else. Write a wWinMain() in a source code file that gets linked into your EXE, simply call the DLL's exported function.
// ...somewhere in a .cpp file within my .dll's sources...
#define WinMain WinMainOld // ...to suppress Win32 declaration of WinMain
#include <windows.h>
#undef WinMain // ...so that WinMain below is not replaced
. . .
#pragma comment(linker, "/export:_WinMain#16") // ...to export it from .dll
extern "C" // ...to suppress C++ name decoration
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR pCmdLine, int nCmdShow)
{
. . .
}
Should you be using WinMain in a DLL? Should it not be DllMain?
If you want to call the WinMain of the dll, you need to replace the CRTWinMainStartup function(_tmainCRTStartup in your liked CRT lib), and make it call your exported WinMain, this stops the linker looking for a local WinMain and still keeps correct flow of the program(the source for the CRT startups should be in the crt source of any compiler)
I find one way to put WinMain inside DLL.
You need to use WinMain instead of wWinMain (I don't know why)
Append a def file into your project and,
append EXPORTS WinMain in def file.
Like this
EXPORTS
WinMain
From the observation, all need exported functions generated, not only WinMain.
After test, the way of __declspec(dllexport) is invalid for WinMain.
Link your program to the DLL library
use #pragma comment(lib, "testDll.lib")
or modify setting in the project.
EXPORT int WINAPI _WinMain_(int (*_main_)(int argc, char **argv), HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR commandLine, int nCmdShow);
int _XMain( int argc, char **argv );
#define XMain WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR commandLine, int nCmdShow)\
{return _WinMain_( _XMain, hInst, hPrevInstance, commandLine, nCmdShow );} \
int _XMain
Then _WinMain_() calls or schedules _XMain().
Over in your application source:
int XMain( int argc, char **argv )
{
}

Resources