Почему String :: sub! () изменить оригинал клонированного объекта в Ruby?

У меня есть структура в моем коде 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, кажется мне смешной:

  1. Если Я не Если передать блок среды, CreateProcess должен получить сам блок. В этом случае лучше, чем мне знать тип блока.

  2. Как мне узнать, действительно ли блок содержит символы Юникода?

    Ожидаю ли я получить блок и проверить его на наличие символов вне текущего кодовая страница? (Я предполагаю, что это то, что MSDN здесь подразумевает под «символами Unicode».)

    Если мне действительно нужно получить блок env, тогда я могу передать его в lpEnvionment вместо NULL, так зачем вообще разрешать NULL?

    Необходимость получить и проверить env-block кажется безумным требованием для каждого вызывающего CreateProcess; это определенно то, что должен обрабатывать сам API.

  3. Когда он говорит «родительский процесс», это означает даже мой процесс, который собирается стать новым родительским, или это означает мой процесс ' родитель ? Мое первое чтение MSDN заставило меня подумать, что я должен каким-то образом сказать, был ли вызов CreateProcess, который запустил мой процесс , был передан блоку среды ANSI или Unicode, но это, конечно, не так.

    I Я предполагаю, что в ОС на базе NT все процессы имеют блок env Unicode, преобразованный из ANSI, если это необходимо при создании процесса, и что процессы не зависят от того блока данных, который был передан CreateProcess как есть.

    (Может быть, все это - пережиток времен Win9x, когда сама ОС не была Unicode? Но даже тогда я не понимаю, как код приложения может принять решение лучше, чем сама ОС, и почему этого и следовало ожидать.)

  4. Помимо кода, который никогда не устанавливает флаг, я видел код, который всегда устанавливает его, если UNICODE был определен во время компиляции. Это не имеет смысла, когда требуется, что находится в блоке env во время выполнения, и когда код может находиться в DLL, загруженной во внешний процесс.

    Блок env является широкополосным процессом, поэтому определение UNICODE во время компиляции кажется несущественным .

  5. Если это просто вопрос, вызываю ли я CreateProcessA или CreateProcessW, тогда флаг должен быть неявным, когда блок равен NULL, так что это тоже не имеет смысла.

В моем собственном коде я решил избежать вопроса и всегда получают копию блока среды в Юникоде (через GetEnvironmentStringsW), всегда передают ее CreateProcess и всегда устанавливают CREATE_UNICODE_ENVIRONMENT. Это единственный способ, которым я могу быть на 100% правильным, исходя из того, что говорит MSDN.

Конечно, то, что я делаю, является избыточным. CreateProcess не может быть настолько глупым, не так ли?

С другой стороны, мы говорим о CreateProcess. Это не самый лучший API-интерфейс, и у него есть множество других ошибок (не в моей голове):

  1. Ошибка, если строка аргумента константа, потому что она изменяет ее на месте.
  2. Создание первого аргумента необязательный и, таким образом, предлагая людям забыть процитировать exe-путь во втором аргументе.
  3. Требовать правильно процитированный exe-путь во втором аргументе, даже если он явно указан в первом.

Так что, возможно, это не так. неправильно полагать, что он ведет себя разумно или, вероятно, позаботится о работе вызывающего абонента ...

Я не знаю, удалять ли параноидальный мусор из моего собственного кода или добавлять его ко всему остальному коду, который я вижу . Ага. : -)

ДОБАВЛЕНО 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? И в этом сценарии как приложение может знать правильное значение флага лучше, чем сама ОС?

15
задан Leo Davidson 18 November 2010 в 09:59
поделиться