您的位置:首页 > 其它

关于CreateProcess 函数的两种版本问题

2011-05-16 14:10 288 查看
以下为收集资料仅供方便查看之用:

vs05里面 项目默认定义了
UNICODE 和 _UNICODE宏

在项目属性 -> C/C++ -> 预处理器 -> 预处理器定义里可以看到有从项目默认继承的UNICODE 和 _UNICODE宏

这导致 CreateProcess 调用的是 CreateProcessW

vc6里面 项目默认没有定义 UNICODE 和 _UNICODE宏

所以 CreateProcess 调用的是 CreateProcessA

而 CreateProcess 的第2个参数 lpCommandLine MSDN有如下说明:

The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter
is a constant string, the function may cause an access violation.

CreateProcessW.会改变这个字符串的内容.因此,这个参数不能是一个指向只读内存的变量或者是字符串字面值.如果这个参数是一个常量字符串,函数有可能会造成存取违规.

LPlong pointer 的意思 (在32位机中 不再区分near pointer 和 long pointer) 就是说 是一个指针

Cconstant 的意思 就是说是一个常量

WWide character的意思 表明是一个宽字符

STRstring 的意思 表示是一个字符串

TTchar 的意思 表示该类型会根据是否定义 _UNICODE UNICODE 被替换为 非W或者W类型

CreateProceesA 第2参数类型是 LPSTR 就是说一个指向 单字节字符串的指针 (现在Windows版本下 原型就是是 char *)

CreateProceesW 第2个参数类型是 LPWSTR 就是说是一个指向宽字节字符串的指针 (原型 wchar_t *)

CreateProcees 第2个参数类型是 LPTSTR 就是说 会根据 U宏 决定是 LPSTR 还是 LPTSTR (原型TCHAR*)

就是说 该函数将第2个参数视为可读写的 该函数不保证该字符串内容不被修改

而CreateProceesW 确实修改了其内容.... (关于如何修改的... 有个实验 呆会说....)

MessageBoxA 跟字符串有关的参数 都是 LPCSTR ( const char*)

MessageBoxW LPCWSTR (const wchar_t*)

MessageBox LPCTSTR (const TCHAR* )

该函数将这2个参数视为不可读写的 并且保证不会修改其内容

所以用 MessageBox(NULL,TEXT("Text"),TEXT("Caption"),0); 就不会有问题

最下面有一段代码将用一个线程 不断监视传给CreateProcess的第2个参数的内容

对CreateProcess的第2个参数 传入的是

TCHAR szCmd[] = TEXT("this is a cmd line");

首先是W版

以下是程序的输出

(每次输出内容都不一定相同 因为主线程和监视线程的调度情况不可预知 这次输出是最能反应实质的输出)

116 104 105 115 0 105 115 32 97
32 99 109 100 32 108 105 110 101

116 104 105 115 32 105 115 0 97
32 99 109 100 32 108 105 110 101

116 104 105 115 32 105 115 32 97
0 99 109 100 32 108 105 110 101

116 104 105 115 32 105 115 32 97 32 99 109 100
0 108 105 110 101

116 104 105 115 32 105 115 32 97 32 99 109 100
32 108 105 110 请按任意键继续. ..

联想到什么了吗?

传入的参数类容是 TEXT("this is a cmd line")

't'=116

'h'=104

'i'=105

's'=115

' '=32 (空格)

...

也就是说 在CreatProcessW执行过程中

监视线程执行了5次 并且检测到 "this is a cmd line" 中的4个空格被分别替换成了 '/0'=0

再联想 cmdline 被认作是一种以空格分隔的(space-delimited ) 不定项目的字符串

所以 CreatProcessW对第2个参数干的事情就是 依次将空格替换成 '/0'(字符串终结符)

this is a cmd line

在5次监视线程插足的时候CreatProcessW将第2参数分别被当作

this

this is

this is a

this is a cmd

this is a cmd line

5个字符串处理

当然 它们都不是合法的应用程序名称

(第1参数为NULL时 将把第2参数的第一个空格前——即是第一个项目 认作应用程序名称)

所以在本例中CreateProcessW 最终会失败

但是也反应出了问题本质~~

虽然函数执行完毕后 会恢复第2参数的内容 但是它曾经是被修改过的! 所以不能传入只读存储区地址!

如果去掉UNICODE _UNICODE宏定义 重新编译 程序输出如下

(同样 只是多次输出中的一次)

116 104 105 115 32 105 115 32 97 32 99 109 100 32 108 105 110 101

116 104 105 115 32 105 115 32 97 32 99 109 100 32 108 105 110 101

116 104 105 115 32 105 115 32 97 32 99 109 100 32 108 105 110 101

116 104 105 115 32 105 115 32 97 32 99 109 100 32 108 105 110 101

116 104 105 115 32 105 115 32 97 32 99 109 100 32 108 105 110 101

116 104 105 115 32 105 115 32 97 32 99 109 100 32 108 105 110 101 101 请按任意键

继续. . .

可以看出 CreateProcessA 没有对第2参数进行修改

以下是代码

#include <windows.h>

#include <process.h>

#include <tchar.h>

#include <stdio.h>

typedef struct tagUserData

{

const TCHAR * pctstr;

int len;

} UserData;

unsigned int __stdcall Monitor(void *pvParam);

int main()

{

STARTUPINFO si;

ZeroMemory(&si,sizeof(si));

si.cb = sizeof(si);

//和楼主代码有点区别

//照理说应该在ZeroMemory之后

//设置 cb 为该结构体的大小

PROCESS_INFORMATION pi;

ZeroMemory(&pi,sizeof(pi));

si.dwFlags = STARTF_USESHOWWINDOW;

si.wShowWindow = TRUE;

TCHAR szCmd[] = TEXT("this is a cmd line");

UserData param;

param.pctstr = szCmd;

param.len = static_cast<int>( _tcslen(szCmd) );

// _tcslen 是 strlen 的"T" 版本

// 建立监视线程

HANDLE hThread =

reinterpret_cast<HANDLE> ( _beginthreadex(NULL,0,Monitor,static_cast<void*>(& param),0,NULL) );

//调高其优先权 利于监视

SetThreadPriority(hThread,THREAD_PRIORITY_HIGHEST);

BOOL bRet = ::CreateProcess (

NULL,

szCmd,

NULL,

NULL,

FALSE,

CREATE_NEW_CONSOLE,

NULL,

NULL,

&si,

&pi);

return 0;

}

unsigned int __stdcall Monitor(void *pvParam)

{

for (;;)

{

UserData *pData = static_cast<UserData*>(pvParam);

for (int i=0;i<pData->len;++i)

_tprintf(TEXT("%d "),pData->pctstr[ i ] );

_tprintf(TEXT("/n"));

}

return 0;

}

转自:http://hi.baidu.com/%C9%D9%C4%EA%B0%FC%C7%E0%CD%DC/blog/item/65098f10d57baf0a203f2e0a.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: