该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 …Run Code Online (Sandbox Code Playgroud) 使用Windows GDI将24位颜色转换为索引颜色,即使在提供的调色板中存在完全匹配,GDI也会选择"足够接近"的颜色.
任何人都可以确认这是一个GDI问题,还是我在某处犯了错误?
也许有一个"请检查整个调色板的颜色匹配"标志,我找不到?
注意:这与量化无关.源是24位但包含256或更少的颜色,因此精确的调色板很容易计算.问题是GDI没有使用完整的调色板.
我通过自己绘制颜色来解决这个问题,但是我更喜欢使用GDI,因为它应该更好地进行优化.问题是,它似乎"快而错".
我的源图像是24位,但使用256(或更少)颜色.我为它生成一个精确的调色板,并要求GDI使用该调色板将图像传输到索引位图.对于某些像素,即使在调色板中的其他位置存在确切的颜色,GDI也会选择相似但不精确的颜色.这会破坏平滑的渐变.
出现此问题:
这个问题不是没有与发生:
我测试了这个:
在每次测试中,我都得到相同的结果.(不只是错误的颜色,但总是相同的错误颜色.)
我不认为问题是色彩管理(ICM/ICC配置文件/等),因为大多数API都说他们没有使用它,我已经尝试在GDI DC以及V5上明确地将其关闭位图标题,我认为它不适用于我的vanlilla-Win2k VM.
可在此处找到简单Win32/GDI/VS2008测试项目的代码:
http://www.pretentiousname.com/data/GdiIndexColor.zip
Win32UI.cpp中的Test1函数是实际测试.它有两个RGBQUAD数组,一个是源图像,另一个是精确的调色板.它验证调色板确实是准确的,然后要求GDI使用上面提到的API转换图像,每次测试结果.对于每个测试,它会告诉您颜色前后的第一个不正确的像素,或者告诉您所有像素都是正确的.
感谢您阅读我的问题!对不起,如果这是我做一些非常愚蠢的事情的结果!:-)