Visual C++ FAQ
Автор: Michael Dunn
Данный материал представляет собой небольшую
подборку часто задаваемых вопросов по Visual C++ и MFC,
ну и естевственно ответов на них. Так же
присутствуют вопросы по ошибкам компилятора и и
общие вопросы программирования в Си.
Содержание:
1. Почему я получаю unresolved external error (LNK2001) в main()
когда пытаюсь сделать release версию ATL проекта?
2. Как сделать новую строчку в многострочном edit ?
3. Как сделать, чтобы диалог не закрывался при
нажатии пользователем Enter или Esc?
4. Я пытаюсь вызвать Windows API, но компилятор выдаёт
undeclared identifier error (C2065). Почему?
6. Я добавляю исходные файлы к проекту, а
компилятор выдаёт ошибку "C1010: unexpected end of file while
looking for precompiled header directive." Почему?
11. Как изменить курсор, когда он находится на моём
окне?
12. Как я могу скрыть или показать окно?
13. Как разрешить или запретить элементы
управления диалога (кнопки, окна редактирования,
и т.д.)?
14. Как заставить окно быть всегда на переднем
плане?
17. Как вывести текст в консольном приложении
различными цветами?
21. Как сделать глобальную переменную, доступной
всем моим файлам .CPP?
22. У меня есть строка, которая является
представлением числа, скажем "10235". Как
преобразовать её в integer?
23: Как из моего приложения запустить другую
программу?
1. Почему я получаю unresolved external error
(LNK2001) в main() когда пытаюсь сделать release
версию ATL проекта?
Release версия ATL проектов содержит оптимизацию, по
средствам чего проект не связан с C runtime library (CRT)
чтобы уменьшить размер Вашего исполняемого
модуля. Если Вы используете функции из CRT
(например, функции манипуляции со строками) или
классы из библиотеки C++, то Вам необходимо
линковать проект с CRT.
В опциях проекта, в закладке C/C++ выберите
категорию Preprocessor. Удалите директиву _ATL_MIN_CRT
из определений препроцессора, тем самым удалив
оптимизацию.
Для получения более детальной информации, в MSDN
задайте поиск по слову "lnk2001 atl".
2. Как сделать новую строчку в
многострочном edit ?
Для создания новой строки используется
"\r\n". Если Вы будете использовать "\r"
или "\n" или даже "\n\r",
то в EDIT-e вместо переноса на следующую строку
будут видны квадратики.
3. Как сделать, чтобы диалог
не закрывался при нажатии пользователем Enter или
Esc?
Для начала разберёмся, почему диалог
закрывается, даже если убрать кнопки OK и Cancel.
CDialog имеет две специальных виртуальных
функции, OnOK() и OnCancel() , которые
вызываются когда пользователь нажимает клавиши
Enter или Esc соответственно. CDialog содержит
функцию EndDialog() , которая собственно и
закрывает диалог. Так как она относится к
функциям специального назначения, то она не
присуствует в диалоговой секции BEGIN_MESSAGE_MAP /END_MESSAGE_MAP ,
и должна быть переопределена по-другому, в
отличие от обычных обработчиков нажатия на
кнопки.
Если у Вас есть кнопки с идентификаторами IDOK и
IDCANCEL, то можно воспользоваться Визардом (ClassWizard)
для добавления обработчиков BN_CLICKED для
этих кнопок, и они будут делать необходимые
действия для OnOK() и OnCancel() . Если у Вас
нет кнопок с этими ID, то можно вручную добавить
эти виртуальные функции. В заголовочном файле
диалогового класса:
class CMyDialog : public CDialog
{
virtual void OnOK();
virtual void OnCancel();
DECLARE_MESSAGE_MAP()
};
А затем в соответствующем .CPP файле:
void CMyDialog::OnOK()
{
}
void CMyDialog::OnCancel()
{
}
Теперь обработчики не будут вызывать EndDialog()
и, соответственно диалог не будет закрываться.
4. Я пытаюсь вызвать Windows API, но компилятор
выдаёт undeclared identifier error (C2065). Почему?
Заголовочные файлы Windows могут использоваться
создания приложения для различных версий Windows
начиная с Windows 95 и NT 3.51. Так получилось, что не все
функции API присутствуют во всех версиях Windows. Так
вот, чтобы компилятор не ругался а,
соответственно и не ипытался использовать
несуществующие в данной версии Windows функции API,
необходимо использовать следующую систему
деректив препроцессора.
Директивы позволяют выборочно включать
прототипы API:
WINVER : версия Windows (в добавление к 9x/Me и NT)
_WIN32_WINDOWS : для Windows 9x/Me
_WIN32_WINNT : для Windows NT
_WIN32_IE : Общие элементы управления
По умолчанию Вы можете использовать только
функции присутствующие в Windows 95, NT 3.51, и pre-IE3 common
controls. Чтобы использовать API в более поздних
версиях Windows, необходимо #define
вышеописанные директивы перед включением
различных Windows заголовков.
Здесь
полный список значений для данных макросов.
6. Я добавляю исходные файлы к
проекту, а компилятор выдаёт ошибку "C1010: unexpected
end of file while looking for precompiled header directive." Почему?
По умолчанию, поекты Visual C++ используют
прекомпилированные заголовки. Данная система
компилирует большие заголовки только один раз
при создании stdafx.cpp. В любом другом файле .CPP
Вашего проекта необходимо добавить #include "stdafx.h" в самом
начале. Компилятор ищет имя "stdafx.h", чтобы
знать, где вставить прекомпилированную
заголовочную информацию.
Если возникает такая ошибка, то необходимо
отключить прекомпилированные заголовки (precompiled
headers). В опциях проекта, в закладке C/C++
выберите категорию Precompiled headers. Кликните
радио кнопку Not using precompiled headers, а затем нажмите
OK.
11. Как изменить курсор, когда он
находится на моём окне?
Обработайте сообщение WM_SETCURSOR , и
вызовите функцию SetCursor() для изменения
курсора. Обратите внимание, что когда окно
принимает это сообщение, при каждом движении
мышки, поэтому позаботьтесь, чтобы обработчик WM_SETCURSOR
работает довольно быстро.
12. Как я могу скрыть или показать
окно?
Чтобы показать окно:
ShowWindow ( hwndYourWindow, SW_SHOW );
Чтобы скрыть его:
ShowWindow ( hwndYourWindow, SW_HIDE );
Так же существуют и другие флаги, которые
позволяют максимизировать и минимизировать
окна. Смотрите страницу ShowWindow() в MSDN.
13. Как разрешить или запретить
элементы управления диалога (кнопки, окна
редактирования, и т.д.)?
Чтобы разрешить элемент управления:
EnableWindow ( hwndYourControl, TRUE );
Чтобы запретить его:
EnableWindow ( hwndYourControl, FALSE );
14. Как заставить окно быть всегда на переднем
плане?
Выводим окно на передний план:
SetWindowPos ( hwndYourWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );
Возвращаем в обратное состояние:
SetWindowPos ( hwndYourWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );
17. Как вывести текст в консольном
приложении различными цветами?
Каждый символ сонсольного приложения имеет
свои аттрибуты, и Win32 консольные функции могут
работать с аттрибутами двумя способами. SetConsoleTextAttribute()
работает с символами, записанными в буфере, в то
время как FillConsoleOutputAttribute() напрямую
изменяет атрибуты символов.
Следующие функции можно использовать для
нормального, жирного и обратного текста
(предполагается, что класс имеет обработчик
консоли через вызов GetStdHandle() ):
void CMyConsoleClass::SetTextNormal()
{
SetConsoleTextAttribute ( m_hConsole,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE );
}
void CMyConsoleClass::SetTextBold()
{
SetConsoleTextAttribute ( m_hConsole,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE |
FOREGROUND_INTENSITY );
}
void CMyConsoleClass::SetTextReverse()
{
SetConsoleTextAttribute ( m_hConsole,
BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE );
}
Обратите внимание, что нет никаких установок
для мерцания и подчёркивания, так что Вам
прийдётся проявить немного изобратательности,
если Вы хотите полностью съэмулировать
текстовые режимы ANSI или VT100 данным методом.
21. Как сделать глобальную
переменную, доступной всем моим файлам .CPP?
Для начала, в одном из файлов .CPP (и только одном)
объявите переменную, которая будет глобальной
(то есть за пределами всех функций и классов).
Например:
int g_volume;
Затем, в заголовочном файле, который будет
включён во все файлы .CPP - такой как stdafx.h -
добавьте объявление extern :
extern int g_volume;
Ключевое слово extern
указывает компилятору, что g_volume объявлена
в других файлах .CPP как int .
Если Вы пропустите первый шаг, то компилятор
выдаст unresolved external error.
22. У меня есть строка, которая
является представлением числа, скажем "10235".
Как преобразовать её в integer?
Используйте функции atoi() или atol() ,
либо если число с плавающей точкой, то , atof() :
char* szNumber = "10235";
int iNum = atoi ( szNumber );
long lNum = atol ( szNumber );
double dNum = atof ( szNumber );
23: Как из моего приложения запустить другую
программу?
Существует несколько функций, позволяющих
запускать другие программы. Самая простая - WinExec() :
WinExec ( "C:\\path\\to\\program.exe", SW_SHOWNORMAL );
Так же существует функция ShellExecute() ,
которая может запускать как экзешники, так и файлы,
связанные с приложениями. Например, можно
"запустить" текстовый файл, как показано
ниже:
ShellExecute ( hwndYourWindow, "open", "C:\\path\\to\\readme.txt",
NULL, NULL, SW_SHOWNORMAL );
В данном примере, ShellExecute() ищет
приложение, связанное с файлами .TXT и запускает
его. ShellExecute() также позволяет
устанавливать начальную директорию для
приложения, а так же дополнительные параметры
командной строки. За более подробным описанием
функции рекомендую лезть в MSDN.
Если Вам необходимо полностью контролировать
запущенное приложение, то необходимо
использовать CreateProcess() . CreateProcess()
имеет кучу параметров, поэтому детальное
описание функции опять же смотрите в MSDN. А здесь
приведу только простой пример:
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi = {0};
BOOL bSuccess;
bSuccess = CreateProcess ( NULL, "\"C:\\Program Files\\dir\\program.exe\"",
NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS,
NULL, NULL, &si, &pi );
Обратите внимание, что если имя программ
содержит пробелы, то его необходимо заключить в
кавычки, как показано выше.
Если CreateProcess() выполнена успешно, то
удостоверьтесь, что дескрипторы в структуре PROCESS_INFORMATION
закрыты, так как они нам больше не понадобытся.
CloseHandle ( pi.hThread );
CloseHandle ( pi.hProcess );
Конечно же, если всё, что Вам нужно, это просто
запустить программу, то необходимость в CreateProcess()
отпадает, а вот ShellExecute() будет в самый раз.
|