如何在Visual Studio中使用CreateProcess函数
我已经看到了一些关于堆栈溢出的CreateProcess()函数的示例,但是我无法让这些示例正常工作。我使用的是Visual Studio,但编程时使用的是C语言。这是我的最新尝试。我可以让它编译和执行,但我无法让它启动应用程序:如何在Visual Studio中使用CreateProcess函数,c,visual-studio,winapi,C,Visual Studio,Winapi,我已经看到了一些关于堆栈溢出的CreateProcess()函数的示例,但是我无法让这些示例正常工作。我使用的是Visual Studio,但编程时使用的是C语言。这是我的最新尝试。我可以让它编译和执行,但我无法让它启动应用程序: PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter STARTUPINFO StartupInfo; //This is an [in] parameter Zero
PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter
STARTUPINFO StartupInfo; //This is an [in] parameter
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof StartupInfo ;
hr = CreateProcess((NULL, (LPTSTR) "C:\\Windows\\System32\\notepad.exe"), NULL,
NULL,NULL,FALSE,0,NULL,
NULL,&StartupInfo,&ProcessInfo);
int error_1 = 0;
if(!hr)
{
error_1 = GetLastError();
}
当我读取“error_1”时,它返回一个“2”,它基于系统错误代码指示“系统找不到指定的文件”。但是,我确信路径是正确的,因为我可以使用命令行中的路径启动“记事本”。我看不出我做错了什么。您需要去掉前两个参数值周围的额外括号 但是,更重要的是,您需要去掉
LPTSTR
类型转换。如果您的项目配置为针对Unicode进行编译,CreateProcess()
将映射到CreateProcessW()
,而LPTSTR
将映射到wchar\u t*
,因此您将键入一个狭窄的const char[]
文本到wchar\u t*
指针,并最终将垃圾传递到CreateProcessW()
,这很容易解释您看到的错误。创建TCHAR[]
字符串文字的正确方法是使用宏而不是类型转换(有关详细信息,请参阅MSDN上的):
但是,请注意:
lpCommandLine[输入、输出、可选]要执行的命令行。此字符串的最大长度为32768个字符,包括Unicode终止空字符。如果
lpApplicationName
为空,则lpCommandLine的模块名称部分仅限于MAX\u PATH
个字符
此函数的Unicode版本,CreateProcessW
,可以修改此字符串的内容。因此,此参数不能是指向只读内存(例如常量变量或文字字符串)的指针。如果此参数为常量字符串,则函数可能会导致访问冲突。
您可以执行以下操作以避免出现这种情况:
TCHAR szCmdLine[] = TEXT("C:\\Windows\\System32\\notepad.exe");
hr = CreateProcess(NULL, szCmdLine, NULL,
NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInfo);
或:
否则,直接使用ANSI版本的CreateProcess()
,您可以安全地将字符串文本传递给:
hr = CreateProcessA(NULL, "C:\\Windows\\System32\\notepad.exe", NULL,
NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInfo);
另外,您不需要指定notepad.exe的完整路径,因为Windows知道它的位置。您可以自己使用“notepad.exe”
但是,如果指定完整路径,则必须考虑应用程序的位。如果您的应用程序编译为32位,并且在64位系统上运行,C:\Windows\System32\notepad.exe
将重定向到C:\Windows\SysWOW64\notepad.exe
,这是32位版本的记事本。如果要运行64位版本的记事本,则必须根据WOW64文档使用C:\Windows\Sysnative\Notepad.exe
:
%windir%\System32
目录是为64位应用程序保留的。创建64位版本的DLL时,大多数DLL文件名未更改,所以32位版本的DLL存储在不同的目录中。WOW64通过使用文件系统重定向器隐藏此差异
在大多数情况下,只要32位应用程序试图访问%windir%\System32
,访问就会重定向到%windir%\SysWOW64
。对%windir%\lastgood\system32
的访问被重定向到%windir%\lastgood\SysWOW64
。对%windir%\regedit.exe的访问被重定向到%windir%\SysWOW64\regedit.exe
32位应用程序可以通过将%windir%\Sysnative
替换为%windir%\System32
来访问本机系统目录。WOW64将Sysnative
识别为一个特殊别名,用于指示文件系统不应重定向访问。此机制灵活且易于使用,因此,建议使用此机制绕过文件系统重定向。请注意,64位应用程序不能使用Sysnative别名,因为它是虚拟目录而不是真实目录
Sysnative
仅适用于在WOW64仿真器内运行的32位应用程序。您可以在32位系统上运行的32位应用程序和64位系统上运行的64位应用程序中使用System32
:
TCHAR szCmdLine[MAX_PATH];
#ifndef _WIN64
BOOL bIsWow64Process = FALSE;
if (IsWow64Process(GetCurrentProcess(), &bIsWow64Process) && bIsWow64Process)
lstrcpy(szCmdLine, TEXT("C:\\Windows\\Sysnative\\notepad.exe"));
else
#endif
lstrcpy(szCmdLine, TEXT("C:\\Windows\\System32\\notepad.exe"));
hr = CreateProcess(NULL, szCmdLine, NULL,
NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInfo);
但是,您应该考虑到并非每个人都在C:\Windows
文件夹中安装Windows,因此您应该询问Windows系统文件夹的实际位置:
TCHAR szSysDir[MAX_PATH];
#ifndef _WIN64
BOOL bIsWow64Process = FALSE;
if (IsWow64Process(GetCurrentProcess(), &bIsWow64Process) && bIsWow64Process)
{
TCHAR szWinDir[MAX_PATH];
GetWindowsDirectory(szWinDir, MAX_PATH);
PathCombine(szSysDir, szWinDir, TEXT("Sysnative");
}
else
#endif
GetSystemDirectory(szSysDir, MAX_PATH);
TCHAR szCmdLine[MAX_PATH];
PathCombine(szCmdLine, szSysDir, TEXT("notepad.exe");
hr = CreateProcess(NULL, szCmdLine, NULL,
NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInfo);
尝试交换前两个参数。第二个参数不能是文字字符串,但第一个可以。对CreateProcess()
的第一个参数使用逗号运算符似乎有些奇怪。您有(NULL,(LPTSTR)“C:\\Windows\\System32\\notepad.exe”)
作为第一个参数,它计算NULL
并将其丢弃,然后计算字符串的转换。检查MSDN on-您没有指定命令行(但我不知道这是否重要)。@JonathanLeffler您是对的-我没有意识到附加的括号。我相信这不是故意的。问题之一是你的演员阵容。关于字符串文字的类型,您在向编译器撒谎。您不应该将CreateProcess()
的第二个参数强制转换为LPTSTR
,因为它是字符串文字,CreateProcess()
可能会修改字符串。无法修改字符串文字,因为它存储在只读内存中。而是将路径存储在字符数组中,并将该数组传递给函数。此外,还应将路径用双引号括起来,以允许在路径中使用空格。保留空格字符是为了将路径与命令行参数分开。我要补充的是,路径应该用双引号括起来。虽然它在这种特定情况下工作,但由于路径不包含空格,因此不会工作
TCHAR szCmdLine[MAX_PATH];
#ifndef _WIN64
BOOL bIsWow64Process = FALSE;
if (IsWow64Process(GetCurrentProcess(), &bIsWow64Process) && bIsWow64Process)
lstrcpy(szCmdLine, TEXT("C:\\Windows\\Sysnative\\notepad.exe"));
else
#endif
lstrcpy(szCmdLine, TEXT("C:\\Windows\\System32\\notepad.exe"));
hr = CreateProcess(NULL, szCmdLine, NULL,
NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInfo);
TCHAR szSysDir[MAX_PATH];
#ifndef _WIN64
BOOL bIsWow64Process = FALSE;
if (IsWow64Process(GetCurrentProcess(), &bIsWow64Process) && bIsWow64Process)
{
TCHAR szWinDir[MAX_PATH];
GetWindowsDirectory(szWinDir, MAX_PATH);
PathCombine(szSysDir, szWinDir, TEXT("Sysnative");
}
else
#endif
GetSystemDirectory(szSysDir, MAX_PATH);
TCHAR szCmdLine[MAX_PATH];
PathCombine(szCmdLine, szSysDir, TEXT("notepad.exe");
hr = CreateProcess(NULL, szCmdLine, NULL,
NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInfo);