草庐IT

windows - Win32 CreateProcess : When is CREATE_UNICODE_ENVIRONMENT *really* needed?

coder 2023-11-09 原文

CreateProcess文档说明(我大胆强调):

lpEnvironment [in, optional]

[...] If the environment block pointed to by lpEnvironment contains Unicode characters, be sure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT. If this parameter is NULL and the environment block of the parent process contains Unicode characters, you must also ensure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT.



MSDN 是错误的并夸大了标志的含义还是真正的要求?

我见过从未设置标志并且似乎工作的代码,但我偏执的部分希望 100% 遵守 MSDN 所说的。话虽如此,我不确定您是否真的可以遵循 MSDN 的规则而不走极端。

当 lpEnvironment 为 NULL 时必须设置(或不设置)CREATE_UNICODE_ENVIRONMENT 让我觉得很荒谬:
  • 如果我不传递环境块,那么 CreateProcess 必须获取块本身。在那种情况下,它比我更了解块的类型。
  • 我如何知道该块是否实际包含 Unicode 字符?

    我是否希望获取该块并检查它是否包含当前代码页之外的字符? (我认为这就是 MSDN 在这里所说的“Unicode 字符”的意思。)

    如果我必须获得 env-block,那么我不妨在 lpEnvionment 而不是 NULL 中传递它,那么为什么还要允许 NULL 呢?

    对于 CreateProcess 的每个调用者来说,必须获取和检查 env-block 似乎是一个疯狂的要求;这肯定是 API 本身应该处理的事情。
  • 当它说“父进程”时,它甚至意味着我的进程,即将成为新的父进程,还是我的进程的父进程?我对 MSDN 的最初阅读让我觉得我必须以某种方式判断启动我的进程的 CreateProcess 调用是否已通过 ANSI 或 Unicode 环境块,但事实并非如此。

    我假设,在基于 NT 的操作系统上,所有进程都有一个 Unicode env 块,如果需要在进程创建时从 ANSI 转换,并且该进程不会挂起按原样传递给 CreateProcess 的任何数据块。

    (也许这整件事是操作系统本身不是 Unicode 的 Win9x 时代的遗留物?尽管如此,我看不出应用程序代码如何做出比操作系统本身更好的决定,也不知道为什么它应该预计会。)
  • 除了从不设置标志的代码外,我还看到如果在编译时定义了 UNICODE 则总是设置它的代码。当要求是运行时 env 块中的内容以及代码可能位于加载到外部进程的 DLL 中时,这毫无意义。

    env 块是进程范围的,因此在编译时定义的 UNICODE 似乎无关紧要。
  • 如果这只是我调用 CreateProcessA 还是 CreateProcessW 的问题,那么当块为 NULL 时该标志应该是隐式的,所以这也没有意义。

  • 在我自己的代码中,我决定避免这个问题并始终获得环境块的 Unicode 副本(通过 GetEnvironmentStringsW),始终将其传递给 CreateProcess 并始终设置 CREATE_UNICODE_ENVIRONMENT。根据 MSDN 的说法,这是我认为 100% 正确的唯一方法。

    不过,我所做的肯定是多余的。 CreateProcess 不会那么蠢吧?

    另一方面,这就是我们正在谈论的 CreateProcess。它不是设计最好的 API,而且还有很多其他的陷阱(在我的脑海中):
  • 如果参数字符串是 const 则失败,因为它就地修改了它。
  • 使第一个参数可选,从而导致人们忘记在第二个参数中引用 exe 路径。
  • 即使在第一个参数中明确给出,也需要在第二个参数中正确引用 exe 路径。

  • 因此,假设它的行为很聪明或可能会为调用者处理家务,也许是不对的......

    我不知道是从我自己的代码中删除偏执的垃圾还是将其添加到我看到的所有其他代码中。啊。 :-)

    添加于 2010 年 11 月 18 日:

    当 env-block 为 NULL 时,该标志肯定是无关紧要的,至少在 Windows 2000 到 Windows 7 中是这样。请参阅下面的测试。

    显然,这并不能断定该标志在所有 future 的操作系统中总是无关紧要的,但我真的不知道它会如何。

    假设我们有祖 parent 创建了即将创建子项的父项:
  • 如果操作系统总是将 Parent 的 env-block 存储为 Unicode——如果祖 parent 传递一个 ANSI 块,则在 Parent 的创建过程中将其从 ANSI 转换——那么 CreateProcess 将错误地在 Parent 传递一个 NULL 块时注意标志. CreateProcess 必须知道 Child 将继承的块将始终是 Unicode。
  • 或者,操作系统可以完全按照来自祖 parent 的方式存储 Parent 的 env-block。 (这似乎不太可能,但有可能。)在这种情况下,父级无法检测祖父级通过的块类型。同样,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");
    }
    

    这输出:
    --- 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
    

    当 env-block 为 NULL 时,标志在那里无关紧要。

    当它不是 NULL 时,标志确实很重要,因为需要告诉 CreateProcess 背后的 void* 是什么(但这很明显,问题纯粹是关于 NULL 的情况)。

    当 env-block 为 NULL 时,任何人都可以想到标志可能重要的任何场景吗?在这种情况下,应用程序怎么可能比操作系统本身更了解标志的正确值?

    最佳答案

    注意在CreateProcess的声明中函数lpEnvironment参数声明为 LPVOID .

    这是什么意思?这意味着您可以使用 CreateProcess 的 Ansi/Unicode 版本。函数并以任意组合传递 Ansi/Unicode 版本环境块。特别是您可以使用 CreateProcess 的 Unicode 版本。并将其传递给 Ansi 环境块,反之亦然。

    这样设置CREATE_UNICODE_ENVIRONMENT需要 如果您实际上使用 unicode 环境块,因为没有其他常规方式(除了一些丑陋的启发式方法)操作系统可能会意识到它是 unicode。

    现在关于您的问题:

  • 如果您没有明确传递环境块 - 新创建的进程最初将具有与其创建者相同的环境变量。除非您需要对新创建的进程进行一些额外的配置 - 仅此而已。
  • 如果您将环境块传递给新创建的进程 - 您必须手动构建它或从某个地方获取它。无论哪种方式,您 必须知道它是否是unicode。
  • 新进程的父进程是它的创建者。在您的特定情况下 - 您的过程。
  • 这完全取决于环境块的创建方式。如果你总是通过拨打 GetEnvironmentStrings 传递你得到的东西- 如果您正在使用 UNICODE 进行编译,则它是 unicode 格式的定义。那么你应该设置 CREATE_UNICODE_ENVIRONMENT如果你在 unicode 中编译。另一方面,如果您手动构建它 - 即使您不使用 unicode 编译,您也可以使用 unicode 构建它。因此 - 你应该设置 CREATE_UNICODE_ENVIRONMENT根据您构建环境块的方式,而不是根据编译定义。
  • 如前所述,两者都是 CreateProcessACreateProcessW可以与 Ansi 或 Unicode 环境块一起使用。这是正好需要此标志的原因。
  • 关于windows - Win32 CreateProcess : When is CREATE_UNICODE_ENVIRONMENT *really* needed?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4206190/

    有关windows - Win32 CreateProcess : When is CREATE_UNICODE_ENVIRONMENT *really* needed?的更多相关文章

    1. ruby-on-rails - unicode 字符串的长度 - 2

      在我的Rails(2.3,Ruby1.8.7)应用程序中,我需要将字符串截断到一定长度。该字符串是unicode,在控制台中运行测试时,例如'א'.length,我意识到返回了双倍长度。我想要一个与编码无关的长度,以便对unicode字符串或latin1编码字符串进行相同的截断。我已经了解了Ruby的大部分unicode资料,但仍然有些一头雾水。应该如何解决这个问题? 最佳答案 Rails有一个返回多字节字符的mb_chars方法。试试unicode_string.mb_chars.slice(0,50)

    2. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

      我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

    3. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

      这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

    4. Vscode+Cmake配置并运行opencv环境(Windows和Ubuntu大同小异) - 2

      之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m

    5. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

      深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

    6. ruby-on-rails - environment.rb 中设置的常量在开发模式中消失 - 2

      了解Rails缓存如何工作的人可以真正帮助我。这是嵌套在Rails::Initializer.runblock中的代码:config.after_initializedoSomeClass.const_set'SOME_CONST','SOME_VAL'end现在,如果我运行script/server并发出请求,一切都很好。然而,在我的Rails应用程序的第二个请求中,一切都因单元化常量错误而变得糟糕。在生产模式下,我可以成功发出第二个请求,这意味着常量仍然存在。我已通过将以上内容更改为以下内容来解决问题:config.after_initializedorequire'some_cl

    7. ruby-on-rails - rails : check if the model was really saved in after_save - 2

      ActiveRecord用于在每次调用保存方法时调用after_save回调,即使模型没有更改并且没有生成插入/更新查询也是如此。这实际上是默认行为。在大多数情况下这没问题。但是一些after_save回调对模型是否实际保存的事情很敏感。有没有办法确定模型是否实际保存在after_save中?我正在运行以下测试代码:classStage 最佳答案 ActiveRecordusetocallafter_savecallbackeachtimesavemethodiscalledevenifthemodelwasnotchangedan

    8. ruby - 如何在 Ruby 中执行 Windows CLI 命令? - 2

      我在目录“C:\DocumentsandSettings\test.exe”中有一个文件,但是当我用单引号编写命令时`C:\DocumentsandSettings\test.exe(我无法在此框中显示),用于在Ruby中执行命令,我无法这样做,我收到的错误是找不到文件或目录。我尝试用“//”和“\”替换“\”,但似乎没有任何效果。我也使用过系统、IO.popen和exec命令,但所有的努力都是徒劳的。exec命令还使程序退出,这是我不想发生的。提前致谢。 最佳答案 反引号环境就像双引号,所以反斜杠用于转义。此外,Ruby会将空格解

    9. ruby - 在 Ruby 中将转义的 unicode (\u008E) 转换为重音字符 (Ž)? - 2

      我遇到了一个非常困难的时期:#containedwithin:"MA\u008EEIKIAI"#shouldbe"MAŽEIKIAI"#natureofstring$pstring3"MA\u008EEIKIAI"$putsstring3MAEIKIAI$string3.inspect"\"MA\\u008EEIKIAI\""$string3.bytes#关于从哪里开始的任何想法?注意:这不是我的previousquestion的副本. 最佳答案 \u008E表示代码点为8e(十六进制)的unicode字符出现在字符串中的那个位置。

    10. ruby - 如何替换 Ruby 1.9 上的 Unicode gem? - 2

      不幸的是,Unicode0.1(sudogeminstallunicode)不能在Ruby1.9上运行。我有以下片段:require"rubygems"require"unicode"str="áéíóúç"Unicode.normalize_KD(str).gsub(/[^\x00-\x7F]/n,"")#=>aeiouc我用它来将标题转换为永久链接,而不删除重音字符。有没有办法使用pack或unpack方法转换此类文本? 最佳答案 更新:更好的选择可能是使用gemunicode_utils这是专门为这些缺失的功能创建的:requ

    随机推荐