У меня есть структура в моем коде Ruby, которая выглядит примерно так
Parameter = Struct.new(:name, :id, :default_value, :minimum, :maximum)
позже, я создаю экземпляр этой структуры, используя
freq = Parameter.new('frequency', 15, 1000.0, 20.0, 20000.0)
В какой-то момент, Мне нужен точный дубликат этой структуры,
[...] Если блок среды, на который указывает lpEnvironment, содержит символы Unicode, убедитесь, что dwCreationFlags включает CREATE_UNICODE_ENVIRONMENT. Если этот параметр имеет значение ПУСТО (NULL) и блок среды родительского процесса содержит символы Юникода, необходимо также убедиться, что dwCreationFlags включает CREATE_UNICODE_ENVIRONMENT.
Является ли MSDN неверным и завышает значение флага или это реальное требование?
Я видел код, который никогда не устанавливает флаг и, кажется, работает, но параноидальная часть меня хочет на 100% соответствовать тому, что говорит MSDN. Сказав это, я не уверен, что вы действительно сможете следовать правилам MSDN, не доходя до крайностей.
Необходимость устанавливать (или не устанавливать) CREATE_UNICODE_ENVIRONMENT, когда lpEnvironment имеет значение NULL, кажется мне смешной:
Если Я не Если передать блок среды, CreateProcess должен получить сам блок. В этом случае лучше, чем мне знать тип блока.
Как мне узнать, действительно ли блок содержит символы Юникода?
Ожидаю ли я получить блок и проверить его на наличие символов вне текущего кодовая страница? (Я предполагаю, что это то, что MSDN здесь подразумевает под «символами Unicode».)
Если мне действительно нужно получить блок env, тогда я могу передать его в lpEnvionment вместо NULL, так зачем вообще разрешать NULL?
Необходимость получить и проверить env-block кажется безумным требованием для каждого вызывающего CreateProcess; это определенно то, что должен обрабатывать сам API.
Когда он говорит «родительский процесс», это означает даже мой процесс, который собирается стать новым родительским, или это означает мой процесс ' родитель ? Мое первое чтение MSDN заставило меня подумать, что я должен каким-то образом сказать, был ли вызов CreateProcess, который запустил мой процесс , был передан блоку среды ANSI или Unicode, но это, конечно, не так.
I Я предполагаю, что в ОС на базе NT все процессы имеют блок env Unicode, преобразованный из ANSI, если это необходимо при создании процесса, и что процессы не зависят от того блока данных, который был передан CreateProcess как есть.
(Может быть, все это - пережиток времен Win9x, когда сама ОС не была Unicode? Но даже тогда я не понимаю, как код приложения может принять решение лучше, чем сама ОС, и почему этого и следовало ожидать.)
Помимо кода, который никогда не устанавливает флаг, я видел код, который всегда устанавливает его, если UNICODE был определен во время компиляции. Это не имеет смысла, когда требуется, что находится в блоке env во время выполнения, и когда код может находиться в DLL, загруженной во внешний процесс.
Блок env является широкополосным процессом, поэтому определение UNICODE во время компиляции кажется несущественным .
Если это просто вопрос, вызываю ли я CreateProcessA или CreateProcessW, тогда флаг должен быть неявным, когда блок равен NULL, так что это тоже не имеет смысла.
В моем собственном коде я решил избежать вопроса и всегда получают копию блока среды в Юникоде (через GetEnvironmentStringsW), всегда передают ее CreateProcess и всегда устанавливают CREATE_UNICODE_ENVIRONMENT. Это единственный способ, которым я могу быть на 100% правильным, исходя из того, что говорит MSDN.
Конечно, то, что я делаю, является избыточным. CreateProcess не может быть настолько глупым, не так ли?
С другой стороны, мы говорим о CreateProcess. Это не самый лучший API-интерфейс, и у него есть множество других ошибок (не в моей голове):
Так что, возможно, это не так. неправильно полагать, что он ведет себя разумно или, вероятно, позаботится о работе вызывающего абонента ...
Я не знаю, удалять ли параноидальный мусор из моего собственного кода или добавлять его ко всему остальному коду, который я вижу . Ага. : -)
ДОБАВЛЕНО 18 / ноя / 2010:
Похоже, что флаг не имеет значения, когда env-block равен NULL, по крайней мере, от Windows 2000 до Windows 7. См. Мой тест ниже.
Очевидно, это не делает вывод о том, что флаг всегда будет неактуальным во всех будущих ОС, но я действительно не понимаю, как это могло быть иначе.
Допустим, у нас есть дедушка и бабушка, которые создали Родитель, который собирается создать дочерний элемент:
Если ОС всегда хранит блок env для Родителя как Unicode - преобразовав его из ANSI во время создания Родителя, если дедушка передал блок ANSI - тогда CreateProcess будет по ошибке платить любое внимание к флагу, когда Родитель передает блок NULL. CreateProcess должен ЗНАТЬ, что блок, который наследует ребенок, ВСЕГДА будет Unicode.
В качестве альтернативы ОС может хранить блок env для Parent точно так же, как он был получен от Grandparent. (Это кажется маловероятным, но возможно.) В этом случае 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");
}
Это выводит:
--- 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? И в этом сценарии как приложение может знать правильное значение флага лучше, чем сама ОС?