Leo*_*son 15 windows unicode winapi createprocess
该CreateProcess的文档状态(我的粗体强调):
lpEnvironment [in,optional]
[...]如果lpEnvironment指向的环境块包含Unicode字符,请确保dwCreationFlags包含CREATE_UNICODE_ENVIRONMENT.如果此参数为NULL并且父进程的环境块包含Unicode字符,则还必须确保dwCreationFlags包含CREATE_UNICODE_ENVIRONMENT.
MSDN是错误的并且夸大了旗帜的含义还是真正的要求?
我见过的代码从未设置过标志并且似乎有效,但我的偏执部分想要100%遵守MSDN所说的内容.这样说,我不确定你真的可以遵循MSDN的规则而不会走极端.
当lpEnvironment为NULL时,必须设置(或不设置)CREATE_UNICODE_ENVIRONMENT会让我觉得很荒谬:
如果我没有传递环境块,那么CreateProcess必须获取块本身.在那种情况下,它比我更了解块的类型.
我怎么知道块实际上是否包含Unicode字符?
我是否希望获得该块并检查当前代码页之外的字符?(我假设这是MSDN在"Unicode字符"中的含义.)
如果我必须获取env-block,那么我不妨在lpEnvionment中传递它而不是NULL,那么为什么甚至允许NULL呢?
必须获取和检查env-block似乎是CreateProcess的每个调用者的疯狂要求; 它肯定是API本身应该处理的东西.
当它说"父进程"它甚至意味着我的进程,即将成为新的父进程,还是它意味着我的进程的父进程?我最初阅读MSDN让我觉得我必须以某种方式判断启动我的进程的CreateProcess调用是否已经传递了ANSI或Unicode环境块,但情况肯定不是这样.
我假设,在基于NT的操作系统上,所有进程都有一个Unicode env块,如果在创建进程时需要从ANSI转换,并且进程不会挂起到按原样传递给CreateProcess的任何数据块.
(也许这整个事情是Win9x时代的一个遗留问题,那时操作系统本身不是Unicode?虽然如此,我看不出应用程序代码如何能够比操作系统本身更好地做出决策,也不知道为什么应该这样做预计会.)
除了从不设置标志的代码,我已经看到了代码,如果在编译时定义UNICODE,它总是设置它.当需求在运行时env块中的内容以及代码可能在加载到外部进程的DLL中时,这没有任何意义.
env块是进程范围的,因此在编译时定义的UNICODE似乎无关紧要.
如果只是我调用CreateProcessA或CreateProcessW,那么当该块为NULL时,该标志应该是隐式的,所以这也没有意义.
在我自己的代码中,我决定避免这个问题并始终获取环境块的Unicode副本(通过GetEnvironmentStringsW),始终将其传递给CreateProcess并始终设置CREATE_UNICODE_ENVIRONMENT.根据MSDN的说法,这是我能看到100%正确的唯一方法.
当然,我正在做的事情是多余的.CreateProcess不可能是那个傻瓜,可以吗?
另一方面,这是我们正在讨论的CreateProcess.它不是设计最好的API,还有许多其他陷阱(在我的脑海中):
因此,或许假设它表现得聪明或者可能会为来电者处理琐事是不正确的......
我不知道是否从我自己的代码中删除偏执垃圾或将其添加到我看到的所有其他代码中.哎呀.:-)
增加18/Nov/2010:
当env-block为NULL时,看起来这个标志似乎无关紧要,至少在Windows 2000到Windows 7中都是如此.请参阅下面的测试.
显然,这并不能确定该标志在将来的操作系统中总是无关紧要,但我真的看不出它是怎么回事.
假设我们有祖父母创建了即将创建Child的Parent:
如果操作系统始终将父级的env-block存储为Unicode - 如果祖父项传递ANSI块,则在父级创建期间将其转换为ANSI - 那么当父传递NULL块时,CreateProcess会出错以便注意该标志.CreateProcess必须知道Child将继承的块将始终是Unicode.
或者,OS可以完全按照祖父母的方式存储父级的env-block.(这似乎不太可能,但它是可能的.)在这种情况下,Parent无法检测祖父母传递的块类型.同样,CreateProcess必须知道块的类型并忽略该标志.
这是我今天早上写的一个测试,它以不同的方式启动子进程,并使子进程报告为env-var(为简洁起见,只是"OS"变量):
wchar_t *szApp = L"C:\\Windows\\system32\\cmd.exe";
wchar_t *szArgs = L"\"C:\\Windows\\system32\\cmd.exe\" /C set OS";
STARTUPINFOW si = {0};
si.cb = sizeof(si);
PROCESS_INFORMATION pi = {0};
// For brevity, this leaks the env-blocks and thread/process handles and doesn't check for errors.
// Must compile as non-Unicode project, else GetEnvironmentStringsA is hidden by WinBase.h
for(int i = 0; i < 3; ++i)
{
const char *t = (i==0) ? "no env" : (i==1) ? "unicode env" : "ansi env";
void *env = (i==0) ? NULL : (i==1) ? (void*)GetEnvironmentStringsW() : (void*)GetEnvironmentStringsA();
printf("--- %s / unicode flag ---\n", t, i);
::CreateProcessW(szApp, szArgs, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, env, NULL, &si, &pi);
::WaitForSingleObject(pi.hProcess, INFINITE);
printf("\n--- %s / ansi flag ---\n", t, i);
::CreateProcessW(szApp, szArgs, NULL, NULL, FALSE, 0, env, NULL, &si, &pi);
::WaitForSingleObject(pi.hProcess, INFINITE);
printf("\n");
}
Run Code Online (Sandbox Code Playgroud)
这输出:
--- no env / unicode flag ---
OS=Windows_NT
--- no env / ansi flag ---
OS=Windows_NT
--- unicode env / unicode flag ---
OS=Windows_NT
--- unicode env / ansi flag ---
--- ansi env / unicode flag ---
--- ansi env / ansi flag ---
OS=Windows_NT
Run Code Online (Sandbox Code Playgroud)
当env-block为NULL时,标志在那里无关紧要.
当它不是NULL时,标志确实很重要,因为CreateProcess需要被告知void*背后的内容(但这很明显,问题纯粹是关于NULL的情况).
当env-block为NULL时,任何人都可以想到任何标志可能重要的场景吗?在那种情况下,应用程序如何比操作系统本身更好地知道标志的正确值?
请注意,在CreateProcess
函数的声明中,lpEnvironment
参数的声明为LPVOID
。
这是什么意思?这意味着您可以使用Ansi / Unicode版本的CreateProcess
功能,并以任何组合形式将其传递给Ansi / Unicode版本的环境块。特别是,您可以使用的Unicode版本CreateProcess
并将其传递给Ansi环境块,反之亦然。
因此,如果您实际使用unicode环境块,CREATE_UNICODE_ENVIRONMENT
则需要进行设置,因为没有其他常规方法(除了一些丑陋的启发式方法),OS可能会意识到它是unicode。
现在关于您的问题:
如果您未明确传递环境块-新创建的进程最初将具有与其创建者相同的环境变量。除非您需要对新创建的流程进行一些额外的配置-否则就不需要这样做。
如果将环境块传递给新创建的过程-您必须手动构造它或从某个地方获取它。无论哪种方式,您都必须知道它是否为unicode。
新流程的父级是其创建者。在您的特定情况下-您的过程。
这仅取决于环境块的创建方式。如果您总是通过调用传递您所得到的信息,GetEnvironmentStrings
那么当您使用define进行编译时,它就在unicode中UNICODE
。然后,CREATE_UNICODE_ENVIRONMENT
如果要使用unicode进行编译,则应进行设置。另一方面,如果您手动构建它-即使您未使用unicode进行编译,也可以使用unicode进行构建。因此-您应CREATE_UNICODE_ENVIRONMENT
根据构造环境块的方式进行设置,而不是根据编译定义进行设置。
前面已经说过,无论是CreateProcessA
和CreateProcessW
可能与ANSI或Unicode的环境块工作。这正是需要此标志的原因。
归档时间: |
|
查看次数: |
4758 次 |
最近记录: |