Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass WinMain (or wWinMain) arguments to normal main

Tags:

c++

winapi

If you try to change build type from Console (/SUBSYSTEM:CONSOLE) to Windows (/SUBSYSTEM:WINDOWS), you'll get an error complaining that entry point WinMain is missing:

MSVCRT.lib(crtexew.obj) : error LNK2001: unresolved external symbol _WinMain@16

I think the best way to get around this would be to call your normal int main(int, char**) from WinMain:

#ifdef _WINDOWS_
INT WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PSTR lpCmdLine, INT nCmdShow)
{
    return main(0, NULL);
}
#endif

The problem is that ImageMagick is using the console parameters (and I plan to use them in future too):

Segmentation fault imagemagick init

So passing NULL and 0 is probably not a good idea. How can I convert WinMain arguments to main arugments?

like image 200
Tomáš Zato - Reinstate Monica Avatar asked Feb 11 '23 09:02

Tomáš Zato - Reinstate Monica


2 Answers

One way would be to use CommandLineToArgvW() to parse the result of GetCommandLineW() into an argv-style array of UTF-16 encoded strings, then use WideCharToMultiByte() to convert them to ANSI strings so you can then pass them to main() (assuming you can't use wmain() instead).

For example:

int w_argc = 0;
LPWSTR* w_argv = CommandLineToArgvW(GetCommandLineW(), &w_argc);
if (w_argv)
{
    char** my_argv = new char*[w_argc];
    int my_argc = 0;

    for (int i = 0; i < w_argc; ++i)
    {
        int w_len = lstrlenW(w_argv[i]);
        int len = WideCharToMultiByte(CP_ACP, 0, w_argv[i], w_len, NULL, 0, NULL, NULL);
        my_argv[my_argc] = new char[len+1];
        WideCharToMultiByte(CP_ACP, 0, wargv[i], w_len, my_argv[my_argc], len+1, NULL, NULL);
        ++my_argc;
    }

    main(my_argc, my_argv);

    for (int i = 0; i < my_argc; ++i)
        delete[] my_argv[i];
    delete[] my_argv;

    LocalFree(w_argv);
}

Alternatively:

int w_argc = 0;
LPWSTR* w_argv = CommandLineToArgvW(GetCommandLineW(), &w_argc);
if (w_argv)
{
    std vector<std::string> my_argv_buf;
    my_argv.reserve(w_argc);

    for (int i = 0; i < w_argc; ++i)
    {
        int w_len = lstrlenW(w_argv[i]);
        int len = WideCharToMultiByte(CP_ACP, 0, w_argv[i], w_len, NULL, 0, NULL, NULL);
        std::string s;
        s.resize(len);
        WideCharToMultiByte(CP_ACP, 0, wargv[i], w_len, &s[0], len, NULL, NULL);
        my_argv_buf.push_back(s);
    }

    std vector<char*> my_argv;
    my_argv.reserve(my_argv_buf.size());
    for (std vector<std::string>::iterator i = my_argv_buf.begin(); i != my_argv_buf.end(); ++i)
        my_argv.push_back(i->c_str());

    main(my_argv.size(), &my_argv[0]);

    LocalFree(w_argv);
}
like image 84
Remy Lebeau Avatar answered Feb 15 '23 11:02

Remy Lebeau


You can use CommandLineToArgvW to parse and convert the command line into the format expected by "normal" C main-style functions.

 int argc;
 LPWSTR *argvw = CommandLineToArgvW(GetCommandLineW(), &argc);

 CallCMainFunction(argvw, argc);
 LocalFree(argvw);

Note that this is in wide characters, as windows natively expects utf-16 command line arguments. If InitializeMagick only operates with narrow chars, you'll have to convert those as well (which can be done with wcstombs_s, with the caveats implied there

like image 42
Logan Capaldo Avatar answered Feb 15 '23 13:02

Logan Capaldo