سؤال

thats a little bit annoying. I try to passing parameters from an NPAPI plugin to an EXE.

First information: The executable is currently a placeholder and prints out only the passed arguments as an message box:

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
    /* Print out the arguments */
    MessageBox(NULL, lpCmdLine, TEXT("World of RPG"), NULL);

    /* Exit with return code 0x00 */
    return 0;
}

When i try to start the Application over Visual Studio (started with the parameter "-console"), the message box will prompted correctly:

enter image description here enter image description here

Yet, i try to execute the executable from my NPAPI Plugin:

/* Javascript call: document.getElementById("myPlugin").startGame("-console"); */
std::string WoRPGAPI::startGame(const std::string& method_args) {
    /* Define JSON result variables */
    FB::VariantMap json;
    Json::StyledWriter writer;

    /* Define process variables*/
    PROCESS_INFORMATION processInformation = { 0 };
    STARTUPINFO startupInfo = { 0 };
    startupInfo.cb = sizeof(startupInfo);

    LPWSTR game_exe = LgetGamePath("World of RPG.exe").c_str(); // example: "C:\\Program Files (x86)\\World of RPG\\World of RPG.exe"
    LPWSTR game_args = method_args.c_str(); // example: "-console"

    /* Create the Process */
    BOOL status = CreateProcess(game_exe, game_args, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation);

    /* Check the process status */
    if (!status) {
        DWORD dLastError = GetLastError();
        LPCTSTR strErrorMessage = NULL;

        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, dLastError, 0, (LPWSTR)&strErrorMessage, 0, NULL);

        json["code"] = dLastError;
        json["message"] = strErrorMessage;
    }

    json["status"] = status;

    /* get JSON back to the browser */
    return writer.write(FB::variantToJsonValue(json));
}

And here is the result:

enter image description here

Ok, try to test with an longer string with startGame("This is a longer string!"). You see, only the first word will be cutten. I've tried over 30 mins to solve that:

enter image description here

Can you tell me, what i'm doing wrong? I've tried a lot of conversion examples to convert std::string to LPWSTR but nothing works. Other methods gave me cryptical output like chinese characters.

هل كانت مفيدة؟

المحلول

  1. MessageBox function takes two arguments correctly typed as LPCTSTR. Assuming unicode that is equal to LPCWSTR or wchar_t const *.
  2. Under unicode, you shouldn't1 work with std::string at all. It is based on char and you will need wchar_t-based string everywhere.
  3. The std::wstring is based on wchar_t, so you want to use that.
  4. Since the arguments are properly const, MessageBox will accept result of std::wstring::c_str() without casting.

Note, that many of the casts in your code are unnecessary. Let's start with:

/* convert/cast LPTSTR to LPCWSTR */
LPCWSTR test = (LPCWSTR) lpCmdLine;

LPCWSTR is wchar_t const * and if you have unicode set (as you seem to), LCTSTR is wchar_t *. And adding const is implicit conversion in C++. So

test = lpCmdLine;

will do the same. Without risking an error by not having unicode selected, in which case LCTSTR expands to char * and the statement would fail with "cannot convert to incompatible pointer type" error. With the cast it compiles, but since the C-style cast does a reinterpret cast, i.e. treats the memory content as the requested type, the result is garbage.

Now what I don't understand is this:

BOOL status = CreateProcess((LPWSTR) LgetGamePath("World of RPG.exe").c_str(), game_args, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation);

The function LgetGamePath gets a narrow string (wide literals have L prefix, which can also be generated with the TEXT() macro), so I would expect it to return a narrow string (you don't seem to show that signature, so I don't know for certain). Now you blindly cast it to wide, which will yield garbage and it shouldn't be able to start the process. On the other hand the conversion of the arguments actually seems correct, as long as the string is ASCII only.

1For portable programs wchar_t is still a mess, because it is 4 bytes on some platforms and 2 bytes on others (including windows that eagerly created wide versions of all interfaces when 2 bytes were enough and were stuck with 2 bytes when Unicode exceeded it). And at least for input and output you usually need a specific encoding, which is often Utf-8 (due to it's backward compatibility with ASCII, but Windows don't support it). So many people, including me, when writing portable programs just prepare conversion functions for calling system interfaces somewhere and work in Utf-8 (like e.g. Gtk) or Utf-16 (stored in uint16_t, not wchar_t, as do Qt or ICU) internally.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top