Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Создание эффективных приложений для Windows Джеффри Рихтер 2004 (Книга).pdf
Скачиваний:
377
Добавлен:
15.06.2014
Размер:
8.44 Mб
Скачать

Есть еще две важные вещи, касающиеся GetModuleHandle. Во-первых, она прове ряет адресное пространство только того процесса, который ее вызвал. Если этот про цесс не использует никаких функций, связанных со стандартными диалоговыми ок нами, то, вызвав GetModuleHandle и передав ей аргумент "ComDlg32", Вы получите NULL - пусть даже модуль ComDlg32.dll и загружен в адресное пространство какого нибудь другого процесса. Во-вторых, вызов этой функции и передача ей NULL дает в результате базовый адрес ЕХЕ-фяйла в адресном пространстве процесса. Так что, вы зывая функцию в виде GetModuleHandle(NULL — даже из кода в DLL, — Вы получаете базовый адрес EXE-, а не DLL-файла.

Описатель предыдущего экземпляра процесса

Я уже говорил, что стартовый код из библиотеки С/С++ всегда передает в функцию (w)WinMain параметр binstExePrev как NULL. Этот параметр предусмотрен исключи тельно для совместимости с 16-разрядными версиями Windows и не имеет никакого смысла для Windows-приложений. Поэтому я всегда пишу заголовок (w)WinMain так:

int WINAPI WinMain( HINSTANCE hinstExe,

HINSTANCE, PSTR pszCmdLine, int nCmdShow);

Поскольку у второго параметра нет имени, компилятор не выдает предупрежде ние

"parameter not referenced" ("нет ссылки на параметр"),

Командная строка процесса

При создании новому процессу передается командная строка, которая почти никог да не бывает пустой — как минимум, она содержит имя исполняемого файла, исполь зованного при создании этого процесса. Однако, как Вы увидите ниже (при обсужде нии функции CreateProcess), возможны случаи, когда процесс получает командную строку, состоящую из единственного символа — нуля, завершающего строку. В момент запуска приложения стартовый код из библиотеки С/С++ считывает командную строку процесса, пропускает имя исполняемого файла и заносит в параметр pszCmdLine функции (w)WinMain указатель на оставшуюся часть командной строки.

Параметр pszCmdLine всегда указывает на ANSI-строку. Но, заменив WinMain на wWinMain, Вы получите доступ к Unicode-версии командной строки для своего про цесса

Программа может анализировать и интерпретировать командную строку как угод но. Поскольку pszCrndLine относится к типу PSTR, а не PCSTR, не стесняйтесь и запи сывайте строку прямо в буфер, на который указывает этот параметр, но ни при каких условиях не переступайте границу буфера. Лично я всегда рассматриваю этот буфер как "только для чтений". Если в командную строку нужно внести изменения, я снача ла копирую буфер, содержащий командную строку, в локальный буфер (в своей про грамме), который затем и модифицирую.

Указатель на полную командную строку процесса можно.получить и вызовом функции

GetCommandLine.

PTSTR GetCommandLine();

Она возвращает указатель на буфер, содержащий полную командную строку, вклю чая полное имя (вместе с путем) исполняемого файла.

Во многих приложениях безусловно удобнее использовать командную строку, предварительно разбитую на отдельные компоненты, доступ к которым приложение может получить через глобальные переменные _argc и _argv (или _wargu). Функ ция CommandLineToArgvW расщепляет Unicode-строку на отдельные компоненты:

PWSTR CommandLineToArgvW( PWSTR pszCmdLine, int pNumArgs);

Буква W в конце имени этой функции намекает на "широкие" (wide) символы и подсказывает, что функция существует только в Unicode-версии. Параметр pszCmdLine указывает на командную строку Его обычно получают предварительным вызовом GetCommandLineW Параметр pNumArgs — это адрес целочисленной переменной, в которой задается количество аргументов в командной строке. Функция Command LineToArgvW возвращает адрес массива указателей на Unicode-строки

CommandLineToArgvW выделает нужную память автоматически. Большинство при ложений не освобождает эту память, полагаясь на операционную систему, которая проводит очистку ресурсов по завершении процесса И такой подход вполне прием лем. Нo если Вы хотите сами освободить эту память, сделайте так:

int pNumArgs;

PWSTR *ppArgv = CommandLineToArgvW(GetCommandLineW(), &pNumArgs);

//используйте эти аргументы if (*ppArgv[1] == L x ) {

//освободите блок памяти HeapFree(GetProcessHeap() 0 ppArgv);

Переменные окружения

С любым процессом связан блок переменных окружения — область памяти, выделен ная в адресном пространстве процесса Каждый блок содержит группу строк такого вида

VarName1-VarValue1\0 VarName2-VarValue2\0 VarName3=VarValue3\0

...

VarNameX=VarValueX\0

\0

Первая часть каждой строки — имя переменной окружения. Зa ним следует знак равенства и значение, присваиваемое переменной Строки в блоке переменных ок ружения должны бьпь отсортированы в алфавитном порядке по именам переменных

Знак равенства разделяет имя переменной и ее значение, так что его нельзя ис пользовать как символ в имени переменной Важную роль играют и пробелы Например, объявив две переменные

XYZ= Windows (обратите внимание на пробел за знаком равенства)

ABC=Windows

и сравнив значения переменных ХУZ и АВС, Вы увидите, что система их различает, — она учитывает любой пробел, поставленный перед знаком равенства или после него Вот что будет, если записать, скажем, так

XYZ =Home (обратите внимание на пробел перед знаком равенства)

XYZ=Work

Вы получите первую переменную с именем "XYZ", содержащую строку "Home", и вторую переменную "XYZ", содержащую строку "Work"

Конец блока переменных окружения помечается дополнительным нулевым сим волом

WINDOWS 98

Чтобы создать исходный набор переменных окружения для Windows 98, надо модифицировать файл Autoexec bat, поместив в него группу строк SET в виде

SET VarName=VarValue

При перезагрузке система учтет новое содержимое файла Autoexecbat, и тогда любые заданные Вами переменные окружения станут доступны всем процессам, инициируемым в сеансе работы с Windows 98

WINDOWS 2000

При регистрации пользователя на входе в Windows 2000 система создает npo цессоболочку, связывая с ним группу строк — переменных окружения. Систе ма получает начальные значения этих строк, анализируя два раздела в рссст pe. В первом:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\

SessionManager\Environment

содержится список переменных окружения, относящихся к системе, а во втором:

HKEY_CURRENT_USER\Environment

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

Пользователь может добавлять, удалять или изменять любые переменные через апплет System из Control Panel B этом апплете надо открыть вкладку Advanced и щелкнуть кнопку Environment Variables — тогда на экране появит ся следующее диалоговое окно.

Модифицировать переменные из списка System Variables разрешается толь ко пользователю с правами администратора.

Кроме того, для модификации записей в реестре Ваша программа может обращаться к Windows-функциям, позволяющим манипулировать с реестром. Однако, чтобы изменения вступили в силу, пользователь должен выйти из си стемы и вновь войти в нее. Некоторые приложения типа Explorer, Task Manager или Control Pancl могут обновлять свои блоки переменных окружения на базе новых значений в реестре, когда их главные окна получают сообщение WM_SET TINGCHANGE, Например, если Вы, изменив реестр, хотите, чтобы какие-то приложения соответственно обновили свои блоки переменных окружения, вызовите

SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE 0, (LPARAM)

TEXT("Envnuntnent"))

