1

I have been spending 2 hours trying to get my path string read from a .ini file to work with the CreateProcess function, which expects a LPCWSTR. For some reason, no matter how I do it, it just will not work.

I have the following code, which I've taken from another SO answer, and amended for my use, however CreateProcess still doesn't start the process.

Can anybody help?

std::ifstream file(file_path.c_str());
    settings new_settings;
    if(file.is_open() && !file.fail())
    {

    std::string key;
    char sign = '=';
    std::string value;
    std::string line;

    while(!file.eof())
    {
        std::getline(file, key, sign);
        std::getline(file, value);

        //fill in settings struct with `value` variable.  Struct contains only `std::string` types.
    }
}

file.close();



    PROCESS_INFORMATION proc_info;      
    STARTUPINFO start_info;     
    memset(&start_info, 0, sizeof(start_info)); 
    start_info->cb = sizeof(STARTUPINFO);   

   std::string path = "C:\\Mydir\\myexe.exe";

    int len;

int slength = (int)path.length() + 1;
len = MultiByteToWideChar(CP_ACP, 0, path.c_str(), slength, 0, 0); 
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, path.c_str(), slength, buf, len);
std::wstring wpath(buf);
delete[] buf;

LPCWSTR p_path = wpath.c_str();

created = CreateProcess(p_path, lpPort, 0,0, FALSE, CREATE_NEW_CONSOLE,NULL,NULL,&start_info ,&proc_info);

DWORD dwErr = GetLastError();  //Returns 0x7b (Invalid Path Or FileName)
Tony The Lion
  • 61,704
  • 67
  • 242
  • 415
  • Is the resulting Unicode string properly null-terminated? – sharptooth Dec 13 '11 at 12:59
  • Have you debugged this? What is the content of p_path? – Luchian Grigore Dec 13 '11 at 13:00
  • Have you tried `CreateProcess(L"C:\\Mydir\\myexe.exe", ...)`? There are two versions of `CreateProcess`: `CreateProcessA()` and `CreateProcessW()`. Is there a reason you are wanting `CreateProcessW()`? – hmjd Dec 13 '11 at 13:06
  • @LuchianGrigore the content of p_path actually looks like my original path string. – Tony The Lion Dec 13 '11 at 13:16
  • @hmjd Passing in the string literal directly with the `L` macro works, yes – Tony The Lion Dec 13 '11 at 13:17
  • @sharptooth how would I check that? – Tony The Lion Dec 13 '11 at 13:25
  • @TonyTheLion: Use the debugger to view the contents. – Puppy Dec 13 '11 at 13:26
  • @Tony The Lion: The best bet would be to output the string to the console or as a message box. – sharptooth Dec 13 '11 at 13:27
  • You could use `std::wcout` to print it. Just checking because the posted code does not do it, but do you check the boolean returned from `CreateProcess()` or do you just query the last error code to determine success or not? – hmjd Dec 13 '11 at 13:30
  • The string conversion seems OK. The code works on my computer, including the CreateProcess[W]. Are you sure that the snippet you posted shows the problem? (It is not compiling out-of-the-box since create, start_info and proc_info are not declared, so maybe some important stuff is missing?) – Werner Henze Dec 13 '11 at 13:31
  • The code ran fine for me, it may be reading from the ini file that is the problem. Could you post the ini file read and print the contents of the read to satisify yourself that it is correct. If you are using `GetPrivateProfileString()` this can be redirected to the registry and you may not be reading the value you think you are. – hmjd Dec 13 '11 at 13:41
  • @WernerHenze I posted the additional proc creation code – Tony The Lion Dec 13 '11 at 13:45
  • @hmjd I'm just using a `std::ifstream` with `std::getline` to read my ini file – Tony The Lion Dec 13 '11 at 13:46
  • @TonyTheLion, still works fine for me. Do you check return value from `CreateProcess()` or just `GetLastError()` and have you printed the value prior to conversion to `wstring`? – hmjd Dec 13 '11 at 13:55
  • @hmjd I have a boolean that gets the return value of `CreateProcess` and it's `0x000000`. Just doing the print thing. – Tony The Lion Dec 13 '11 at 13:56
  • Ok, so the message box prints the string I put it, correctly – Tony The Lion Dec 13 '11 at 13:57
  • @Tony: If `LPCWSTR p_path = L"C:\\Mydir\\myexe.exe"` works, but `LPCWSTR p_path = wpath.c_str()` doesn't, you will have to find out the difference between `wpath` and `L"C:\\Mydir\\myexe.exe"`. A simple `for` loop would reveal that. – sbi Dec 13 '11 at 14:17
  • What's that file-stuff for? It is not referenced by your CreateProcess related code, so why do you add it to your question? Could you please provide a minimal compiling code snippet that shows the error? – Werner Henze Dec 13 '11 at 14:19
  • Could you post example content of the file being loaded? – hmjd Dec 13 '11 at 14:50
  • @sbi yea I did that, and there was a space at the beginning of my string read from the ini file.. Thanks :) – Tony The Lion Dec 13 '11 at 15:01
  • 1
    @Tony: Put a `istrm >> std::ws` before the `std::getline()` (and don't forget to undo your experiments with `skipws`). – sbi Dec 13 '11 at 16:34

1 Answers1

1
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, path.c_str(), slength, buf, len);
std::wstring wpath(buf);
delete[] buf;

I'm fairly sure this is incorrect. You should resize the wstring and use that buffer instead.

std::wstring wpath;
wpath.resize(len);
MultiByteToWideChar(CP_ACP, 0, path.c_str(), slength, &wpath[0], len);
CreateProcess(wpath.c_str(), ...
Puppy
  • 144,682
  • 38
  • 256
  • 465
  • As far as I'm aware you should never write into the pointer returned by wstring.c_str() http://www.cplusplus.com/reference/string/string/c_str/ It would be much safer to create a std::vector< wchar_t > and use that instead – obmarg Dec 13 '11 at 13:07
  • @obmarg: I don't write into that pointer. Also, cplusplus.com is a shitty reference. – Puppy Dec 13 '11 at 13:09
  • Ah, my bad. I clearly skim-read your post (and yeah, it was just the first usable Google result). I'm still not convinced &wpath[0] is much safer. – obmarg Dec 13 '11 at 13:13
  • @obmarg: Strings and vectors are explicitly contiguous memory, and it's *intended* to operate that way, for exactly this reason- compatibility with C functions. – Puppy Dec 13 '11 at 13:19
  • Fair enough, I was always under the impression this was not guaranteed to be the case for strings. http://stackoverflow.com/questions/1042940/writing-directly-to-stdstring-internal-buffers seems to at least partially back me up (at least pre C++11 anyway). – obmarg Dec 13 '11 at 13:26
  • After a little more investigation - strings themselves aren't guaranteed to be contiguous, but &string[0] is. Learn something new every day I suppose. – obmarg Dec 13 '11 at 13:33
  • @obmarg: Strings were not explicitly guaranteed to be contiguous, but because of the guarantees of certain member functions, there was no other way to implement them, so for all intents and purposes, they are. C++11 just made it explicit. – Puppy Dec 13 '11 at 13:45
  • std::wstring wString( oldString.begin(), oldString.end()); should be better. – AlexTheo Dec 13 '11 at 14:12
  • @obmarg: IIRC, strings were not guaranteed to be contiguous in C++98, but that was changed in C++03. ICBWT. – sbi Dec 13 '11 at 14:13