Аргументы, передаваемые CreateProcess, не анализируются, как я ожидал

Я пытаюсь использовать devcon.exe для проверки состояния различных аппаратных средств. В этом примере я пытаюсь проверить свой статус SATA HBA, но devcon ноет по этому поводу. Вот код:

int main(int argc, char** argv) {
    std::string cmdLine("\"C:\\Users\\afalanga\\Documents\\Visual Studio 2010\\Projects\\PlayGround\\Debug\\devcon.exe\" status PCI\\VEN_8086^&DEV_3A22^&SUBSYS_75201462^&REV_00");

    char* pCmdLine(new char[cmdLine.length() + 10]);
    memset(pCmdLine, 0, cmdLine.length() + 10);

    for(int i(0); i < cmdLine.length(); i++)
        pCmdLine[i] = cmdLine.at(i);

    STARTUPINFO si = { sizeof(STARTUPINFO) };
    PROCESS_INFORMATION pi = {0};

    if(!CreateProcess(NULL, pCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
        std::cout << "Create child process failed.  Error code: "
                  << GetLastError() << std::endl;
        return 1;
    }

    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);

    return 0;
}

Проблема в том, что когда вышеприведенное выполняется, devcon жалуется, что «подходящие устройства не найдены». Однако, если я скопирую/вставлю эту командную строку из отладчика в свою командную строку и нажму клавишу ввода (или, конечно, удалю все кавычки, которые окружает ее отладчик), команда будет выполняться идеально, как и ожидалось.

Что я ошибаюсь в передаче строки? То, что выше, является результатом чтения документов CreateProcess() в MSDN (выяснилось, что первый аргумент не обязательно нужен, и аргументы cmd вообще не должны туда идти). Причина, по которой я выделяю 10 дополнительных байтов памяти для копирования строки, заключается в том, что «все», что может измениться внутри функции CreateProcess(), может сделать это, не топая другую память. По крайней мере, так я думал, когда делал это.


person Andrew Falanga    schedule 13.03.2012    source источник
comment
Не имеет отношения, но у вас происходит утечка памяти, и с какой стати использовать memset вместо простого ()?   -  person ildjarn    schedule 13.03.2012


Ответы (4)


Метасимволы командной строки анализируются командным процессором. В частности, вы используете ^, чтобы CMD.EXE не нарушал команду на амперсанд. Но вы выполняете программу напрямую, минуя CMD.EXE. Таким образом, ^ переходит к devcon.exe, которого они сбивают с толку.

Решение: удалите символы ^.

Ваша проблема на самом деле противоположна вашему названию. Командная строка, которую вы передали CreateProcess, передается прямо в приложение точно так, как вы ее указали.

person Raymond Chen    schedule 13.03.2012
comment
Благодарю вас! Вот и все. Как мне изменить заголовок для лучшей ссылки? - person Andrew Falanga; 14.03.2012

std::string cmdLine("\"C:\\Users\\afalanga\\Documents\\Visual Studio 2010\\Projects\\PlayGround\\Debug\\devcon.exe\" status PCI\\VEN_8086^&DEV_3A22^&SUBSYS_75201462^&REV_00

Предположительно, символы вставки ^ являются остатками команды, введенной в интерпретаторе командной строки, где они служат для отключения специального значения &.

Просто удалите каретки.

Также обратите внимание, что в вашем текущем коде происходит утечка памяти.

Чтобы избежать этого, сделайте, например.

string commandLineArg = cmdLine + '\0';

... CreateProcess( 0, &commandLineArg[0], ... )
person Cheers and hth. - Alf    schedule 13.03.2012
comment
Я чувствую себя довольно глупо. Я пропустил ошибку удаления [] буфера. Это была простая программа, которую я использовал для отладки проблемы, которая заключалась в большом фрагменте кода. Я на самом деле стираю память там. Однако я думаю, что этот подход намного более элегантен. Спасибо за предложение. - person Andrew Falanga; 14.03.2012

Можете ли вы попробовать так:

CreateProcess(NULL, pCmdLine.c_str(), ...);

person perreal    schedule 13.03.2012

Я использовал:

TCHAR var[] = _T(" C:\\filepathe\\foo");

CreateProcess(NULL, var,...);
person ShowLove    schedule 25.05.2016