如何在DETACHED_PROCESS中执行.bat文件



我有一个简单的C++控制台应用程序,它启动notepad.exe并加载文件D:\MyTextFile.txt,然后控制台应用程序退出,但notepad仍在运行。代码运行良好:

int _tmain(int argc, _TCHAR* argv[])
{
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
ZeroMemory( &pi, sizeof(pi) );
WCHAR pCmd[] = {'n','o','t','e','p','a','d','.','e','x','e',' ','D',':','\','M','y','T','e','x','t','F','i','l','e','.','t','x','t',0};
BOOL result = CreateProcess
(   
_T("C:\Windows\System32\notepad.exe"), // Module name
pCmd,                                     // Command line (as modifiable array)
NULL,                                     // Process handle not inheritable
NULL,                                     // Thread handle not inheritable
FALSE,                                    // Set bInheritHandles to FALSE
DETACHED_PROCESS,                         // Detach process
NULL,                                     // Use parent's environment block
NULL,                                     // Use parent's starting directory
&si,                                      // Pointer to STARTUPINFO structure
&pi                                       // Pointer to PROCESS_INFORMATION structure (returned)
);
return (result) ? 0 : -1;
}

但是,如果我用cmd替换记事本,用MyBatFile.bat替换MyTextFile.txt,那么它就不起作用了。MyBatFile.bat:的内容

C:WindowsSystem32notepad.exe   D:MyTextFile.txt

修改控制台应用程序:

int _tmain(int argc, _TCHAR* argv[])
{
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
ZeroMemory( &pi, sizeof(pi) );
WCHAR pCmd[] = {'c','m','d','.','e','x','e',' ','/','C',' ','D',':','\','M','y','B','a','t','F','i','l','e','.','b','a','t',0};
BOOL result = CreateProcess
(   
_T("C:\Windows\System32\cmd.exe"), // Module name
pCmd,                                 // Command line (as modifiable array)
NULL,                                 // Process handle not inheritable
NULL,                                 // Thread handle not inheritable
FALSE,                                // Set bInheritHandles to FALSE
DETACHED_PROCESS,                     // Detach process
NULL,                                 // Use parent's environment block
NULL,                                 // Use parent's starting directory
&si,                                  // Pointer to STARTUPINFO structure
&pi                                   // Pointer to PROCESS_INFORMATION structure (returned)
);
return (result) ? 0 : -1;
}

当我执行上面的代码时,我看到一个命令提示符闪烁得很快,但它似乎没有执行MyBatFile.bat。然而,如果我用CREATE_UNICODE_ENVIRONMENT替换DETACHED_PROCESS,那么MyBatFile.pat就会被执行,但由于进程不再分离,命令提示符会挂起,直到我关闭记事本,这是不希望的。有人知道我如何修改我的代码,以便能够在分离的进程中执行MyBatFile.bat吗?

我无法解释原因,但如果我选择CREATE_NO_WINDOW而不是DETACHED_PROCESS,它似乎适用于.bat文件(通过cmd.exe(。以下代码似乎适用于.exe文件和.bat文件:

// RunDetached.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
int getIndexOfStringIgnoreCare(WCHAR* bigStingToSearchThrough, WCHAR* subStingToFind);
int getFirstIndexOfChar(WCHAR* stringToInvestigate, int startIndex, WCHAR charToLookFor);
int getLastIndexOfChar(WCHAR* stringToInvestigate, int startIndex, WCHAR charToLookFor);
int _tmain(int argc, _TCHAR* argv[])
{
WCHAR* pOriginalCmd = ::GetCommandLine();
// Test code (modify paths to RunDetached.exe and MyFile.txt appropriately)
//    pOriginalCmd = _T(""D:\My Visual Studio Projects\RunDetached\debug\RunDetached.exe" "C:\Windows\System32\notepad.exe" "D:\1.txt"");
int CmdLen = (int)wcslen(pOriginalCmd);
// Determine where certain characters are located (excl means the particular index is not included, e.g. 
// if indexExcl is 5 then index 4 is the last included index).
int beginningOf1stArg   = getFirstIndexOfChar(pOriginalCmd, 0,                     L'"');
int endOf1stArgExcl     = getFirstIndexOfChar(pOriginalCmd, beginningOf1stArg + 1, L'"') + 1;
int beginningOf2ndArg   = getFirstIndexOfChar(pOriginalCmd, endOf1stArgExcl   + 1, L'"');
int endOf2ndArgExcl     = getFirstIndexOfChar(pOriginalCmd, beginningOf2ndArg + 1, L'"') + 1;
int beginningOf3rdArg   = getFirstIndexOfChar(pOriginalCmd, endOf2ndArgExcl   + 1, L'"');
int endOfLastArgExcl    = getLastIndexOfChar (pOriginalCmd, CmdLen            - 1, L'"') + 1;
int beginningOfFileName = getLastIndexOfChar (pOriginalCmd, endOf2ndArgExcl   - 2, L'\') + 1;
int endOfFileNameExcl   = endOf2ndArgExcl - 1;
if ((beginningOf1stArg < 0) || (endOf1stArgExcl     < 0) || (beginningOf2ndArg < 0) || (endOf2ndArgExcl < 0) ||
(endOfLastArgExcl  < 0) || (beginningOfFileName < 0) || (endOfFileNameExcl < 0))
{
return -1;
}
// Determine the application to execute including full path. E.g. for notepad this should be:
// C:WindowsSystem32notepad.exe (without any double-quotes)
int lengthOfApplicationNameAndPathInChars = (endOf2ndArgExcl -1) - (beginningOf2ndArg + 1);  // Skip double-quotes
WCHAR* lpApplicationNameAndPath = (WCHAR*)malloc(sizeof(WCHAR) * (lengthOfApplicationNameAndPathInChars + 1));
memcpy(lpApplicationNameAndPath, &pOriginalCmd[beginningOf2ndArg + 1], sizeof(WCHAR) * (lengthOfApplicationNameAndPathInChars));
lpApplicationNameAndPath[lengthOfApplicationNameAndPathInChars] = (WCHAR)0;  // Null terminate
// Determine the command argument. Must be in modifyable memory and should start with the
// application name without the path. E.g. for notepad with command argument D:MyFile.txt:
// "notepad.exe" "D:MyFile.txt" (with the double-quotes).
WCHAR* modifiedCmd = NULL;
if (0 < beginningOf3rdArg)
{
int lengthOfApplicationNameInChars = endOfFileNameExcl - beginningOfFileName;  // Application name without path
int lengthOfRestOfCmdInChars = CmdLen - beginningOf3rdArg;
int neededCmdLengthInChars = 1 + lengthOfApplicationNameInChars + 2 + lengthOfRestOfCmdInChars; // Two double-quotes and one space extra
modifiedCmd = (WCHAR*)malloc(sizeof(WCHAR) * (neededCmdLengthInChars + 1));  // Extra char is null-terminator
modifiedCmd[0] = L'"';                                                             // Start with double-quoute
memcpy(&modifiedCmd[1], &pOriginalCmd[beginningOfFileName], sizeof(WCHAR) * (lengthOfApplicationNameInChars));
modifiedCmd[1 + (lengthOfApplicationNameInChars)] = L'"';
modifiedCmd[1 + (lengthOfApplicationNameInChars) + 1] = L' ';
memcpy(&modifiedCmd[1 + (lengthOfApplicationNameInChars) + 2], &pOriginalCmd[beginningOf3rdArg], sizeof(WCHAR) * lengthOfRestOfCmdInChars);
modifiedCmd[neededCmdLengthInChars] = (WCHAR)0;
}
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
ZeroMemory( &pi, sizeof(pi) );
BOOL result = CreateProcess                       // Start the process
(
lpApplicationNameAndPath,                     // Module name and full path
modifiedCmd,                                  // Command line
NULL,                                         // Process handle not inheritable
NULL,                                         // Thread handle not inheritable
FALSE,                                        // Set bInheritHandles to FALSE
(0 <= getIndexOfStringIgnoreCare              // Special case for cmd.exe (don't 
(lpApplicationNameAndPath, L"cmd.exe")) ? // know why but it seems to work)
CREATE_NO_WINDOW : DETACHED_PROCESS,
NULL,                                         // Use parent's environment block
NULL,                                         // Use parent's starting directory
&si,                                          // Pointer to STARTUPINFO structure
&pi                                           // Pointer to PROCESS_INFORMATION structure (returned)
);
free(lpApplicationNameAndPath);
if (modifiedCmd != NULL)
{
free(modifiedCmd);
}
if (result) return 0;
wchar_t msg[2048];
FormatMessage
(
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
msg, sizeof(msg),
NULL
);
fputws(msg, stderr);
_flushall();
return -1;
}
bool compareCharsIgnoreCase(WCHAR char1, WCHAR char2)
{
if (char1 == char2)
{
return true;
}
const int UPPER_LOWER_CASE_OFFSET_IN_ASCII_TABLE = 'a' - 'A';
if ((L'A' <= char1) && (char1 <= L'Z'))
{
return ((char1 + UPPER_LOWER_CASE_OFFSET_IN_ASCII_TABLE) == char2);
}
if ((L'a' <= char1) && (char1 <= L'z'))
{
return ((char1 - UPPER_LOWER_CASE_OFFSET_IN_ASCII_TABLE) == char2);
}
return false;
}
int getIndexOfStringIgnoreCare(WCHAR* bigStringToSearchThrough, WCHAR* subStringToFind)
{
if ((bigStringToSearchThrough == NULL) || (subStringToFind == NULL))
{
return -1;
}
int bigStringLen = (int)wcslen(bigStringToSearchThrough);
int subStringLen = (int)wcslen(subStringToFind);
if ((5000 < bigStringLen) || (5000 < subStringLen))   // Sanity check
{
return -1;
}
for (int i = 0; i < (bigStringLen - subStringLen + 1); i++)
{
for (int j = 0; j < subStringLen; j++)
{
if (!compareCharsIgnoreCase(bigStringToSearchThrough[i + j], subStringToFind[j]))
{
break;
}
else if ((j + 1) == subStringLen)
{
return i;
}
}
}
return -1;
}

int getFirstIndexOfChar(WCHAR* stringToInvestigate, int startIndex, WCHAR charToLookFor)
{
int stringLen = (int)wcslen(stringToInvestigate);
if (5000 < stringLen)   // Sanity check
{
return -1;
}
for (int i = startIndex; i < stringLen; i++)
{
if (stringToInvestigate[i] == charToLookFor)
{
return i;
}
}
return -1;
}
int getLastIndexOfChar(WCHAR* stringToInvestigate, int startIndex, WCHAR charToLookFor)
{
int stringLen = (int)wcslen(stringToInvestigate);
if (5000 < stringLen)   // Sanity check
{
return -1;
}
for (int i = min(stringLen - 1, startIndex); 0 <= i; i--)
{
if (stringToInvestigate[i] == charToLookFor)
{
return i;
}
}
return -1;
}

所以,有了上面的代码,你可以同时进行

"RunDetached.exe" "C:WindowsSystem32notepad.exe"   "D:MyTextFile.txt"

"RunDetached.exe" "C:WindowsSystem32cmd.exe" "/c" "D:MyBatFile.bat"

并且您的呼叫应用程序不会挂起。用双引号将每个参数括起来很重要,因为我在代码中使用这些来查找不同的参数。

最新更新