Обычно дочерний процесс наследует набор переменных окружения от родитель ского Однако последний способен управлячь чем, какие переменные окружения на следуются дочерним процессом, а какие — нет. Но об этом я расскажу, когда мы зай

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

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

Увы, многим пользователям не под силу разобраться в переменных окружения, а значит, трудно указать правильные значения. Ведь для этого надо не только хорошо знать синтаксис переменных, но и, конечно, понимать, что стоит за теми или иными их значениями. С другой стороны, почти все (а может, и все) приложения, основан ные на GUI, дают возможность тонкой настройки через диалоговые окна. Такой под ход, естественно, нагляднее и проще.

А теперь, если у Вас еще не пропало жсланис манипулировать переменными ок ружения, поговорим о предназначенных для этой цели функциях. GetEnvironment Variable позволяет выявлять присутствие той или иной переменной окружения и определять ее значение:

DWORD GetEnvironmentVariable( PCTSTR pszName, PTSTR pszValue, DWORD cchValue);

При вызове GetEnvironmentVariable параметр pszName должен указывать на имя интересующей Вас переменной, pszValue — на буфер, в который будет помещено зна чение переменной, а в cchValue следует сообщить размер буфера в символах. Функ ция возвращает либо количество символов, скопированных в буфер, либо 0, если ей не удалось обнаружить переменную окружения с таким именем.

Кстати, в реестре многие строки содержат подставляемые части, например.

%USERPROFILE%\My Documents