https://wiki.shelek.ru/api.php?action=feedcontributions&user=%D0%90%D0%BB%D0%B5%D0%BA%D1%81%D0%B5%D0%B91153%2B%2B&feedformat=atomВесельчак У - Вклад участника [ru]2024-03-29T09:02:56ZВклад участникаMediaWiki 1.25.1https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_4&diff=654FAQ:WinAPI, VCPP Part 42008-11-13T07:30:29Z<p>Алексей1153++: /* Как узнать, когда после запуска приложение уже готово к работе? */ CWinApp::Run().</p>
<hr />
<div>===Как создавать всплывающие подсказки (ToolTip)?===<br />
Этот элемент управления называется "Balloon ToolTip". (В МСДН есть статья под названием "Using ToolTip Controls")<br />
[[Изображение:context_help.GIF]]<br />
<br />
Тематические ссылки:<br />
* http://www.codeproject.com/shell/LiviuBirjegaCode.asp<br />
* http://www.codeproject.com/useritems/wtlntray.asp<br />
<br />
<br />
Для того, чтобы подсказка имела вид "облака" (как в комиксах), нужно установить недокументированный стиль<br />
TTS_BALLOON==0x40<br />
<br />
Вот ещё пара полезных функций API для работы с подсказками<br />
<syntaxhighlight lang="cpp"><br />
CToolTipCtrl::SetDelayTime(TTDT_INITIAL, время_в_миллисекундах);//через какое время появится на экране после наведения курсора<br />
CToolTipCtrl::SetDelayTime(TTDT_AUTOPOP, время_в_миллисекундах);//время горения подсказки на экране<br />
<br />
//время в миллисекундах - тип DWORD<br />
</syntaxhighlight><br />
<br />
===Что делает функция ScrollWindow()===<br />
Функция ScrollWindow() всего лишь двигает рисунок, уже нарисованный на контексте окна, на заданное количество пикселов.<br />
<br />
К примеру, у имеется нарисованное изображение на клиентской части окна, и нужно сделать скролинг этой части.<br />
<br />
Первый путь: Стереть что уже было нарисовано, и перерисовывать все заново с учетом скролинга.<br />
<br />
Второй путь: Передвинуть ту часть, которая останется в зоне видимости, и дорисовать недостаюшую часть. Функция ScrollWindow() как раз и пригодится, чтобы передвинуть рисунок на заданное количество пикселов. Останется потом только дорисовать.<br />
<br />
===Почему список CComboBox не выпадает, хотя клавишами "вверх" и "вниз" значения перебираются?===<br />
Нужно задать высоту выпадающего списка: находясь в редакторе форм, нужно щёлкнуть по стрелке комбобокса и за нижний маркер растянуть вниз, тем самым и задать размер выпадающего списка.<br />
<br />
===Как программно поменять настройки Internet Explorer?===<br />
Можно воспользоваться редактированием реестра:<br />
<br />
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\AdvancedOptions\ (всякие настройки)<br />
<br />
===Как узнать, когда после запуска приложение уже готово к работе?===<br />
<br />
* Можно переопределить функцию CWinApp::Run(). Эта функция вызывается непосредственно перед запуском оконной процедуры<br />
<syntaxhighlight lang="cpp"><br />
int CMyApp::Run() <br />
{<br />
//1) приложение готово к работе, сейчас вызовется Run , в котором реализована обработка очереди сообщений процесса<br />
<br />
//2) запускается очередь<br />
int res=/*return*/ CWinApp::Run();<br />
<br />
//3) было получено сообщение WM_QUIT, вышли из CWinApp::Run()<br />
<br />
//4) возвращаемое приложением значение<br />
return res;<br />
}<br />
</syntaxhighlight><br />
<br />
* Можно так же переопределить функцию CWinApp::OnIdle. Эта функция вызывается всякий раз, когда в очереди сообщений приложения нет больше сообщений. Самый первый вызов функции будет соответствовать моменту, когда приложение стало быть готово к работе.<br />
<br />
===Как получить короткое и длинное имя файла?===<br />
Можно использовать функции API<br />
<syntaxhighlight lang="cpp"><br />
GetShortPathName(<br />
LPCSTR lpszLongPath,<br />
LPSTR lpszShortPath,<br />
DWORD cchBuffer); //получить короткий путь<br />
</syntaxhighlight><br />
и<br />
<syntaxhighlight lang="cpp"><br />
GetLongPathName(<br />
LPCSTR lpszShortPath,<br />
LPSTR lpszLongPath,<br />
DWORD cchBuffer); //получить полный путь<br />
</syntaxhighlight><br />
<br />
<br />
Например имеется путь к файлу:<br />
<br />
D:\program files\Microsoft Office\OFFICE11\winword.exe<br />
<br />
функция GetShortPathName() поможет привести его к виду:<br />
<br />
d:\PROGRA~1\MICROS~2\OFFICE11\WINWORD.EXE<br />
<br />
а функция GetLongPathName() - наоборот.<br />
<br />
Максимальная длина пути файла равна MAX_PATH (==260) символам<br />
<br />
===В чём разница между сообщениями WM_MOVE и WM_MOVING?===<br />
<br />
Сообщение VM_MOVING посылается окну, когда пользователь перемещает окно.<br />
<br />
Сообщение VM_MOVE посылается окну, когда пользователь завершил перемещение окна (отпустил кнопку мыши).<br />
<br />
=== Как из программы определить каталог, в котором находится эта программа?===<br />
Это можно сделать при помощи функции, которая возвращает абсолютное имя модуля.<br />
<syntaxhighlight lang="cpp"><br />
GetModuleFileName()<br />
</syntaxhighlight><br />
<br />
В MFC можно использовать переменную-член класса CWinApp, определённую как<br />
<syntaxhighlight lang="cpp"><br />
LPCTSTR m_pszExeName;<br />
</syntaxhighlight><br />
<br />
Получить доступ можно двумя способами:<br />
<syntaxhighlight lang="cpp"><br />
//1<br />
AfxGetApp()->m_pszExeName;<br />
<br />
//2<br />
//extern CMyApp theApp<br />
theApp.m_pszExeName;<br />
</syntaxhighlight><br />
<br />
===Как получить полное имя пользователя и организации, то есть то, что на диалоге system properties (горячая кнопка [ Win ] + Break ) на закладке General перечислено под пунктом Registred To? ===<br />
Значение можно взять в реестре:<br />
<br />
тут (для Windows NT)<br />
<br />
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion<br />
<br />
или тут (W98, W95)<br />
<br />
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion<br />
<br />
===Как определить первый свободный ID, который можно использовать при динамическом создании элементов управления?===<br />
Можно поступить так: начать перебор значений ID со значения 1000 и, проверяя функцией GetDlgItem(), увеличивать значение на единицу до тех пор, пока не будет найден свободный ID.<br />
<br />
===Как изменить цвет рамки приложения?===<br />
Это можно сделать, если перехватить сообщение WM_NCPAINT, которое отвечает за прорисовку не клиентской части окна.<br />
<br />
===Я запускаю экзешник при помощи ::ShellExecute(). Процедура тут же возвращает управление, а как дождаться, когда запущенный процесс завершится, только потом продолжить выполнение программы?===<br />
Нужно использовать функции<br />
<br />
* CreateProcess()<br />
* WaitForSingeObject()<br />
<br />
<syntaxhighlight lang="cpp"><br />
STARTUPINFO StartupInfo;<br />
PROCESS_INFORMATION ProcessInfo;<br />
DWORD dwRetValue;<br />
RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));<br />
StartupInfo.cb = sizeof(StartupInfo);<br />
<br />
//запуск экзешника<br />
if(!CreateProcess(<br />
szApplicationName,<br />
szCommandLine, //командная строка (можно указать NULL)<br />
NULL, NULL, FALSE,<br />
NORMAL_PRIORITY_CLASS,<br />
NULL,<br />
szCurrentDirectory, //рабочая директория (можно указать NULL)<br />
&StartupInfo,<br />
&ProcessInfo))<br />
{<br />
//ошибка запуска<br />
DWORD dwdErr=GetLastError(); //определяем ошибку<br />
}<br />
else<br />
{<br />
//ждём 30 секунд момента, пока процесс завершится<br />
//(ProcessInfo.hProcess перейдёт в сигнальное состояние)<br />
//если задать INFINITE, будет ждать до бесконечности<br />
DWORD dwd=WaitForSingleObject(ProcessInfo.hProcess, 30000);<br />
<br />
//dwd покажет причину завершения процедуры WaitForSingleObject<br />
//WAIT_OBJECT_0 Состояние объекта переведено в сигнальное <br />
//WAIT_TIMEOUT Кончился таймаут<br />
<br />
//к теме не относится, но для мутекса ещё есть возвращаемое значение:<br />
//WAIT_ABANDONED Объект является мутексом, который был занят потоком, затем поток завершился,<br />
// не разблокировав мутекс. Мутекс находится в несигнальном состоянии<br />
<br />
<br />
//если нужно - смотрим, какое значение вернуло приложение<br />
GetExitCodeProcess(ProcessInfo.hProcess, &dwRetValue);<br />
<br />
//освобождаем хендлы, открытые CreateProcess<br />
CloseHandle(ProcessInfo.hThread);<br />
CloseHandle(ProcessInfo.hProcess);<br />
}<br />
</syntaxhighlight><br />
<br />
В szApplicationName может быть либо полный путь к файлу, либо только имя файла. В последнем случае файл будет искаться в текущем каталоге.<br />
<br />
szCommandLine может быть NULL, если не надо передавать командную строку запускаемому процессу.<br />
<br />
szCurrentDirectory может быть NULL, тогда текущий каталог будет как у родительского процесса.<br />
<br />
===Как сменить иконку у диалога или мейнфрейма? (поставить свою иконку из ресурсов)===<br />
<br />
Пример:<br />
<syntaxhighlight lang="cpp"><br />
HICON m_hIcon;<br />
...<br />
...<br />
HICON m_hIcon = AfxGetApp()->LoadIcon(IDR_1);<br />
SetIcon(m_hIcon, TRUE);<br />
</syntaxhighlight><br />
<br />
где<br />
<br />
* IDR_1 - ИД иконки в ресурсах<br />
* m_hIcon - хендл типа HICON (естественно - не временный, а, скажем, член класса)<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_4&diff=653FAQ:WinAPI, VCPP Part 42008-11-12T16:42:50Z<p>Алексей1153++: </p>
<hr />
<div>===Как создавать всплывающие подсказки (ToolTip)?===<br />
Этот элемент управления называется "Balloon ToolTip". (В МСДН есть статья под названием "Using ToolTip Controls")<br />
[[Изображение:context_help.GIF]]<br />
<br />
Тематические ссылки:<br />
* http://www.codeproject.com/shell/LiviuBirjegaCode.asp<br />
* http://www.codeproject.com/useritems/wtlntray.asp<br />
<br />
<br />
Для того, чтобы подсказка имела вид "облака" (как в комиксах), нужно установить недокументированный стиль<br />
TTS_BALLOON==0x40<br />
<br />
Вот ещё пара полезных функций API для работы с подсказками<br />
<syntaxhighlight lang="cpp"><br />
CToolTipCtrl::SetDelayTime(TTDT_INITIAL, время_в_миллисекундах);//через какое время появится на экране после наведения курсора<br />
CToolTipCtrl::SetDelayTime(TTDT_AUTOPOP, время_в_миллисекундах);//время горения подсказки на экране<br />
<br />
//время в миллисекундах - тип DWORD<br />
</syntaxhighlight><br />
<br />
===Что делает функция ScrollWindow()===<br />
Функция ScrollWindow() всего лишь двигает рисунок, уже нарисованный на контексте окна, на заданное количество пикселов.<br />
<br />
К примеру, у имеется нарисованное изображение на клиентской части окна, и нужно сделать скролинг этой части.<br />
<br />
Первый путь: Стереть что уже было нарисовано, и перерисовывать все заново с учетом скролинга.<br />
<br />
Второй путь: Передвинуть ту часть, которая останется в зоне видимости, и дорисовать недостаюшую часть. Функция ScrollWindow() как раз и пригодится, чтобы передвинуть рисунок на заданное количество пикселов. Останется потом только дорисовать.<br />
<br />
===Почему список CComboBox не выпадает, хотя клавишами "вверх" и "вниз" значения перебираются?===<br />
Нужно задать высоту выпадающего списка: находясь в редакторе форм, нужно щёлкнуть по стрелке комбобокса и за нижний маркер растянуть вниз, тем самым и задать размер выпадающего списка.<br />
<br />
===Как программно поменять настройки Internet Explorer?===<br />
Можно воспользоваться редактированием реестра:<br />
<br />
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\AdvancedOptions\ (всякие настройки)<br />
<br />
===Как узнать, когда после запуска приложение уже готово к работе?===<br />
Можно переопределить функцию CWinApp::OnIdle. Эта функция вызывается всякий раз, когда в очереди сообщений приложения нет больше сообщений. Самый первый вызов функции будет соответствовать моменту, когда приложение стало быть готово к работе.<br />
<br />
===Как получить короткое и длинное имя файла?===<br />
Можно использовать функции API<br />
<syntaxhighlight lang="cpp"><br />
GetShortPathName(<br />
LPCSTR lpszLongPath,<br />
LPSTR lpszShortPath,<br />
DWORD cchBuffer); //получить короткий путь<br />
</syntaxhighlight><br />
и<br />
<syntaxhighlight lang="cpp"><br />
GetLongPathName(<br />
LPCSTR lpszShortPath,<br />
LPSTR lpszLongPath,<br />
DWORD cchBuffer); //получить полный путь<br />
</syntaxhighlight><br />
<br />
<br />
Например имеется путь к файлу:<br />
<br />
D:\program files\Microsoft Office\OFFICE11\winword.exe<br />
<br />
функция GetShortPathName() поможет привести его к виду:<br />
<br />
d:\PROGRA~1\MICROS~2\OFFICE11\WINWORD.EXE<br />
<br />
а функция GetLongPathName() - наоборот.<br />
<br />
Максимальная длина пути файла равна MAX_PATH (==260) символам<br />
<br />
===В чём разница между сообщениями WM_MOVE и WM_MOVING?===<br />
<br />
Сообщение VM_MOVING посылается окну, когда пользователь перемещает окно.<br />
<br />
Сообщение VM_MOVE посылается окну, когда пользователь завершил перемещение окна (отпустил кнопку мыши).<br />
<br />
=== Как из программы определить каталог, в котором находится эта программа?===<br />
Это можно сделать при помощи функции, которая возвращает абсолютное имя модуля.<br />
<syntaxhighlight lang="cpp"><br />
GetModuleFileName()<br />
</syntaxhighlight><br />
<br />
В MFC можно использовать переменную-член класса CWinApp, определённую как<br />
<syntaxhighlight lang="cpp"><br />
LPCTSTR m_pszExeName;<br />
</syntaxhighlight><br />
<br />
Получить доступ можно двумя способами:<br />
<syntaxhighlight lang="cpp"><br />
//1<br />
AfxGetApp()->m_pszExeName;<br />
<br />
//2<br />
//extern CMyApp theApp<br />
theApp.m_pszExeName;<br />
</syntaxhighlight><br />
<br />
===Как получить полное имя пользователя и организации, то есть то, что на диалоге system properties (горячая кнопка [ Win ] + Break ) на закладке General перечислено под пунктом Registred To? ===<br />
Значение можно взять в реестре:<br />
<br />
тут (для Windows NT)<br />
<br />
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion<br />
<br />
или тут (W98, W95)<br />
<br />
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion<br />
<br />
===Как определить первый свободный ID, который можно использовать при динамическом создании элементов управления?===<br />
Можно поступить так: начать перебор значений ID со значения 1000 и, проверяя функцией GetDlgItem(), увеличивать значение на единицу до тех пор, пока не будет найден свободный ID.<br />
<br />
===Как изменить цвет рамки приложения?===<br />
Это можно сделать, если перехватить сообщение WM_NCPAINT, которое отвечает за прорисовку не клиентской части окна.<br />
<br />
===Я запускаю экзешник при помощи ::ShellExecute(). Процедура тут же возвращает управление, а как дождаться, когда запущенный процесс завершится, только потом продолжить выполнение программы?===<br />
Нужно использовать функции<br />
<br />
* CreateProcess()<br />
* WaitForSingeObject()<br />
<br />
<syntaxhighlight lang="cpp"><br />
STARTUPINFO StartupInfo;<br />
PROCESS_INFORMATION ProcessInfo;<br />
DWORD dwRetValue;<br />
RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));<br />
StartupInfo.cb = sizeof(StartupInfo);<br />
<br />
//запуск экзешника<br />
if(!CreateProcess(<br />
szApplicationName,<br />
szCommandLine, //командная строка (можно указать NULL)<br />
NULL, NULL, FALSE,<br />
NORMAL_PRIORITY_CLASS,<br />
NULL,<br />
szCurrentDirectory, //рабочая директория (можно указать NULL)<br />
&StartupInfo,<br />
&ProcessInfo))<br />
{<br />
//ошибка запуска<br />
DWORD dwdErr=GetLastError(); //определяем ошибку<br />
}<br />
else<br />
{<br />
//ждём 30 секунд момента, пока процесс завершится<br />
//(ProcessInfo.hProcess перейдёт в сигнальное состояние)<br />
//если задать INFINITE, будет ждать до бесконечности<br />
DWORD dwd=WaitForSingleObject(ProcessInfo.hProcess, 30000);<br />
<br />
//dwd покажет причину завершения процедуры WaitForSingleObject<br />
//WAIT_OBJECT_0 Состояние объекта переведено в сигнальное <br />
//WAIT_TIMEOUT Кончился таймаут<br />
<br />
//к теме не относится, но для мутекса ещё есть возвращаемое значение:<br />
//WAIT_ABANDONED Объект является мутексом, который был занят потоком, затем поток завершился,<br />
// не разблокировав мутекс. Мутекс находится в несигнальном состоянии<br />
<br />
<br />
//если нужно - смотрим, какое значение вернуло приложение<br />
GetExitCodeProcess(ProcessInfo.hProcess, &dwRetValue);<br />
<br />
//освобождаем хендлы, открытые CreateProcess<br />
CloseHandle(ProcessInfo.hThread);<br />
CloseHandle(ProcessInfo.hProcess);<br />
}<br />
</syntaxhighlight><br />
<br />
В szApplicationName может быть либо полный путь к файлу, либо только имя файла. В последнем случае файл будет искаться в текущем каталоге.<br />
<br />
szCommandLine может быть NULL, если не надо передавать командную строку запускаемому процессу.<br />
<br />
szCurrentDirectory может быть NULL, тогда текущий каталог будет как у родительского процесса.<br />
<br />
===Как сменить иконку у диалога или мейнфрейма? (поставить свою иконку из ресурсов)===<br />
<br />
Пример:<br />
<syntaxhighlight lang="cpp"><br />
HICON m_hIcon;<br />
...<br />
...<br />
HICON m_hIcon = AfxGetApp()->LoadIcon(IDR_1);<br />
SetIcon(m_hIcon, TRUE);<br />
</syntaxhighlight><br />
<br />
где<br />
<br />
* IDR_1 - ИД иконки в ресурсах<br />
* m_hIcon - хендл типа HICON (естественно - не временный, а, скажем, член класса)<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_3&diff=652FAQ:WinAPI, VCPP Part 32008-11-12T16:38:45Z<p>Алексей1153++: </p>
<hr />
<div>=== Как узнать, что пользователь меняет текст в приложении на основе CRichEditView?===<br />
<br />
Нужно добавить обработчик сообщения EN_CHANGE. Сообщение генерируется CRichEditView каждый раз, когда пользователь изменяет текст в окне CRichEditView.<br />
<br />
===Чем отличается метод CArray::GetSize от метода CArray::GetCount?===<br />
<br />
Эти методы абсолютно идентичны. Скорее всего, в более старых версиях библиотек функции, одинаковые по смыслу, имели разные имена. Поэтому в целях совместимости разработчики оставили обе функции.<br />
<br />
===Как загрузить текстовую строку из ресурса?===<br />
<br />
Пример:<br />
<br />
<syntaxhighlight lang="cpp"><br />
CString m_Temp;<br />
<br />
m_Temp.LoadString(ID_MYSTRING);<br />
</syntaxhighlight><br />
<br />
===Как поменять иконку у элемента item в CListCtrl?===<br />
<br />
Пример:<br />
<br />
<syntaxhighlight lang="cpp"><br />
// заполняем структуру LVITEM<br />
LVITEM lvItem;<br />
<br />
memset(&lvItem, 0, sizeof(lvItem));<br />
<br />
lvItem.mask = LVIF_IMAGE; // меняться будет картинка<br />
lvItem.iItem = ...; // индекс элемента списка (Zero-based)<br />
lvItem.iSubItem = 0;<br />
lvItem.iImage = ...; //индекс иконки (из списка элемента)<br />
<br />
pList->SetItem(&lvItem);<br />
</syntaxhighlight><br />
<br />
===Имеется класс Class1, содержащий член типа "Class2*". А в Class2 имеется член типа "Class1*". Компилятор выдаёт ошибку. Что надо делать?===<br />
<br />
Перекрёстное определение обходится следующим образом: код обоих классов разносится в пары файлов *.h и *.cpp, а перед каждым классом прописывается предопределение другого класса:<br />
<br />
Файл "class1.h":<br />
<br />
<syntaxhighlight lang="cpp"><br />
class Class2; // предопределение Class2<br />
<br />
class Class1<br />
{<br />
Class2* m_p2; // компилятор разрешит объявление указателя Class2*<br />
<br />
void F1(Class2* p); //компилятор разрешит объявление указателя Class2*<br />
void F2(Class1* p);<br />
};<br />
</syntaxhighlight><br />
<br />
Файл "class1.cpp":<br />
<br />
<syntaxhighlight lang="cpp"><br />
#include "class1.h"<br />
#include "class2.h"<br />
<br />
void Class1::F1(Class2* p)<br />
{<br />
// ...<br />
}<br />
<br />
void Class1::F2(Class1* p)<br />
{<br />
// ...<br />
}<br />
</syntaxhighlight><br />
<br />
Файл "class2.h":<br />
<br />
<syntaxhighlight lang="cpp"><br />
class Class1; // предопределение Class1<br />
<br />
Class2<br />
{<br />
Class1* m_p1; // компилятор разрешит объявление указателя Class1*<br />
<br />
void F3(Class1* p); // компилятор разрешит объявление указателя Class1*<br />
};<br />
</syntaxhighlight><br />
<br />
Файл "class2.cpp":<br />
<br />
<syntaxhighlight lang="cpp"><br />
#include "class2.h"<br />
#include "class1.h"<br />
<br />
void Class2::F3(Class1* p)<br />
{<br />
// ...<br />
}<br />
</syntaxhighlight><br />
<br />
После предопределения класса компилятор позволяет объявлять указатель на класс, так как переменная указателя на любой тип имеет всегда один и тот же размер (4 байта).<br />
<br />
===Как переключить раскладку клавиатуры в другом (активном) процессе?===<br />
<br />
Для этого можно использовать функции:<br />
* GetKeyboardLayout - определить текущую раскладку<br />
* LoadKeyboardLayout - загрузить новую раскладку<br />
* VerLanguageName - получить строку с описанием языка<br />
<br />
Подробности - в MSDN.<br />
<br />
===Как получить хендл элемента управления, зная его идентификатор?===<br />
<br />
Пример: пусть элемент Edit лежит на окне CMyWnd.<br />
Тогда:<br />
<br />
<syntaxhighlight lang="cpp"><br />
void CMyWnd::некая_процедура()<br />
{<br />
// для MFC<br />
CEdit* ed = (CEdit*)GetDlgItem(ID_EDIT1);<br />
HWND hwnd = ed->GetSafeHwnd();<br />
if(hwnd)<br />
{<br />
// ...<br />
}<br />
<br />
// для Win32 API<br />
HWND hwnd = GetDlgItem(m_hWnd, ID_EDIT1);<br />
if(hwnd)<br />
{<br />
// ...<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
===Как из дочернего окна закрыть приложение?===<br />
<br />
Для этого нужно послать родительскому окну сообщение WM_CLOSE.<br />
<br />
Через указатель на родительское окно:<br />
<br />
<syntaxhighlight lang="cpp"><br />
pParent->PostMessage(WM_CLOSE);<br />
</syntaxhighlight><br />
<br />
При помощи хендла родительского окна:<br />
<br />
<syntaxhighlight lang="cpp"><br />
::PostMessage(pParent->m_hWnd, WM_CLOSE, (WPARAM)0, (LPARAM)0);<br />
</syntaxhighlight><br />
<br />
Примечание: WM_CLOSE аналогично нажатию на крестик окна. То есть, это "мягкое" закрытие окна, так как это сообщение приложение может обработать по своему.<br />
Если же точно так же отправить сообщение WM_QUIT (при этом в wParam указывается значение, возвращаемое процессом после жавершения), то оконная процедура, получив это сообщение, просто прекращает работу и приложение закрывается сразу.<br />
<br />
===Как корректно перевести тип BSTR в CString и наоборот?===<br />
<br />
# Для конвертирования BSTR в CString нужно просто присвоить переменной типа CString переменную типа BSTR. Оператор "=" класса CString сам выполнит всю работу.<br />
# Для конвертирования BSTR в CString нужно выполнить код:<br />
<br />
<syntaxhighlight lang="cpp"><br />
// указатель на будущий буфер с BSTR.<br />
// По сути, BSTR определён как typedef WCHAR* BSTR;<br />
// то есть - указатель на 16-битный символ юникод.<br />
BSTR bstrHE=0;<br />
<br />
// строка для конвертации<br />
CString Str="мой текст";<br />
<br />
// Выделяем память и загружаем адрес блока в bstrHE<br />
bstrHE=Str.AllocSysString();<br />
<br />
// ... <br />
// тут работаем с bstrHE[]<br />
// ...<br />
<br />
// освобождаем память<br />
SysFreeString(bstrHE);<br />
</syntaxhighlight><br />
<br />
===Как получить доступ к графическим ресурсам элементов текущей темы оформления Windows?===<br />
<br />
Для этого нужно использовать функции:<br />
* OpenThemeData<br />
* DrawThemeBackground<br />
* DrawFrameControl<br />
* CloseThemeData<br />
<br />
Подробности - в MSDN.<br />
<br />
===Имеется класс, производный от CDialog. Когда диалог в фокусе, нажатие на Enter или Esc приводит к закрытию диалога. Как это запретить?===<br />
<br />
При нажатии Enter происходит выполнение команды IDOK, при нажатии Esc - IDCANCEL.<br />
Нужно переопределить в классе виртуальные функции OnOk() и OnCancel(), которые соответственно вызываются для этих команд. При помощи визарда эти функции добавить можно следующим образом.<br />
<br />
Поместить на диалог две кнопки с идентификаторами IDOK и IDCANCEL (при создании нового диалога они там есть сразу), двойной щелчок по кнопке добавит соответствующий обработчик. В обработчиках надо удалить вызовы СDialog::OnOK() и CDialog::OnCancel(), тогда диалог закрываться не будет.<br />
<br />
Однако тогда диалог станет невозможно закрыть кнопкой с крестиком. Это обходится так: добавляем обработчик сообщения WM_CLOSE - OnClose(), и в нём делаем вызов OnOk() или OnCancel():<br />
<br />
<syntaxhighlight lang="cpp"><br />
void CPlayersPropsDialog::OnClose() <br />
{<br />
CDialog::OnClose();<br />
CDialog::OnCancel(); // добавлено<br />
}<br />
</syntaxhighlight><br />
<br />
===Я написал в VC++ простейший макрос, где невозможно ошибиться, а компилятор всё же выдаёт ошибку.===<br />
<br />
Скорее всего после одного из символов соединения строк "\" имеется пробел или табуляция. Их надо удалить. Можно найти их "на ощупь", а можно включить показ непечатных символов в студии. Найти эту команду можно так:<br />
<br />
Tools->Customize...->вкладка Commands. В окошке Category выбрать "Edit", и среди кнопок справа найти кнопку, на которой написано "a.b". Эту кнопку надо перенести на одну из панелей инструментов студии.<br />
<br />
===Как получить список всех процессов, включая idle?===<br />
<br />
Использовать функции:<br />
* Process32First<br />
* Precess32Next<br />
<br />
Подробности - в MSDN.<br />
<br />
===Как программно установить переменные окружения?===<br />
<br />
Чтобы добавить или изменить их программно, необходимо воспользоваться ключом реестра<br />
<br />
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment<br />
<br />
Затем нужно отправить широковещательное сообщение WM_SETTINGCHANGE - это позволит приложениям узнать об изменениях:<br />
<br />
<syntaxhighlight lang="cpp"><br />
::SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0);<br />
</syntaxhighlight><br />
<br />
===Как сделать, чтобы у окна был черный фон?===<br />
<br />
Нужно переопределить обработчик сообщения WM_CTLCOLOR - OnCtlColor():<br />
<br />
<syntaxhighlight lang="cpp"><br />
// глобальная переменная или член класса CMyDlg,<br />
// инициализированный в OnInitDialog()<br />
CBrush br(RGB(0, 0, 0));<br />
<br />
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
HBRUSH hbr = CMyDlg::OnCtlColor(pDC, pWnd, nCtlColor);<br />
<br />
// фон диалога (или View)<br />
if(nCtlColor == CTLCOLOR_DLG)<br />
{<br />
return (HBRUSH)br;<br />
}<br />
<br />
// фон элементов SCtatic, лежащих на форме (если нужно)<br />
if(nCtlColor == CTLCOLOR_STATIC)<br />
{<br />
// делаем фон текста статика прозрачным<br />
pDC->SetBkMode(TRANSPARENT);<br />
return (HBRUSH)br;<br />
}<br />
<br />
return hbr;<br />
}<br />
</syntaxhighlight><br />
<br />
===Почему на моем компьютере экзешник, созданный в MFC запускается, а на других компьютерах - нет? Требует какую-то dll.===<br />
<br />
Нужно выбирать режим Release: Menu->Build->Configurations...->Release.<br />
Экзешник, соответственно, брать из папки Release проекта.<br />
<br />
===Как в диалог добавить меню?===<br />
<br />
Нужно создать в редакторе ресурсов новое меню, затем вставить его в диалог:<br />
# Открыть в редакторе диалог;<br />
# В свойствах (во вкладке General, окошко Menu) указать идентификатор ресурса меню;<br />
# При помощи визарда добавить для меню обработчики OnCommand() и OnUpdateСommand().<br />
<br />
===Почему не вызывается OnUpdate для пунктов меню (не получается ни затенить, ни отметку поставить)?===<br />
<br />
В диалоге (CDialog) у меню апдейт не происходит сам, в отличие от мейнфрейма (CFrameWnd). Для этого нужно сделать апдейт самим, в обработчике сообщения WM_KICKIDLE.<br />
<br />
Визардом этот обработчик не добавляется, поэтому можно переопределить виртуальную DefWindowProc() и там обработать:<br />
<br />
<syntaxhighlight lang="cpp"><br />
#include <afxpriv.h> // этот файл надо включить, там определёна WM_KICKIDLE<br />
<br />
LRESULT CMyDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
if(message == WM_KICKIDLE)<br />
{<br />
// делаем апдейт для всех пунктов меню<br />
CMenu* pMainMenu = GetMenu();<br />
if(pMainMenu)<br />
{<br />
CCmdUI cmdUI;<br />
for(UINT n=0; n<pMainMenu->GetMenuItemCount(); n++)<br />
{<br />
CMenu* pSubMenu=pMainMenu->GetSubMenu(n);<br />
if(!pSubMenu)<br />
continue;<br />
<br />
cmdUI.m_nIndexMax = pSubMenu->GetMenuItemCount();<br />
for(UINT i=0; i<cmdUI.m_nIndexMax; i++)<br />
{<br />
cmdUI.m_nIndex = i;<br />
cmdUI.m_nID = pSubMenu->GetMenuItemID(i);<br />
cmdUI.m_pMenu = pSubMenu;<br />
cmdUI.DoUpdate(this, FALSE);<br />
}<br />
}<br />
}<br />
}<br />
<br />
return CDialog::DefWindowProc(message, wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
===Как в главном окне отключить системное меню (в левом верхнем углу) и кнопки (в правом верхнем углу)?===<br />
<br />
При создании окна нужно убрать стиль WS_SYSMENU. Теперь пользователь корректно может закрыть окно только Alt+F4, ну, или если вы предоставите ему дополнительную возможность сделать это.<br />
<br />
Пример 1. (для SDI, MDI)<br />
<br />
<syntaxhighlight lang="cpp"><br />
// этот обработчик уже добавлен визардом<br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
if(!CFrameWnd::PreCreateWindow(cs))<br />
return FALSE;<br />
// TODO: Modify the Window class or styles here by modifying<br />
// the CREATESTRUCT cs<br />
<br />
///////////////////////////////<br />
// добавленная часть<br />
{<br />
// убираем стиль<br />
cs.style& =~ WS_SYSMENU;<br />
}<br />
///////////////////////////////<br />
<br />
return TRUE;<br />
}<br />
</syntaxhighlight><br />
<br />
Пример 2. (для диалога)<br />
Если диалог описан в ресурсах, то в свойствах диалога убрать галочки:<br />
* "System menu"<br />
* "Minimize box"<br />
* "Maximize box"<br />
<br />
===Как запретить пользователю нажать на кнопку?===<br />
<br />
Нужно применить метод класса CWnd::EnableWindow(...) для кнопки. Значение 0 параметра делает кнопку неактивной, 1 - делает активной (кстати, не только для кнопки можно, а для любого класса, производного от класса CWnd).<br />
<br />
Пусть имеется некий диалог, на нём лежит кнопка c ID == IDC_1. В любом месте кода диалога (кроме конструктора и деструктора, хотя, если проверить наличие валидного хендла диалога, как в примере, то ничего страшного не будет и там) выполняем код:<br />
<br />
<syntaxhighlight lang="cpp"><br />
// делаем кнопку неактивной<br />
if(m_hWnd)<br />
{<br />
CWnd* pw = 0;<br />
pw = GetDlgItem(IDC_1);<br />
if(pw)<br />
{<br />
pw->EnableWindow(0);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
===Что означают сообщения, которые студия выводит при компиляции, вроде таких: Loaded 'C:\WINDOWS\SYSTEM\WSOCK32.DLL', no matching symbolic information found?===<br />
<br />
Это строка говорит о том, что студия не смогла найти отладочные символы для WSOCK32.DLL. В этом нет ничего страшного. Просто, при наличии отладочных символов в процессе отладки, можно получить доступ к именам функции из системных DLL. Например, вместо ''KERNEL32! 0x77E8B184()'' увидим ''KERNEL32!CreateThread''.<br />
<br />
===Как обработать сообщения, которые приходят к элементу управления?===<br />
<br />
Скажем, нужно обработать сообщения, приходящие к элементу класса CEdit. Нужно произвести от CEdit свой класс и в виртуальной процедуре класса WindowProc перехватить нужные сообщения.<br />
<br />
<syntaxhighlight lang="cpp"><br />
virtual LRESULT WindowProc(<br />
UINT message,<br />
WPARAM wParam,<br />
LPARAM lParam <br />
);<br />
</syntaxhighlight><br />
<br />
Пример. Полностью выключаем, скажем, обработку сообщения WM_CHAR.<br />
<br />
<syntaxhighlight lang="cpp"><br />
LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
switch(message)<br />
{<br />
case WM_CHAR:<br />
{<br />
return 0;<br />
}<br />
break;<br />
}<br />
<br />
return CEdit::WindowProc(message, wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
Чтобы связать экземпляр класса с элементом управления на форме, добавьте визардом для<br />
элемента управления переменную класса (выбрав не Value, а Control).<br />
<br />
===Как настроить количество пробелов в табуляции?===<br />
<br />
Есть пара способов:<br />
# Tools->Options->Tabs->Insert Spaces<br />
# Правой кнопкой мыши щёлкнуть по тексту, в контекстном меню выбрать properties.<br />
<br />
===Как автоматически расставить отступы?===<br />
<br />
Нужно в студии выделить текст для форматирования и нажать Alt+F8.<br />
<br />
Ещё есть программа Artistic Style ( http://sourceforge.net/projects/astyle/ ), которая занимается переформатированием кода.<br />
<br />
===Поиск границ блока.===<br />
<br />
Сочетание клавиш CTRL+"}" ищет парную фигурную скобку в тексте и переходит к ней.<br />
<br />
===Вертикальное выделение текста.===<br />
<br />
Если удерживать клавишу Alt, а затем начать выделять текст мышкой, то область выделения принимает форму прямоугольника, что позволяет выделять вертикальные фрагменты текста.<br />
<br />
===Как узнать количество установленных в CListCtrl столбцов?===<br />
<br />
Пример:<br />
<syntaxhighlight lang="cpp"><br />
// указатель на переменную-элемент управления<br />
CListCtrl* pL = ...;<br />
<br />
// получаем количество столбцов<br />
int count = pL->GetHeaderCtrl()->GetItemCount();<br />
</syntaxhighlight><br />
<br />
===Как получить иконку приложения?===<br />
<br />
Если приложение запущено, то нужно найти его главное окно и послать ему сообщение WM_GETICON.<br />
<br />
<syntaxhighlight lang="cpp"><br />
// функция возвращант хендл иконки <br />
LRESULT SendMessage(hWnd, WM_GETICON, wParam, 0);<br />
<br />
// hWnd == хендл окна приложения<br />
// wParam == <br />
// 1)==ICON_BIG - получить большую иконку<br />
// 2)==ICON_SMALL - получить маленькую иконку<br />
// 3)==ICON_SMALL2 - получить маленькую иконку, если она определена<br />
// в приложении. Если её нет, то маленькую иконку, <br />
// сгенерированную системой из большой иконки<br />
</syntaxhighlight><br />
<br />
===Как в CString можно найти или вырезать часть строки?===<br />
<br />
Это можно сделать при помощи методов класса CString:<br />
<br />
<syntaxhighlight lang="cpp"><br />
// вырезает кусок строки<br />
CString Mid(int nFirst) const;<br />
CString Mid(int nFirst, int nCount) const;<br />
<br />
// возвращает кусок строки (сначала или с конца)<br />
CString Left(int nCount) const;<br />
CString Right(int nCount) const;<br />
<br />
// возвращает начальный кусок строки, в котором есть только<br />
// символы из набора, представленного в lpszCharSet<br />
CString SpanIncluding(LPCTSTR lpszCharSet) const;<br />
<br />
// возвращает начальный кусок строки, в котором нет<br />
// символов из набора, представленного в lpszCharSet<br />
CString SpanExcluding(LPCTSTR lpszCharSet) const; <br />
<br />
// убирает "пробелоподобные" символы из самого начала строки.<br />
// то есть - пробел, табуляцию (\t), возврат каретки, перевод строки (/r/n)<br />
void TrimLeft();<br />
<br />
// убирает все повторы символа из самого начала строки<br />
void TrimLeft(TCHAR chTarget);<br />
<br />
// убирает из самого начала строки все символа из набора lpszTargets <br />
void TrimLeft(LPCTSTR lpszTargets);<br />
void TrimRight();<br />
void TrimRight(TCHAR chTarget);<br />
void TrimRight(LPCTSTR lpszTargets);<br />
<br />
// поиск в строке<br />
int Find(TCHAR ch) const;<br />
int Find(LPCTSTR lpszSub) const;<br />
int Find(TCHAR ch, int nStart) const;<br />
int Find(LPCTSTR pstr, int nStart) const;<br />
<br />
// поиск, начиная с конца<br />
int ReverseFind(TCHAR ch) const;<br />
<br />
// поиск позиции первого символа, одного из набора,<br />
// представленного в lpszCharSet<br />
int FindOneOf(LPCTSTR lpszCharSet) const;<br />
</syntaxhighlight><br />
<br />
===Как отобразить на элементах управления промежуточные результаты длительных вычислений?===<br />
<br />
В общем случае это делается принудительной перерисовкой нужного окна путём объявления этого окна невалидным.<br />
<br />
<syntaxhighlight lang="cpp"><br />
pWnd->Invalidate(0);<br />
</syntaxhighlight><br />
<br />
Затем непосредственной отсылки в оконную процедуру сообщения WM_PAINT.<br />
<br />
<syntaxhighlight lang="cpp"><br />
pWnd->UpdateWindow();<br />
</syntaxhighlight><br />
<br />
Пример:<br />
<syntaxhighlight lang="cpp"><br />
CWnd* pWnd = ...; // окно, которое надо перерисовывать<br />
<br />
for(int i=0; i<10000; i++)<br />
{<br />
// меняется содержимое окна<br />
// ...<br />
<br />
// немедленная перерисовка<br />
pWnd->Invalidate(0);<br />
pWnd->UpdateWindow();<br />
}<br />
</syntaxhighlight><br />
<br />
Также можно также просто вызвать метод RedrawWindow() с параметрами по умолчанию.<br />
<br />
===Я написал DLL, которую используют несколько приложений. Всё работает, но когда происходит очередной вызов функции из DLL, почему то, данные в функции обнуляются. С чем это связано?===<br />
<br />
Переменные и массивы в DLL, содержимое которых должно использоваться несколькими процессами, должны объявляться статическими. Статическая переменная или массив инициализируются только один раз в момент загрузки DLL.<br />
<br />
Пример:<br />
<br />
<syntaxhighlight lang="cpp"><br />
DWORD calltest()<br />
{<br />
// будет выполнено только при первом вызове<br />
static DWORD callcount = 0;<br />
static DWORD str[1000] = {0}; <br />
<br />
// будет выполняться каждый раз<br />
callcount++;<br />
return callcount;<br />
}<br />
</syntaxhighlight><br />
<br />
===Как открыть проекцию файла в память и как с ней работать?===<br />
<br />
Создание проекции:<br />
<br />
<syntaxhighlight lang="cpp"><br />
HANDLE CreateFileMapping(<br />
HANDLE hFile, // хендл уже открытого файла<br />
LPSECURITY_ATTRIBUTES lpAttributes,<br />
DWORD flProtect, // способ открытия проекции<br />
DWORD dwMaximumSizeHigh, // размер файла (старшие 4 байта, обычно - 0)<br />
DWORD dwMaximumSizeLow, // размер файла (младшие 4 байта)<br />
LPCTSTR lpName<br />
);<br />
</syntaxhighlight><br />
<br />
Доступ к созданной проекции производится процедурой:<br />
<br />
<syntaxhighlight lang="cpp"><br />
LPVOID MapViewOfFile(<br />
HANDLE hFileMappingObject, // хендл проекции<br />
DWORD dwDesiredAccess, // способ работы с проекцией<br />
DWORD dwFileOffsetHigh,<br />
DWORD dwFileOffsetLow, // смещение от начала файла (младшие 4 байта)<br />
SIZE_T dwNumberOfBytesToMap // длина в байтах (если 0 - то весь файл)<br />
);<br />
</syntaxhighlight><br />
<br />
Далее с файлом можно работать как с обычным массивом в памяти.<br />
<br />
После работы с проекцией, её надо освободить.<br />
<br />
<syntaxhighlight lang="cpp"><br />
BOOL UnmapViewOfFile(<br />
LPCVOID lpBaseAddress // адрес, который вернула процедура MapViewOfFile<br />
);<br />
</syntaxhighlight><br />
<br />
Пример:<br />
<br />
<syntaxhighlight lang="cpp"><br />
HANDLE hFile = ...; // хендл уже открытого файла<br />
DWORD dwdFileLen = ...; // размер открытого файла<br />
HANDLE hMapFile = 0; // хендл для проекции<br />
<br />
// создаём проекцию "только для чтения"<br />
hMapFile = ::CreateFileMapping(hFile, 0, PAGE_READONLY, 0, dwdFileLen, 0);<br />
<br />
// хендл hFile можно закрыть уже здесь, в принципе,<br />
// но мы сделаем это позже<br />
<br />
// получаем доступ к проекции (тоже только для чтения)<br />
BYTE* pbyFile = (BYTE*)::MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);<br />
<br />
///////////////////<br />
// тут работаем с массивом pbyFile[dwdFileLen] как с обычным,<br />
// только не забываем, что он открыт только для чтения<br />
// ...<br />
// ...<br />
// ...<br />
///////////////////<br />
<br />
// отключаем файл данных от адресного пространства<br />
UnmapViewOfFile(pbyFile);<br />
<br />
// освобождаем хендл проекции<br />
CloseHandle(hMapFile)<br />
<br />
// освобождаем хендл открытого файла<br />
CloseHandle(hFile);<br />
</syntaxhighlight><br />
<br />
===Как в MFC Grid control отобразить картинку в ячейке?===<br />
<br />
Нужно создать список изображений (CImageList), затем передать указатель на список в таблицу. Поскольку элемент управления лишь копирует указатель, список должен создаваться динамически, либо быть членом класса, экземпляр которого существует всё время работы таблицы.<br />
<br />
<syntaxhighlight lang="cpp"><br />
CImageList m_ImageList;<br />
CGridCtrL m_Grid1;<br />
<br />
// ...<br />
<br />
// неким образом создаётся список<br />
m_ImageList.Create(...);<br />
<br />
// ...<br />
<br />
//вставляем в элемент управления<br />
m_Grid1.SetImageList(&m_ImageList);<br />
</syntaxhighlight><br />
<br />
===Как при помощи IPicture отобразить картинку из файла? ===<br />
<br />
Пример - несложная функция, отображающая картинку из файла. Поддерживаются форматы BMP, GIF, JPEG, PNG, TIFF, EMF.<br />
<br />
<syntaxhighlight lang="cpp"><br />
#include "atlconv.h"<br />
#define HandleIsValid(H) (H != (HANDLE) - 1 && H != (HANDLE)0)<br />
<br />
// *pDestDC - CDC, на который предполагается вывод картинки<br />
// pchzFilePath - путь к файлу<br />
// pWid - (возвращает) ширина картинки<br />
// pHig - (возвращает) высота картинки<br />
bool DrawBitmapFromFile(CDC* pDestDC, const char* pchzFilePath, int *pWid = 0, int *pHig = 0)<br />
{<br />
bool result = false;<br />
<br />
if (pWid)<br />
*pWid = 0;<br />
<br />
if (pHig)<br />
*pHig = 0;<br />
<br />
int Wid = 0;<br />
int Hig = 0;<br />
<br />
IPicture* pPic = 0;<br />
try<br />
{<br />
IPicture* ptmpPic = 0;<br />
USES_CONVERSION;<br />
HRESULT hr;<br />
<br />
CString txt = pchzFilePath;<br />
hr = ::OleLoadPicturePath(<br />
const_cast<LPOLESTR>(T2COLE(txt)),<br />
0,<br />
0,<br />
0,<br />
IID_IPicture,<br />
reinterpret_cast<void **>(&ptmpPic)<br />
);<br />
<br />
if(hr == S_OK && ptmpPic)<br />
{<br />
pPic = ptmpPic;<br />
}<br />
else<br />
{<br />
throw 0;<br />
}<br />
<br />
OLE_XPOS_HIMETRIC cxSrc;<br />
OLE_YPOS_HIMETRIC cySrc;<br />
<br />
if(S_OK != pPic->get_Width(&cxSrc))<br />
{<br />
throw 0;<br />
}<br />
<br />
if(S_OK != pPic->get_Height(&cySrc))<br />
{<br />
throw 0;<br />
}<br />
<br />
Wid = cxSrc / 26;<br />
Hig = cySrc / 26;<br />
<br />
// рисуем<br />
if(S_OK != pPic->Render(pDestDC->GetSafeHdc(),<br />
0, Hig, Wid, -Hig, 0, 0, cxSrc, cySrc, 0))<br />
{<br />
throw 0;<br />
}<br />
}<br />
catch (...)<br />
{<br />
result = false;<br />
}<br />
<br />
if(pPic)<br />
{<br />
pPic->Release();<br />
pPic = 0;<br />
}<br />
<br />
if(pWid)<br />
{<br />
*pWid = Wid;<br />
}<br />
<br />
if(pHig)<br />
{<br />
*pHig = Hig;<br />
}<br />
<br />
return result;<br />
}<br />
</syntaxhighlight><br />
<br />
===Как позволить пользователю начать ввод новой строки в многострочном поле редактирования?===<br />
<br />
Нужно в редакторе ресурсов поставить для свойств окошка CEdit галочку "WantReturn" или добавить стиль ES_WANTRETURN при создании CEdit элемента управления динамически. Тогда при нажатии Enter в поле редактирования будет вводиться новая строка.<br />
<br />
===Как выводят картинку-логотип (splash screen) при запуске программы?===<br />
<br />
Для этого используется класс, производный от CDialog. Этот диалог после создания показывает себя на экран, выводя на себя рисунок. Также запускает таймер, по срабатывани которого диалог гасится. Создаётся диалог в процедуре InitInstance приложения.<br />
<br />
В VC6++ также есть уже готовый компонент: Project->Add To Project -> Components and Controls->(в папке "Visual C++ Components" есть SplashScreen.).<br />
<br />
===Как сделать, чтобы при выпадении списка у ComboBox была не одна строка, а больше? Вроде все свойства покрутил, не помогает: вместо выпадающего списка - одна строка и скролл.===<br />
<br />
В редакторе ресурсов надо щелкнуть в комбобоксе на треугольнике - появляется рамка для растягивания вниз - размер выпадающего списка.<br />
<br />
===VC++.NET. На форму установил ActiveX ListView. Как объявить класс и переменную для этого элемента?===<br />
<br />
Щёлкнуть правой кнопкой мыши на элементе, в меню - add variable или add class.<br />
<br />
===Как работать с буфером обмена (Clipboard)?===<br />
<br />
====КОПИРОВАНИЕ В БУФЕР ОБМЕНА====<br />
<br />
Алгоритм:<br />
# Готовим данные<br />
#* Выделяем память из кучи, вызывая GlobalAlloc()<br />
#* Получаем указатель на выделенную память, вызывая GlobalLock()<br />
#* Заполняем данные<br />
#* Освобождаем указатель, вызывая GlobalUnlock();<br />
# Открываем буфер обмена, вызывая OpenClipboard();<br />
# Очищаем буфер, вызывая EmptyClipboard();<br />
# Вызываем SetClipboardData() один раз для каждого формата вставляемых данных (имеется в виду - если одни и те же данные представлены в разных форматах, и приложение может эти форматы создать)<br />
# Закрываем буфер, вызывая CloseClipboard();<br />
# ВЫЗЫВАТЬ GlobalFree() НЕ НУЖНО, в этом случае это предоставлено системе<br />
<br />
Скажем, хотим поместить в буфер обмена текст.<br />
<syntaxhighlight lang="cpp"><br />
//готовим данные<br />
//выделяем из кучи память для данных<br />
HANDLE hglbCopy = GlobalAlloc(GMEM_MOVEABLE,10);<br />
if(!hglbCopy)<br />
return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)<br />
return;<br />
<br />
//заполняем данные<br />
strcpy((char*)lpStr,"my text");<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
//очищаем<br />
EmptyClipboard();<br />
<br />
//текстовый формат<br />
SetClipboardData(CF_TEXT,hglbCopy);<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</syntaxhighlight><br />
<br />
<br />
<br />
====ИЗВЛЕЧЕНИЕ ИЗ БУФЕРА ОБМЕНА====<br />
<br />
Алгоритм:<br />
# Проверяем, что поддерживается нужный формат данных, вызывая IsClipboardFormatAvailable()<br />
# Открываем буфер обмена, вызывая OpenClipboard();<br />
# Достаём данные<br />
#* Получаем из буфера хендл требуемого формата, вызывая GetClipboardData()<br />
#* Получаем указатель на выделенную память, вызывая GlobalLock()<br />
#* Работаем с данными<br />
#* Освобождаем указатель, вызывая GlobalUnlock();<br />
# Закрываем буфер, вызывая CloseClipboard();<br />
<br />
Скажем, хотим извлечь из буфера обмена текст.<br />
<syntaxhighlight lang="cpp"><br />
//Проверяем, что поддерживается нужный формат данных,<br />
if(!IsClipboardFormatAvailable(CF_TEXT))<br />
return;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
<br />
//достаём данные<br />
<br />
//текстовый формат<br />
HANDLE hglbCopy = GetClipboardData(CF_TEXT);<br />
if(!hglbCopy)<br />
return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)<br />
return;<br />
<br />
//читаем данные<br />
char data[10];<br />
memmove(data,lpStr,sizeof(data));<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</syntaxhighlight><br />
<br />
<br />
===Как получить полный путь к экзешнику из самой программы?===<br />
Можно прочитать параметры командной строки - в командную строку первым параметром система всегда передаёт заключённый в кавычки полный путь к файлу запущенной программы. Достаём путь следующим образом:<br />
<syntaxhighlight lang="cpp"><br />
BOOL CMyApp::InitInstance()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName содержит искомый путь<br />
<br />
//...<br />
//...<br />
}<br />
</syntaxhighlight><br />
<br />
===Каким способом exe файл может заменить самого себя? ===<br />
<br />
К примеру, программа должна обновляется через Internet и хочет обновить свой exe-файл. Но так как он в данный момент запущен, это будет, естественно, невозможно сделать напрямую.<br />
Один из способов - сделать копию экзешника и из него обновиться<br />
<br />
<syntaxhighlight lang="cpp"><br />
#define def_exeNAMEup "c:\\myprog_toupdate.exe" //путь к старому файлу<br />
#define def_exeNAMEdnld "c:\\myprog_downloaded.exe" //путь к новому файлу (уже "скачали":) )<br />
#define def_keyUdate "/update"<br />
<br />
void CTESTFAQApp::UpdateItself()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName - содержит искомый путь<br />
<br />
//делаем копию экзешника с другим именем<br />
CopyFile(csFullExeName,def_exeNAMEup,0);<br />
<br />
//передаём в параметры нового процесса ключ и путь к текущему файлу<br />
CString csParams=def_keyUdate;<br />
csParams+=" ";<br />
csParams+=csFullExeName;<br />
<br />
//запускаем копию<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(def_exeNAMEup,def_keyUdate,0,0,0,0,0,0,&si,&pi))<br />
{<br />
//завершаем текущий процесс<br />
ExitFromMyApp();<br />
}<br />
}<br />
<br />
void CTESTFAQApp::ExitFromMyApp()<br />
{<br />
exit(0);<br />
}<br />
<br />
BOOL CTESTFAQApp::InitInstance()<br />
{<br />
//смотрим, не запущено ли для апдейта?<br />
CString txt;<br />
txt=m_lpCmdLine;<br />
if(txt.Find(def_keyUdate)==0)<br />
{<br />
//делаем айдейт<br />
txt.Replace(def_keyUdate,"");<br />
txt.TrimLeft();<br />
<br />
CString csFullExeName=txt;<br />
<br />
//берём откуда то уже скачанный файл обновления<br />
//...<br />
CString csFull_Downloaded_ExeName=def_exeNAMEdnld;<br />
<br />
//копируем файл (обновляем старый то есть)<br />
CopyFile(csFull_Downloaded_ExeName,csFullExeName,0);<br />
<br />
//запускаем обновлённого мученника<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(csFullExeName,0,0,0,0,0,0,0,&si,&pi))<br />
<br />
ExitFromMyApp();<br />
}<br />
//...<br />
//...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как производится конвертация из кодировки UTF8 в 1251 и наоборот?===<br />
<br />
Можно перевести строку из UTF8 в Unicode, затем из Unicode в 1251<br />
<br />
Ниже приведена структура, содержащая процедуры перекодирования,<br />
а также процедуру с примером использования<br />
<syntaxhighlight lang="cpp"><br />
//описание структуры<br />
struct coder<br />
{<br />
//utf8->unicode<br />
static wchar_t* utf8_to_unicode__dontForgetDeleteArr(const char *utf8_string)<br />
{<br />
wchar_t* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len=MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,0,0);<br />
if(!res_len)<br />
{<br />
return 0;<br />
}<br />
<br />
//выделяем память<br />
pRes = new wchar_t[res_len];<br />
if(!pRes)<br />
{<br />
return 0;<br />
}<br />
<br />
//преобразование<br />
if(!MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,pRes,res_len))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//unicode->1251<br />
static char * unicode_to_1251__dontForgetDeleteArr(const wchar_t *unicode_string)<br />
{<br />
char* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len = WideCharToMultiByte(1251,0,unicode_string,-1,0,0,0,0);<br />
if(!res_len)<br />
{<br />
return 0;<br />
}<br />
<br />
//выделяем память<br />
pRes=new char[res_len];<br />
if(!pRes)<br />
{<br />
return 0;<br />
}<br />
<br />
//преобразование<br />
if(!WideCharToMultiByte(1251,0,unicode_string,-1,pRes,res_len,0,0))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//процедура с примером<br />
static void Example()<br />
{<br />
wchar_t* unicode_string=0;<br />
char* cp1251_string=0;<br />
<br />
//исходный текст<br />
char utf8_string[] = "UTF-8 + русский текст";<br />
<br />
for(;;)<br />
{<br />
unicode_string=utf8_to_unicode__dontForgetDeleteArr(utf8_string);<br />
if(!unicode_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать в unicode!");<br />
break;<br />
}<br />
<br />
cp1251_string = unicode_to_1251__dontForgetDeleteArr(unicode_string);<br />
<br />
if(!cp1251_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать из unicode!");<br />
break;<br />
}<br />
<br />
break;<br />
}<br />
<br />
//cp1251_string - результат<br />
AfxMessageBox(cp1251_string);<br />
<br />
//не забываем удалить массивы<br />
if(unicode_string)<br />
{<br />
delete [] unicode_string;<br />
unicode_string=0;<br />
}<br />
<br />
if(cp1251_string)<br />
{<br />
delete [] cp1251_string;<br />
cp1251_string=0;<br />
}<br />
}<br />
};<br />
<br />
//вызов примера<br />
coder::Example();<br />
</syntaxhighlight><br />
<br />
===Как работать с базой данных Access из программы на VC.net?===<br />
Проще всего подключить ADO компоненты и сделать все на них.<br />
<br />
Компоненты ADO (ADODC,DATAGRID и т.п.) это ActiveX.<br />
<br />
В редакторе ресурсов, во всплывающем меню, есть Insert ActiveX Control -> открывается список всех компонент, зарегистрированных на машине. Нужно найти компоненты (Это компоненты от MS и они помечены (OLEDB)) и вставить их в диалог. Для того что бы иметь возможность управлять ими, нужно импортировать обертки для них, это делается при помощи ClassWizard, там есть импорт->класс->указать файл с компонентой (OSX). Появляется список всех классов, объявленных внутри.<br />
<br />
Расставляем нужные галочки, нажимаем ОК.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_4&diff=615FAQ:WinAPI, VCPP Part 42008-10-23T20:13:32Z<p>Алексей1153++: </p>
<hr />
<div>===Как создавать всплывающие подсказки (ToolTip)?===<br />
Этот элемент управления называется "Balloon ToolTip". (В МСДН есть статья под названием "Using ToolTip Controls")<br />
[[Изображение:context_help.GIF]]<br />
<br />
Тематические ссылки:<br />
* http://www.codeproject.com/shell/LiviuBirjegaCode.asp<br />
* http://www.codeproject.com/useritems/wtlntray.asp<br />
<br />
<br />
Для того, чтобы подсказка имела вид "облака" (как в комиксах), нужно установить недокументированный стиль<br />
TTS_BALLOON==0x40<br />
<br />
Вот ещё пара полезных функций API для работы с подсказками<br />
<syntaxhighlight lang="cpp"><br />
CToolTipCtrl::SetDelayTime(TTDT_INITIAL, время_в_миллисекундах);//через какое время появится на экране после наведения курсора<br />
CToolTipCtrl::SetDelayTime(TTDT_AUTOPOP, время_в_миллисекундах);//время горения подсказки на экране<br />
<br />
//время в миллисекундах - тип DWORD<br />
</syntaxhighlight><br />
<br />
===Что делает функция ScrollWindow()===<br />
Функция ScrollWindow() всего лишь двигает рисунок, уже нарисованный на контексте окна, на заданное количество пикселов.<br />
<br />
К примеру, у имеется нарисованное изображение на клиентской части окна, и нужно сделать скролинг этой части.<br />
<br />
Первый путь: Стереть что уже было нарисовано, и перерисовывать все заново с учетом скролинга.<br />
<br />
Второй путь: Передвинуть ту часть, которая останется в зоне видимости, и дорисовать недостаюшую часть. Функция ScrollWindow() как раз и пригодится, чтобы передвинуть рисунок на заданное количество пикселов. Останется потом только дорисовать.<br />
<br />
===Почему список CComboBox не выпадает, хотя клавишами "вверх" и "вниз" значения перебираются?===<br />
Нужно задать высоту выпадающего списка: находясь в редакторе форм, нужно щёлкнуть по стрелке комбобокса и за нижний маркер растянуть вниз, тем самым и задать размер выпадающего списка.<br />
<br />
===Как программно поменять настройки Internet Explorer?===<br />
Можно воспользоваться редактированием реестра:<br />
<syntaxhighlight lang="cpp"><br />
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\AdvancedOptions\ (всякие настройки)<br />
</syntaxhighlight><br />
<br />
===Как узнать, когда после запуска приложение уже готово к работе?===<br />
Можно переопределить функцию CWinApp::OnIdle. Эта функция вызывается всякий раз, когда в очереди сообщений приложения нет больше сообщений. Самый первый вызов функции будет соответствовать моменту, когда приложение стало быть готово к работе.<br />
<br />
===Как получить короткое и длинное имя файла?===<br />
Можно использовать функции API<br />
<syntaxhighlight lang="cpp"><br />
GetShortPathName(<br />
LPCSTR lpszLongPath,<br />
LPSTR lpszShortPath,<br />
DWORD cchBuffer); //получить короткий путь<br />
</syntaxhighlight><br />
и<br />
<syntaxhighlight lang="cpp"><br />
GetLongPathName(<br />
LPCSTR lpszShortPath,<br />
LPSTR lpszLongPath,<br />
DWORD cchBuffer); //получить полный путь<br />
</syntaxhighlight><br />
<br />
<br />
Например имеется путь к файлу:<br />
<br />
D:\program files\Microsoft Office\OFFICE11\winword.exe<br />
<br />
функция GetShortPathName() поможет привести его к виду:<br />
<br />
d:\PROGRA~1\MICROS~2\OFFICE11\WINWORD.EXE<br />
<br />
а функция GetLongPathName() - наоборот.<br />
<br />
Максимальная длина пути файла равна MAX_PATH (==260) символам<br />
<br />
===В чём разница между сообщениями WM_MOVE и WM_MOVING?===<br />
<br />
Сообщение VM_MOVING посылается окну, когда пользователь перемещает окно.<br />
<br />
Сообщение VM_MOVE посылается окну, когда пользователь завершил перемещение окна (отпустил кнопку мыши).<br />
<br />
=== Как из программы определить каталог, в котором находится эта программа?===<br />
Это можно сделать при помощи функции, которая возвращает абсолютное имя модуля.<br />
<syntaxhighlight lang="cpp"><br />
GetModuleFileName()<br />
</syntaxhighlight><br />
<br />
В MFC можно использовать переменную-член класса CWinApp, определённую как<br />
<syntaxhighlight lang="cpp"><br />
LPCTSTR m_pszExeName;<br />
</syntaxhighlight><br />
<br />
Получить доступ можно двумя способами:<br />
<syntaxhighlight lang="cpp"><br />
//1<br />
AfxGetApp()->m_pszExeName;<br />
<br />
//2<br />
//extern CMyApp theApp<br />
theApp.m_pszExeName;<br />
</syntaxhighlight><br />
<br />
===Как получить полное имя пользователя и организации, то есть то, что на диалоге system properties (горячая кнопка [ Win ] + Break ) на закладке General перечислено под пунктом Registred To? ===<br />
Значение можно взять в реестре:<br />
<br />
тут (для Windows NT)<br />
<syntaxhighlight lang="cpp"><br />
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion<br />
</syntaxhighlight><br />
<br />
или тут (W98, W95)<br />
<syntaxhighlight lang="cpp"><br />
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion<br />
</syntaxhighlight><br />
<br />
===Как определить первый свободный ID, который можно использовать при динамическом создании элементов управления?===<br />
Можно поступить так: начать перебор значений ID со значения 1000 и, проверяя функцией GetDlgItem(), увеличивать значение на единицу до тех пор, пока не будет найден свободный ID.<br />
<br />
===Как изменить цвет рамки приложения?===<br />
Это можно сделать, если перехватить сообщение WM_NCPAINT, которое отвечает за прорисовку не клиентской части окна.<br />
<br />
===Я запускаю экзешник при помощи ::ShellExecute(). Процедура тут же возвращает управление, а как дождаться, когда запущенный процесс завершится, только потом продолжить выполнение программы?===<br />
Нужно использовать функции<br />
<br />
CreateProcess()<br />
<br />
WaitForSingeObject()<br />
<br />
<syntaxhighlight lang="cpp"><br />
STARTUPINFO StartupInfo;<br />
PROCESS_INFORMATION ProcessInfo;<br />
DWORD dwRetValue;<br />
RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));<br />
StartupInfo.cb = sizeof(StartupInfo);<br />
<br />
//запуск экзешника<br />
if(!CreateProcess(<br />
szApplicationName,<br />
szCommandLine, //командная строка (можно указать NULL)<br />
NULL, NULL, FALSE,<br />
NORMAL_PRIORITY_CLASS,<br />
NULL,<br />
szCurrentDirectory, //рабочая директория (можно указать NULL)<br />
&StartupInfo,<br />
&ProcessInfo))<br />
{<br />
//ошибка запуска<br />
DWORD dwdErr=GetLastError(); //определяем ошибку<br />
}<br />
else<br />
{<br />
//ждём 30 секунд момента, пока процесс завершится<br />
//(ProcessInfo.hProcess перейдёт в сигнальное состояние)<br />
//если задать INFINITE, будет ждать до бесконечности<br />
DWORD dwd=WaitForSingleObject(ProcessInfo.hProcess, 30000);<br />
<br />
//dwd покажет причину завершения процедуры WaitForSingleObject<br />
//WAIT_OBJECT_0 Состояние объекта переведено в сигнальное <br />
//WAIT_TIMEOUT Кончился таймаут<br />
<br />
//к теме не относится, но для мутекса ещё есть возвращаемое значение:<br />
//WAIT_ABANDONED Объект является мутексом, который был занят потоком, затем поток завершился,<br />
// не разблокировав мутекс. Мутекс находится в несигнальном состоянии<br />
<br />
<br />
//если нужно - смотрим, какое значение вернуло приложение<br />
GetExitCodeProcess(ProcessInfo.hProcess, &dwRetValue);<br />
<br />
//освобождаем хендлы, открытые CreateProcess<br />
CloseHandle(ProcessInfo.hThread);<br />
CloseHandle(ProcessInfo.hProcess);<br />
}<br />
</syntaxhighlight><br />
<br />
В szApplicationName может быть либо полный путь к файлу, либо только имя файла. В последнем случае файл будет искаться в текущем каталоге.<br />
<br />
szCommandLine может быть NULL, если не надо передавать командную строку запускаемому процессу.<br />
<br />
szCurrentDirectory может быть NULL, тогда текущий каталог будет как у родительского процесса.<br />
<br />
===Как сменить иконку у диалога или мейнфрейма? (поставить свою иконку из ресурсов)===<br />
<br />
Пример:<br />
<syntaxhighlight lang="cpp"><br />
HICON m_hIcon;<br />
...<br />
...<br />
HICON m_hIcon = AfxGetApp()->LoadIcon(IDR_1);<br />
SetIcon(m_hIcon, TRUE);<br />
</syntaxhighlight><br />
<br />
где<br />
<br />
IDR_1 - ИД иконки в ресурсах<br />
<br />
m_hIcon - хендл типа HICON (естественно - не временный, а, скажем, член класса)<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_3&diff=614FAQ:WinAPI, VCPP Part 32008-10-23T20:03:31Z<p>Алексей1153++: </p>
<hr />
<div>=== Как узнать, что пользователь меняет текст в приложении на основе CRichEditView?===<br />
Нужно добавить обработчик сообщения EN_CHANGE. Сообщение генерируется CRichEditView каждый раз, когда пользователь изменяет текст в окне CRichEditView<br />
<br />
===Чем отличается метод CArray::GetSize от метода CArray::GetCount?===<br />
Эти методы абсолютно идентичны. Скорее всего, в более старых версиях библиотек функции, одинаковые по смыслу, имели разные имена. Поэтому в целях совместимости разработчики оставили обе функции)<br />
<br />
===Как загрузить текстовую строку из ресурса?===<br />
Пример:<br />
<syntaxhighlight lang="cpp"><br />
CString m_Temp;<br />
m_Temp.LoadString(ID_MYSTRING);<br />
</syntaxhighlight><br />
<br />
===Как поменять иконку у элемента item в CListCtrl?===<br />
Пример:<br />
<syntaxhighlight lang="cpp"><br />
//заполняем структуру LVITEM<br />
LVITEM lvItem;<br />
memset(&lvItem,0,sizeof(lvItem));<br />
<br />
lvItem.mask =LVIF_IMAGE;//меняться будет картинка<br />
lvItem.iItem =...;// индекс элемента списка (Zero-based)<br />
lvItem.iSubItem =0;<br />
lvItem.iImage =...; //индекс иконки (из списка элемента)<br />
<br />
pList->SetItem(&lvItem);<br />
</syntaxhighlight><br />
<br />
===Имеется класс Class1, содержащий член типа "указатель на Class2". В Class2 также имеется указатель на Class1. Компилятор выдаёт ошибку. Что надо делать?===<br />
Перекрёстное определение обходится следующим образом: код обоих классов разносится в пары файлов *.h и *.cpp, а перед каждым классом вписывается предопределение другого класса:<br />
<br />
<br />
файл "class1.h"<br />
<syntaxhighlight lang="cpp"><br />
class Class2;//предопределение Class2<br />
<br />
Class1<br />
{<br />
Class2* m_p2;//компилятор разрешит объявление указателя Class2*<br />
<br />
void F1(Class2* p);//компилятор разрешит объявление указателя Class2*<br />
void F2(Class1* p);<br />
};<br />
</syntaxhighlight><br />
<br />
файл "class1.cpp"<br />
<syntaxhighlight lang="cpp"><br />
#include "class1.h"<br />
#include "class2.h"<br />
<br />
void Class1::F1(Class2* p)<br />
{<br />
...<br />
}<br />
<br />
void Class1::F2(Class1* p)<br />
{<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
файл "class2.h"<br />
<syntaxhighlight lang="cpp"><br />
class Class1;//предопределение Class1<br />
<br />
Class2<br />
{<br />
Class1* m_p1;//компилятор разрешит объявление указателя Class1*<br />
<br />
void F3(Class1* p);//компилятор разрешит объявление указателя Class1*<br />
};<br />
</syntaxhighlight><br />
<br />
<br />
файл "class2.cpp"<br />
<syntaxhighlight lang="cpp"><br />
#include "class2.h"<br />
#include "class1.h"<br />
<br />
void Class2::F3(Class1* p)<br />
{<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
После предопределения класса компилятор позволяет объявлять указатель на класс, так как переменная указателя на любой тип имеет всегда один и тот же размер.<br />
<br />
===Как переключить раскладку в другом (то есть в активном) процессе?===<br />
Для этого можно использовать функции<br />
<br />
* GetKeyboardLayout(...); // определить текущую раскладку<br />
* LoadKeyboardLayout(...); // загрузить новую раскладку<br />
* VerLanguageName(...); // получить строку с описанием языка<br />
<br />
Подробности - в MSDN<br />
<br />
===Как получить хендл элемента управления, зная его идентификатор?===<br />
Пример:<br />
Пусть элемент Edit лежит на окне CMyWnd.<br />
Тогда:<br />
<syntaxhighlight lang="cpp"><br />
void CMyWnd::некая_процедура()<br />
{<br />
//для MFC<br />
CEdit* ed=(CEdit* ) GetDlgItem(ID_EDIT1);<br />
HWND hwnd=ed->GetSafeHwnd();<br />
if(hwnd)<br />
{<br />
...<br />
}<br />
<br />
//для Win32 API<br />
HWND hwnd=GetDlgItem(m_hWnd,ID_EDIT1);<br />
if(hwnd)<br />
{<br />
...<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
===Как из дочернего окна закрыть приложение?===<br />
Для этого нужно послать родительскому окну сообщение WM_CLOSE:<br />
<br />
через указатель на родительское окно:<br />
<syntaxhighlight lang="cpp"><br />
pParent->PostMessage(WM_CLOSE);<br />
</syntaxhighlight><br />
<br />
при помощи хендла родительского окна:<br />
<syntaxhighlight lang="cpp"><br />
::PostMessage(pParent->m_hWnd,WM_CLOSE,(WPARAM)0,(LPARAM)0);<br />
</syntaxhighlight><br />
<br />
===Как корректно перевести тип BSTR в CString и наоборот?===<br />
<br />
# для конвертирования BSTR в CString нужно просто присвоить переменной типа CString переменную типа BSTR.<br />
Оператор "=" класса CString сам выполнит всю работу.<br />
<br />
# для конвертирования BSTR в CString нужно выполнить код:<br />
<br />
<syntaxhighlight lang="cpp"><br />
//указатель на будущий буфер с BSTR.<br />
BSTR bstrHE=0;<br />
// (По сути, BSTR определён как <br />
// typedef WCHAR* BSTR;<br />
// то есть указатель на 16-битный символ юникод)<br />
<br />
//строка для конвертации<br />
CString Str="мой текст";<br />
<br />
//Выделяем память и загружаем адрес блока в bstrHE<br />
bstrHE=Str.AllocSysString();<br />
<br />
//... <br />
//тут работаем с bstrHE[]<br />
//...<br />
<br />
//освобождаем память<br />
SysFreeString(bstrHE);<br />
</syntaxhighlight><br />
<br />
===Как получить доступ к графическим ресурсам элементов текущей темы оформления Windows?===<br />
<br />
Для этого нужно использовать функции<br />
<br />
* OpenThemeData(...);<br />
* DrawThemeBackground(...);<br />
* DrawFrameControl(...);<br />
* CloseThemeData(...);<br />
<br />
(подробности - в MSDN)<br />
<br />
===Имеется класс, производный от CDialog. Когда диалог в фокусе, нажатие на Enter или Esc приводит к закрытию диалога. Как это запретить?===<br />
При нажатии Enter происходит выполнение команды IDOK,при нажатии Esc - IDCANCEL.<br />
<br />
Нужно переопределить в классе виртуальные функции OnOk() и OnCancel(), которые соответственно вызываются для этих команд. При помощи визарда эти функции добавить можно так:<br />
<br />
Положить на диалог две кнопки с идентификаторами IDOK и IDCANCEL (при создании нового диалога они там есть сразу), затем двойной щелчок по кнопке добавит соответствующий обработчик. В обработчиках надо удалить вызовы СDialog::OnOK() и CDialog::OnCancel(), тогда диалог закрываться не будет.<br />
<br />
Однако тогда диалог станет невозможно закрыть кнопкой с крестиком. Это обходится так: добавляем обработчик сообщения WM_CLOSE - OnClose(), и в нём делаем вызов OnOk() или OnCancel():<br />
<syntaxhighlight lang="cpp"><br />
void CPlayersPropsDialog::OnClose() <br />
{<br />
CDialog::OnClose();<br />
CDialog::OnCancel();//добавлено<br />
}<br />
</syntaxhighlight><br />
<br />
===Я написал в VC++ простейший макрос, где невозможно ошибиться, а компилятор всё же выдаёт ошибку. Не пойму, в чём дело?===<br />
<br />
Скорее всего после одного из символов соединения строк "\" имеется пробел или табуляция. Их надо удалить. Можно найти их "на ощупь", а можно включить показ непечатных символов в студии. Найти эту команду можно так:<br />
<br />
Tools->Customize...->вкладка Commands. В окошке Category выбрать "Edit", и среди кнопок справа найти кнопку, на которой написано "a.b"<br />
<br />
Эту кнопку надо перетащить на одну из панелей инструментов студии.<br />
<br />
===Как получить список всех процессов, включая idle?===<br />
<br />
Использовать функции<br />
* Process32First(...);<br />
* Precess32Next(...);<br />
<br />
(подробности - в MSDN)<br />
<br />
===Как программно установить переменные окружения?===<br />
Чтобы добавить или изменить их программно, необходимо воспользоваться ключом реестра<br />
<syntaxhighlight lang="cpp"><br />
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment<br />
</syntaxhighlight><br />
<br />
Затем нужно отправить широковещательное сообщение WM_SETTINGCHANGE (это позволит приложениям узнать об изменениях):<br />
<syntaxhighlight lang="cpp"><br />
::SendMessage(HWND_BROADCAST,WM_SETTINGCHANGE,0,0);<br />
</syntaxhighlight><br />
<br />
<br />
===Как сделать, чтобы у окна был черный фон?===<br />
Нужно переопределить обработчик сообщения WM_CTLCOLOR - OnCtlColor():<br />
<br />
<syntaxhighlight lang="cpp"><br />
//глобальная переменная или член класса CMyDlg,<br />
// инициализированный в OnInitDialog()<br />
CBrush br(RGB(0,0,0));<br />
<br />
<br />
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
HBRUSH hbr = CMyDlg::OnCtlColor(pDC, pWnd, nCtlColor);<br />
<br />
//фон диалога (или View)<br />
if(nCtlColor==CTLCOLOR_DLG)<br />
{<br />
return (HBRUSH)br;<br />
}<br />
<br />
//фон элементов SCtatic, лежащих на форме (если нужно)<br />
if(nCtlColor==CTLCOLOR_STATIC)<br />
{<br />
//делаем фон текста статика прозрачным<br />
pDC->SetBkMode(TRANSPARENT);<br />
return (HBRUSH)br;<br />
}<br />
<br />
return hbr;<br />
}<br />
</syntaxhighlight><br />
<br />
===Почему на моем компьютере экзешник, созданный в MFC запускается, а на других компьютерах - нет? Требует какую-то dll-ку.===<br />
Нужно выбирать режим Release:<br />
<br />
Menu->Build->Configurations...->Release,<br />
<br />
и экзешник, соответственно, брать из папки Release проекта.<br />
<br />
===Как в диалог добавить меню?===<br />
Нужно создать в редакторе ресурсов новое меню, затем вставить его в диалог:<br />
<br />
# открыть в редакторе диалог,<br />
# в свойствах (во вкладке General, окошко Menu) указать идентификатор ресурса меню.<br />
# при помощи визарда добавить для меню обработчики OnCommand() и OnUpdateСommand().<br />
<br />
===Почему не вызывается OnUpdate для пунктов меню (не получается ни затенить, ни отметку поставить)?===<br />
В диалоге (CDialog) у меню апдейт не происходит сам, в отличие от мейнфрейма (CFrameWnd). Для этого нужно сделать самим апдейт в обработчике сообщения WM_KICKIDLE.<br />
<br />
Визардом этот обработчик не добавляется, поэтому можно переопределить виртуальную DefWindowProc() и там обработать:<br />
<syntaxhighlight lang="cpp"><br />
#include <afxpriv.h> //этот файл надо включить, там определёна WM_KICKIDLE<br />
<br />
LRESULT CMyDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
if(message==WM_KICKIDLE)<br />
{<br />
//делаем апдейт для всех пунктов меню<br />
CMenu* pMainMenu=GetMenu();<br />
if(pMainMenu)<br />
{<br />
CCmdUI cmdUI;<br />
for(UINT n=0; n < pMainMenu->GetMenuItemCount(); n++)<br />
{<br />
CMenu* pSubMenu = pMainMenu->GetSubMenu(n);<br />
if(!pSubMenu)continue;<br />
<br />
cmdUI.m_nIndexMax = pSubMenu->GetMenuItemCount();<br />
for(UINT i=0; i<cmdUI.m_nIndexMax; i++)<br />
{<br />
cmdUI.m_nIndex = i;<br />
cmdUI.m_nID = pSubMenu->GetMenuItemID(i);<br />
cmdUI.m_pMenu = pSubMenu;<br />
cmdUI.DoUpdate(this, FALSE);<br />
}<br />
}<br />
}<br />
}<br />
<br />
return CDialog::DefWindowProc(message, wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
===Как в главном окне отключить системное меню (в левом верхнем углу) и кнопки(в правом верхнем углу)?===<br />
При создании окна нужно убрать стиль WS_SYSMENU (теперь пользователь корректно может закрыть окно только Alt+F4, ну или если вы предоставите ему дополнительную возможность сделать это)<br />
<br />
Пример 1. (для SDI, MDI)<br />
<syntaxhighlight lang="cpp"><br />
//этот обработчик уже добавлен визардом<br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
if( !CFrameWnd::PreCreateWindow(cs) )<br />
return FALSE;<br />
// TODO: Modify the Window class or styles here by modifying<br />
// the CREATESTRUCT cs<br />
<br />
///////////////////////////////<br />
//добавленная часть<br />
{<br />
//убираем стиль<br />
cs.style&=~WS_SYSMENU;<br />
}<br />
///////////////////////////////<br />
<br />
return TRUE;<br />
}<br />
</syntaxhighlight><br />
<br />
Пример 2. (для диалога)<br />
<br />
Если диалог описан в ресурсах, то в свойствах диалога убрать галочки<br />
<br />
* "System menu"<br />
* "Minimize box"<br />
* "Maximize box"<br />
<br />
===Как запретить пользователю нажать на кнопку?===<br />
Нужно применить метод класса CWnd::EnableWindow(...) для кнопки. Значение параметра 0 делает кнопку неактивной, 1 - делает активной (кстати, не только для кнопки можно, а для любого класса, производного от класса CWnd).<br />
<br />
<br />
Пусть имеется некий диалог, на нём лежит кнопка c ID == IDC_1. В любом месте кода диалога (кроме конструктора и деструктора, хотя, если проверить наличие валидного хендла диалога, как в примере, то ничего страшного не будет и там) выполняем код<br />
<syntaxhighlight lang="cpp"><br />
//делаем кнопку неактивной<br />
if(m_hWnd)<br />
{<br />
CWnd* pw=0;<br />
pw=GetDlgItem(IDC_1);<br />
if(pw)<br />
{<br />
pw->EnableWindow(0);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
===Что означают сообщения, которые студия выводит при компиляции, вроде таких: Loaded 'C:\WINDOWS\SYSTEM\WSOCK32.DLL', no matching symbolic information found. ===<br />
Это строка говорит о том, что студия не смогла найти отладочные символы для WSOCK32.DLL. В этом нет ничего страшного, просто при наличии отладочных символов в процессе отладки можно получить доступ к именам функции из системных DLL. Например, вместо<br />
<syntaxhighlight lang="cpp"><br />
KERNEL32! 0x77E8B184()<br />
</syntaxhighlight><br />
увидим<br />
<br />
<syntaxhighlight lang="cpp"><br />
KERNEL32!CreateThread.<br />
</syntaxhighlight><br />
<br />
===Как обработать сообщения, которое приходит к некому элементу управления?===<br />
Скажем, нужно обработать сообщения, приходящие к элементу класса CEdit. Нужно произвести от CEdit свой класс, и в виртуальной процедуре класса WindowProc перехватить нужные сообщения.<br />
<syntaxhighlight lang="cpp"><br />
virtual LRESULT WindowProc(<br />
UINT message,<br />
WPARAM wParam,<br />
LPARAM lParam <br />
);<br />
</syntaxhighlight><br />
<br />
Пример. Полностью выключаем, скажем, обработку сообщения WM_CHAR<br />
<syntaxhighlight lang="cpp"><br />
LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
switch(message)<br />
{<br />
case WM_CHAR:<br />
{<br />
return 0;<br />
}<br />
break;<br />
}<br />
<br />
return CEdit::WindowProc(message, wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
Чтобы связать экземпляр класса с элементом управления на форме, добавьте визардом для<br />
элемента управления переменную класса (выбрав не Value а Control).<br />
<br />
===Как настроить количество пробелов в табуляции?===<br />
Есть пара способов:<br />
<br />
# Tools->Options->Tabs->Insert Spaces<br />
# правой кнопкой мыши щёлкнуть по тексту, в контекстном меню выбрать properties<br />
<br />
===Как автоматически расставить отступы?===<br />
Нужно в студии выделить текст для форматирования, нажать Alt+F8.<br />
<br />
Ещё есть программа Artistic Style ( http://sourceforge.net/projects/astyle/ ), которая занимается переформатированием кода.<br />
<br />
===Поиск границ блока===<br />
Сочетание клавиш CTRL+ "}" ищет парную фигурную скобку в тексте и переходит к ней.<br />
<br />
===Вертикальное выделение текста===<br />
Если удерживать клавишу Alt, а затем начать выделять текст мышкой, то область выделения принимает форму прямоугольника, что позволяет выделять вертикальные фрагменты текста.<br />
<br />
===Как узнать количество установленных в CListCtrl столбцов?===<br />
Пример<br />
<syntaxhighlight lang="cpp"><br />
//указатель на переменную-элемент управления<br />
CListCtrl* pL=...;<br />
<br />
//получаем количество столбцов<br />
int count=pL->GetHeaderCtrl()->GetItemCount();<br />
</syntaxhighlight><br />
<br />
===Как получить иконку приложения?===<br />
Если приложение запущено, то нужно найти его главное окно и послать ему сообщение WM_GETICON.<br />
<syntaxhighlight lang="cpp"><br />
//функция возвращант хендл иконки <br />
LRESULT SendMessage(hWnd, WM_GETICON, wParam, 0);<br />
<br />
//hWnd == хендл окна приложения<br />
//wParam == <br />
// 1)==ICON_BIG - получить большую иконку<br />
// 2)==ICON_SMALL - получить маленькую иконку<br />
// 3)==ICON_SMALL2 - получить маленькую иконку, если она определена<br />
// в приложении. Если её нет, то маленькую иконку, <br />
// сгенерированную системой из большой иконки<br />
</syntaxhighlight><br />
<br />
===Как в CString можно найти или вырезать часть строки?===<br />
Это можно сделать при помощи методов класса CString:<br />
<syntaxhighlight lang="cpp"><br />
//вырезает кусок строки<br />
CString Mid(int nFirst) const;<br />
CString Mid(int nFirst, int nCount) const;<br />
<br />
//возвращает кусок строки (сначала или с конца)<br />
CString Left(int nCount ) const;<br />
CString Right(int nCount ) const;<br />
<br />
//возвращает начальный кусок строки, в котором есть только<br />
//символы из набора, представленного в lpszCharSet<br />
CString SpanIncluding(LPCTSTR lpszCharSet ) const;<br />
<br />
//возвращает начальный кусок строки, в котором нет<br />
//символов из набора, представленного в lpszCharSet<br />
CString SpanExcluding(LPCTSTR lpszCharSet ) const; <br />
<br />
//убирает "пробелоподобные" символы из самого начала строки<br />
//(то есть - пробел, табуляцию (\t), возврат каретки, перевод строки (/r/n))<br />
void TrimLeft();<br />
//убирает все повторы символа из самого начала строки<br />
void TrimLeft(TCHAR chTarget );<br />
//убирает из самого начала строки все символа из набора lpszTargets <br />
void TrimLeft(LPCTSTR lpszTargets );<br />
<br />
void TrimRight();<br />
void TrimRight(TCHAR chTarget );<br />
void TrimRight(LPCTSTR lpszTargets );<br />
<br />
//поиск в строке<br />
int Find( TCHAR ch ) const;<br />
int Find( LPCTSTR lpszSub ) const;<br />
int Find( TCHAR ch, int nStart ) const;<br />
int Find( LPCTSTR pstr, int nStart ) const;<br />
<br />
//поиск, начиная с конца<br />
int ReverseFind( TCHAR ch ) const;<br />
<br />
//поиск позиции первого символа, одного из набора,<br />
// представленного в lpszCharSet<br />
int FindOneOf( LPCTSTR lpszCharSet ) const;<br />
</syntaxhighlight><br />
<br />
===Как отобразить на элементах управления промежуточные результаты длительных вычислений?===<br />
В общем случае это делается принудительной перерисовкой нужного окна путём объявления этого окна невалидным<br />
<syntaxhighlight lang="cpp"><br />
pWnd->Invalidate(0);<br />
</syntaxhighlight><br />
а затем непосредственной отсылки в оконную процедуру сообщения WM_PAINT<br />
<syntaxhighlight lang="cpp"><br />
pWnd->UpdateWindow();<br />
</syntaxhighlight><br />
<br />
Пример:<br />
<syntaxhighlight lang="cpp"><br />
CWnd* pWnd=...;//окно, которое надо перерисовывать<br />
<br />
for(int i=0; i<10000; i++)<br />
{<br />
//меняется содержимое окна<br />
//...<br />
<br />
//немедленная перерисовка<br />
pWnd->Invalidate(0);<br />
pWnd->UpdateWindow();<br />
}<br />
</syntaxhighlight><br />
<br />
Также можно также просто вызвать метод RedrawWindow() с параметрами по умолчанию.<br />
<br />
===Я написал DLL, которую используют несколько приложений. Всё вроде работает, но когда происходит очередной вызов функции из DLL, почему то данные в функции обнуляются. С чем это связано?===<br />
Переменные и массивы в DLL, содержимое которых должно использоваться несколькими процессами, должны объявляться статическими. Статическая переменная или массив инициализируются только один раз в момент загрузки DLL.<br />
Пример:<br />
<syntaxhighlight lang="cpp"><br />
DWORD calltest()<br />
{<br />
//будет выполнено только при первом вызове<br />
static DWORD callcount=0;<br />
static DWORD str[1000]={0}; <br />
<br />
//будет выполняться каждый раз<br />
callcount++;<br />
return callcount;<br />
}<br />
</syntaxhighlight><br />
<br />
===Как открыть проекцию файла в память и как с ней работать?===<br />
<br />
Создание проекции:<br />
<syntaxhighlight lang="cpp"><br />
HANDLE CreateFileMapping(<br />
HANDLE hFile, //хендл уже открытого файла<br />
LPSECURITY_ATTRIBUTES lpAttributes,<br />
DWORD flProtect, //способ открытия проекции<br />
DWORD dwMaximumSizeHigh, //размер файла (старшие 4 байта, обычно==0)<br />
DWORD dwMaximumSizeLow, //размер файла (младшие 4 байта)<br />
LPCTSTR lpName<br />
);<br />
</syntaxhighlight><br />
<br />
Доступ к созданной проекции производится процедурой:<br />
<syntaxhighlight lang="cpp"><br />
LPVOID MapViewOfFile(<br />
HANDLE hFileMappingObject, //хендл проекции<br />
DWORD dwDesiredAccess, //способ работы с проекцией<br />
DWORD dwFileOffsetHigh,<br />
DWORD dwFileOffsetLow, //смещение от начала файла (младшие 4 байта)<br />
SIZE_T dwNumberOfBytesToMap //длина в байтах (если ==0 - то весь файл)<br />
);<br />
</syntaxhighlight><br />
<br />
далее с файлом можно работать как с обычным массивом в памяти.<br />
<br />
После работы с проекцией, её надо освободить процедурой<br />
<syntaxhighlight lang="cpp"><br />
BOOL UnmapViewOfFile(<br />
LPCVOID lpBaseAddress //адрес, который вернула процедура MapViewOfFile<br />
);<br />
</syntaxhighlight><br />
<br />
Пример:<br />
<syntaxhighlight lang="cpp"><br />
HANDLE hFile=...;//хендл уже открытого файла<br />
DWORD dwdFileLen=...;//размер открытого файла<br />
<br />
HANDLE hMapFile=0;//хендл для проекции<br />
<br />
//создаём проекцию "только для чтения"<br />
hMapFile=::CreateFileMapping(hFile,0,PAGE_READONLY,0,dwdFileLen,0);<br />
<br />
//хендл hFile можно закрыть уже здесь, в принципе,<br />
//но мы сделаем это позже<br />
<br />
//получаем доступ к проекции (тоже только для чтения)<br />
BYTE* pbyFile=(BYTE*)::MapViewOfFile(hMapFile,FILE_MAP_READ,0,0,0);<br />
<br />
///////////////////<br />
//тут работаем с массивом pbyFile[dwdFileLen] как с обычным,<br />
//только не забываем, что он открыт только для чтения<br />
//...<br />
//...<br />
//...<br />
///////////////////<br />
<br />
//отключаем файл данных от адресного пространства<br />
UnmapViewOfFile(pbyFile);<br />
<br />
//освобождаем хендл проекции<br />
CloseHandle(hMapFile)<br />
<br />
//освобождаем хендл открытого файла<br />
CloseHandle(hFile);<br />
</syntaxhighlight><br />
<br />
===Как в MFC Grid control отобразить картинку в ячейке?===<br />
Нужно создать список изображений (CImageList), затем передать указатель на список в таблицу. Поскольку элемент управления лишь копирует указатель, список должен создаваться динамически, либо быть членом класса, экземпляр которого существует всё время работы таблицы.<br />
<syntaxhighlight lang="cpp"><br />
CImageList m_ImageList;<br />
CGridCtrL m_Grid1;<br />
...<br />
...<br />
//неким образом создаётся список<br />
m_ImageList.Create(...);<br />
//...<br />
<br />
//вставляем в элемент управления<br />
m_Grid1.SetImageList(&m_ImageList);<br />
<br />
//<br />
</syntaxhighlight><br />
<br />
===Как при помощи IPicture отобразить картинку из файла? ===<br />
Пример - несложная функция, отображающая картинку из файла. Поддерживаются форматы BMP, GIF, JPEG, PNG, TIFF, EMF<br />
<syntaxhighlight lang="cpp"><br />
#include "atlconv.h"<br />
#define HandleIsValid(H) (H!=(HANDLE)-1 && H!=(HANDLE)0)<br />
<br />
//*pDestDC - CDC, на который предполагается вывод картинки<br />
//pchzFilePath - путь к файлу<br />
//pWid - (возвращает) ширина картинки<br />
//pHig - (возвращает) высота картинки<br />
bool DrawBitmapFromFile(CDC* pDestDC,const char* pchzFilePath,int *pWid=0,int *pHig=0)<br />
{<br />
bool result=false;<br />
<br />
if(pWid)*pWid=0;<br />
if(pHig)*pHig=0;<br />
<br />
int Wid=0;<br />
int Hig=0;<br />
<br />
IPicture* pPic=0;<br />
try<br />
{<br />
IPicture* ptmpPic=0;<br />
USES_CONVERSION;<br />
HRESULT hr;<br />
<br />
CString txt=pchzFilePath;<br />
hr=::OleLoadPicturePath(<br />
const_cast<LPOLESTR>(T2COLE(txt)),<br />
0,0,0,IID_IPicture,<br />
reinterpret_cast<void **>(&ptmpPic)<br />
);<br />
<br />
if(hr==S_OK && ptmpPic)<br />
{<br />
pPic=ptmpPic;<br />
}<br />
else<br />
{<br />
throw 0;<br />
}<br />
<br />
OLE_XPOS_HIMETRIC cxSrc;<br />
OLE_YPOS_HIMETRIC cySrc;<br />
<br />
if(S_OK!=pPic->get_Width(&cxSrc))<br />
{<br />
throw 0;<br />
}<br />
<br />
if(S_OK!=pPic->get_Height(&cySrc))<br />
{<br />
throw 0;<br />
}<br />
<br />
Wid=cxSrc/26;<br />
Hig=cySrc/26;<br />
<br />
//рисуем<br />
if(S_OK !=pPic->Render(pDestDC->GetSafeHdc(),<br />
0,Hig,Wid,-Hig,0,0,cxSrc,cySrc,0))<br />
{<br />
throw 0;<br />
}<br />
}<br />
catch(...)<br />
{<br />
result=false;<br />
}<br />
<br />
if(pPic)<br />
{<br />
pPic->Release();<br />
pPic=0;<br />
}<br />
<br />
<br />
if(pWid)<br />
{<br />
*pWid=Wid;<br />
}<br />
<br />
if(pHig)<br />
{<br />
*pHig=Hig;<br />
}<br />
<br />
return result;<br />
}<br />
</syntaxhighlight><br />
<br />
===Как позволить пользователю начать ввод новой строки в многострочном поле редактирования?===<br />
Нужно в редакторе ресурсов поставить для свойств окошка CEdit галочку "WantReturn" или добавить стиль ES_WANTRETURN при создании CEdit элемента управления динамически. Тогда при нажатии Enter в поле редактирования будет вводиться новая строка.<br />
<br />
===Как выводят картинку-логотип(splash screen) при запуске программы?===<br />
Для этого используется класс, производный от CDialog. Этот диалог после создания показывает себя на экран, выводя на себя рисунок. Также запускает таймер, по срабатывани которого диалог гасится. Создаётся диалог в процедуре InitInstance приложения.<br />
<br />
В VC6++ также есть уже готовый компонент<br />
<br />
Project->Add To Project -> Components and Controls->(в папке "Visual C++ Components" есть SplashScreen.)<br />
<br />
===Как сделать, чтобы при выпадении списка у ComboBox была не одна строка, а больше, вроде все свойства покрутил, не помогает Вместо выпадающего списка одна строка и скролл...===<br />
В редакторе ресурсов надо щелкнуть в комбобоксе на треугольнике - появляется рамка для растягивания вниз - размер выпадающего списка.<br />
<br />
===В VC++.net, что делать после того, как на форму установил ActiveX ListView, как объявить класс и переменную для этого элемента?===<br />
Щёлкнуть правой кнопкой мыши на элементе, в меню - add variable или add class<br />
<br />
===Как работать с буфером обмена (Clipboard)?===<br />
<br />
====КОПИРОВАНИЕ В БУФЕР ОБМЕНА====<br />
<br />
Алгоритм:<br />
# Готовим данные<br />
#* Выделяем память из кучи, вызывая GlobalAlloc()<br />
#* Получаем указатель на выделенную память, вызывая GlobalLock()<br />
#* Заполняем данные<br />
#* Освобождаем указатель, вызывая GlobalUnlock();<br />
# Открываем буфер обмена, вызывая OpenClipboard();<br />
# Очищаем буфер, вызывая EmptyClipboard();<br />
# Вызываем SetClipboardData() один раз для каждого формата вставляемых данных (имеется в виду - если одни и те же данные представлены в разных форматах, и приложение может эти форматы создать)<br />
# Закрываем буфер, вызывая CloseClipboard();<br />
# ВЫЗЫВАТЬ GlobalFree() НЕ НУЖНО, в этом случае это предоставлено системе<br />
<br />
Скажем, хотим поместить в буфер обмена текст.<br />
<syntaxhighlight lang="cpp"><br />
//готовим данные<br />
//выделяем из кучи память для данных<br />
HANDLE hglbCopy = GlobalAlloc(GMEM_MOVEABLE,10);<br />
if(!hglbCopy)return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)return;<br />
<br />
//заполняем данные<br />
strcpy((char*)lpStr,"my text");<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
//очищаем<br />
EmptyClipboard();<br />
<br />
//текстовый формат<br />
SetClipboardData(CF_TEXT,hglbCopy);<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</syntaxhighlight><br />
<br />
<br />
<br />
====ИЗВЛЕЧЕНИЕ ИЗ БУФЕРА ОБМЕНА====<br />
<br />
Алгоритм:<br />
# Проверяем, что поддерживается нужный формат данных, вызывая IsClipboardFormatAvailable()<br />
# Открываем буфер обмена, вызывая OpenClipboard();<br />
# Достаём данные<br />
#* Получаем из буфера хендл требуемого формата, вызывая GetClipboardData()<br />
#* Получаем указатель на выделенную память, вызывая GlobalLock()<br />
#* Работаем с данными<br />
#* Освобождаем указатель, вызывая GlobalUnlock();<br />
# Закрываем буфер, вызывая CloseClipboard();<br />
<br />
Скажем, хотим извлечь из буфера обмена текст.<br />
<syntaxhighlight lang="cpp"><br />
//Проверяем, что поддерживается нужный формат данных,<br />
if(!IsClipboardFormatAvailable(CF_TEXT))return;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
<br />
//достаём данные<br />
<br />
//текстовый формат<br />
HANDLE hglbCopy = GetClipboardData(CF_TEXT);<br />
if(!hglbCopy)return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)return;<br />
<br />
//читаем данные<br />
char data[10];<br />
memmove(data,lpStr,sizeof(data));<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</syntaxhighlight><br />
<br />
<br />
===Как получить полный путь к экзешнику из самой программы?===<br />
Можно прочитать параметры командной строки - в командную строку первым параметром система всегда передаёт заключённый в кавычки полный путь к файлу запущенной программы. Достаём путь следующим образом:<br />
<syntaxhighlight lang="cpp"><br />
BOOL CMyApp::InitInstance()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName содержит искомый путь<br />
<br />
//...<br />
//...<br />
}<br />
</syntaxhighlight><br />
<br />
===Каким способом exe файл может заменить самого себя? ===<br />
<br />
К примеру, программа должна обновляется через Internet и хочет обновить свой exe-файл. Но так как он в данный момент запущен, это будет, естественно, невозможно сделать напрямую.<br />
Один из способов - сделать копию экзешника и из него обновиться<br />
<br />
<syntaxhighlight lang="cpp"><br />
#define def_exeNAMEup "c:\\myprog_toupdate.exe" //путь к старому файлу<br />
#define def_exeNAMEdnld "c:\\myprog_downloaded.exe" //путь к новому файлу (уже "скачали":) )<br />
#define def_keyUdate "/update"<br />
<br />
void CTESTFAQApp::UpdateItself()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName - содержит искомый путь<br />
<br />
//делаем копию экзешника с другим именем<br />
CopyFile(csFullExeName,def_exeNAMEup,0);<br />
<br />
//передаём в параметры нового процесса ключ и путь к текущему файлу<br />
CString csParams=def_keyUdate;<br />
csParams+=" ";<br />
csParams+=csFullExeName;<br />
<br />
//запускаем копию<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(def_exeNAMEup,def_keyUdate,0,0,0,0,0,0,&si,&pi))<br />
{<br />
//завершаем текущий процесс<br />
ExitFromMyApp();<br />
}<br />
}<br />
<br />
void CTESTFAQApp::ExitFromMyApp()<br />
{<br />
exit(0);<br />
}<br />
<br />
BOOL CTESTFAQApp::InitInstance()<br />
{<br />
//смотрим, не запущено ли для апдейта?<br />
CString txt;<br />
txt=m_lpCmdLine;<br />
if(txt.Find(def_keyUdate)==0)<br />
{<br />
//делаем айдейт<br />
txt.Replace(def_keyUdate,"");<br />
txt.TrimLeft();<br />
<br />
CString csFullExeName=txt;<br />
<br />
//берём откуда то уже скачанный файл обновления<br />
//...<br />
CString csFull_Downloaded_ExeName=def_exeNAMEdnld;<br />
<br />
//копируем файл (обновляем старый то есть)<br />
CopyFile(csFull_Downloaded_ExeName,csFullExeName,0);<br />
<br />
//запускаем обновлённого мученника<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(csFullExeName,0,0,0,0,0,0,0,&si,&pi))<br />
<br />
ExitFromMyApp();<br />
<br />
}<br />
//...<br />
//...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как производится конвертация из кодировки UTF8 в 1251 и наоборот?===<br />
<br />
Можно перевести строку из UTF8 в Unicode, затем из Unicode в 1251<br />
<br />
Ниже приведена структура, содержащая процедуры перекодирования,<br />
а также процедуру с примером использования<br />
<syntaxhighlight lang="cpp"><br />
//описание структуры<br />
struct coder<br />
{<br />
//utf8->unicode<br />
static wchar_t* utf8_to_unicode__dontForgetDeleteArr(const char *utf8_string)<br />
{<br />
wchar_t* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len=MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,0,0);<br />
if(!res_len)<br />
{<br />
return 0;<br />
}<br />
<br />
//выделяем память<br />
pRes = new wchar_t[res_len];<br />
if(!pRes)<br />
{<br />
return 0;<br />
}<br />
<br />
//преобразование<br />
if(!MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,pRes,res_len))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//unicode->1251<br />
static char * unicode_to_1251__dontForgetDeleteArr(const wchar_t *unicode_string)<br />
{<br />
char* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len = WideCharToMultiByte(1251,0,unicode_string,-1,0,0,0,0);<br />
if(!res_len)<br />
{<br />
return 0;<br />
}<br />
<br />
//выделяем память<br />
pRes=new char[res_len];<br />
if(!pRes)<br />
{<br />
return 0;<br />
}<br />
<br />
//преобразование<br />
if(!WideCharToMultiByte(1251,0,unicode_string,-1,pRes,res_len,0,0))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//процедура с примером<br />
static void Example()<br />
{<br />
wchar_t* unicode_string=0;<br />
char* cp1251_string=0;<br />
<br />
//исходный текст<br />
char utf8_string[] = "UTF-8 + русский текст";<br />
<br />
for(;;)<br />
{<br />
<br />
unicode_string=utf8_to_unicode__dontForgetDeleteArr(utf8_string);<br />
if(!unicode_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать в unicode!");<br />
break;<br />
}<br />
<br />
cp1251_string = unicode_to_1251__dontForgetDeleteArr(unicode_string);<br />
<br />
if(!cp1251_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать из unicode!");<br />
break;<br />
}<br />
<br />
break;<br />
}<br />
<br />
//cp1251_string - результат<br />
AfxMessageBox(cp1251_string);<br />
<br />
//не забываем удалить массивы<br />
if(unicode_string)<br />
{<br />
delete [] unicode_string;<br />
unicode_string=0;<br />
}<br />
<br />
if(cp1251_string)<br />
{<br />
delete [] cp1251_string;<br />
cp1251_string=0;<br />
}<br />
}<br />
};<br />
<br />
//вызов примера<br />
coder::Example();<br />
</syntaxhighlight><br />
<br />
===Как работать с базой данных Access из программы на VC.net?===<br />
Проще всего подключить ADO компоненты и сделать все на них.<br />
<br />
Компоненты ADO (ADODC,DATAGRID и т.п.) это ActiveX.<br />
<br />
В редакторе ресурсов, во всплывающем меню, есть Insert ActiveX Control -> открывается список всех компонент, зарегистрированных на машине. Нужно найти компоненты (Это компоненты от MS и они помечены (OLEDB)) и вставить их в диалог. Для того что бы иметь возможность управлять ими, нужно импортировать обертки для них, это делается при помощи ClassWizard, там есть импорт->класс->указать файл с компонентой (OSX). Появляется список всех классов, объявленных внутри.<br />
<br />
Расставляем нужные галочки, нажимаем ОК.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_2&diff=613FAQ:WinAPI, VCPP Part 22008-10-23T19:01:18Z<p>Алексей1153++: </p>
<hr />
<div>===Как сделать обработчик сообщения для нескольких элементов управления сразу?===<br />
<br />
Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand():<br />
<br />
<syntaxhighlight lang="cpp"><br />
BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam)<br />
{<br />
//командное сообщение<br />
WORD wMess=(wParam >> 16);<br />
<br />
//ID элемента управления<br />
int nID=(int)(wParam &0x0000ffff));<br />
<br />
//хендл элемента управления<br />
HWND hW=(HWND)lParam;<br />
<br />
// смотрим, какой элемент управления<br />
switch (nID)<br />
{<br />
//CButton (кнопки, переключатели, флажки)<br />
case ID_BN1:<br />
case ID_BN2:<br />
case ID_BN3:<br />
{<br />
//смотрим, какое сообщение<br />
switch (wMess)<br />
{<br />
case BN_CLICKED:<br />
{<br />
...<br />
}<br />
break;<br />
}<br />
}<br />
break;<br />
<br />
//CEdit<br />
case ID_ED1:<br />
case ID_ED2:<br />
case ID_ED3:<br />
case ID_ED4:<br />
{<br />
// смотрим, какое сообщение<br />
switch (wMess)<br />
{<br />
case EN_CHANGE:<br />
{<br />
...<br />
}<br />
break;<br />
<br />
case EN_KILLFOCUS:<br />
{<br />
...<br />
}<br />
break;<br />
}<br />
}<br />
break;<br />
}<br />
<br />
return CDialog::OnCommand(wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
===Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать?===<br />
<br />
Лечится проблема так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются.<br />
<br />
===Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы?===<br />
<br />
Нужно использовать функцию GetModuleFileName():<br />
<br />
<syntaxhighlight lang="cpp"><br />
TCHAR pszFileName[MAX_PATH];<br />
pszFileName[0]=0;<br />
<br />
GetModuleFileName(NULL, pszFileName, MAX_PATH);<br />
CString stModulePath=pszFileName;<br />
<br />
// ищем первый слеш с конца и удаляем<br />
// его вместе с именем файла EXE<br />
int nEnd=stModulePath.ReverseFind('\\');//'<br />
stModulePath.Delete(nEnd, stModulePath.GetLength() - nEnd);<br />
<br />
// stModulePath - содержит путь<br />
</syntaxhighlight><br />
<br />
===Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame?===<br />
<br />
<syntaxhighlight lang="cpp"><br />
#include "MainFrm.h"<br />
<br />
// CMyApp - класс вашего приложения. theApp - глобальная переменная,<br />
// поэтому для доступа к ней используем extern<br />
<br />
extern CMyApp theApp;<br />
<br />
void CMyView::F()<br />
{<br />
// Получаем главное окно приложения в любом месте программы<br />
CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);<br />
<br />
pMainFrame->m_wndDlgBar. ...; // Делаем что хотим<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
===Как загрузить и показать один из стандартных курсоров?===<br />
<br />
<syntaxhighlight lang="cpp"><br />
HCURSOR hCursor;<br />
<br />
hCursor=AfxGetApp()->LoadStandardCursor(IDC_UPARROW);<br />
<br />
if(hCursor)<br />
{<br />
SetCursor(hCursor);<br />
}<br />
</syntaxhighlight><br />
<br />
Идентификаторы стандартных курсоров:<br />
* IDC_ARROW<br />
* IDC_IBEAM<br />
* IDC_WAIT<br />
* IDC_CROSS<br />
* IDC_UPARROW<br />
* IDC_SIZENWSE<br />
* IDC_SIZENESW<br />
* IDC_SIZEWE<br />
* IDC_SIZENS<br />
* IDC_SIZEALL<br />
<br />
===Как запретить пользователю закрыть программу нажатием на кнопку с крестиком?===<br />
<br />
Для этого нужно добавить обработчик сообщения WM_CLOSE (функция OnClose() в MFC) в главное окно программы. Для диалоговых приложений такое окно - это главный диалог, для одно- и многодокументных приложений - это CMainFrame.<br />
<br />
<syntaxhighlight lang="cpp"><br />
void CMainFrame::OnClose()<br />
{<br />
if(...)<br />
{<br />
// не разрешаем закрыть<br />
return;<br />
}<br />
<br />
CFrameWnd::OnClose();<br />
}<br />
</syntaxhighlight><br />
<br />
===Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab?===<br />
<br />
Последовательность действий следующая:<br />
# Помещаем на форму нужное количество элементов RadioButton;<br />
# У первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство;<br />
# Порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется.<br />
<br />
===Где лучше устанавливать начальные значения элемента CComboBox?===<br />
<br />
Это можно сделать парой способов:<br />
# В редакторе форм - открыть свойства элемента CComboBox, "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter);<br />
# В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView).<br />
<br />
===Как перевести RichEdit в режим замены символов?===<br />
<br />
Имеется несколько способов.<br />
<br />
1. Программно, если известен хендл элемента (hWnd), это делается так:<br />
<br />
<syntaxhighlight lang="cpp"><br />
// помещаем сообщение WM_KEYDOWN с нужными параметрами <br />
//в конец очереди сообщений элемента управления <br />
::PostMessage(hWnd, WM_KEYDOWN, VK_INSERT, 1);<br />
</syntaxhighlight><br />
<br />
2. Пользователь во время работы может нажать клавишу Insert.<br />
<br />
===Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы?===<br />
<br />
Это можно сделать так:<br />
<br />
<syntaxhighlight lang="cpp"><br />
AfxGetApp()->m_pMainWnd->...;<br />
</syntaxhighlight><br />
<br />
или так<br />
<syntaxhighlight lang="cpp"><br />
extern CMyAppXXX theApp; // здесь CMyAppXXX - название класса вашего приложения<br />
theApp.m_pMainWnd->...;<br />
</syntaxhighlight><br />
<br />
===Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы?===<br />
<br />
Это можно сделать методом SetScaleToFitSize():<br />
<br />
<syntaxhighlight lang="cpp"><br />
void CMyView::OnInitialUpdate()<br />
{<br />
CFormView::OnInitialUpdate();<br />
<br />
// скрываем полосы прокрутки<br />
GetParentFrame()->RecalcLayout();<br />
<br />
// это уберёт полосы прокрутки со вьюхи<br />
ResizeParentToFit();<br />
<br />
SIZE s={0, 0};<br />
SetScaleToFitSize(s);<br />
// далее вызовется обработчик OnPaint(), о котором ниже<br />
<br />
//...<br />
}<br />
</syntaxhighlight><br />
<br />
Также обратите внимание на одну особенность: в отладочной версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s={0, 0} происходит с ошибкой (программа при этом завершается).<br />
Обходится это так:<br />
<br />
<syntaxhighlight lang="cpp"><br />
void CMyView::OnPaint()<br />
{<br />
#ifdef _DEBUG<br />
CPaintDC dc(this);<br />
#else<br />
CFormView::OnPaint();<br />
#endif<br />
}<br />
</syntaxhighlight><br />
<br />
Или так:<br />
<br />
<syntaxhighlight lang="cpp"><br />
void CMyView::OnPaint()<br />
{<br />
CPaintDC dc(this);<br />
}<br />
</syntaxhighlight><br />
<br />
===Как нарисовать прямоугольник с вертикальным цветовым градиентом?===<br />
<br />
Нужно задать граничные значения цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников, а, значит - плавность градиента, задаётся точностью.<br />
<br />
Пример:<br />
<br />
<syntaxhighlight lang="cpp"><br />
// вертикальный градиент<br />
// pdc - указатель на контекст устройства<br />
// pSize - указатель на структуру<br />
// SIZE с размером прямоугольника<br />
// dwdColor1, dwdColor2 - начальный и конечный цвет<br />
// bySteps - количество шагов градиента (1...255)<br />
void sFillVertGradientRect(CDC* pdc, SIZE *pSize, COLORREF dwdColor1,<br />
COLORREF dwdColor2, BYTE bySteps)<br />
{<br />
WORD i=0;<br />
long W=0;<br />
long H=0;<br />
long x1=0;<br />
long x2=0;<br />
<br />
BYTE R1=0;<br />
BYTE G1=0;<br />
BYTE B1=0;<br />
BYTE R2=0;<br />
BYTE G2=0;<br />
BYTE B2=0;<br />
<br />
float dh=0;<br />
float dR=0;<br />
float dG=0;<br />
float dB=0;<br />
float y1=0;<br />
float y2=0;<br />
float Rc=0;<br />
float Gc=0;<br />
float Bc=0;<br />
<br />
if(!bySteps)<br />
{<br />
bySteps=1;<br />
}<br />
<br />
//ширина и высота<br />
W=pSize->cx;<br />
H=pSize->cy;<br />
<br />
// раскладываем цвета на их составляющие<br />
// для удобства дальнейших вычислений<br />
R1=(BYTE)((dwdColor1 & 0x000000ff) );<br />
G1=(BYTE)((dwdColor1 & 0x0000ff00) >> 8 );<br />
B1=(BYTE)((dwdColor1 & 0x00ff0000) >> 16 );<br />
R2=(BYTE)((dwdColor2 & 0x000000ff) );<br />
G2=(BYTE)((dwdColor2 & 0x0000ff00) >> 8 );<br />
B2=(BYTE)((dwdColor2 & 0x00ff0000) >> 16 );<br />
<br />
// высота разноцветных прямоугольников<br />
dh=(float)H / (float)bySteps;<br />
<br />
// величина шагов составляющих цветов<br />
dR=(float)(R2 - R1) / (float)bySteps;<br />
dG=(float)(G2 - G1) / (float)bySteps;<br />
dB=(float)(B2 - B1) / (float)bySteps;<br />
<br />
// выводим прямоугольники<br />
x1=0;<br />
x2=W;<br />
y1=0;<br />
y2=dh;<br />
Rc=R1;<br />
Gc=G1;<br />
Bc=B1;<br />
<br />
for(i=0; i<bySteps; i++)<br />
{<br />
// текущий цвет<br />
pdc->FillSolidRect(<br />
x1,<br />
(int)y1,<br />
x2-x1,<br />
(int)(y2-y1),<br />
RGB((BYTE)Rc, (BYTE)Gc, (BYTE)Bc)<br />
);<br />
<br />
// следующий цвет и координаты<br />
y1+=dh;<br />
y2+=dh;<br />
Rc+=dR;<br />
Gc+=dG;<br />
Bc+=dB;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
Пример вызова:<br />
<br />
<syntaxhighlight lang="cpp"><br />
SIZE Size={100, 100};<br />
sFillGradientRect(&dc, &Size, RGB(200,0,0), RGB(0,200,0), 10);<br />
</syntaxhighlight><br />
<br />
===Как под Windows отслеживать изменение файла?===<br />
<br />
Нужно использовать функции:<br />
* FindFirstChangeNotification<br />
* FindNextChangeNotification<br />
* FindCloseChangeNotification<br />
<br />
(подробности - в MSDN)<br />
<br />
===Как конвертировать массив char[] в CString?===<br />
<br />
Это можно сделать методами самого класса CString:<br />
<br />
<syntaxhighlight lang="cpp"><br />
char buf[]="text";<br />
// строка должна обязательно заканчиваться нулём!!!<br />
<br />
// конвертируем так<br />
CString txt(buf);<br />
<br />
// или так<br />
CString txt;<br />
txt=buf;<br />
</syntaxhighlight><br />
<br />
===Как зарезервировать в CString буфер нужной длины?===<br />
<br />
Это можно сделать при помощи методов класса:<br />
<br />
<syntaxhighlight lang="cpp"><br />
CString::GetBuffer(...);<br />
</syntaxhighlight><br />
<br />
и<br />
<br />
<syntaxhighlight lang="cpp"><br />
CString::GetBufferSetLength(...);<br />
</syntaxhighlight><br />
<br />
Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку ''не меньше'' заданной длины, а второй возвращает строку, точно равную заданной длине. Обе могут перераспределять память, если необходимо. В обычных случаях лучше использовать GetBuffer.<br />
<br />
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе. "-1" удобно использовать, если известно, что строка заканчивается нулем.<br />
<br />
===Как передать больше одного параметр в процедуру потока?===<br />
<br />
Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру.<br />
<br />
Пример:<br />
<br />
<syntaxhighlight lang="cpp"><br />
struct mystr<br />
{<br />
CEdit* pEd;<br />
CDialog* pDlg;<br />
DWORD* pdwd;<br />
int *pn;<br />
};<br />
</syntaxhighlight><br />
<br />
запуск потока:<br />
<br />
<syntaxhighlight lang="cpp"><br />
mystr *pparam=new mystr; // экземпляр не должен быть временным!!!<br />
<br />
memset(pparam, 0, sizeof(*pparam));<br />
pparam->pEd=...;<br />
pparam->pdwd=...;<br />
<br />
::AfxBeginThread(thread, pparam);<br />
// тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как<br />
// он у нас удалился в процедуре потока<br />
</syntaxhighlight><br />
<br />
Процедура потока:<br />
<br />
<syntaxhighlight lang="cpp"><br />
// поток:<br />
UINT threadLoader(LPVOID pParam)<br />
{<br />
// копируем данные из структуры в локальную структуру<br />
mystr data=*((mystr*)pParam);<br />
// освобождаем память временной структуры<br />
delete ((mystr*)pParam);<br />
pParam=0;<br />
<br />
...<br />
data.pDlg->...;<br />
(*data.pdwd)=...;<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
===Как убрать главное меню из окна CMainFrame?===<br />
<br />
Это можно сделать в виртуальной функции PreCreateWindow:<br />
<br />
<syntaxhighlight lang="cpp"><br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
// обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow<br />
cs.hMenu=0;<br />
<br />
if(!CFrameWnd::PreCreateWindow(cs))<br />
{<br />
return FALSE;<br />
}<br />
<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
===Как работающая программа может определить, что пользователь завершает работу Windows?===<br />
<br />
Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу.<br />
<br />
===Как сделать всплывающую подсказку для класса CWnd и классов, от него производных?===<br />
<br />
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для элементов управления CStatic не забудьте поставить свойство Notify):<br />
<br />
<syntaxhighlight lang="cpp"><br />
class CMyDlg:puplic CDialog<br />
{<br />
CToolTipCtrl m_ToolTip; // мембер класса CMyDlg<br />
};<br />
<br />
// массив, в котором перечислены идентификаторы элементов управления<br />
// и тексты подсказок к ним<br />
struct<br />
{<br />
int ID;<br />
const char* pch;<br />
};<br />
<br />
m_a_Tips[]=<br />
{<br />
{IDC_BUTTON1, "Кнопка"},<br />
{IDC_STATIC1, "Текст"},<br />
{0, 0} // признак конца массива<br />
};<br />
<br />
// в инициализации диалога (хотя, в принципе,<br />
// можно и не тут) создаём и привязываем подсказки<br />
BOOL CMyDlg::OnInitDialog()<br />
{<br />
CDialog::OnInitDialog();<br />
<br />
// создаём элемент TOOLTIP<br />
m_ToolTip.Create(this);<br />
<br />
// Привязка подсказок<br />
for(int i=0; m_a_Tips[i].ID; i++)<br />
{<br />
m_ToolTip.AddTool(<br />
GetDlgItem(m_a_Tips[i].ID),<br />
m_a_Tips[i].pch<br />
);<br />
}<br />
<br />
// включаем показ подсказок<br />
m_ToolTip.Activate(1);<br />
<br />
...<br />
}<br />
<br />
// для того, чтобы подсказки отображались как реакция на движение<br />
// курсора мыши, транслируем получаемые окнами сообщения в<br />
// виртуальной PreTranslateMessage()<br />
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg)<br />
{<br />
// транслируем<br />
if(m_ToolTip.m_hWnd)<br />
{<br />
m_ToolTip.RelayEvent(pMsg);<br />
}<br />
<br />
return CDialog::PreTranslateMessage(pMsg);<br />
}<br />
</syntaxhighlight><br />
<br />
===Как в отладчике Visual С++ просмотреть содержимое std::vector<string>?===<br />
<br />
Это можно сделать так: к примеру, имеется:<br />
<br />
<syntaxhighlight lang="cpp"><br />
std::vector<string> V;<br />
</syntaxhighlight><br />
<br />
В режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения:<br />
* "V._Myfirst" - будет показан первый элемент V<br />
* "V._Myfirst+1" - второй элемент V<br />
* и так далее<br />
<br />
===Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах?===<br />
<br />
Для этого нужно использовать процедуру API:<br />
<br />
<syntaxhighlight lang="cpp"><br />
BOOL GetTextExtentPoint32(<br />
HDC hdc, // хендл контекста<br />
LPCTSTR lpString, // выводимая строка<br />
int cbString, // длина строки в символах<br />
LPSIZE lpSize // указатель на структуру SIZE, куда будут помещены размеры<br />
);<br />
</syntaxhighlight><br />
<br />
Функция вычисляет ширину строки символов, оканчивающейся нулём. Поэтому, чтобы вычислить габариты многострочного текста, текст, в начале, необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_4&diff=609FAQ:WinAPI, VCPP Part 42008-10-17T16:29:37Z<p>Алексей1153++: </p>
<hr />
<div>===Как создавать всплывающие подсказки (ToolTip) ?===<br />
Этот элемент управления называется "Balloon ToolTip". (В МСДН есть статья под названием "Using ToolTip Controls")<br />
[[Изображение:context_help.GIF]]<br />
<br />
Тематические ссылки:<br />
<br />
http://www.codeproject.com/shell/LiviuBirjegaCode.asp<br />
<br />
http://www.codeproject.com/useritems/wtlntray.asp<br />
<br />
<br />
Для того, чтобы подсказка имела вид "облака" (как в коммиксах), нужно установить недокументированный стиль<br />
TTS_BALLOON==0x40<br />
<br />
Вот ещё пара полезных функций API для работы с подсказками<br />
<syntaxhighlight><br />
CToolTipCtrl::SetDelayTime(TTDT_INITIAL, мс );//через какое время появится на экране после наведения курсора<br />
CToolTipCtrl::SetDelayTime(TTDT_AUTOPOP, мс );//время горения подсказки на экране<br />
<br />
//мс - время в миллисекундах , тип DWORD<br />
</syntaxhighlight><br />
<br />
<br />
===Что делает функция ScrollWindow()===<br />
Функция ScrollWindow() всего лишь двигает рисунок, уже нарисованный на контексте окна, на заданное количество пикселов.<br />
<br />
К примеру, у имеется нарисованное изображение на клиентской части окна, и нужно сделать скролинг этой части.<br />
<br />
Первый путь: Стереть что уже было нарисовано, и перерисовывать все заново с учетом скролинга.<br />
<br />
Второй путь: Передвинуть ту часть, которая останется в зоне видимости, и дорисовать недостаюшую часть. Функция ScrollWindow() как раз и пригодится, чтобы передвинуть рисунок на заданное количество пикселов. Останется потом только дорисовать.<br />
<br />
===Почему список CComboBox не выпадает, хотя клавишами "вверх" и "вниз" значения перебираются?===<br />
Нужно задать высоту выпадающего списка: находясь в редакторе форм, нужно щёлкнуть по стрелке комбобокса и за нижний маркер растянуть вниз, тем самым и задать размер выпадающего списка.<br />
<br />
===Как программно поменять настройки Internet Explorer?===<br />
Можно воспользоваться редактированием реестра:<br />
<syntaxhighlight><br />
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\AdvancedOptions\ (всякие настройки)<br />
</syntaxhighlight><br />
<br />
===Как узнать, когда после запуска приложение уже готово к работе?===<br />
Можно переопределить функцию CWinApp::OnIdle. Эта функция вызывается всякий раз, когда в очереди сообщений приложения нет больше сообщений. Самый первый вызов функции будет соответствовать моменту, когда приложение стало быть готово к работе.<br />
<br />
===Как получить короткое и длинное имя файла?===<br />
Можно использовать функции API<br />
<syntaxhighlight><br />
GetShortPathName(<br />
LPCSTR lpszLongPath,<br />
LPSTR lpszShortPath,<br />
DWORD cchBuffer); //получить короткий путь<br />
</syntaxhighlight><br />
и<br />
<syntaxhighlight><br />
GetLongPathName(<br />
LPCSTR lpszShortPath,<br />
LPSTR lpszLongPath,<br />
DWORD cchBuffer); //получить полный путь<br />
</syntaxhighlight><br />
<br />
<br />
Например имеется путь к файлу:<br />
<syntaxhighlight><br />
D:\program files\Microsoft Office\OFFICE11\winword.exe<br />
</syntaxhighlight><br />
функция GetShortPathName() поможет привести его к виду:<br />
<syntaxhighlight><br />
d:\PROGRA~1\MICROS~2\OFFICE11\WINWORD.EXE<br />
</syntaxhighlight><br />
а функция GetLongPathName() - наоборот.<br />
<br />
Максимальная длина пути файла равна MAX_PATH (==260) символам<br />
<br />
===В чём разница между сообщениями WM_MOVE и WM_MOVING?===<br />
<br />
Сообщение VM_MOVING посылается окну, когда пользователь перемещает окно.<br />
<br />
Сообщение VM_MOVE посылается окну, когда пользователь завершил перемещение окна (отпустил кнопку мыши).<br />
<br />
=== Как из программы определить каталог, в котором находится эта программа?===<br />
Это можно сделать при помощи функции, которая возвращает абсолютное имя модуля.<br />
<syntaxhighlight><br />
GetModuleFileName()<br />
</syntaxhighlight><br />
<br />
В MFC можно использовать переменную-член класса CWinApp, определённую как<br />
<syntaxhighlight><br />
LPCTSTR m_pszExeName;<br />
</syntaxhighlight><br />
<br />
Получить доступ можно двумя способами:<br />
<syntaxhighlight><br />
//1<br />
AfxGetApp()->m_pszExeName;<br />
<br />
//2<br />
//extern CMyApp theApp<br />
theApp.m_pszExeName;<br />
</syntaxhighlight><br />
<br />
===Как получить полное имя пользователя и организации, то есть то, что на диалоге system properties (горячая кнопка [ Win ] + Break ) на закладке General перечисленно под пунктом Registred To? ===<br />
Значение можно взять в реестре:<br />
<br />
тут (для Windows NT)<br />
<syntaxhighlight><br />
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion<br />
</syntaxhighlight><br />
<br />
или тут (W98, W95)<br />
<syntaxhighlight><br />
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion<br />
</syntaxhighlight><br />
<br />
===Как определить первый свободный ID, который можно использовать при динамичском создании элементов управления?===<br />
Можно поступить так: начать перебор значений ID со значения 1000 и, проверяя функцией GetDlgItem(), увеличивать значение на единицу до тех пор, пока не будет найден свободный ID.<br />
<br />
===Как изменить цвет рамки приложения?===<br />
Это можно сделать, если перехватить сообщение WM_NCPAINT, которое отвечает за прорисовку не-клиентской части окна.<br />
<br />
===Я запускаю экзешник при помощи ::ShellExecute(). Процедура тут же возвращает управление, а как дождаться, когда запущенный процесс завершится, только потом продолжить выполнение программы?===<br />
Нужно использовать функции<br />
<br />
CreateProcess()<br />
<br />
WaitForSingeObject()<br />
<br />
<syntaxhighlight><br />
STARTUPINFO StartupInfo;<br />
PROCESS_INFORMATION ProcessInfo;<br />
DWORD dwRetValue;<br />
RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));<br />
StartupInfo.cb = sizeof(StartupInfo);<br />
<br />
//запуск экзешника<br />
if(!CreateProcess(<br />
szApplicationName,<br />
szCommandLine, //командная строка (можно указать NULL)<br />
NULL, NULL, FALSE,<br />
NORMAL_PRIORITY_CLASS,<br />
NULL,<br />
szCurrentDirectory, //рабочая директория (можно указать NULL)<br />
&StartupInfo,<br />
&ProcessInfo))<br />
{<br />
//ошибка запуска<br />
DWORD dwdErr=GetLastError(); //определяем ошибку<br />
}<br />
else<br />
{<br />
//ждём 30 секунд момента, пока процесс завершится<br />
//(ProcessInfo.hProcess перейдёт в сигнальное состояние)<br />
DWORD dwd=WaitForSingleObject(ProcessInfo.hProcess, 30000);<br />
//если задать INFINITE , будет ждать до бесконечности<br />
<br />
//dwd покажет причину завершения процедуры WaitForSingleObject<br />
//WAIT_OBJECT_0 Состояние объекта переведено в сигнальное <br />
//WAIT_TIMEOUT Кончился таймаут<br />
<br />
//к теме не относится, но для мутекса ещё есть возвращаемое значение:<br />
//WAIT_ABANDONED Объект является мутексом, который был занят потоком, затем поток завершился,<br />
// не разблокировав мутекс. Мутекс находится в несигнальном состоянии<br />
<br />
<br />
//если нужно - смотрим, какое значение вернуло приложение<br />
GetExitCodeProcess(ProcessInfo.hProcess, &dwRetValue);<br />
<br />
//освобождаем хендлы, открытые CreateProcess<br />
CloseHandle(ProcessInfo.hThread);<br />
CloseHandle(ProcessInfo.hProcess);<br />
}<br />
</syntaxhighlight><br />
<br />
В szApplicationName может быть либо полный путь к файлу, либо только имя файла. В последнем случае файл будет искаться в текущем каталоге.<br />
<br />
szCommandLine может быть NULL, если не надо передавать командную строку запускаемому процессу.<br />
<br />
szCurrentDirectory может быть NULL, тогда текущий каталог будет как у родительского процесса.<br />
<br />
===Как сменить иконку у диалога или мейнфрейма? (поставить свою иконку из ресурсов)===<br />
<br />
Пример:<br />
<syntaxhighlight><br />
HICON m_hIcon;<br />
...<br />
...<br />
HICON m_hIcon = AfxGetApp()->LoadIcon(IDR_1);<br />
SetIcon(m_hIcon, TRUE);<br />
</syntaxhighlight><br />
<br />
где<br />
<br />
IDR_1 - ИД иконки в ресурсах<br />
<br />
m_hIcon - хендл типа HICON (естественно - не временный, а, скажем, член класса)<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_3&diff=607FAQ:WinAPI, VCPP Part 32008-10-14T18:13:29Z<p>Алексей1153++: </p>
<hr />
<div><br />
=== Как узнать, что пользователь меняет текст в приложении на основе CRichEditView?===<br />
Нужно добавить обработчик сообщения EN_CHANGE. Сообщение генерируется CRichEditView каждый раз, когда пользователь изменяет текст в окне CRichEditView<br />
<br />
===Чем отличается метод CArray::GetSize от метода CArray::GetCount?===<br />
Эти методы абсолютно идентичны. Скорее всего, в более старых версиях библиотек функции, одинаковые по смыслу, имели разные имена. Поэтому в целях совместимости разработчики оставили обе функции)<br />
<br />
===Как загрузить текстовую строку из ресурса?===<br />
Пример:<br />
<syntaxhighlight><br />
CString m_Temp;<br />
m_Temp.LoadString(ID_MYSTRING);<br />
</syntaxhighlight><br />
<br />
===Как поменять иконку у элемента item в CListCtrl?===<br />
Пример:<br />
<syntaxhighlight><br />
//заполняем структуру LVITEM<br />
LVITEM lvItem;<br />
memset(&lvItem,0,sizeof(lvItem));<br />
<br />
lvItem.mask = LVIF_IMAGE;//меняться будет картинка<br />
lvItem.iItem = ...;// индекс элемента списка (Zero-based)<br />
lvItem.iSubItem = 0;<br />
lvItem.iImage = ...; //индекс иконки (из списка контрола)<br />
<br />
pList->SetItem(&lvItem);<br />
</syntaxhighlight><br />
<br />
===Имеется класс Class1, содержащий мембер типа "указатель на Class2". В Class2 также имеется указатель на Class1. Компилятор выдаёт ошибку. Что надо делать?===<br />
Перекрёстное определение обходится следкющим образом: код обоих классов разносится в пары файлов *.h и *.cpp, а перед каждым классом вписывается предопределение другого класса:<br />
<br />
<br />
файл "class1.h"<br />
<syntaxhighlight><br />
class Class2;//предопределение Class2<br />
<br />
Class1<br />
{<br />
Class2* m_p2;//компилятор разрешит объявление указателя Class2*<br />
<br />
void F1(Class2* p);//компилятор разрешит объявление указателя Class2*<br />
void F2(Class1* p);<br />
};<br />
</syntaxhighlight><br />
<br />
файл "class1.cpp"<br />
<syntaxhighlight><br />
#include "class1.h"<br />
#include "class2.h"<br />
<br />
void Class1::F1(Class2* p)<br />
{<br />
...<br />
}<br />
<br />
void Class1::F2(Class1* p)<br />
{<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
файл "class2.h"<br />
<syntaxhighlight><br />
class Class1;//предопределение Class1<br />
<br />
Class2<br />
{<br />
Class1* m_p1;//компилятор разрешит объявление указателя Class1*<br />
<br />
void F3(Class1* p);//компилятор разрешит объявление указателя Class1*<br />
};<br />
</syntaxhighlight><br />
<br />
<br />
файл "class2.cpp"<br />
<syntaxhighlight><br />
#include "class2.h"<br />
#include "class1.h"<br />
<br />
void Class2::F3(Class1* p)<br />
{<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
После предопределениея класса компилятор позволяет объявлять указатель на класс, так как переменная указателя на любой тип имеет всегда один и тот же размер.<br />
<br />
===Как переключить раскладку в другом (то есть в активном) процессе?===<br />
Для этого можно использовать функции<br />
<syntaxhighlight><br />
GetKeyboardLayout(...); // определить текущую раскладку<br />
LoadKeyboardLayout(...); // загрузить новую раскладку<br />
VerLanguageName(...); // получить строку с описанием языка<br />
</syntaxhighlight><br />
<br />
Подробности - в MSDN<br />
<br />
===Как получить хендл элемента управления, зная его идентификатор?===<br />
Пример:<br />
Пусть элемент Edit лежит на окне CMyWnd.<br />
Тогда:<br />
<syntaxhighlight><br />
void CMyWnd::некая_процедура()<br />
{<br />
//для MFC<br />
CEdit* ed=(CEdit* ) GetDlgItem(ID_EDIT1);<br />
HWND hwnd=ed->GetSafeHwnd();<br />
if(hwnd)<br />
{<br />
...<br />
}<br />
<br />
//для Win32 API<br />
HWND hwnd=GetDlgItem(m_hWnd,ID_EDIT1);<br />
if(hwnd)<br />
{<br />
...<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
===Как из дочернего окна закрыть приложение?===<br />
Для этого нужно послать родительскому окну сообщение WM_CLOSE:<br />
<br />
через указатель на родительское окно:<br />
<syntaxhighlight><br />
pParent->PostMessage(WM_CLOSE);<br />
</syntaxhighlight><br />
<br />
при помощи хендла рордительского окна:<br />
<syntaxhighlight><br />
::PostMessage(pParent->m_hWnd,WM_CLOSE,(WPARAM)0,(LPARAM)0);<br />
</syntaxhighlight><br />
<br />
===Как корректно перевести тип BSTR в CString и наоборот?===<br />
<br />
1) для конвертирования BSTR в CString нужно просто присвоить переменной типа CString переменную типа BSTR.<br />
Оператор "=" класса CString сам выполнит всю работу.<br />
<br />
2) для конвертирования BSTR в CString нужно выполнить код:<br />
<syntaxhighlight><br />
<br />
//указатель на будущий буфер с BSTR.<br />
BSTR bstrHE=0;<br />
// (По сути, BSTR определён как <br />
// typedef WCHAR* BSTR;<br />
// то есть указатель на 16-битный символ юникод)<br />
<br />
//строка для конвертации<br />
CString Str="мой текст";<br />
<br />
//Выделяем память и загружаем адрес блока в bstrHE<br />
bstrHE=Str.AllocSysString();<br />
<br />
//... <br />
//тут работаем с bstrHE[]<br />
//...<br />
<br />
//освобождаем память<br />
SysFreeString(bstrHE);<br />
</syntaxhighlight><br />
<br />
===Как получить доступ к графическим ресурсам элементов текущей темы оформления Windows?===<br />
<br />
Для этого нужно использовать функции<br />
<br />
<syntaxhighlight><br />
OpenThemeData(...);<br />
DrawThemeBackground(...);<br />
DrawFrameControl(...);<br />
CloseThemeData(...);<br />
</syntaxhighlight><br />
<br />
(подробности - в MSDN)<br />
<br />
===Имеется класс , производный от CDialog. Когда диалог в фокусе, нажатие на Enter или Esc приводит к закрытию диалога. Как это запретить?===<br />
При нажатии Enter происходит выполнение команды IDOK,при нажатии Esc - IDCANCEL.<br />
<br />
Нужно переопределить в классе виртуальные функции OnOk() и OnCancel(), которые соответственно вызываются для этих команд. При помощи визарда эти функции добавить можно так:<br />
<br />
Положить на диалог две кнопки с идентификаторами IDOK и IDCANCEL (при создании нового диалога они там есть сразу), затем двойной щелчок по кнопке добавит соответствующий обработчик. В обработчиках надо удалить вызовы СDialog::OnOK() и CDialog::OnCancel(), тогда диалог закрываться не будет.<br />
<br />
Однако тогда диалог станет невозможно закрыть кнопкой с крестиком. Это обходится так: добавляем обработчик сообщения WM_CLOSE - OnClose(), и в нём делаем вызов OnOk() или OnCancel():<br />
<syntaxhighlight><br />
void CPlayersPropsDialog::OnClose() <br />
{<br />
CDialog::OnClose();<br />
CDialog::OnCancel();//добавлено<br />
}<br />
</syntaxhighlight><br />
<br />
===Я написал в VC++ простейший макрос , где невозможно ошибиться, а компилятор всё же выдаёт ошибку. Не пойму, в чём дело?===<br />
<br />
Скорее всего после одного из символов соединения строк "\" имеется пробел или табуляция. Их надо удалить. Можно найти их "наощупь", а можно включить показ непечатных символов в студии. Найти эту команду можно так:<br />
<br />
Tools->Customize...->вкладка Commands. В окошке Category выбрать "Edit", и среди кнопок справа найти кнопку, на которой написано "a.b"<br />
<br />
Эту кнопку надо перетащить на одну из панелей инструментов студии.<br />
<br />
===Как получить список всех процесов, включая idle?===<br />
<br />
Использовать функции<br />
<syntaxhighlight><br />
Process32First(...);<br />
Precess32Next(...);<br />
</syntaxhighlight><br />
<br />
(подробности - в MSDN)<br />
<br />
===Как программно установить переменные окружения?===<br />
Чтобы добавить или изменить их программно, необходимо воспользоваться ключом реестра<br />
<syntaxhighlight><br />
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment<br />
</syntaxhighlight><br />
<br />
Затем нужно отправить широковещательное сообщение WM_SETTINGCHANGE (это позволит приложениям узнать об изменениях):<br />
<syntaxhighlight><br />
::SendMessage(HWND_BROADCAST,WM_SETTINGCHANGE,0,0);<br />
</syntaxhighlight><br />
<br />
<br />
===Как сделать, чтобы у окна был черный фон?===<br />
Нужно переопределить обработчик сообщения WM_CTLCOLOR - OnCtlColor() :<br />
<br />
<syntaxhighlight><br />
CBrush br(RGB(0,0,0)); //глобальная переменная или член класса CMyDlg,<br />
// инициализированный в OnInitDialog()<br />
<br />
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
HBRUSH hbr = CMyDlg::OnCtlColor(pDC, pWnd, nCtlColor);<br />
<br />
//фон диалога (или View)<br />
if(nCtlColor==CTLCOLOR_DLG)<br />
{<br />
return (HBRUSH)br;<br />
}<br />
<br />
//фон элементов SCtatic, лежащих на форме (если нужно)<br />
if(nCtlColor==CTLCOLOR_STATIC)<br />
{<br />
//делаем фон текста статика прозрачным<br />
pDC->SetBkMode(TRANSPARENT);<br />
return (HBRUSH)br;<br />
}<br />
<br />
return hbr;<br />
}<br />
</syntaxhighlight><br />
<br />
===Почему на моем компьютере экзешник, созданный в MFC запускается, а на других компьютерах - нет? Требует какую-то dll-ку.===<br />
Нужно выбирать режим Release :<br />
<br />
Menu->Build->Configurations...->Release,<br />
<br />
и экзешник, соответственно, брать из папки Release проекта.<br />
<br />
===Как в диалог добавить меню?===<br />
Нужно создать в редакторе ресурсов новое меню, затем вставить его в диалог:<br />
<br />
1)открыть в редакторе диалог,<br />
<br />
2)в свойствах (во вкладке General, окошко Menu) указать идентивикатор ресурса меню.<br />
<br />
3)при помощи визарда добавить для меню обработчики OnCommand() и OnUpdateСommand().<br />
<br />
===Почему не вызывается OnUpdate для пунктов меню (не получается ни затенить, ни отметку поставить)?===<br />
В диалоге (CDialog) у меню апдейт не происходит сам, в отличие от мейнфрейма (CFrameWnd). Для этого нужно сделать самим апдейт в обработчике сообщения WM_KICKIDLE.<br />
<br />
Визардом этот обработчик не добавляется, поэтому можно переопределить виртуальную DefWindowProc() и там обработать:<br />
<syntaxhighlight><br />
#include <afxpriv.h> //этот файл надо включить, там определёна WM_KICKIDLE<br />
<br />
LRESULT CMyDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
if(message==WM_KICKIDLE)<br />
{<br />
//делаем апдейт для всех пунктов меню<br />
CMenu* pMainMenu=GetMenu();<br />
if(pMainMenu)<br />
{<br />
CCmdUI cmdUI;<br />
for (UINT n=0; n < pMainMenu->GetMenuItemCount(); ++n)<br />
{<br />
CMenu* pSubMenu = pMainMenu->GetSubMenu(n);<br />
if(!pSubMenu)continue;<br />
<br />
cmdUI.m_nIndexMax = pSubMenu->GetMenuItemCount();<br />
for (UINT i = 0; i < cmdUI.m_nIndexMax;++i)<br />
{<br />
cmdUI.m_nIndex = i;<br />
cmdUI.m_nID = pSubMenu->GetMenuItemID(i);<br />
cmdUI.m_pMenu = pSubMenu;<br />
cmdUI.DoUpdate(this, FALSE);<br />
}<br />
}<br />
}<br />
}<br />
<br />
return CDialog::DefWindowProc(message, wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
===Как в главном окне отключить системное меню (в левом верхнем углу) и кнопки(в правом верхнем углу)?===<br />
При создании окна нужно убрать стиль WS_SYSMENU (теперь пользователь корректно может закрыть окно только Alt+F4, ну или если вы предоставите ему дополнительную возможность сделать это)<br />
<br />
Пример 1. (для SDI, MDI)<br />
<syntaxhighlight><br />
//этот обработчик уже добавлен визардом<br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
if( !CFrameWnd::PreCreateWindow(cs) )<br />
return FALSE;<br />
// TODO: Modify the Window class or styles here by modifying<br />
// the CREATESTRUCT cs<br />
<br />
///////////////////////////////<br />
//добавленная часть<br />
{<br />
//убираем стиль<br />
cs.style&=~WS_SYSMENU;<br />
}<br />
///////////////////////////////<br />
<br />
return TRUE;<br />
}<br />
</syntaxhighlight><br />
<br />
Пример 2. (для диалога)<br />
<br />
Если диалог описан в ресурсах, то в свойствах диалога убрать галочки<br />
<br />
"System menu"<br />
<br />
"Minimize box"<br />
<br />
"Maximize box"<br />
<br />
===Как запретить пользователю нажать на кнопку?===<br />
Нужно применить метод класса CWnd::EnableWindow(...) для кнопки. Значение параметра 0 делает кнопку неактивной, 1 - делает активной (кстати, не только для кнопки можно, а для любого класса, производного от класса CWnd).<br />
<br />
<br />
Пусть имеется некий диалог, на нём лежит кнопка c ID == IDC_1. В любом месте кода диалога (кроме конструктора и деструктора , хотя, если проверить наличие валидного хендла диалога, как в примере, то ничего страшного не будет и там) выполняем код<br />
<syntaxhighlight><br />
//делаем кнопку неактивной<br />
if(m_hWnd)<br />
{<br />
CWnd* pw=0;<br />
pw=GetDlgItem(IDC_1);<br />
if(pw)pw->EnableWindow(0);<br />
}<br />
</syntaxhighlight><br />
<br />
===Что означают сообщения, которые студия выводит при компиляции, вроде таких : Loaded 'C:\WINDOWS\SYSTEM\WSOCK32.DLL', no matching symbolic information found. ===<br />
Это строка говорит о том, что студия не смогла найти отладочные символы для WSOCK32.DLL. В этом нет ничего страшного, просто при наличии отладочных символов в процессе отладки можно получить доступ к именам функции из системных DLL. Например, вместо<br />
<syntaxhighlight><br />
KERNEL32! 0x77E8B184()<br />
</syntaxhighlight><br />
увидим<br />
<br />
<syntaxhighlight><br />
KERNEL32!CreateThread.<br />
</syntaxhighlight><br />
<br />
===Как обработать сообщения, которое приходит к некому элементу управления?===<br />
Скажем, нужно обработать сообщения, приходящие к элементу класса CEdit. Нужно произвести от CEdit свой класс, и в виртуальной процедуре класса WindowProc перехватить нужные сообщения.<br />
<syntaxhighlight><br />
virtual LRESULT WindowProc(<br />
UINT message,<br />
WPARAM wParam,<br />
LPARAM lParam <br />
);<br />
</syntaxhighlight><br />
<br />
Пример. Полностью выключаем, скажем, обработку сообщения WM_CHAR<br />
<syntaxhighlight><br />
LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
switch(message)<br />
{<br />
case WM_CHAR:<br />
{<br />
return 0;<br />
}<br />
break;<br />
}<br />
<br />
return CEdit::WindowProc(message, wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
Чтобы связать экземпляр класса с элементо на форме, добавьте визардом для<br />
контрола переменную класса (выбрав не Value а Control).<br />
<br />
===Как настроить количество пробелов в табуляции?===<br />
Есть пара способов:<br />
<br />
1) Tools->Options->Tabs->Insert Spaces<br />
<br />
2) правой кнопкой мыши щёлкнуть по тексту, в контекстном меню выбрать properties<br />
<br />
===Как автоматически расставить отступы?===<br />
Нужно в студии выделить текст для форматирования, нажать Alt+F8.<br />
<br />
Ещё есть программа Artistic Style ( http://sourceforge.net/projects/astyle/ ), которая занимается переформатированием кода.<br />
<br />
===Поиск границ блока===<br />
Сочетание клавиш CTRL+ "}" ищет парную фигурную скобку в тексте и переходит к ней.<br />
<br />
===Вертикальное выделение текста===<br />
Если удерживать клавишу Alt, а затем начать выделять текст мышкой, то область выделения принимает форму прямоугольника, что позволяет выделять вертикальные фрагменты текста.<br />
<br />
===Как узнать количество установленных в CListCtrl столбцов?===<br />
Пример<br />
<syntaxhighlight><br />
//указатель на переменную-контрол<br />
CListCtrl* pL=...;<br />
<br />
//получаем количество столбцов<br />
int count=pL->GetHeaderCtrl()->GetItemCount();<br />
</syntaxhighlight><br />
<br />
===Как получить иконку приложения?===<br />
Если приложение запущено, то нужно найти его главное окно и послать ему сообщение WM_GETICON.<br />
<syntaxhighlight><br />
//функция возвращант хендл иконки <br />
LRESULT SendMessage(hWnd, WM_GETICON, wParam, 0);<br />
<br />
//hWnd == хендл окна приложения<br />
//wParam == <br />
// 1)==ICON_BIG - получить большую иконку<br />
// 2)==ICON_SMALL - получить маленькую иконку<br />
// 3)==ICON_SMALL2 - получить маленькую иконку, если она определена<br />
// в приложении. Если её нет, то маленькую иконку, <br />
// сгенерированную системой из большой иконки<br />
</syntaxhighlight><br />
<br />
===Как в CString можно найти или вырезать часть строки?===<br />
Это можно сделать при помощи методов класса CString:<br />
<syntaxhighlight><br />
//вырезает кусок строки<br />
CString Mid(int nFirst) const;<br />
CString Mid(int nFirst, int nCount) const;<br />
<br />
//возвращает кусок строки (сначала или с конца)<br />
CString Left(int nCount ) const;<br />
CString Right(int nCount ) const;<br />
<br />
//возвращает начальный кусок строки, в котором есть только<br />
//символы из набора,представленного в lpszCharSet<br />
CString SpanIncluding(LPCTSTR lpszCharSet ) const;<br />
<br />
//возвращает начальный кусок строки, в котором нет<br />
//символов из набора,представленного в lpszCharSet<br />
CString SpanExcluding(LPCTSTR lpszCharSet ) const; <br />
<br />
//убирает "пробелоподобные" символы из самого начала строки<br />
//(то есть - пробел, табуляцию (\t) , возврат каретки, перевод строки (/r/n))<br />
void TrimLeft();<br />
//убирает все повторы символа из самого начала строки<br />
void TrimLeft(TCHAR chTarget );<br />
//убирает из самого начала строки все символа из набора lpszTargets <br />
void TrimLeft(LPCTSTR lpszTargets );<br />
<br />
void TrimRight();<br />
void TrimRight(TCHAR chTarget );<br />
void TrimRight(LPCTSTR lpszTargets );<br />
<br />
//поиск в строке<br />
int Find( TCHAR ch ) const;<br />
int Find( LPCTSTR lpszSub ) const;<br />
int Find( TCHAR ch, int nStart ) const;<br />
int Find( LPCTSTR pstr, int nStart ) const;<br />
<br />
//поиск, начиная с конца<br />
int ReverseFind( TCHAR ch ) const;<br />
<br />
//поиск позиции первого символа, одного из набора,<br />
// представленного в lpszCharSet<br />
int FindOneOf( LPCTSTR lpszCharSet ) const;<br />
</syntaxhighlight><br />
<br />
===Как отобразить на элементах управления промежуточные результаты длительных вичислений ?===<br />
В общем случае это делается принудительной перерисовкой нужного окна путём объявления этого окна невалидным<br />
<syntaxhighlight><br />
pWnd->Invalidate(0);<br />
</syntaxhighlight><br />
а затем непосредственной отсылки в оконную процедуру сообщения WM_PAINT<br />
<syntaxhighlight><br />
pWnd->UpdateWindow();<br />
</syntaxhighlight><br />
<br />
Пример:<br />
<syntaxhighlight><br />
CWnd* pWnd=...;//окно, которое надо перерисовывать<br />
<br />
for(int i=0;i<10000)<br />
{<br />
//меняется содержимое окна<br />
//...<br />
<br />
//немедленная перерисовка<br />
pWnd->Invalidate(0);<br />
pWnd->UpdateWindow();<br />
}<br />
</syntaxhighlight><br />
<br />
Также можно также просто вызвать метод RedrawWindow() с параметрами по умолчанию.<br />
<br />
===Я написал DLL, которую используют несколько приложений. Всё вроде работает, но когда происходит очередной вызов функции из DLL, почему то данные в функции обнуляются. С чем это связано?===<br />
Переменные и массивы в DLL, содержимое которых должно использоваться несколькими процессами, должны объявляться статическими. Статическая переменная или массив инициализируются только один раз в момент загрузки DLL.<br />
Пример:<br />
<syntaxhighlight><br />
DWORD calltest()<br />
{<br />
//будет выполнено только при первом вызове<br />
static DWORD callcount=0;<br />
static DWORD str[1000]={0}; <br />
<br />
//будет выполняться каждый раз<br />
return ++callcount;<br />
}<br />
</syntaxhighlight><br />
<br />
===Как открыть проекцию файла в память и как с ней работать?===<br />
<br />
Создание проекции:<br />
<syntaxhighlight><br />
HANDLE CreateFileMapping(<br />
HANDLE hFile, //хендл уже открытого файла<br />
LPSECURITY_ATTRIBUTES lpAttributes,<br />
DWORD flProtect, //способ открытия проекции<br />
DWORD dwMaximumSizeHigh, //размер файла (старшие 4 байта , обычно==0)<br />
DWORD dwMaximumSizeLow, //размер файла (младшие 4 байта)<br />
LPCTSTR lpName<br />
);<br />
</syntaxhighlight><br />
<br />
Доступ к созданной проекции производится процедурой:<br />
<syntaxhighlight><br />
LPVOID MapViewOfFile(<br />
HANDLE hFileMappingObject, //хендл проекции<br />
DWORD dwDesiredAccess, //способ работы с проекцией<br />
DWORD dwFileOffsetHigh,<br />
DWORD dwFileOffsetLow, //смещение от начала файла (младшие 4 байта)<br />
SIZE_T dwNumberOfBytesToMap //длина в байтах (если ==0 - то весь файл)<br />
);<br />
</syntaxhighlight><br />
<br />
далее с файлом можно работать как с обычным массивом в памяти.<br />
<br />
После работы с проекцией, её надо освободить процедурой<br />
<syntaxhighlight><br />
BOOL UnmapViewOfFile(<br />
LPCVOID lpBaseAddress //адрес, который вернула процедура MapViewOfFile<br />
);<br />
</syntaxhighlight><br />
<br />
Пример:<br />
<syntaxhighlight><br />
HANDLE hFile=...;//хендл уже открытого файла<br />
DWORD dwdFileLen=...;//размер открытого файла<br />
<br />
HANDLE hMapFile=0;//хендл для проекции<br />
<br />
//создаём проекцию "только для чтения"<br />
hMapFile=::CreateFileMapping(hFile,0,PAGE_READONLY,0,dwdFileLen,0);<br />
<br />
//хендл hFile можно закрыть уже здесь, в принципе,<br />
//но мы сделаем это позже<br />
<br />
//получаем доступ к проекции (тоже только для чтения)<br />
BYTE* pbyFile=(BYTE*)::MapViewOfFile(hMapFile,FILE_MAP_READ,0,0,0);<br />
<br />
///////////////////<br />
//тут работаем с массивом pbyFile[dwdFileLen] как с обычным,<br />
//только не забываем, что он открыт только для чтения<br />
//...<br />
//...<br />
//...<br />
///////////////////<br />
<br />
//отключаем файл данных от адресного пространства<br />
UnmapViewOfFile(pbyFile);<br />
<br />
//освобождаем хендл проекции<br />
CloseHandle(hMapFile)<br />
<br />
//освобождаем хендл открытого файла<br />
CloseHandle(hFile);<br />
</syntaxhighlight><br />
<br />
===Как в MFC Grid control отобразить картинку в ячейке?===<br />
Нужно создать список изображений (CImageList), затем передать указатель на список в таблицу. Поскольку элемент управления лишь копирует указатель, список должен создаваться динамически, либо быть членом класса, экземпляр которого существует всё время работы таблицы.<br />
<syntaxhighlight><br />
CImageList m_ImageList;<br />
CGridCtrL m_Grid1;<br />
...<br />
...<br />
//неким образом создаётся список<br />
m_ImageList.Create(...);<br />
//...<br />
<br />
//вставляем в контрол<br />
m_Grid1.SetImageList(&m_ImageList);<br />
<br />
//<br />
</syntaxhighlight><br />
<br />
===Как при помощи IPicture отобразить картинку из файла? ===<br />
Пример - несложная функция, отображающая картинку из файла. Поддерживаются форматы BMP, GIF, JPEG, PNG, TIFF, EMF<br />
<syntaxhighlight><br />
#include "atlconv.h"<br />
#define HandleIsValid(H) (H!=(HANDLE)-1 && H!=(HANDLE)0)<br />
<br />
//*pDestDC - CDC, на который предполагается вывод картинки<br />
//pchzFilePath - путь к файлу<br />
//pWid - (возвращает) ширина картинки<br />
//pHig - (возвращает) высота картинки<br />
bool DrawBitmapFromFile(CDC* pDestDC,const char* pchzFilePath,int *pWid=0,int *pHig=0)<br />
{<br />
bool result=false;<br />
<br />
if(pWid)*pWid=0;<br />
if(pHig)*pHig=0;<br />
<br />
int Wid=0;<br />
int Hig=0;<br />
<br />
IPicture* pPic=0;<br />
try<br />
{<br />
IPicture* ptmpPic=0;<br />
USES_CONVERSION;<br />
HRESULT hr;<br />
<br />
CString txt=pchzFilePath;<br />
hr= ::OleLoadPicturePath(<br />
const_cast<LPOLESTR>(T2COLE(txt)),<br />
0,0,0,IID_IPicture,<br />
reinterpret_cast<void **>(&ptmpPic)<br />
);<br />
<br />
if(hr==S_OK && ptmpPic)<br />
{<br />
pPic=ptmpPic;<br />
}<br />
else<br />
{<br />
throw 0;<br />
}<br />
<br />
OLE_XPOS_HIMETRIC cxSrc;<br />
OLE_YPOS_HIMETRIC cySrc;<br />
<br />
if(S_OK!=pPic->get_Width(&cxSrc))throw 0;<br />
if(S_OK!=pPic->get_Height(&cySrc))throw 0;<br />
<br />
Wid=cxSrc/26;<br />
Hig=cySrc/26;<br />
<br />
//рисуем<br />
if(S_OK !=pPic->Render(pDestDC->GetSafeHdc(),<br />
0,Hig,Wid,-Hig,0,0,cxSrc,cySrc,0))throw 0;<br />
}<br />
catch(...)<br />
{<br />
result=false;<br />
}<br />
<br />
if(pPic)<br />
{<br />
pPic->Release();<br />
pPic=0;<br />
}<br />
<br />
<br />
if(pWid)*pWid=Wid;<br />
if(pHig)*pHig=Hig;<br />
<br />
return result;<br />
}<br />
</syntaxhighlight><br />
<br />
===Как позволить пользователю начать ввод новой строки в многострочном поле редактирования?===<br />
Нужно в редакторе ресурсов поставить для свойств окошка CEdit галочку "WantReturn" или добавить стиль ES_WANTRETURN при создании CEdit контрола динамически. Тогда при нажатии Enter в поле редиктирования будет вводиться новая строка.<br />
<br />
===Как выводят картинку-логотип(splash screen) при запуске программы?===<br />
Для этого используется класс, производный от CDialog. Этот диалог после создания показывает себя на экран, выводя на себя рисунок. Также запускает таймер, по срабатывани которого диалог гасится. Создаётся диалог в процедуре InitInstance приложения.<br />
<br />
В VC6++ также есть уже готовый компонент<br />
<br />
Project->Add To Project -> Components and Controls->(в папке "Visual C++ Components" есть SplashScreen.)<br />
<br />
===Как сделать, чтобы при выпадении списка у ComboBox была не одна строка, а больше, вроде все свойства покрутил, не помогает Вместо выпадающего списка одна строка и скролл...===<br />
В редакторе ресурсов надо щелкнуть в комбобоксе на треугольнике - появляется рамка для растягивания вниз - размер выпадающего списка.<br />
<br />
===В VC++.net, что делать после того, как на форму установил ActiveX ListView, как объявить класс и переменную для этого элемента?===<br />
Щёлкнуть правой кнопкой мыши на элементе, в меню - add variable или add class<br />
<br />
===Как работать с буфером обмена (Clipboard)?===<br />
<br />
КОПИРОВАНИЕ В БУФЕР ОБМЕНА:<br />
<br />
Алгоритм<br />
<syntaxhighlight><br />
1.Готовим данные<br />
а. Выделяем память из кучи, вызывая GlobalAlloc()<br />
б. Получаем указатель на выделенную память, вызывая GlobalLock()<br />
в. Заполняем данные<br />
г. Освобождаем указатель, вызывая GlobalUnlock();<br />
<br />
2.Открываем буфер обмена, вызывая OpenClipboard();<br />
<br />
3.Очищаем буфер, вызывая EmptyClipboard();<br />
<br />
4.Вызываем SetClipboardData() один раз для каждого формата<br />
вставляемых данных (имеется в виду - если одни и те же<br />
данные представлены в разных форматах, и приложение<br />
может эти форматы создать)<br />
<br />
5.Закрываем буфер, вызывая CloseClipboard();<br />
<br />
6.ВЫЗЫВАТЬ GlobalFree() НЕ НУЖНО, в этом случае это<br />
предоставлено системе<br />
</syntaxhighlight><br />
<br />
Скажем, хотим поместить в буфер обмена текст.<br />
<syntaxhighlight><br />
//готовим данные<br />
//выделяем из кучи память для данных<br />
HANDLE hglbCopy = GlobalAlloc(GMEM_MOVEABLE,10);<br />
if(!hglbCopy)return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)return;<br />
<br />
//заполняем данные<br />
strcpy((char*)lpStr,"my text");<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
//очищаем<br />
EmptyClipboard();<br />
<br />
//текстовый формат<br />
SetClipboardData(CF_TEXT,hglbCopy);<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</syntaxhighlight><br />
<br />
---<br />
<br />
ИЗВЛЕЧЕНИЕ ИЗ БУФЕРА ОБМЕНА<br />
<br />
Алгоритм<br />
<syntaxhighlight><br />
1.Проверяем, что поддерживается нужный формат данных,<br />
вызывая IsClipboardFormatAvailable()<br />
<br />
2.Открываем буфер обмена, вызывая OpenClipboard();<br />
<br />
3.Достаём данные<br />
а.Получаем из буфера хендл требуемого формата,<br />
вызывая GetClipboardData()<br />
б.Получаем указатель на выделенную память, вызывая GlobalLock()<br />
в.Работаем с данными<br />
г.Освобождаем указатель, вызывая GlobalUnlock();<br />
<br />
4.Закрываем буфер, вызывая CloseClipboard();<br />
</syntaxhighlight><br />
<br />
Скажем, хотим извлечь из буфера обмена текст.<br />
<syntaxhighlight><br />
//Проверяем, что поддерживается нужный формат данных,<br />
if(!IsClipboardFormatAvailable(CF_TEXT))return;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
<br />
//достаём данные<br />
<br />
//текстовый формат<br />
HANDLE hglbCopy = GetClipboardData(CF_TEXT);<br />
if(!hglbCopy)return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)return;<br />
<br />
//читаем данные<br />
char data[10];<br />
memmove(data,lpStr,sizeof(data));<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</syntaxhighlight><br />
<br />
<br />
===Как получить полный путь к экзешнику из самой программы?===<br />
Можно прочитать параметры командной строки - в командную строку первым параметром система всегда передаёт заключённый в кавычки полный путь к файлу запущенной программы. Достаём путь следующим образом:<br />
<syntaxhighlight><br />
BOOL CMyApp::InitInstance()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName содержит искомый путь<br />
<br />
//...<br />
//...<br />
}<br />
</syntaxhighlight><br />
<br />
===Каким способом exe файл может заменить самого себя? ===<br />
<br />
К примеру, программа должна обновляется через Internet и хочет обновить свой exe-файл. Но так как он в данный момент запущен, это будет, естественно, невозможно сделать напрямую.<br />
Один из способов - сделать копию экзешника и из него обновиться<br />
<br />
<syntaxhighlight><br />
#define def_exeNAMEup "c:\\myprog_toupdate.exe" //путь к старому файлу<br />
#define def_exeNAMEdnld "c:\\myprog_downloaded.exe" //путь к новому файлу (уже "скачали" :) )<br />
#define def_keyUdate "/update"<br />
<br />
void CTESTFAQApp::UpdateItself()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName - содержит искомый путь<br />
<br />
//делаем копию экзешника с другим именем<br />
CopyFile(csFullExeName,def_exeNAMEup,0);<br />
<br />
//передаём в параметры нового процесса ключ и путь к текущему файлу<br />
CString csParams=def_keyUdate;<br />
csParams+=" ";<br />
csParams+=csFullExeName;<br />
<br />
//запускаем копию<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(def_exeNAMEup,def_keyUdate,0,0,0,0,0,0,&si,&pi))<br />
{<br />
//завершаем текущий процесс<br />
ExitFromMyApp();<br />
}<br />
}<br />
<br />
void CTESTFAQApp::ExitFromMyApp()<br />
{<br />
exit(0);<br />
}<br />
<br />
BOOL CTESTFAQApp::InitInstance()<br />
{<br />
<br />
//смотрим, не запустили ли для апдейта?<br />
<br />
CString txt;<br />
txt=m_lpCmdLine;<br />
if(txt.Find(def_keyUdate)==0)<br />
{<br />
//делаем айдейт<br />
txt.Replace(def_keyUdate,"");<br />
txt.TrimLeft();<br />
<br />
CString csFullExeName=txt;<br />
<br />
//берём откуда то уже скачанный файл обновления<br />
//...<br />
CString csFull_Downloaded_ExeName=def_exeNAMEdnld;<br />
<br />
//копируем файл (обновляем старый то есть)<br />
CopyFile(csFull_Downloaded_ExeName,csFullExeName,0);<br />
<br />
//запускаем обновлённого мученника<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(csFullExeName,0,0,0,0,0,0,0,&si,&pi))<br />
<br />
ExitFromMyApp();<br />
<br />
}<br />
//...<br />
//...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как производится конвертация из кодировки UTF8 в 1251 и наоборот ?===<br />
<br />
Можно перевести строку из UTF8 в Unicode, затем из Unicode в 1251<br />
<br />
Ниже приведена структура, содержащая процедуры перекодирования,<br />
а также процедуру с примером использования<br />
<syntaxhighlight><br />
//описание структуры<br />
struct coder<br />
{<br />
//utf8->unicode<br />
static wchar_t* utf8_to_unicode__dontForgetDeleteArr(const char *utf8_string)<br />
{<br />
wchar_t* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len=MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,0,0);<br />
if(!res_len)return 0;<br />
<br />
//выделяем память<br />
pRes = new wchar_t[res_len];<br />
if(!pRes)return 0;<br />
<br />
//преобразование<br />
if(!MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,pRes,res_len))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//unicode->1251<br />
static char * unicode_to_1251__dontForgetDeleteArr(const wchar_t *unicode_string)<br />
{<br />
char* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len = WideCharToMultiByte(1251,0,unicode_string,-1,0,0,0,0);<br />
if(!res_len)return 0;<br />
<br />
//выделяем память<br />
pRes=new char[res_len];<br />
if(!pRes)return 0;<br />
<br />
//преобразование<br />
if(!WideCharToMultiByte(1251,0,unicode_string,-1,pRes,res_len,0,0))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//процедура с примером<br />
static void Example()<br />
{<br />
wchar_t* unicode_string=0;<br />
char* cp1251_string=0;<br />
<br />
//исходный текст<br />
char utf8_string[] = "UTF-8 + русский текст";<br />
<br />
for(;;)<br />
{<br />
<br />
unicode_string=utf8_to_unicode__dontForgetDeleteArr(utf8_string);<br />
if(!unicode_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать в unicode!");<br />
break;<br />
}<br />
<br />
cp1251_string = unicode_to_1251__dontForgetDeleteArr(unicode_string);<br />
<br />
if(!cp1251_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать из unicode!");<br />
break;<br />
}<br />
<br />
break;<br />
}<br />
<br />
//cp1251_string - результат<br />
AfxMessageBox(cp1251_string);<br />
<br />
<br />
//не забываем удалить массивы<br />
if(unicode_string)<br />
{<br />
delete [] unicode_string;<br />
unicode_string=0;<br />
}<br />
if(cp1251_string)<br />
{<br />
delete [] cp1251_string;<br />
cp1251_string=0;<br />
}<br />
}<br />
};<br />
<br />
//вызов примера<br />
coder::Example();<br />
</syntaxhighlight><br />
<br />
===Как работать с базой данных Access из программы на VC.net?===<br />
Проще всего подключить ADO компоненты и сделать все на них.<br />
<br />
Компоненты ADO (ADODC,DATAGRID и т.п.) это ActiveX.<br />
<br />
В редакторе ресурсов, во всплывающем меню, есть Insert ActiveX Control -> открывается список всех компоент, зарегистрированых на машине. Нужно найти компоненты (Это компоненты от MS и они помечены (OLEDB)) и вставить их в диалог. Для того что бы иметь возможность управлять ими, нужно импортировать обертки для них, это делается при помощи ClassWizard, там есть импорт->класс->указать файл с компоентой (OSX). Появляется список всех классов, объявленых внутри.<br />
<br />
Расставляем нужные галочки, нажимаем ОК.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_3&diff=606FAQ:WinAPI, VCPP Part 32008-10-14T18:09:33Z<p>Алексей1153++: </p>
<hr />
<div><br />
=== Как узнать, что пользователь меняет текст в приложении на основе CRichEditView?===<br />
Нужно добавить обработчик сообщения EN_CHANGE. Сообщение генерируется CRichEditView каждый раз, когда пользователь изменяет текст в окне CRichEditView<br />
<br />
===Чем отличается метод CArray::GetSize от метода CArray::GetCount?===<br />
Эти методы абсолютно идентичны. Скорее всего, в более старых версиях библиотек функции, одинаковые по смыслу, имели разные имена. Поэтому в целях совместимости разработчики оставили обе функции)<br />
<br />
===Как загрузить текстовую строку из ресурса?===<br />
Пример:<br />
<syntaxhighlight><br />
CString m_Temp;<br />
m_Temp.LoadString(ID_MYSTRING);<br />
</syntaxhighlight><br />
<br />
===Как поменять иконку у элемента item в CListCtrl?===<br />
Пример:<br />
<syntaxhighlight><br />
//заполняем структуру LVITEM<br />
LVITEM lvItem;<br />
memset(&lvItem,0,sizeof(lvItem));<br />
<br />
lvItem.mask = LVIF_IMAGE;//меняться будет картинка<br />
lvItem.iItem = ...;// индекс элемента списка (Zero-based)<br />
lvItem.iSubItem = 0;<br />
lvItem.iImage = ...; //индекс иконки (из списка контрола)<br />
<br />
pList->SetItem(&lvItem);<br />
</syntaxhighlight><br />
<br />
===Имеется класс Class1, содержащий мембер типа "указатель на Class2". В Class2 также имеется указатель на Class1. Компилятор выдаёт ошибку. Что надо делать?===<br />
Перекрёстное определение обходится следкющим образом: код обоих классов разносится в пары файлов *.h и *.cpp, а перед каждым классом вписывается предопределение другого класса:<br />
<br />
<br />
файл "class1.h"<br />
<syntaxhighlight><br />
class Class2;//предопределение Class2<br />
<br />
Class1<br />
{<br />
Class2* m_p2;//компилятор разрешит объявление указателя Class2*<br />
<br />
void F1(Class2* p);//компилятор разрешит объявление указателя Class2*<br />
void F2(Class1* p);<br />
};<br />
</c<br />
ode><br />
<br />
файл "class1.cpp"<br />
<syntaxhighlight><br />
#include "class1.h"<br />
#include "class2.h"<br />
<br />
void Class1::F1(Class2* p)<br />
{<br />
...<br />
}<br />
<br />
void Class1::F2(Class1* p)<br />
{<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
файл "class2.h"<br />
<syntaxhighlight><br />
class Class1;//предопределение Class1<br />
<br />
Class2<br />
{<br />
Class1* m_p1;//компилятор разрешит объявление указателя Class1*<br />
<br />
void F3(Class1* p);//компилятор разрешит объявление указателя Class1*<br />
};<br />
</syntaxhighlight><br />
<br />
<br />
файл "class2.cpp"<br />
<syntaxhighlight><br />
#include "class2.h"<br />
#include "class1.h"<br />
<br />
void Class2::F3(Class1* p)<br />
{<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
После предопределениея класса компилятор позволяет объявлять указатель на класс, так как переменная указателя на любой тип имеет всегда один и тот же размер.<br />
<br />
===Как переключить раскладку в другом (то есть в активном) процессе?===<br />
Для этого можно использовать функции<br />
<syntaxhighlight><br />
GetKeyboardLayout(...); // определить текущую раскладку<br />
LoadKeyboardLayout(...); // загрузить новую раскладку<br />
VerLanguageName(...); // получить строку с описанием языка<br />
</syntaxhighlight><br />
<br />
Подробности - в MSDN<br />
<br />
===Как получить хендл элемента управления, зная его идентификатор?===<br />
Пример:<br />
Пусть элемент Edit лежит на окне CMyWnd.<br />
Тогда:<br />
<syntaxhighlight><br />
void CMyWnd::некая_процедура()<br />
{<br />
//для MFC<br />
CEdit* ed=(CEdit* ) GetDlgItem(ID_EDIT1);<br />
HWND hwnd=ed->GetSafeHwnd();<br />
if(hwnd)<br />
{<br />
...<br />
}<br />
<br />
//для Win32 API<br />
HWND hwnd=GetDlgItem(m_hWnd,ID_EDIT1);<br />
if(hwnd)<br />
{<br />
...<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
===Как из дочернего окна закрыть приложение?===<br />
Для этого нужно послать родительскому окну сообщение WM_CLOSE:<br />
<br />
через указатель на родительское окно:<br />
<syntaxhighlight><br />
pParent->PostMessage(WM_CLOSE);<br />
</syntaxhighlight><br />
<br />
при помощи хендла рордительского окна:<br />
<syntaxhighlight><br />
::PostMessage(pParent->m_hWnd,WM_CLOSE,(WPARAM)0,(LPARAM)0);<br />
</syntaxhighlight><br />
<br />
===Как корректно перевести тип BSTR в CString и наоборот?===<br />
<br />
1) для конвертирования BSTR в CString нужно просто присвоить переменной типа CString переменную типа BSTR.<br />
Оператор "=" класса CString сам выполнит всю работу.<br />
<br />
2) для конвертирования BSTR в CString нужно выполнить код:<br />
<syntaxhighlight><br />
<br />
//указатель на будущий буфер с BSTR.<br />
BSTR bstrHE=0;<br />
// (По сути, BSTR определён как <br />
// typedef WCHAR* BSTR;<br />
// то есть указатель на 16-битный символ юникод)<br />
<br />
//строка для конвертации<br />
CString Str="мой текст";<br />
<br />
//Выделяем память и загружаем адрес блока в bstrHE<br />
bstrHE=Str.AllocSysString();<br />
<br />
//... <br />
//тут работаем с bstrHE[]<br />
//...<br />
<br />
//освобождаем память<br />
SysFreeString(bstrHE);<br />
</syntaxhighlight><br />
<br />
===Как получить доступ к графическим ресурсам элементов текущей темы оформления Windows?===<br />
<br />
Для этого нужно использовать функции<br />
<br />
<syntaxhighlight><br />
OpenThemeData(...);<br />
DrawThemeBackground(...);<br />
DrawFrameControl(...);<br />
CloseThemeData(...);<br />
</syntaxhighlight><br />
<br />
(подробности - в MSDN)<br />
<br />
===Имеется класс , производный от CDialog. Когда диалог в фокусе, нажатие на Enter или Esc приводит к закрытию диалога. Как это запретить?===<br />
При нажатии Enter происходит выполнение команды IDOK,при нажатии Esc - IDCANCEL.<br />
<br />
Нужно переопределить в классе виртуальные функции OnOk() и OnCancel(), которые соответственно вызываются для этих команд. При помощи визарда эти функции добавить можно так:<br />
<br />
Положить на диалог две кнопки с идентификаторами IDOK и IDCANCEL (при создании нового диалога они там есть сразу), затем двойной щелчок по кнопке добавит соответствующий обработчик. В обработчиках надо удалить вызовы СDialog::OnOK() и CDialog::OnCancel(), тогда диалог закрываться не будет.<br />
<br />
Однако тогда диалог станет невозможно закрыть кнопкой с крестиком. Это обходится так: добавляем обработчик сообщения WM_CLOSE - OnClose(), и в нём делаем вызов OnOk() или OnCancel():<br />
<syntaxhighlight><br />
void CPlayersPropsDialog::OnClose() <br />
{<br />
CDialog::OnClose();<br />
CDialog::OnCancel();//добавлено<br />
}<br />
</syntaxhighlight><br />
<br />
===Я написал в VC++ простейший макрос , где невозможно ошибиться, а компилятор всё же выдаёт ошибку. Не пойму, в чём дело?===<br />
<br />
Скорее всего после одного из символов соединения строк "\" имеется пробел или табуляция. Их надо удалить. Можно найти их "наощупь", а можно включить показ непечатных символов в студии. Найти эту команду можно так:<br />
<br />
Tools->Customize...->вкладка Commands. В окошке Category выбрать "Edit", и среди кнопок справа найти кнопку, на которой написано "a.b"<br />
<br />
Эту кнопку надо перетащить на одну из панелей инструментов студии.<br />
<br />
===Как получить список всех процесов, включая idle?===<br />
<br />
Использовать функции<br />
<syntaxhighlight><br />
Process32First(...);<br />
Precess32Next(...);<br />
</syntaxhighlight><br />
<br />
(подробности - в MSDN)<br />
<br />
===Как программно установить переменные окружения?===<br />
Чтобы добавить или изменить их программно, необходимо воспользоваться ключом реестра<br />
<syntaxhighlight><br />
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment<br />
</syntaxhighlight><br />
<br />
Затем нужно отправить широковещательное сообщение WM_SETTINGCHANGE (это позволит приложениям узнать об изменениях):<br />
<syntaxhighlight><br />
::SendMessage(HWND_BROADCAST,WM_SETTINGCHANGE,0,0);<br />
</syntaxhighlight><br />
<br />
<br />
===Как сделать, чтобы у окна был черный фон?===<br />
Нужно переопределить обработчик сообщения WM_CTLCOLOR - OnCtlColor() :<br />
<br />
<syntaxhighlight><br />
CBrush br(RGB(0,0,0)); //глобальная переменная или член класса CMyDlg,<br />
// инициализированный в OnInitDialog()<br />
<br />
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
HBRUSH hbr = CMyDlg::OnCtlColor(pDC, pWnd, nCtlColor);<br />
<br />
//фон диалога (или View)<br />
if(nCtlColor==CTLCOLOR_DLG)<br />
{<br />
return (HBRUSH)br;<br />
}<br />
<br />
//фон элементов SCtatic, лежащих на форме (если нужно)<br />
if(nCtlColor==CTLCOLOR_STATIC)<br />
{<br />
//делаем фон текста статика прозрачным<br />
pDC->SetBkMode(TRANSPARENT);<br />
return (HBRUSH)br;<br />
}<br />
<br />
return hbr;<br />
}<br />
</syntaxhighlight><br />
<br />
===Почему на моем компьютере экзешник, созданный в MFC запускается, а на других компьютерах - нет? Требует какую-то dll-ку.===<br />
Нужно выбирать режим Release :<br />
<br />
Menu->Build->Configurations...->Release,<br />
<br />
и экзешник, соответственно, брать из папки Release проекта.<br />
<br />
===Как в диалог добавить меню?===<br />
Нужно создать в редакторе ресурсов новое меню, затем вставить его в диалог:<br />
<br />
1)открыть в редакторе диалог,<br />
<br />
2)в свойствах (во вкладке General, окошко Menu) указать идентивикатор ресурса меню.<br />
<br />
3)при помощи визарда добавить для меню обработчики OnCommand() и OnUpdateСommand().<br />
<br />
===Почему не вызывается OnUpdate для пунктов меню (не получается ни затенить, ни отметку поставить)?===<br />
В диалоге (CDialog) у меню апдейт не происходит сам, в отличие от мейнфрейма (CFrameWnd). Для этого нужно сделать самим апдейт в обработчике сообщения WM_KICKIDLE.<br />
<br />
Визардом этот обработчик не добавляется, поэтому можно переопределить виртуальную DefWindowProc() и там обработать:<br />
<syntaxhighlight><br />
#include <afxpriv.h> //этот файл надо включить, там определёна WM_KICKIDLE<br />
<br />
LRESULT CMyDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
if(message==WM_KICKIDLE)<br />
{<br />
//делаем апдейт для всех пунктов меню<br />
CMenu* pMainMenu=GetMenu();<br />
if(pMainMenu)<br />
{<br />
CCmdUI cmdUI;<br />
for (UINT n=0; n < pMainMenu->GetMenuItemCount(); ++n)<br />
{<br />
CMenu* pSubMenu = pMainMenu->GetSubMenu(n);<br />
if(!pSubMenu)continue;<br />
<br />
cmdUI.m_nIndexMax = pSubMenu->GetMenuItemCount();<br />
for (UINT i = 0; i < cmdUI.m_nIndexMax;++i)<br />
{<br />
cmdUI.m_nIndex = i;<br />
cmdUI.m_nID = pSubMenu->GetMenuItemID(i);<br />
cmdUI.m_pMenu = pSubMenu;<br />
cmdUI.DoUpdate(this, FALSE);<br />
}<br />
}<br />
}<br />
}<br />
<br />
return CDialog::DefWindowProc(message, wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
===Как в главном окне отключить системное меню (в левом верхнем углу) и кнопки(в правом верхнем углу)?===<br />
При создании окна нужно убрать стиль WS_SYSMENU (теперь пользователь корректно может закрыть окно только Alt+F4, ну или если вы предоставите ему дополнительную возможность сделать это)<br />
<br />
Пример 1. (для SDI, MDI)<br />
<syntaxhighlight><br />
//этот обработчик уже добавлен визардом<br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
if( !CFrameWnd::PreCreateWindow(cs) )<br />
return FALSE;<br />
// TODO: Modify the Window class or styles here by modifying<br />
// the CREATESTRUCT cs<br />
<br />
///////////////////////////////<br />
//добавленная часть<br />
{<br />
//убираем стиль<br />
cs.style&=~WS_SYSMENU;<br />
}<br />
///////////////////////////////<br />
<br />
return TRUE;<br />
}<br />
</syntaxhighlight><br />
<br />
Пример 2. (для диалога)<br />
<br />
Если диалог описан в ресурсах, то в свойствах диалога убрать галочки<br />
<br />
"System menu"<br />
<br />
"Minimize box"<br />
<br />
"Maximize box"<br />
<br />
===Как запретить пользователю нажать на кнопку?===<br />
Нужно применить метод класса CWnd::EnableWindow(...) для кнопки. Значение параметра 0 делает кнопку неактивной, 1 - делает активной (кстати, не только для кнопки можно, а для любого класса, производного от класса CWnd).<br />
<br />
<br />
Пусть имеется некий диалог, на нём лежит кнопка c ID == IDC_1. В любом месте кода диалога (кроме конструктора и деструктора , хотя, если проверить наличие валидного хендла диалога, как в примере, то ничего страшного не будет и там) выполняем код<br />
<syntaxhighlight><br />
//делаем кнопку неактивной<br />
if(m_hWnd)<br />
{<br />
CWnd* pw=0;<br />
pw=GetDlgItem(IDC_1);<br />
if(pw)pw->EnableWindow(0);<br />
}<br />
</syntaxhighlight><br />
<br />
===Что означают сообщения, которые студия выводит при компиляции, вроде таких : Loaded 'C:\WINDOWS\SYSTEM\WSOCK32.DLL', no matching symbolic information found. ===<br />
Это строка говорит о том, что студия не смогла найти отладочные символы для WSOCK32.DLL. В этом нет ничего страшного, просто при наличии отладочных символов в процессе отладки можно получить доступ к именам функции из системных DLL. Например, вместо<br />
<syntaxhighlight><br />
KERNEL32! 0x77E8B184()<br />
</syntaxhighlight><br />
увидим<br />
<br />
<syntaxhighlight><br />
KERNEL32!CreateThread.<br />
</syntaxhighlight><br />
<br />
===Как обработать сообщения, которое приходит к некому элементу управления?===<br />
Скажем, нужно обработать сообщения, приходящие к элементу класса CEdit. Нужно произвести от CEdit свой класс, и в виртуальной процедуре класса WindowProc перехватить нужные сообщения.<br />
<syntaxhighlight><br />
virtual LRESULT WindowProc(<br />
UINT message,<br />
WPARAM wParam,<br />
LPARAM lParam <br />
);<br />
</syntaxhighlight><br />
<br />
Пример. Полностью выключаем, скажем, обработку сообщения WM_CHAR<br />
<syntaxhighlight><br />
LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
switch(message)<br />
{<br />
case WM_CHAR:<br />
{<br />
return 0;<br />
}<br />
break;<br />
}<br />
<br />
return CEdit::WindowProc(message, wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
Чтобы связать экземпляр класса с элементо на форме, добавьте визардом для<br />
контрола переменную класса (выбрав не Value а Control).<br />
<br />
===Как настроить количество пробелов в табуляции?===<br />
Есть пара способов:<br />
<br />
1) Tools->Options->Tabs->Insert Spaces<br />
<br />
2) правой кнопкой мыши щёлкнуть по тексту, в контекстном меню выбрать properties<br />
<br />
===Как автоматически расставить отступы?===<br />
Нужно в студии выделить текст для форматирования, нажать Alt+F8.<br />
<br />
Ещё есть программа Artistic Style ( http://sourceforge.net/projects/astyle/ ), которая занимается переформатированием кода.<br />
<br />
===Поиск границ блока===<br />
Сочетание клавиш CTRL+ "}" ищет парную фигурную скобку в тексте и переходит к ней.<br />
<br />
===Вертикальное выделение текста===<br />
Если удерживать клавишу Alt, а затем начать выделять текст мышкой, то область выделения принимает форму прямоугольника, что позволяет выделять вертикальные фрагменты текста.<br />
<br />
===Как узнать количество установленных в CListCtrl столбцов?===<br />
Пример<br />
<syntaxhighlight><br />
//указатель на переменную-контрол<br />
CListCtrl* pL=...;<br />
<br />
//получаем количество столбцов<br />
int count=pL->GetHeaderCtrl()->GetItemCount();<br />
</syntaxhighlight><br />
<br />
===Как получить иконку приложения?===<br />
Если приложение запущено, то нужно найти его главное окно и послать ему сообщение WM_GETICON.<br />
<syntaxhighlight><br />
//функция возвращант хендл иконки <br />
LRESULT SendMessage(hWnd, WM_GETICON, wParam, 0);<br />
<br />
//hWnd == хендл окна приложения<br />
//wParam == <br />
// 1)==ICON_BIG - получить большую иконку<br />
// 2)==ICON_SMALL - получить маленькую иконку<br />
// 3)==ICON_SMALL2 - получить маленькую иконку, если она определена<br />
// в приложении. Если её нет, то маленькую иконку, <br />
// сгенерированную системой из большой иконки<br />
</syntaxhighlight><br />
<br />
===Как в CString можно найти или вырезать часть строки?===<br />
Это можно сделать при помощи методов класса CString:<br />
<syntaxhighlight><br />
//вырезает кусок строки<br />
CString Mid(int nFirst) const;<br />
CString Mid(int nFirst, int nCount) const;<br />
<br />
//возвращает кусок строки (сначала или с конца)<br />
CString Left(int nCount ) const;<br />
CString Right(int nCount ) const;<br />
<br />
//возвращает начальный кусок строки, в котором есть только<br />
//символы из набора,представленного в lpszCharSet<br />
CString SpanIncluding(LPCTSTR lpszCharSet ) const;<br />
<br />
//возвращает начальный кусок строки, в котором нет<br />
//символов из набора,представленного в lpszCharSet<br />
CString SpanExcluding(LPCTSTR lpszCharSet ) const; <br />
<br />
//убирает "пробелоподобные" символы из самого начала строки<br />
//(то есть - пробел, табуляцию (\t) , возврат каретки, перевод строки (/r/n))<br />
void TrimLeft();<br />
//убирает все повторы символа из самого начала строки<br />
void TrimLeft(TCHAR chTarget );<br />
//убирает из самого начала строки все символа из набора lpszTargets <br />
void TrimLeft(LPCTSTR lpszTargets );<br />
<br />
void TrimRight();<br />
void TrimRight(TCHAR chTarget );<br />
void TrimRight(LPCTSTR lpszTargets );<br />
<br />
//поиск в строке<br />
int Find( TCHAR ch ) const;<br />
int Find( LPCTSTR lpszSub ) const;<br />
int Find( TCHAR ch, int nStart ) const;<br />
int Find( LPCTSTR pstr, int nStart ) const;<br />
<br />
//поиск, начиная с конца<br />
int ReverseFind( TCHAR ch ) const;<br />
<br />
//поиск позиции первого символа, одного из набора,<br />
// представленного в lpszCharSet<br />
int FindOneOf( LPCTSTR lpszCharSet ) const;<br />
</syntaxhighlight><br />
<br />
===Как отобразить на элементах управления промежуточные результаты длительных вичислений ?===<br />
В общем случае это делается принудительной перерисовкой нужного окна путём объявления этого окна невалидным<br />
<syntaxhighlight><br />
pWnd->Invalidate(0);<br />
</syntaxhighlight><br />
а затем непосредственной отсылки в оконную процедуру сообщения WM_PAINT<br />
<syntaxhighlight><br />
pWnd->UpdateWindow();<br />
</syntaxhighlight><br />
<br />
Пример:<br />
<syntaxhighlight><br />
CWnd* pWnd=...;//окно, которое надо перерисовывать<br />
<br />
for(int i=0;i<10000)<br />
{<br />
//меняется содержимое окна<br />
//...<br />
<br />
//немедленная перерисовка<br />
pWnd->Invalidate(0);<br />
pWnd->UpdateWindow();<br />
}<br />
</syntaxhighlight><br />
<br />
Также можно также просто вызвать метод RedrawWindow() с параметрами по умолчанию.<br />
<br />
===Я написал DLL, которую используют несколько приложений. Всё вроде работает, но когда происходит очередной вызов функции из DLL, почему то данные в функции обнуляются. С чем это связано?===<br />
Переменные и массивы в DLL, содержимое которых должно использоваться несколькими процессами, должны объявляться статическими. Статическая переменная или массив инициализируются только один раз в момент загрузки DLL.<br />
Пример:<br />
<syntaxhighlight><br />
DWORD calltest()<br />
{<br />
//будет выполнено только при первом вызове<br />
static DWORD callcount=0;<br />
static DWORD str[1000]={0}; <br />
<br />
//будет выполняться каждый раз<br />
return ++callcount;<br />
}<br />
</syntaxhighlight><br />
<br />
===Как открыть проекцию файла в память и как с ней работать?===<br />
<br />
Создание проекции:<br />
<syntaxhighlight><br />
HANDLE CreateFileMapping(<br />
HANDLE hFile, //хендл уже открытого файла<br />
LPSECURITY_ATTRIBUTES lpAttributes,<br />
DWORD flProtect, //способ открытия проекции<br />
DWORD dwMaximumSizeHigh, //размер файла (старшие 4 байта , обычно==0)<br />
DWORD dwMaximumSizeLow, //размер файла (младшие 4 байта)<br />
LPCTSTR lpName<br />
);<br />
</syntaxhighlight><br />
<br />
Доступ к созданной проекции производится процедурой:<br />
<syntaxhighlight><br />
LPVOID MapViewOfFile(<br />
HANDLE hFileMappingObject, //хендл проекции<br />
DWORD dwDesiredAccess, //способ работы с проекцией<br />
DWORD dwFileOffsetHigh,<br />
DWORD dwFileOffsetLow, //смещение от начала файла (младшие 4 байта)<br />
SIZE_T dwNumberOfBytesToMap //длина в байтах (если ==0 - то весь файл)<br />
);<br />
</syntaxhighlight><br />
<br />
далее с файлом можно работать как с обычным массивом в памяти.<br />
<br />
После работы с проекцией, её надо освободить процедурой<br />
<syntaxhighlight><br />
BOOL UnmapViewOfFile(<br />
LPCVOID lpBaseAddress //адрес, который вернула процедура MapViewOfFile<br />
);<br />
</syntaxhighlight><br />
<br />
Пример:<br />
<syntaxhighlight><br />
HANDLE hFile=...;//хендл уже открытого файла<br />
DWORD dwdFileLen=...;//размер открытого файла<br />
<br />
HANDLE hMapFile=0;//хендл для проекции<br />
<br />
//создаём проекцию "только для чтения"<br />
hMapFile=::CreateFileMapping(hFile,0,PAGE_READONLY,0,dwdFileLen,0);<br />
<br />
//хендл hFile можно закрыть уже здесь, в принципе,<br />
//но мы сделаем это позже<br />
<br />
//получаем доступ к проекции (тоже только для чтения)<br />
BYTE* pbyFile=(BYTE*)::MapViewOfFile(hMapFile,FILE_MAP_READ,0,0,0);<br />
<br />
///////////////////<br />
//тут работаем с массивом pbyFile[dwdFileLen] как с обычным,<br />
//только не забываем, что он открыт только для чтения<br />
//...<br />
//...<br />
//...<br />
///////////////////<br />
<br />
//отключаем файл данных от адресного пространства<br />
UnmapViewOfFile(pbyFile);<br />
<br />
//освобождаем хендл проекции<br />
CloseHandle(hMapFile)<br />
<br />
//освобождаем хендл открытого файла<br />
CloseHandle(hFile);<br />
</syntaxhighlight><br />
<br />
===Как в MFC Grid control отобразить картинку в ячейке?===<br />
Нужно создать список изображений (CImageList), затем передать указатель на список в таблицу. Поскольку элемент управления лишь копирует указатель, список должен создаваться динамически, либо быть членом класса, экземпляр которого существует всё время работы таблицы.<br />
<syntaxhighlight><br />
CImageList m_ImageList;<br />
CGridCtrL m_Grid1;<br />
...<br />
...<br />
//неким образом создаётся список<br />
m_ImageList.Create(...);<br />
//...<br />
<br />
//вставляем в контрол<br />
m_Grid1.SetImageList(&m_ImageList);<br />
<br />
//<br />
</syntaxhighlight><br />
<br />
===Как при помощи IPicture отобразить картинку из файла? ===<br />
Пример - несложная функция, отображающая картинку из файла. Поддерживаются форматы BMP, GIF, JPEG, PNG, TIFF, EMF<br />
<syntaxhighlight><br />
#include "atlconv.h"<br />
#define HandleIsValid(H) (H!=(HANDLE)-1 && H!=(HANDLE)0)<br />
<br />
//*pDestDC - CDC, на который предполагается вывод картинки<br />
//pchzFilePath - путь к файлу<br />
//pWid - (возвращает) ширина картинки<br />
//pHig - (возвращает) высота картинки<br />
bool DrawBitmapFromFile(CDC* pDestDC,const char* pchzFilePath,int *pWid=0,int *pHig=0)<br />
{<br />
bool result=false;<br />
<br />
if(pWid)*pWid=0;<br />
if(pHig)*pHig=0;<br />
<br />
int Wid=0;<br />
int Hig=0;<br />
<br />
IPicture* pPic=0;<br />
try<br />
{<br />
IPicture* ptmpPic=0;<br />
USES_CONVERSION;<br />
HRESULT hr;<br />
<br />
CString txt=pchzFilePath;<br />
hr= ::OleLoadPicturePath(<br />
const_cast<LPOLESTR>(T2COLE(txt)),<br />
0,0,0,IID_IPicture,<br />
reinterpret_cast<void **>(&ptmpPic)<br />
);<br />
<br />
if(hr==S_OK && ptmpPic)<br />
{<br />
pPic=ptmpPic;<br />
}<br />
else<br />
{<br />
throw 0;<br />
}<br />
<br />
OLE_XPOS_HIMETRIC cxSrc;<br />
OLE_YPOS_HIMETRIC cySrc;<br />
<br />
if(S_OK!=pPic->get_Width(&cxSrc))throw 0;<br />
if(S_OK!=pPic->get_Height(&cySrc))throw 0;<br />
<br />
Wid=cxSrc/26;<br />
Hig=cySrc/26;<br />
<br />
//рисуем<br />
if(S_OK !=pPic->Render(pDestDC->GetSafeHdc(),<br />
0,Hig,Wid,-Hig,0,0,cxSrc,cySrc,0))throw 0;<br />
}<br />
catch(...)<br />
{<br />
result=false;<br />
}<br />
<br />
if(pPic)<br />
{<br />
pPic->Release();<br />
pPic=0;<br />
}<br />
<br />
<br />
if(pWid)*pWid=Wid;<br />
if(pHig)*pHig=Hig;<br />
<br />
return result;<br />
}<br />
</syntaxhighlight><br />
<br />
===Как позволить пользователю начать ввод новой строки в многострочном поле редактирования?===<br />
Нужно в редакторе ресурсов поставить для свойств окошка CEdit галочку "WantReturn" или добавить стиль ES_WANTRETURN при создании CEdit контрола динамически. Тогда при нажатии Enter в поле редиктирования будет вводиться новая строка.<br />
<br />
===Как выводят картинку-логотип(splash screen) при запуске программы?===<br />
Для этого используется класс, производный от CDialog. Этот диалог после создания показывает себя на экран, выводя на себя рисунок. Также запускает таймер, по срабатывани которого диалог гасится. Создаётся диалог в процедуре InitInstance приложения.<br />
<br />
В VC6++ также есть уже готовый компонент<br />
<br />
Project->Add To Project -> Components and Controls->(в папке "Visual C++ Components" есть SplashScreen.)<br />
<br />
===Как сделать, чтобы при выпадении списка у ComboBox была не одна строка, а больше, вроде все свойства покрутил, не помогает Вместо выпадающего списка одна строка и скролл...===<br />
В редакторе ресурсов надо щелкнуть в комбобоксе на треугольнике - появляется рамка для растягивания вниз - размер выпадающего списка.<br />
<br />
===В VC++.net, что делать после того, как на форму установил ActiveX ListView, как объявить класс и переменную для этого элемента?===<br />
Щёлкнуть правой кнопкой мыши на элементе, в меню - add variable или add class<br />
<br />
===Как работать с буфером обмена (Clipboard)?===<br />
<br />
КОПИРОВАНИЕ В БУФЕР ОБМЕНА:<br />
<br />
Алгоритм<br />
<syntaxhighlight><br />
1.Готовим данные<br />
а. Выделяем память из кучи, вызывая GlobalAlloc()<br />
б. Получаем указатель на выделенную память, вызывая GlobalLock()<br />
в. Заполняем данные<br />
г. Освобождаем указатель, вызывая GlobalUnlock();<br />
<br />
2.Открываем буфер обмена, вызывая OpenClipboard();<br />
<br />
3.Очищаем буфер, вызывая EmptyClipboard();<br />
<br />
4.Вызываем SetClipboardData() один раз для каждого формата<br />
вставляемых данных (имеется в виду - если одни и те же<br />
данные представлены в разных форматах, и приложение<br />
может эти форматы создать)<br />
<br />
5.Закрываем буфер, вызывая CloseClipboard();<br />
<br />
6.ВЫЗЫВАТЬ GlobalFree() НЕ НУЖНО, в этом случае это<br />
предоставлено системе<br />
</syntaxhighlight><br />
<br />
Скажем, хотим поместить в буфер обмена текст.<br />
<syntaxhighlight><br />
//готовим данные<br />
//выделяем из кучи память для данных<br />
HANDLE hglbCopy = GlobalAlloc(GMEM_MOVEABLE,10);<br />
if(!hglbCopy)return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)return;<br />
<br />
//заполняем данные<br />
strcpy((char*)lpStr,"my text");<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
//очищаем<br />
EmptyClipboard();<br />
<br />
//текстовый формат<br />
SetClipboardData(CF_TEXT,hglbCopy);<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</syntaxhighlight><br />
<br />
---<br />
<br />
ИЗВЛЕЧЕНИЕ ИЗ БУФЕРА ОБМЕНА<br />
<br />
Алгоритм<br />
<syntaxhighlight><br />
1.Проверяем, что поддерживается нужный формат данных,<br />
вызывая IsClipboardFormatAvailable()<br />
<br />
2.Открываем буфер обмена, вызывая OpenClipboard();<br />
<br />
3.Достаём данные<br />
а.Получаем из буфера хендл требуемого формата,<br />
вызывая GetClipboardData()<br />
б.Получаем указатель на выделенную память, вызывая GlobalLock()<br />
в.Работаем с данными<br />
г.Освобождаем указатель, вызывая GlobalUnlock();<br />
<br />
4.Закрываем буфер, вызывая CloseClipboard();<br />
</syntaxhighlight><br />
<br />
Скажем, хотим извлечь из буфера обмена текст.<br />
<syntaxhighlight><br />
//Проверяем, что поддерживается нужный формат данных,<br />
if(!IsClipboardFormatAvailable(CF_TEXT))return;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
<br />
//достаём данные<br />
<br />
//текстовый формат<br />
HANDLE hglbCopy = GetClipboardData(CF_TEXT);<br />
if(!hglbCopy)return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)return;<br />
<br />
//читаем данные<br />
char data[10];<br />
memmove(data,lpStr,sizeof(data));<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</syntaxhighlight><br />
<br />
<br />
===Как получить полный путь к экзешнику из самой программы?===<br />
Можно прочитать параметры командной строки - в командную строку первым параметром система всегда передаёт заключённый в кавычки полный путь к файлу запущенной программы. Достаём путь следующим образом:<br />
<syntaxhighlight><br />
BOOL CMyApp::InitInstance()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName содержит искомый путь<br />
<br />
//...<br />
//...<br />
}<br />
</syntaxhighlight><br />
<br />
===Каким способом exe файл может заменить самого себя? ===<br />
<br />
К примеру, программа должна обновляется через Internet и хочет обновить свой exe-файл. Но так как он в данный момент запущен, это будет, естественно, невозможно сделать напрямую.<br />
Один из способов - сделать копию экзешника и из него обновиться<br />
<br />
<syntaxhighlight><br />
#define def_exeNAMEup "c:\\myprog_toupdate.exe" //путь к старому файлу<br />
#define def_exeNAMEdnld "c:\\myprog_downloaded.exe" //путь к новому файлу (уже "скачали" :) )<br />
#define def_keyUdate "/update"<br />
<br />
void CTESTFAQApp::UpdateItself()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName - содержит искомый путь<br />
<br />
//делаем копию экзешника с другим именем<br />
CopyFile(csFullExeName,def_exeNAMEup,0);<br />
<br />
//передаём в параметры нового процесса ключ и путь к текущему файлу<br />
CString csParams=def_keyUdate;<br />
csParams+=" ";<br />
csParams+=csFullExeName;<br />
<br />
//запускаем копию<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(def_exeNAMEup,def_keyUdate,0,0,0,0,0,0,&si,&pi))<br />
{<br />
//завершаем текущий процесс<br />
ExitFromMyApp();<br />
}<br />
}<br />
<br />
void CTESTFAQApp::ExitFromMyApp()<br />
{<br />
exit(0);<br />
}<br />
<br />
BOOL CTESTFAQApp::InitInstance()<br />
{<br />
<br />
//смотрим, не запустили ли для апдейта?<br />
<br />
CString txt;<br />
txt=m_lpCmdLine;<br />
if(txt.Find(def_keyUdate)==0)<br />
{<br />
//делаем айдейт<br />
txt.Replace(def_keyUdate,"");<br />
txt.TrimLeft();<br />
<br />
CString csFullExeName=txt;<br />
<br />
//берём откуда то уже скачанный файл обновления<br />
//...<br />
CString csFull_Downloaded_ExeName=def_exeNAMEdnld;<br />
<br />
//копируем файл (обновляем старый то есть)<br />
CopyFile(csFull_Downloaded_ExeName,csFullExeName,0);<br />
<br />
//запускаем обновлённого мученника<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(csFullExeName,0,0,0,0,0,0,0,&si,&pi))<br />
<br />
ExitFromMyApp();<br />
<br />
}<br />
//...<br />
//...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как производится конвертация из кодировки UTF8 в 1251 и наоборот ?===<br />
<br />
Можно перевести строку из UTF8 в Unicode, затем из Unicode в 1251<br />
<br />
Ниже приведена структура, содержащая процедуры перекодирования,<br />
а также процедуру с примером использования<br />
<syntaxhighlight><br />
//описание структуры<br />
struct coder<br />
{<br />
//utf8->unicode<br />
static wchar_t* utf8_to_unicode__dontForgetDeleteArr(const char *utf8_string)<br />
{<br />
wchar_t* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len=MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,0,0);<br />
if(!res_len)return 0;<br />
<br />
//выделяем память<br />
pRes = new wchar_t[res_len];<br />
if(!pRes)return 0;<br />
<br />
//преобразование<br />
if(!MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,pRes,res_len))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//unicode->1251<br />
static char * unicode_to_1251__dontForgetDeleteArr(const wchar_t *unicode_string)<br />
{<br />
char* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len = WideCharToMultiByte(1251,0,unicode_string,-1,0,0,0,0);<br />
if(!res_len)return 0;<br />
<br />
//выделяем память<br />
pRes=new char[res_len];<br />
if(!pRes)return 0;<br />
<br />
//преобразование<br />
if(!WideCharToMultiByte(1251,0,unicode_string,-1,pRes,res_len,0,0))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//процедура с примером<br />
static void Example()<br />
{<br />
wchar_t* unicode_string=0;<br />
char* cp1251_string=0;<br />
<br />
//исходный текст<br />
char utf8_string[] = "UTF-8 + русский текст";<br />
<br />
for(;;)<br />
{<br />
<br />
unicode_string=utf8_to_unicode__dontForgetDeleteArr(utf8_string);<br />
if(!unicode_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать в unicode!");<br />
break;<br />
}<br />
<br />
cp1251_string = unicode_to_1251__dontForgetDeleteArr(unicode_string);<br />
<br />
if(!cp1251_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать из unicode!");<br />
break;<br />
}<br />
<br />
break;<br />
}<br />
<br />
//cp1251_string - результат<br />
AfxMessageBox(cp1251_string);<br />
<br />
<br />
//не забываем удалить массивы<br />
if(unicode_string)<br />
{<br />
delete [] unicode_string;<br />
unicode_string=0;<br />
}<br />
if(cp1251_string)<br />
{<br />
delete [] cp1251_string;<br />
cp1251_string=0;<br />
}<br />
}<br />
};<br />
<br />
//вызов примера<br />
coder::Example();<br />
</syntaxhighlight><br />
<br />
===Как работать с базой данных Access из программы на VC.net?===<br />
Проще всего подключить ADO компоненты и сделать все на них.<br />
<br />
Компоненты ADO (ADODC,DATAGRID и т.п.) это ActiveX.<br />
<br />
В редакторе ресурсов, во всплывающем меню, есть Insert ActiveX Control -> открывается список всех компоент, зарегистрированых на машине. Нужно найти компоненты (Это компоненты от MS и они помечены (OLEDB)) и вставить их в диалог. Для того что бы иметь возможность управлять ими, нужно импортировать обертки для них, это делается при помощи ClassWizard, там есть импорт->класс->указать файл с компоентой (OSX). Появляется список всех классов, объявленых внутри.<br />
<br />
Расставляем нужные галочки, нажимаем ОК.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_3&diff=605FAQ:WinAPI, VCPP Part 32008-10-08T18:12:27Z<p>Алексей1153++: /* Как получить список всех процесов, включая idle? */</p>
<hr />
<div><br />
<br />
=== Как узнать, что пользователь меняет текст в приложении на основе CRichEditView?===<br />
Нужно добавить обработчик сообщения EN_CHANGE. Сообщение генерируется CRichEditView каждый раз, когда пользователь изменяет текст в окне CRichEditView<br />
<br />
===Чем отличается метод CArray::GetSize от метода CArray::GetCount?===<br />
Эти методы абсолютно идентичны. Скорее всего, в более старых версиях библиотек функции, одинаковые по смыслу, имели разные имена. Поэтому в целях совместимости разработчики оставили обе функции)<br />
<br />
===Как загрузить текстовую строку из ресурса?===<br />
Пример:<br />
<syntaxhighlight><br />
CString m_Temp;<br />
m_Temp.LoadString(ID_MYSTRING);<br />
</syntaxhighlight><br />
<br />
===Как поменять иконку у элемента item в CListCtrl?===<br />
Пример:<br />
<syntaxhighlight><br />
//заполняем структуру LVITEM<br />
LVITEM lvItem;<br />
memset(&lvItem,0,sizeof(lvItem));<br />
<br />
lvItem.mask = LVIF_IMAGE;//меняться будет картинка<br />
lvItem.iItem = ...;// индекс элемента списка (Zero-based)<br />
lvItem.iSubItem = 0;<br />
lvItem.iImage = ...; //индекс иконки (из списка контрола)<br />
<br />
pList->SetItem(&lvItem);<br />
</syntaxhighlight><br />
<br />
===Имеется класс Class1, содержащий мембер типа "указатель на Class2". В Class2 также имеется указатель на Class1. Компилятор выдаёт ошибку. Что надо делать?===<br />
Перекрёстное определение обходится следкющим образом: код обоих классов разносится в пары файлов *.h и *.cpp, а перед каждым классом вписывается предопределение другого класса:<br />
<br />
файл "class1.h"<br />
<syntaxhighlight>class Class2;//предопределение Class2<br />
<br />
Class1<br />
{<br />
Class2* m_p2;//компилятор разрешит объявление указателя Class2*<br />
<br />
void F1(Class2* p);//компилятор разрешит объявление указателя Class2*<br />
void F2(Class1* p);<br />
};<br />
</syntaxhighlight><br />
<br />
файл "class1.cpp"<br />
<syntaxhighlight>#include "class1.h"<br />
#include "class2.h"<br />
<br />
void Class1::F1(Class2* p)<br />
{<br />
...<br />
}<br />
<br />
void Class1::F2(Class1* p)<br />
{<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
файл "class2.h"<br />
<syntaxhighlight>class Class1;//предопределение Class1<br />
<br />
Class2<br />
{<br />
Class1* m_p1;//компилятор разрешит объявление указателя Class1*<br />
<br />
void F3(Class1* p);//компилятор разрешит объявление указателя Class1*<br />
};<br />
</syntaxhighlight><br />
<br />
файл "class2.cpp"<br />
<syntaxhighlight>#include "class2.h"<br />
#include "class1.h"<br />
<br />
void Class2::F3(Class1* p)<br />
{<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
После предопределениея класса компилятор позволяет объявлять указатель на класс, так как переменная указателя на любой тип имеет всегда один и тот же размер.<br />
<br />
===Как переключить раскладку в другом (то есть в активном) процессе?===<br />
Для этого можно использовать функции<br />
<syntaxhighlight><br />
GetKeyboardLayout(...); // определить текущую раскладку<br />
LoadKeyboardLayout(...); // загрузить новую раскладку<br />
VerLanguageName(...); // получить строку с описанием языка<br />
</syntaxhighlight><br />
<br />
Подробности - в MSDN<br />
<br />
===Как получить хендл элемента управления, зная его идентификатор?===<br />
Пример:<br />
Пусть элемент Edit лежит на окне CMyWnd.<br />
Тогда:<br />
<syntaxhighlight><br />
void CMyWnd::некая_процедура()<br />
{<br />
//для MFC<br />
CEdit* ed=(CEdit* ) GetDlgItem(ID_EDIT1);<br />
HWND hwnd=ed->GetSafeHwnd();<br />
if(hwnd)<br />
{<br />
...<br />
}<br />
<br />
//для Win32 API<br />
HWND hwnd=GetDlgItem(m_hWnd,ID_EDIT1);<br />
if(hwnd)<br />
{<br />
...<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
===Как из дочернего окна закрыть приложение?===<br />
Для этого нужно послать родительскому окну сообщение WM_CLOSE:<br />
<br />
через указатель на родительское окно:<br />
<syntaxhighlight><br />
pParent->PostMessage(WM_CLOSE);<br />
</syntaxhighlight><br />
<br />
при помощи хендла рордительского окна:<br />
<syntaxhighlight><br />
::PostMessage(pParent->m_hWnd,WM_CLOSE,(WPARAM)0,(LPARAM)0);<br />
</syntaxhighlight><br />
<br />
===Как корректно перевести тип BSTR в CString и наоборот?===<br />
<br />
1) для конвертирования BSTR в CString нужно просто присвоить переменной типа CString переменную типа BSTR.<br />
Оператор "=" класса CString сам выполнит всю работу.<br />
<br />
2) для конвертирования BSTR в CString нужно выполнить код:<br />
<syntaxhighlight><br />
<br />
//указатель на будущий буфер с BSTR.<br />
BSTR bstrHE=0;<br />
// (По сути, BSTR определён как <br />
// typedef WCHAR* BSTR;<br />
// то есть указатель на 16-битный символ юникод)<br />
<br />
//строка для конвертации<br />
CString Str="мой текст";<br />
<br />
//Выделяем память и загружаем адрес блока в bstrHE<br />
bstrHE=Str.AllocSysString();<br />
<br />
//... <br />
//тут работаем с bstrHE[]<br />
//...<br />
<br />
//освобождаем память<br />
SysFreeString(bstrHE);<br />
</syntaxhighlight><br />
<br />
===Как получить доступ к графическим ресурсам элементов текущей темы оформления Windows?===<br />
<br />
Для этого нужно использовать функции<br />
<br />
<syntaxhighlight><br />
OpenThemeData(...);<br />
DrawThemeBackground(...);<br />
DrawFrameControl(...);<br />
CloseThemeData(...);<br />
</syntaxhighlight><br />
<br />
(подробности - в MSDN)<br />
<br />
===Имеется класс , производный от CDialog. Когда диалог в фокусе, нажатие на Enter или Esc приводит к закрытию диалога. Как это запретить?===<br />
При нажатии Enter происходит выполнение команды IDOK,при нажатии Esc - IDCANCEL.<br />
<br />
Нужно переопределить в классе виртуальные функции OnOk() и OnCancel(), которые соответственно вызываются для этих команд. При помощи визарда эти функции добавить можно так:<br />
<br />
Положить на диалог две кнопки с идентификаторами IDOK и IDCANCEL (при создании нового диалога они там есть сразу), затем двойной щелчок по кнопке добавит соответствующий обработчик. В обработчиках надо удалить вызовы СDialog::OnOK() и CDialog::OnCancel(), тогда диалог закрываться не будет.<br />
<br />
Однако тогда диалог станет невозможно закрыть кнопкой с крестиком. Это обходится так: добавляем обработчик сообщения WM_CLOSE - OnClose(), и в нём делаем вызов OnOk() или OnCancel():<br />
<syntaxhighlight><br />
void CPlayersPropsDialog::OnClose() <br />
{<br />
CDialog::OnClose();<br />
CDialog::OnCancel();//добавлено<br />
}<br />
</syntaxhighlight><br />
<br />
===Я написал в VC++ простейший макрос , где невозможно ошибиться, а компилятор всё же выдаёт ошибку. Не пойму, в чём дело?===<br />
<br />
Скорее всего после одного из символов соединения строк "\" имеется пробел или табуляция. Их надо удалить. Можно найти их "наощупь", а можно включить показ непечатных символов в студии. Найти эту команду можно так:<br />
<br />
Tools->Customize...->вкладка Commands. В окошке Category выбрать "Edit", и среди кнопок справа найти кнопку, на которой написано "a.b"<br />
<br />
Эту кнопку надо перетащить на одну из панелей инструментов студии.<br />
<br />
===Как получить список всех процесов, включая idle?===<br />
<br />
Использовать функции<br />
<syntaxhighlight><br />
Process32First(...);<br />
Precess32Next(...);<br />
</syntaxhighlight><br />
<br />
(подробности - в MSDN)<br />
<br />
===Как программно установить переменные окружения?===<br />
Чтобы добавить или изменить их программно, необходимо воспользоваться ключом реестра<br />
<syntaxhighlight><br />
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment<br />
</syntaxhighlight><br />
<br />
Затем нужно отправить широковещательное сообщение WM_SETTINGCHANGE (это позволит приложениям узнать об изменениях):<br />
<syntaxhighlight><br />
::SendMessage(HWND_BROADCAST,WM_SETTINGCHANGE,0,0);<br />
</syntaxhighlight><br />
<br />
<br />
===Как сделать, чтобы у окна был черный фон?===<br />
Нужно переопределить обработчик сообщения WM_CTLCOLOR - OnCtlColor() :<br />
<br />
<syntaxhighlight><br />
CBrush br(RGB(0,0,0)); //глобальная переменная или член класса CMyDlg,<br />
// инициализированный в OnInitDialog()<br />
<br />
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
HBRUSH hbr = CMyDlg::OnCtlColor(pDC, pWnd, nCtlColor);<br />
<br />
//фон диалога (или View)<br />
if(nCtlColor==CTLCOLOR_DLG)<br />
{<br />
return (HBRUSH)br;<br />
}<br />
<br />
//фон элементов SCtatic, лежащих на форме (если нужно)<br />
if(nCtlColor==CTLCOLOR_STATIC)<br />
{<br />
//делаем фон текста статика прозрачным<br />
pDC->SetBkMode(TRANSPARENT);<br />
return (HBRUSH)br;<br />
}<br />
<br />
return hbr;<br />
}<br />
</syntaxhighlight><br />
<br />
===Почему на моем компьютере экзешник, созданный в MFC запускается, а на других компьютерах - нет? Требует какую-то dll-ку.===<br />
Нужно выбирать режим Release :<br />
<br />
Menu->Build->Configurations...->Release,<br />
<br />
и экзешник, соответственно, брать из папки Release проекта<br />
===Как в диалог добавить меню?===<br />
Надо сделать в ресурсах меню, затем вставить в диалог:<br />
<br />
открыть в редакторе диалог, в свойствах (во вкладке General, окошко Menu) указать идентивикатор ресурса меню.<br />
При помощи визарда добавить для меню обработчики OnCommand() и OnUpdateСommand().<br />
===Я добавил визардом меню в диалог. Добавил обработчики для пунктов меню. Пункты работают, но OnUpdate для пунктов не вызывается - то есть не получается ни затенить, ни чек поставить. Что делать?===<br />
В диалоге у меню апдейта не происходит сам, в отличие от мейнфрейма.<br />
Для этого нужно сделать самим апдейт в обработчике сообщения WM_KICKIDLE.<br />
Визардом обработчик не добавляется, поэтому можно переопределить виртуальную DefWindowProc() и там обработать:<br />
<pre><br />
#include <afxpriv.h> //этот файл надо включить, там определёна WM_KICKIDLE<br />
<br />
LRESULT CMyDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
if(message==WM_KICKIDLE)<br />
{<br />
//делаем апдейт для всех пунктов меню<br />
CMenu* pMainMenu=GetMenu();<br />
if(pMainMenu)<br />
{<br />
CCmdUI cmdUI;<br />
for (UINT n=0; n < pMainMenu->GetMenuItemCount(); ++n)<br />
{<br />
CMenu* pSubMenu = pMainMenu->GetSubMenu(n);<br />
if(!pSubMenu)continue;<br />
<br />
cmdUI.m_nIndexMax = pSubMenu->GetMenuItemCount();<br />
for (UINT i = 0; i < cmdUI.m_nIndexMax;++i)<br />
{<br />
cmdUI.m_nIndex = i;<br />
cmdUI.m_nID = pSubMenu->GetMenuItemID(i);<br />
cmdUI.m_pMenu = pSubMenu;<br />
cmdUI.DoUpdate(this, FALSE);<br />
}<br />
}<br />
}<br />
}<br />
<br />
<br />
<br />
return CDialog::DefWindowProc(message, wParam, lParam);<br />
}<br />
</pre><br />
<br />
===Как на Visual C++ 6.0 в Главном окне отключить системное меню (в левом верхнем углу) и кнопки(в правом верхнем углу)?===<br />
При создании окна нужно убрать стиль WS_SYSMENU<br />
(теперь пользователь корректно может закрыть окно только Alt+F4,<br />
ну или если вы предоставите ему дополнительную возможность сделать это)<br />
<br />
<br />
Пример 1. (для SDI, MDI)<br />
<pre><br />
//этот обработчик уже добавлен визардом<br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
if( !CFrameWnd::PreCreateWindow(cs) )<br />
return FALSE;<br />
// TODO: Modify the Window class or styles here by modifying<br />
// the CREATESTRUCT cs<br />
<br />
///////////////////////////////<br />
//добавленная часть<br />
{<br />
//убираем стиль<br />
cs.style&=~WS_SYSMENU;<br />
}<br />
///////////////////////////////<br />
<br />
return TRUE;<br />
}<br />
</pre><br />
Пример 2. (для диалога)<br />
Если диалог описан в ресурсах, то в свойствах диалога убрать галочки<br />
"System menu"<br />
"Minimize box"<br />
"Maximize box"<br />
<br />
===Хочу сделать так, чтобы пользователь не мог нажать на кнопку, пока программа не разрешит.===<br />
Нужно применить метод класса CWnd::EnableWindow(...) для кнопки.<br />
Значение параметра 0 делает кнопку неактивной, 1 - делает активной.<br />
(кстате, не только для кнопки можно, а для любого класса, производного<br />
от класса CWnd)<br />
<br />
<br />
Пусть имеется некий диалог, на нём лежит кнопка c ID == IDC_1.<br />
в любом месте кода диалога (кроме конструктора и деструктора , хотя, если<br />
проверить наличие валидного хендла диалога, как в примере, то ничего<br />
страшного не будет и там)<br />
<pre><br />
//делаем кнопку неактивной<br />
if(m_hWnd)<br />
{<br />
CWnd* pw=0;<br />
pw=GetDlgItem(IDC_1);<br />
if(pw)pw->EnableWindow(0);<br />
}<br />
</pre><br />
<br />
===Что означают сообщения, которые студия выводит при компиляции, вроде таких : Loaded 'C:\WINDOWS\SYSTEM\WSOCK32.DLL', no matching symbolic information found. ===<br />
Это строка говорит о том, что студия не смогла найти отладочные<br />
символы для WSOCK32.DLL. В этом нет ничего страшного, просто при наличии<br />
отладочных символов в процессе отладки можно получить доступ к именам<br />
функции из системных DLL. Например, вместо<br />
KERNEL32! 0x77E8B184() -<br />
увидим<br />
KERNEL32!CreateThread.<br />
===Как обработать сообщения, которое приходит к некому контролу (скажем CEdit)?===<br />
Нужно произвести от CEdit свой класс, и в виртуальной процедуре класса WindowProc перехватить нужные сообщения.<br />
<pre><br />
virtual LRESULT WindowProc(<br />
UINT message,<br />
WPARAM wParam,<br />
LPARAM lParam <br />
);<br />
</pre><br />
Пример. Полностью выключаем, скажем, обработку сообщения WM_CHAR<br />
<pre><br />
LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
switch(message)<br />
{<br />
case WM_CHAR:<br />
{<br />
return 0;<br />
}<br />
break;<br />
}<br />
<br />
return CEdit::WindowProc(message, wParam, lParam);<br />
}<br />
</pre><br />
Чтобы связать экземпляр класса с контролом на форме, добавьте визардом для<br />
контрола переменную класса (выбрав не Value а Control).<br />
<br />
===Как настроить количество пробелов в табуляции?===<br />
Tools->Options->Tabs->Insert Spaces<br />
(или правой кнопкой мыши по тексту-> properties)<br />
===Как автоматически расставить отступы?===<br />
Выделить текст для форматирования, нажать Alt+F8<br />
<br />
Есть ещё программа Artistic Style, которая занимается<br />
переформатированием кода<br />
http://sourceforge.net/projects/astyle/<br />
===Поиск границ блока===<br />
"CTRL+ }" ищет парную фигурную скобку в тексте и переходит на неё<br />
===Вертикальное выделение текста===<br />
"Alt + выделение мышкой" - позволяет выделять вертикальные фрагменты текста<br />
===Как узнать количество установленных в CListCtrl столбцов?===<br />
<pre><br />
CListCtrl* pL=...; //указатель на переменную-контрол<br />
<br />
int count=pL->GetHeaderCtrl()->GetItemCount();<br />
</pre><br />
<br />
===Как получить иконку приложения?===<br />
Если приложение запущено, то нужно найти его главное окно и<br />
послать ему сообщение WM_GETICON.<br />
<pre><br />
//функция возвращант хендл иконки <br />
LRESULT SendMessage(hWnd, WM_GETICON, wParam, 0);<br />
<br />
//hWnd == хендл окна приложения<br />
//wParam == <br />
// 1)==ICON_BIG - получить большую иконку<br />
// 2)==ICON_SMALL - получить маленькую иконку<br />
// 3)==ICON_SMALL2 - получить маленькую иконку, если она определена<br />
// в приложении. Если её нет, то маленькую иконку, <br />
// сгенерированную системой из большой иконки<br />
</pre><br />
===Как в CString можно найти или вырезать часть строки?===<br />
есть такие методы в CString:<br />
<pre><br />
//вырезает кусок строки<br />
CString Mid(int nFirst) const;<br />
CString Mid(int nFirst, int nCount) const;<br />
<br />
//возвращает кусок строки (сначала или с конца)<br />
CString Left(int nCount ) const;<br />
CString Right(int nCount ) const;<br />
<br />
//возвращает начальный кусок строки, в котором есть только<br />
//символы из набора,представленного в lpszCharSet<br />
CString SpanIncluding(LPCTSTR lpszCharSet ) const;<br />
<br />
//возвращает начальный кусок строки, в котором нет<br />
//символов из набора,представленного в lpszCharSet<br />
CString SpanExcluding(LPCTSTR lpszCharSet ) const; <br />
<br />
//убирает "пробелоподобные" символы из самого начала строки<br />
//(то есть - пробел, табуляцию (\t) , возврат каретки, перевод строки (/r/n))<br />
void TrimLeft();<br />
//убирает все повторы символа из самого начала строки<br />
void TrimLeft(TCHAR chTarget );<br />
//убирает из самого начала строки все символа из набора lpszTargets <br />
void TrimLeft(LPCTSTR lpszTargets ); <br />
<br />
void TrimRight();<br />
void TrimRight(TCHAR chTarget );<br />
void TrimRight(LPCTSTR lpszTargets ); <br />
<br />
//поиск в строке<br />
int Find( TCHAR ch ) const;<br />
int Find( LPCTSTR lpszSub ) const;<br />
int Find( TCHAR ch, int nStart ) const;<br />
int Find( LPCTSTR pstr, int nStart ) const;<br />
<br />
//поиск, начиная с конца<br />
int ReverseFind( TCHAR ch ) const;<br />
<br />
//поиск позиции первого символа, одного из набора,<br />
// представленного в lpszCharSet<br />
int FindOneOf( LPCTSTR lpszCharSet ) const;<br />
</pre><br />
<br />
===Есть у меня CListBox и я в ходе выполнения программы добавляю в него строки. Но я не могу посмотреть что именно добавляется. Вывод результатов происходит в конце выполнения процедуры...===<br />
Если нужно делать принудительную перерисовку окна во время<br />
длительных вычислений, то нужно вызывать для окна, которое<br />
надо перерисовать метод<br />
RedrawWindow()<br />
с параметрами по умолчанию, или пару<br />
Invalidate(0);<br />
UpdateWindow();<br />
Это приводит к пометке всего окна к перерисовке и отправлению<br />
сообщения WM_PAINT в оконную процедуру в обход очереди<br />
сообщений, вызывая немедленную перерисовку окна.<br />
<pre><br />
CWnd* pw=...;//окно, которое надо перерисовывать<br />
<br />
for(int i=0;i<10000)<br />
{<br />
//меняется содержимое окна<br />
//...<br />
<br />
//немедленная перерисовка<br />
pw->Invalidate(0);<br />
pw->UpdateWindow();<br />
}<br />
</pre><br />
<br />
===Я написал DLL, которую используют несколько приложений. Всё вроде работает, но когда происходит очередной вызов функции из DLL, почему то данные в функции обнуляются. С чем это связано?===<br />
Переменные и массивы в DLL, содержимое которых должно использоваться несколькими процессами, должны объявляться статическими. Статическая переменная или массив инициализируются только один раз в момент загрузки DLL.<br />
Пример:<br />
<pre><br />
DWORD calltest()<br />
{<br />
//будет выполнено только при первом вызове<br />
static DWORD callcount=0;<br />
static DWORD str[1000]={0}; <br />
<br />
//будет выполняться каждый раз<br />
return ++callcount;<br />
}<br />
</pre><br />
<br />
===Как открыть проекцию файла в память и как с ней работать?===<br />
Создаем проекцию<br />
<pre><br />
HANDLE CreateFileMapping(<br />
HANDLE hFile, //хендл уже открытого файла<br />
LPSECURITY_ATTRIBUTES lpAttributes,<br />
DWORD flProtect, //способ открытия проекции<br />
DWORD dwMaximumSizeHigh, //размер файла (старшие 4 байта , обычно==0)<br />
DWORD dwMaximumSizeLow, //размер файла (младшие 4 байта)<br />
LPCTSTR lpName<br />
);<br />
</pre><br />
Доступ к созданной проекции производится процедурой<br />
<pre><br />
LPVOID MapViewOfFile(<br />
HANDLE hFileMappingObject, //хендл проекции<br />
DWORD dwDesiredAccess, //способ работы с проекцией<br />
DWORD dwFileOffsetHigh,<br />
DWORD dwFileOffsetLow, //смещение от начала файла (младшие 4 байта)<br />
SIZE_T dwNumberOfBytesToMap //длина в байтах (если ==0 - то весь файл)<br />
);<br />
</pre><br />
далее с файлом можно работать как с обычным массивом в памяти.<br />
<br />
После работы с проекцией, её надо освободить процедурой<br />
<pre><br />
BOOL UnmapViewOfFile(<br />
LPCVOID lpBaseAddress //адрес, который вернула процедура MapViewOfFile<br />
);<br />
</pre><br />
Пример.<br />
<pre><br />
HANDLE hMapFile=0;//для проекции<br />
<br />
HANDLE hFile=...;//хендл уже открытого файла<br />
DWORD dwdFileLen=...;//размер открытого файла<br />
<br />
//создаём проекцию "только для чтения"<br />
hMapFile=::CreateFileMapping(hFile,0,PAGE_READONLY,0,dwdFileLen,0);<br />
<br />
//хендл hFile можно закрыть уже здесь, в принципе,<br />
//но мы сделаем это позже<br />
<br />
//получаем доступ к проекции (тоже только для чтения)<br />
BYTE* pbyFile=(BYTE*)::MapViewOfFile(hMapFile,FILE_MAP_READ,0,0,0);<br />
<br />
///////////////////<br />
//тут работаем с массивом pbyFile[dwdFileLen] как с обычным,<br />
//только не забываем, что он открыт только для чтения<br />
//...<br />
//...<br />
//...<br />
///////////////////<br />
<br />
<br />
//отключаем файл данных от адресного пространства<br />
UnmapViewOfFile(pbyFile);<br />
<br />
//освобождаем хендл проекции<br />
CloseHandle(hMapFile)<br />
<br />
//освобождаем хендл открытого файла<br />
CloseHandle(hFile);<br />
</pre><br />
<br />
===Использую MFC Grid control 2.25, не получается отобразить картинку в ячейке. Как это делается?===<br />
Нужно создать список изображений (CImageList), затем передать указатель на список в контрол. Поскольку контрол лишь копирует указатель, список должен создаваться динамически, либо быть членом класса, экземпляр которого существует всё время работы контрола.<br />
<pre><br />
m_GridMarket<br />
CImageList m_ImageList;<br />
CGridCtrL m_Grid1<br />
...<br />
...<br />
//неким образом создаётся список<br />
m_ImageList.Create(...);<br />
//...<br />
<br />
//вставляем в контрол<br />
m_Grid1.SetImageList(&m_ImageList);<br />
<br />
//<br />
</pre><br />
<br />
===Как при помощи IPicture отобразить картинку из файла? ===<br />
Пример - несложная функция, отображающая картинку из файла<br />
<br />
поддерживаются форматы<br />
BMP, GIF, JPEG, PNG, TIFF, EMF<br />
<pre><br />
#include "atlconv.h"<br />
#define HandleIsValid(H) (H!=(HANDLE)-1 && H!=(HANDLE)0)<br />
<br />
//*pDestDC - CDC, на который предполагается вывод картинки<br />
//pchzFilePath - путь к файлу<br />
//pWid - (возвращает) ширина картинки<br />
//pHig - (возвращает) высота картинки<br />
bool DrawBitmapFromFile(CDC* pDestDC,const char* pchzFilePath,int *pWid=0,int *pHig=0)<br />
{<br />
bool result=false;<br />
<br />
if(pWid)*pWid=0;<br />
if(pHig)*pHig=0;<br />
<br />
int Wid=0;<br />
int Hig=0;<br />
<br />
IPicture* pPic=0;<br />
try<br />
{<br />
IPicture* ptmpPic=0;<br />
USES_CONVERSION;<br />
HRESULT hr;<br />
<br />
CString txt=pchzFilePath;<br />
hr= ::OleLoadPicturePath(<br />
const_cast<LPOLESTR>(T2COLE(txt)),<br />
0,0,0,IID_IPicture,<br />
reinterpret_cast<void **>(&ptmpPic)<br />
);<br />
<br />
if(hr==S_OK && ptmpPic)<br />
{<br />
pPic=ptmpPic;<br />
}<br />
else<br />
{<br />
throw 0;<br />
}<br />
<br />
OLE_XPOS_HIMETRIC cxSrc;<br />
OLE_YPOS_HIMETRIC cySrc;<br />
<br />
if(S_OK!=pPic->get_Width(&cxSrc))throw 0;<br />
if(S_OK!=pPic->get_Height(&cySrc))throw 0;<br />
<br />
Wid=cxSrc/26;<br />
Hig=cySrc/26;<br />
<br />
//рисуем<br />
if(S_OK !=pPic->Render(pDestDC->GetSafeHdc(),<br />
0,Hig,Wid,-Hig,0,0,cxSrc,cySrc,0))throw 0;<br />
}<br />
catch(...)<br />
{<br />
result=false;<br />
}<br />
<br />
if(pPic)<br />
{<br />
pPic->Release();<br />
pPic=0;<br />
}<br />
<br />
<br />
if(pWid)*pWid=Wid;<br />
if(pHig)*pHig=Hig;<br />
<br />
return result;<br />
}<br />
<br />
</pre><br />
===У меня модальное диалоговое окно, в нем поле редактирования мультилайновое, т.е. чтобы перейти на новую строку надо нажать ентер, но вызывается стандартный обработчик диалогового окна. Подскажите, что делать?===<br />
Нужно в редакторе ресурсов поставить для CEdit окошка галочку<br />
свойства WantReturn,<br />
<br />
или добавить ES_WANTRETURN при создании CEdit контрола динамически.<br />
===Как выводят картинку-логотип(splash screen) при запуске программы? То есть, когда загружается программа на экран выводится картинка, потом она исчезает(загрузка программы закончена) и пользователь может приступать к работе ===<br />
Для этого используется класс, производный от CDialog. Этот диалог после создания показывает себя на экран, выводя на себя рисунок. Также запускает таймер, по срабатывани которого диалог гасится. Создаётся диалог InitInstance приложения.<br />
<br />
В VC6++ также есть уже готовый компонент<br />
Project->Add To Project -> Components and Controls->(в папке "Visual C++ Components" есть SplashScreen.)<br />
<br />
===Как сделать, чтобы при выпадении списка у ComboBox была не одна строка, а больше, вроде все свойства покрутил, не помогает Вместо выпадающего списка одна строка и скролл...===<br />
В редакторе ресурсов надо щелкнуть в комбобоксе на треугольнике - появляется рамка для растягивания вниз - размер выпадающего списка.<br />
===В VC++.net, что делать после того, как на форму установил ActiveX ListView, как объявить класс и переменную для этого элемента?===<br />
Щёлкнуть правой кнопкой мыши на элементе, в меню - add variable или add class<br />
<br />
===Как вставить данные в буфер обмена (Clipboard)? Как их оттуда вытащить?===<br />
<br />
1) копирование в буфер обмена:<br />
<br />
1.Готовим данные<br />
а.Выделяем память из кучи, вызывая GlobalAlloc()<br />
б.Получаем указатель на выделенную память, вызывая GlobalLock()<br />
в.Заполняем данные<br />
г.Освобождаем указатель, вызывая GlobalUnlock();<br />
<br />
2.Открываем буфер обмена, вызывая OpenClipboard();<br />
3.Очищаем буфер, вызывая EmptyClipboard();<br />
4.Вызываем SetClipboardData() один раз для каждого формата<br />
вставляемых данных (имеется в виду - если одни и те же<br />
данные представлены в разных форматах, и приложение<br />
может эти форматы создать)<br />
5.Закрываем буфер, вызывая CloseClipboard();<br />
6.ВЫЗЫВАТЬ GlobalFree() НЕ НУЖНО, в этом случае это<br />
предоставлено системе<br />
<br />
Скажем, хотим поместить в буфер обмена текст.<br />
<pre><br />
//готовим данные<br />
//выделяем из кучи память для данных<br />
HANDLE hglbCopy = GlobalAlloc(GMEM_MOVEABLE,10);<br />
if(!hglbCopy)return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)return;<br />
<br />
//заполняем данные<br />
strcpy((char*)lpStr,"my text");<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
//очищаем<br />
EmptyClipboard();<br />
<br />
//текстовый формат<br />
SetClipboardData(CF_TEXT,hglbCopy);<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</pre><br />
2) извлечение из буфера обмена<br />
<br />
1.Проверяем, что поддерживается нужный формат данных,<br />
вызывая IsClipboardFormatAvailable()<br />
2.Открываем буфер обмена, вызывая OpenClipboard();<br />
3.Достаём данные<br />
а.Получаем из буфера хендл требуемого формата,<br />
вызывая GetClipboardData()<br />
б.Получаем указатель на выделенную память, вызывая GlobalLock()<br />
в.Работаем с данными<br />
г.Освобождаем указатель, вызывая GlobalUnlock();<br />
4.Закрываем буфер, вызывая CloseClipboard();<br />
<pre><br />
//Проверяем, что поддерживается нужный формат данных,<br />
if(!IsClipboardFormatAvailable(CF_TEXT))return;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
<br />
//достаём данные<br />
<br />
//текстовый формат<br />
HANDLE hglbCopy = GetClipboardData(CF_TEXT);<br />
if(!hglbCopy)return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)return;<br />
<br />
//читаем данные<br />
char data[10];<br />
memmove(data,lpStr,sizeof(data));<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</pre><br />
<br />
===Как получить полный путь к экзешнику из самой программы?===<br />
В командную строку первым параметром система всегда передаёт заключённый в кавычки полный путь к файлу запущенной программы. Достаём путь таким образом:<br />
<pre><br />
BOOL CMyApp::InitInstance()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName - содержит искомый путь<br />
<br />
//...<br />
//...<br />
}<br />
</pre><br />
<br />
===Каким способом exe файл может заменить самого себя? То есть, моя программа обновляется, например, через Internet, и хочет обновить свой exe-файл. Но так как он в данный момент запущен - это будет, естественно, запрещено. Как это можно проще всего сделать?===<br />
Один из способов - сделать копию экзешника и из него обновиться<br />
<pre><br />
<br />
#define def_exeNAMEup "c:\\myprog_update.exe"<br />
#define def_exeNAMEdnld "c:\\myprog_downloaded.exe"<br />
#define def_keyUdate "/update"<br />
<br />
void CTESTFAQApp::UpdateItself()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName - содержит искомый путь<br />
<br />
//делаем копию экзешника с другим именем<br />
CopyFile(csFullExeName,def_exeNAMEup,0);<br />
<br />
<br />
<br />
//передаём в параметры нового процесса ключ и путь к текущему файлу<br />
CString csParams=def_keyUdate;<br />
csParams+=" ";<br />
csParams+=csFullExeName;<br />
<br />
//запускаем копию<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(def_exeNAMEup,def_keyUdate,0,0,0,0,0,0,&si,&pi))<br />
{<br />
//завершаем текущий процесс<br />
ExitFromMyApp();<br />
}<br />
}<br />
<br />
void CTESTFAQApp::ExitFromMyApp()<br />
{<br />
exit(0);<br />
}<br />
<br />
BOOL CTESTFAQApp::InitInstance()<br />
{<br />
<br />
//смотрим, не запустили ли для апдейта?<br />
<br />
CString txt;<br />
txt=m_lpCmdLine;<br />
if(txt.Find(def_keyUdate)==0)<br />
{<br />
//делаем айдейт<br />
txt.Replace(def_keyUdate,"");<br />
txt.TrimLeft();<br />
<br />
CString csFullExeName=txt;<br />
<br />
//берём откуда то уже скачанный файл обновления<br />
//...<br />
CString csFull_Downloaded_ExeName=def_exeNAMEdnld;<br />
<br />
//копируем файл (обновляем старый то есть)<br />
CopyFile(csFull_Downloaded_ExeName,csFullExeName,0);<br />
<br />
//запускаем обновлённого мученника<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(csFullExeName,0,0,0,0,0,0,0,&si,&pi))<br />
<br />
ExitFromMyApp();<br />
<br />
}<br />
//...<br />
//...<br />
}<br />
</pre><br />
===Есть строка символов (страничка из Инета) в кодировке utf-8 (строка char*). Как мне ее получить в формате String или в char* в кодировке ANSI (cp 1251)?===<br />
<br />
Можно перевести строку из UTF8 в Unicode, затем из Unicode в 1251<br />
<br />
Ниже приведена структура, содержащая процедуры перекодирования,<br />
а также процедуру с примером использования<br />
<pre><br />
//описание структуры<br />
struct coder<br />
{<br />
//utf8->unicode<br />
static wchar_t* utf8_to_unicode__dontForgetDeleteArr(const char *utf8_string)<br />
{<br />
wchar_t* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len=MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,0,0);<br />
if(!res_len)return 0;<br />
<br />
//выделяем память<br />
pRes = new wchar_t[res_len];<br />
if(!pRes)return 0;<br />
<br />
//преобразование<br />
if(!MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,pRes,res_len))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//unicode->1251<br />
static char * unicode_to_1251__dontForgetDeleteArr(const wchar_t *unicode_string)<br />
{<br />
char* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len = WideCharToMultiByte(1251,0,unicode_string,-1,0,0,0,0);<br />
if(!res_len)return 0;<br />
<br />
//выделяем память<br />
pRes=new char[res_len];<br />
if(!pRes)return 0;<br />
<br />
//преобразование<br />
if(!WideCharToMultiByte(1251,0,unicode_string,-1,pRes,res_len,0,0))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//процедура с примером<br />
static void Example()<br />
{<br />
wchar_t* unicode_string=0;<br />
char* cp1251_string=0;<br />
<br />
//исходный текст<br />
char utf8_string[] = "UTF-8 + русский текст";<br />
<br />
for(;;)<br />
{<br />
<br />
unicode_string=utf8_to_unicode__dontForgetDeleteArr(utf8_string);<br />
if(!unicode_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать в unicode!");<br />
break;<br />
}<br />
<br />
cp1251_string = unicode_to_1251__dontForgetDeleteArr(unicode_string);<br />
<br />
if(!cp1251_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать из unicode!");<br />
break;<br />
}<br />
<br />
break;<br />
}<br />
<br />
//cp1251_string - результат<br />
AfxMessageBox(cp1251_string);<br />
<br />
<br />
//не забываем удалить массивы<br />
if(unicode_string)<br />
{<br />
delete [] unicode_string;<br />
unicode_string=0;<br />
}<br />
if(cp1251_string)<br />
{<br />
delete [] cp1251_string;<br />
cp1251_string=0;<br />
}<br />
}<br />
};<br />
<br />
//вызов примера<br />
coder::Example();<br />
</pre><br />
<br />
===Как организовать взаимодействие программы на VC.net с Access-овской базой данных?===<br />
Проще всего подключить ADO компоненты и сделать все на них.<br />
Компоненты ADO (ADODC,DATAGRID и т.п.) это ActiveX.<br />
В редакторе ресурсов, во всплывающем меню, есть Insert ActiveX Control -> открывается список всех компоент,<br />
зарегистрированых на машине. Нужно найти компоненты (Это компоненты от MS и они помечены (OLEDB)) и вставить их в диалог. Для того что бы иметь возможность управлять ими, нужно импортировать обертки для них, это делается при помощи ClassWisard, там есть импорт->класс->указать файл с компоентой (OSX).<br />
Появляется список всех классов, объявленых внутри.<br />
Проставляем галочки, нажимаем ОК.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_3&diff=604FAQ:WinAPI, VCPP Part 32008-10-08T18:12:16Z<p>Алексей1153++: /* Как получить доступ к графическим ресурсам элементов текущей темы оформления Windows? */</p>
<hr />
<div><br />
<br />
=== Как узнать, что пользователь меняет текст в приложении на основе CRichEditView?===<br />
Нужно добавить обработчик сообщения EN_CHANGE. Сообщение генерируется CRichEditView каждый раз, когда пользователь изменяет текст в окне CRichEditView<br />
<br />
===Чем отличается метод CArray::GetSize от метода CArray::GetCount?===<br />
Эти методы абсолютно идентичны. Скорее всего, в более старых версиях библиотек функции, одинаковые по смыслу, имели разные имена. Поэтому в целях совместимости разработчики оставили обе функции)<br />
<br />
===Как загрузить текстовую строку из ресурса?===<br />
Пример:<br />
<syntaxhighlight><br />
CString m_Temp;<br />
m_Temp.LoadString(ID_MYSTRING);<br />
</syntaxhighlight><br />
<br />
===Как поменять иконку у элемента item в CListCtrl?===<br />
Пример:<br />
<syntaxhighlight><br />
//заполняем структуру LVITEM<br />
LVITEM lvItem;<br />
memset(&lvItem,0,sizeof(lvItem));<br />
<br />
lvItem.mask = LVIF_IMAGE;//меняться будет картинка<br />
lvItem.iItem = ...;// индекс элемента списка (Zero-based)<br />
lvItem.iSubItem = 0;<br />
lvItem.iImage = ...; //индекс иконки (из списка контрола)<br />
<br />
pList->SetItem(&lvItem);<br />
</syntaxhighlight><br />
<br />
===Имеется класс Class1, содержащий мембер типа "указатель на Class2". В Class2 также имеется указатель на Class1. Компилятор выдаёт ошибку. Что надо делать?===<br />
Перекрёстное определение обходится следкющим образом: код обоих классов разносится в пары файлов *.h и *.cpp, а перед каждым классом вписывается предопределение другого класса:<br />
<br />
файл "class1.h"<br />
<syntaxhighlight>class Class2;//предопределение Class2<br />
<br />
Class1<br />
{<br />
Class2* m_p2;//компилятор разрешит объявление указателя Class2*<br />
<br />
void F1(Class2* p);//компилятор разрешит объявление указателя Class2*<br />
void F2(Class1* p);<br />
};<br />
</syntaxhighlight><br />
<br />
файл "class1.cpp"<br />
<syntaxhighlight>#include "class1.h"<br />
#include "class2.h"<br />
<br />
void Class1::F1(Class2* p)<br />
{<br />
...<br />
}<br />
<br />
void Class1::F2(Class1* p)<br />
{<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
файл "class2.h"<br />
<syntaxhighlight>class Class1;//предопределение Class1<br />
<br />
Class2<br />
{<br />
Class1* m_p1;//компилятор разрешит объявление указателя Class1*<br />
<br />
void F3(Class1* p);//компилятор разрешит объявление указателя Class1*<br />
};<br />
</syntaxhighlight><br />
<br />
файл "class2.cpp"<br />
<syntaxhighlight>#include "class2.h"<br />
#include "class1.h"<br />
<br />
void Class2::F3(Class1* p)<br />
{<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
После предопределениея класса компилятор позволяет объявлять указатель на класс, так как переменная указателя на любой тип имеет всегда один и тот же размер.<br />
<br />
===Как переключить раскладку в другом (то есть в активном) процессе?===<br />
Для этого можно использовать функции<br />
<syntaxhighlight><br />
GetKeyboardLayout(...); // определить текущую раскладку<br />
LoadKeyboardLayout(...); // загрузить новую раскладку<br />
VerLanguageName(...); // получить строку с описанием языка<br />
</syntaxhighlight><br />
<br />
Подробности - в MSDN<br />
<br />
===Как получить хендл элемента управления, зная его идентификатор?===<br />
Пример:<br />
Пусть элемент Edit лежит на окне CMyWnd.<br />
Тогда:<br />
<syntaxhighlight><br />
void CMyWnd::некая_процедура()<br />
{<br />
//для MFC<br />
CEdit* ed=(CEdit* ) GetDlgItem(ID_EDIT1);<br />
HWND hwnd=ed->GetSafeHwnd();<br />
if(hwnd)<br />
{<br />
...<br />
}<br />
<br />
//для Win32 API<br />
HWND hwnd=GetDlgItem(m_hWnd,ID_EDIT1);<br />
if(hwnd)<br />
{<br />
...<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
===Как из дочернего окна закрыть приложение?===<br />
Для этого нужно послать родительскому окну сообщение WM_CLOSE:<br />
<br />
через указатель на родительское окно:<br />
<syntaxhighlight><br />
pParent->PostMessage(WM_CLOSE);<br />
</syntaxhighlight><br />
<br />
при помощи хендла рордительского окна:<br />
<syntaxhighlight><br />
::PostMessage(pParent->m_hWnd,WM_CLOSE,(WPARAM)0,(LPARAM)0);<br />
</syntaxhighlight><br />
<br />
===Как корректно перевести тип BSTR в CString и наоборот?===<br />
<br />
1) для конвертирования BSTR в CString нужно просто присвоить переменной типа CString переменную типа BSTR.<br />
Оператор "=" класса CString сам выполнит всю работу.<br />
<br />
2) для конвертирования BSTR в CString нужно выполнить код:<br />
<syntaxhighlight><br />
<br />
//указатель на будущий буфер с BSTR.<br />
BSTR bstrHE=0;<br />
// (По сути, BSTR определён как <br />
// typedef WCHAR* BSTR;<br />
// то есть указатель на 16-битный символ юникод)<br />
<br />
//строка для конвертации<br />
CString Str="мой текст";<br />
<br />
//Выделяем память и загружаем адрес блока в bstrHE<br />
bstrHE=Str.AllocSysString();<br />
<br />
//... <br />
//тут работаем с bstrHE[]<br />
//...<br />
<br />
//освобождаем память<br />
SysFreeString(bstrHE);<br />
</syntaxhighlight><br />
<br />
===Как получить доступ к графическим ресурсам элементов текущей темы оформления Windows?===<br />
<br />
Для этого нужно использовать функции<br />
<br />
<syntaxhighlight><br />
OpenThemeData(...);<br />
DrawThemeBackground(...);<br />
DrawFrameControl(...);<br />
CloseThemeData(...);<br />
</syntaxhighlight><br />
<br />
(подробности - в MSDN)<br />
<br />
===Имеется класс , производный от CDialog. Когда диалог в фокусе, нажатие на Enter или Esc приводит к закрытию диалога. Как это запретить?===<br />
При нажатии Enter происходит выполнение команды IDOK,при нажатии Esc - IDCANCEL.<br />
<br />
Нужно переопределить в классе виртуальные функции OnOk() и OnCancel(), которые соответственно вызываются для этих команд. При помощи визарда эти функции добавить можно так:<br />
<br />
Положить на диалог две кнопки с идентификаторами IDOK и IDCANCEL (при создании нового диалога они там есть сразу), затем двойной щелчок по кнопке добавит соответствующий обработчик. В обработчиках надо удалить вызовы СDialog::OnOK() и CDialog::OnCancel(), тогда диалог закрываться не будет.<br />
<br />
Однако тогда диалог станет невозможно закрыть кнопкой с крестиком. Это обходится так: добавляем обработчик сообщения WM_CLOSE - OnClose(), и в нём делаем вызов OnOk() или OnCancel():<br />
<syntaxhighlight><br />
void CPlayersPropsDialog::OnClose() <br />
{<br />
CDialog::OnClose();<br />
CDialog::OnCancel();//добавлено<br />
}<br />
</syntaxhighlight><br />
<br />
===Я написал в VC++ простейший макрос , где невозможно ошибиться, а компилятор всё же выдаёт ошибку. Не пойму, в чём дело?===<br />
<br />
Скорее всего после одного из символов соединения строк "\" имеется пробел или табуляция. Их надо удалить. Можно найти их "наощупь", а можно включить показ непечатных символов в студии. Найти эту команду можно так:<br />
<br />
Tools->Customize...->вкладка Commands. В окошке Category выбрать "Edit", и среди кнопок справа найти кнопку, на которой написано "a.b"<br />
<br />
Эту кнопку надо перетащить на одну из панелей инструментов студии.<br />
<br />
===Как получить список всех процесов, включая idle?===<br />
<br />
Использовать функции<br />
<syntaxhighlight><br />
Process32First(...);<br />
Precess32Next(...);<br />
</syntaxhighlight><br />
<br />
(подробности - в MSDN)<br />
<br />
===Как программно установить переменные окружения?===<br />
Чтобы добавить или изменить их программно, необходимо воспользоваться ключом реестра<br />
<syntaxhighlight><br />
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment<br />
</syntaxhighlight><br />
<br />
Затем нужно отправить широковещательное сообщение WM_SETTINGCHANGE (это позволит приложениям узнать об изменениях):<br />
<syntaxhighlight><br />
::SendMessage(HWND_BROADCAST,WM_SETTINGCHANGE,0,0);<br />
</syntaxhighlight><br />
<br />
<br />
===Как сделать, чтобы у окна был черный фон?===<br />
Нужно переопределить обработчик сообщения WM_CTLCOLOR - OnCtlColor() :<br />
<br />
<syntaxhighlight><br />
CBrush br(RGB(0,0,0)); //глобальная переменная или член класса CMyDlg,<br />
// инициализированный в OnInitDialog()<br />
<br />
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
HBRUSH hbr = CMyDlg::OnCtlColor(pDC, pWnd, nCtlColor);<br />
<br />
//фон диалога (или View)<br />
if(nCtlColor==CTLCOLOR_DLG)<br />
{<br />
return (HBRUSH)br;<br />
}<br />
<br />
//фон элементов SCtatic, лежащих на форме (если нужно)<br />
if(nCtlColor==CTLCOLOR_STATIC)<br />
{<br />
//делаем фон текста статика прозрачным<br />
pDC->SetBkMode(TRANSPARENT);<br />
return (HBRUSH)br;<br />
}<br />
<br />
return hbr;<br />
}<br />
</syntaxhighlight><br />
<br />
===Почему на моем компьютере экзешник, созданный в MFC запускается, а на других компьютерах - нет? Требует какую-то dll-ку.===<br />
Нужно выбирать режим Release :<br />
<br />
Menu->Build->Configurations...->Release,<br />
<br />
и экзешник, соответственно, брать из папки Release проекта<br />
===Как в диалог добавить меню?===<br />
Надо сделать в ресурсах меню, затем вставить в диалог:<br />
<br />
открыть в редакторе диалог, в свойствах (во вкладке General, окошко Menu) указать идентивикатор ресурса меню.<br />
При помощи визарда добавить для меню обработчики OnCommand() и OnUpdateСommand().<br />
===Я добавил визардом меню в диалог. Добавил обработчики для пунктов меню. Пункты работают, но OnUpdate для пунктов не вызывается - то есть не получается ни затенить, ни чек поставить. Что делать?===<br />
В диалоге у меню апдейта не происходит сам, в отличие от мейнфрейма.<br />
Для этого нужно сделать самим апдейт в обработчике сообщения WM_KICKIDLE.<br />
Визардом обработчик не добавляется, поэтому можно переопределить виртуальную DefWindowProc() и там обработать:<br />
<pre><br />
#include <afxpriv.h> //этот файл надо включить, там определёна WM_KICKIDLE<br />
<br />
LRESULT CMyDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
if(message==WM_KICKIDLE)<br />
{<br />
//делаем апдейт для всех пунктов меню<br />
CMenu* pMainMenu=GetMenu();<br />
if(pMainMenu)<br />
{<br />
CCmdUI cmdUI;<br />
for (UINT n=0; n < pMainMenu->GetMenuItemCount(); ++n)<br />
{<br />
CMenu* pSubMenu = pMainMenu->GetSubMenu(n);<br />
if(!pSubMenu)continue;<br />
<br />
cmdUI.m_nIndexMax = pSubMenu->GetMenuItemCount();<br />
for (UINT i = 0; i < cmdUI.m_nIndexMax;++i)<br />
{<br />
cmdUI.m_nIndex = i;<br />
cmdUI.m_nID = pSubMenu->GetMenuItemID(i);<br />
cmdUI.m_pMenu = pSubMenu;<br />
cmdUI.DoUpdate(this, FALSE);<br />
}<br />
}<br />
}<br />
}<br />
<br />
<br />
<br />
return CDialog::DefWindowProc(message, wParam, lParam);<br />
}<br />
</pre><br />
<br />
===Как на Visual C++ 6.0 в Главном окне отключить системное меню (в левом верхнем углу) и кнопки(в правом верхнем углу)?===<br />
При создании окна нужно убрать стиль WS_SYSMENU<br />
(теперь пользователь корректно может закрыть окно только Alt+F4,<br />
ну или если вы предоставите ему дополнительную возможность сделать это)<br />
<br />
<br />
Пример 1. (для SDI, MDI)<br />
<pre><br />
//этот обработчик уже добавлен визардом<br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
if( !CFrameWnd::PreCreateWindow(cs) )<br />
return FALSE;<br />
// TODO: Modify the Window class or styles here by modifying<br />
// the CREATESTRUCT cs<br />
<br />
///////////////////////////////<br />
//добавленная часть<br />
{<br />
//убираем стиль<br />
cs.style&=~WS_SYSMENU;<br />
}<br />
///////////////////////////////<br />
<br />
return TRUE;<br />
}<br />
</pre><br />
Пример 2. (для диалога)<br />
Если диалог описан в ресурсах, то в свойствах диалога убрать галочки<br />
"System menu"<br />
"Minimize box"<br />
"Maximize box"<br />
<br />
===Хочу сделать так, чтобы пользователь не мог нажать на кнопку, пока программа не разрешит.===<br />
Нужно применить метод класса CWnd::EnableWindow(...) для кнопки.<br />
Значение параметра 0 делает кнопку неактивной, 1 - делает активной.<br />
(кстате, не только для кнопки можно, а для любого класса, производного<br />
от класса CWnd)<br />
<br />
<br />
Пусть имеется некий диалог, на нём лежит кнопка c ID == IDC_1.<br />
в любом месте кода диалога (кроме конструктора и деструктора , хотя, если<br />
проверить наличие валидного хендла диалога, как в примере, то ничего<br />
страшного не будет и там)<br />
<pre><br />
//делаем кнопку неактивной<br />
if(m_hWnd)<br />
{<br />
CWnd* pw=0;<br />
pw=GetDlgItem(IDC_1);<br />
if(pw)pw->EnableWindow(0);<br />
}<br />
</pre><br />
<br />
===Что означают сообщения, которые студия выводит при компиляции, вроде таких : Loaded 'C:\WINDOWS\SYSTEM\WSOCK32.DLL', no matching symbolic information found. ===<br />
Это строка говорит о том, что студия не смогла найти отладочные<br />
символы для WSOCK32.DLL. В этом нет ничего страшного, просто при наличии<br />
отладочных символов в процессе отладки можно получить доступ к именам<br />
функции из системных DLL. Например, вместо<br />
KERNEL32! 0x77E8B184() -<br />
увидим<br />
KERNEL32!CreateThread.<br />
===Как обработать сообщения, которое приходит к некому контролу (скажем CEdit)?===<br />
Нужно произвести от CEdit свой класс, и в виртуальной процедуре класса WindowProc перехватить нужные сообщения.<br />
<pre><br />
virtual LRESULT WindowProc(<br />
UINT message,<br />
WPARAM wParam,<br />
LPARAM lParam <br />
);<br />
</pre><br />
Пример. Полностью выключаем, скажем, обработку сообщения WM_CHAR<br />
<pre><br />
LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
switch(message)<br />
{<br />
case WM_CHAR:<br />
{<br />
return 0;<br />
}<br />
break;<br />
}<br />
<br />
return CEdit::WindowProc(message, wParam, lParam);<br />
}<br />
</pre><br />
Чтобы связать экземпляр класса с контролом на форме, добавьте визардом для<br />
контрола переменную класса (выбрав не Value а Control).<br />
<br />
===Как настроить количество пробелов в табуляции?===<br />
Tools->Options->Tabs->Insert Spaces<br />
(или правой кнопкой мыши по тексту-> properties)<br />
===Как автоматически расставить отступы?===<br />
Выделить текст для форматирования, нажать Alt+F8<br />
<br />
Есть ещё программа Artistic Style, которая занимается<br />
переформатированием кода<br />
http://sourceforge.net/projects/astyle/<br />
===Поиск границ блока===<br />
"CTRL+ }" ищет парную фигурную скобку в тексте и переходит на неё<br />
===Вертикальное выделение текста===<br />
"Alt + выделение мышкой" - позволяет выделять вертикальные фрагменты текста<br />
===Как узнать количество установленных в CListCtrl столбцов?===<br />
<pre><br />
CListCtrl* pL=...; //указатель на переменную-контрол<br />
<br />
int count=pL->GetHeaderCtrl()->GetItemCount();<br />
</pre><br />
<br />
===Как получить иконку приложения?===<br />
Если приложение запущено, то нужно найти его главное окно и<br />
послать ему сообщение WM_GETICON.<br />
<pre><br />
//функция возвращант хендл иконки <br />
LRESULT SendMessage(hWnd, WM_GETICON, wParam, 0);<br />
<br />
//hWnd == хендл окна приложения<br />
//wParam == <br />
// 1)==ICON_BIG - получить большую иконку<br />
// 2)==ICON_SMALL - получить маленькую иконку<br />
// 3)==ICON_SMALL2 - получить маленькую иконку, если она определена<br />
// в приложении. Если её нет, то маленькую иконку, <br />
// сгенерированную системой из большой иконки<br />
</pre><br />
===Как в CString можно найти или вырезать часть строки?===<br />
есть такие методы в CString:<br />
<pre><br />
//вырезает кусок строки<br />
CString Mid(int nFirst) const;<br />
CString Mid(int nFirst, int nCount) const;<br />
<br />
//возвращает кусок строки (сначала или с конца)<br />
CString Left(int nCount ) const;<br />
CString Right(int nCount ) const;<br />
<br />
//возвращает начальный кусок строки, в котором есть только<br />
//символы из набора,представленного в lpszCharSet<br />
CString SpanIncluding(LPCTSTR lpszCharSet ) const;<br />
<br />
//возвращает начальный кусок строки, в котором нет<br />
//символов из набора,представленного в lpszCharSet<br />
CString SpanExcluding(LPCTSTR lpszCharSet ) const; <br />
<br />
//убирает "пробелоподобные" символы из самого начала строки<br />
//(то есть - пробел, табуляцию (\t) , возврат каретки, перевод строки (/r/n))<br />
void TrimLeft();<br />
//убирает все повторы символа из самого начала строки<br />
void TrimLeft(TCHAR chTarget );<br />
//убирает из самого начала строки все символа из набора lpszTargets <br />
void TrimLeft(LPCTSTR lpszTargets ); <br />
<br />
void TrimRight();<br />
void TrimRight(TCHAR chTarget );<br />
void TrimRight(LPCTSTR lpszTargets ); <br />
<br />
//поиск в строке<br />
int Find( TCHAR ch ) const;<br />
int Find( LPCTSTR lpszSub ) const;<br />
int Find( TCHAR ch, int nStart ) const;<br />
int Find( LPCTSTR pstr, int nStart ) const;<br />
<br />
//поиск, начиная с конца<br />
int ReverseFind( TCHAR ch ) const;<br />
<br />
//поиск позиции первого символа, одного из набора,<br />
// представленного в lpszCharSet<br />
int FindOneOf( LPCTSTR lpszCharSet ) const;<br />
</pre><br />
<br />
===Есть у меня CListBox и я в ходе выполнения программы добавляю в него строки. Но я не могу посмотреть что именно добавляется. Вывод результатов происходит в конце выполнения процедуры...===<br />
Если нужно делать принудительную перерисовку окна во время<br />
длительных вычислений, то нужно вызывать для окна, которое<br />
надо перерисовать метод<br />
RedrawWindow()<br />
с параметрами по умолчанию, или пару<br />
Invalidate(0);<br />
UpdateWindow();<br />
Это приводит к пометке всего окна к перерисовке и отправлению<br />
сообщения WM_PAINT в оконную процедуру в обход очереди<br />
сообщений, вызывая немедленную перерисовку окна.<br />
<pre><br />
CWnd* pw=...;//окно, которое надо перерисовывать<br />
<br />
for(int i=0;i<10000)<br />
{<br />
//меняется содержимое окна<br />
//...<br />
<br />
//немедленная перерисовка<br />
pw->Invalidate(0);<br />
pw->UpdateWindow();<br />
}<br />
</pre><br />
<br />
===Я написал DLL, которую используют несколько приложений. Всё вроде работает, но когда происходит очередной вызов функции из DLL, почему то данные в функции обнуляются. С чем это связано?===<br />
Переменные и массивы в DLL, содержимое которых должно использоваться несколькими процессами, должны объявляться статическими. Статическая переменная или массив инициализируются только один раз в момент загрузки DLL.<br />
Пример:<br />
<pre><br />
DWORD calltest()<br />
{<br />
//будет выполнено только при первом вызове<br />
static DWORD callcount=0;<br />
static DWORD str[1000]={0}; <br />
<br />
//будет выполняться каждый раз<br />
return ++callcount;<br />
}<br />
</pre><br />
<br />
===Как открыть проекцию файла в память и как с ней работать?===<br />
Создаем проекцию<br />
<pre><br />
HANDLE CreateFileMapping(<br />
HANDLE hFile, //хендл уже открытого файла<br />
LPSECURITY_ATTRIBUTES lpAttributes,<br />
DWORD flProtect, //способ открытия проекции<br />
DWORD dwMaximumSizeHigh, //размер файла (старшие 4 байта , обычно==0)<br />
DWORD dwMaximumSizeLow, //размер файла (младшие 4 байта)<br />
LPCTSTR lpName<br />
);<br />
</pre><br />
Доступ к созданной проекции производится процедурой<br />
<pre><br />
LPVOID MapViewOfFile(<br />
HANDLE hFileMappingObject, //хендл проекции<br />
DWORD dwDesiredAccess, //способ работы с проекцией<br />
DWORD dwFileOffsetHigh,<br />
DWORD dwFileOffsetLow, //смещение от начала файла (младшие 4 байта)<br />
SIZE_T dwNumberOfBytesToMap //длина в байтах (если ==0 - то весь файл)<br />
);<br />
</pre><br />
далее с файлом можно работать как с обычным массивом в памяти.<br />
<br />
После работы с проекцией, её надо освободить процедурой<br />
<pre><br />
BOOL UnmapViewOfFile(<br />
LPCVOID lpBaseAddress //адрес, который вернула процедура MapViewOfFile<br />
);<br />
</pre><br />
Пример.<br />
<pre><br />
HANDLE hMapFile=0;//для проекции<br />
<br />
HANDLE hFile=...;//хендл уже открытого файла<br />
DWORD dwdFileLen=...;//размер открытого файла<br />
<br />
//создаём проекцию "только для чтения"<br />
hMapFile=::CreateFileMapping(hFile,0,PAGE_READONLY,0,dwdFileLen,0);<br />
<br />
//хендл hFile можно закрыть уже здесь, в принципе,<br />
//но мы сделаем это позже<br />
<br />
//получаем доступ к проекции (тоже только для чтения)<br />
BYTE* pbyFile=(BYTE*)::MapViewOfFile(hMapFile,FILE_MAP_READ,0,0,0);<br />
<br />
///////////////////<br />
//тут работаем с массивом pbyFile[dwdFileLen] как с обычным,<br />
//только не забываем, что он открыт только для чтения<br />
//...<br />
//...<br />
//...<br />
///////////////////<br />
<br />
<br />
//отключаем файл данных от адресного пространства<br />
UnmapViewOfFile(pbyFile);<br />
<br />
//освобождаем хендл проекции<br />
CloseHandle(hMapFile)<br />
<br />
//освобождаем хендл открытого файла<br />
CloseHandle(hFile);<br />
</pre><br />
<br />
===Использую MFC Grid control 2.25, не получается отобразить картинку в ячейке. Как это делается?===<br />
Нужно создать список изображений (CImageList), затем передать указатель на список в контрол. Поскольку контрол лишь копирует указатель, список должен создаваться динамически, либо быть членом класса, экземпляр которого существует всё время работы контрола.<br />
<pre><br />
m_GridMarket<br />
CImageList m_ImageList;<br />
CGridCtrL m_Grid1<br />
...<br />
...<br />
//неким образом создаётся список<br />
m_ImageList.Create(...);<br />
//...<br />
<br />
//вставляем в контрол<br />
m_Grid1.SetImageList(&m_ImageList);<br />
<br />
//<br />
</pre><br />
<br />
===Как при помощи IPicture отобразить картинку из файла? ===<br />
Пример - несложная функция, отображающая картинку из файла<br />
<br />
поддерживаются форматы<br />
BMP, GIF, JPEG, PNG, TIFF, EMF<br />
<pre><br />
#include "atlconv.h"<br />
#define HandleIsValid(H) (H!=(HANDLE)-1 && H!=(HANDLE)0)<br />
<br />
//*pDestDC - CDC, на который предполагается вывод картинки<br />
//pchzFilePath - путь к файлу<br />
//pWid - (возвращает) ширина картинки<br />
//pHig - (возвращает) высота картинки<br />
bool DrawBitmapFromFile(CDC* pDestDC,const char* pchzFilePath,int *pWid=0,int *pHig=0)<br />
{<br />
bool result=false;<br />
<br />
if(pWid)*pWid=0;<br />
if(pHig)*pHig=0;<br />
<br />
int Wid=0;<br />
int Hig=0;<br />
<br />
IPicture* pPic=0;<br />
try<br />
{<br />
IPicture* ptmpPic=0;<br />
USES_CONVERSION;<br />
HRESULT hr;<br />
<br />
CString txt=pchzFilePath;<br />
hr= ::OleLoadPicturePath(<br />
const_cast<LPOLESTR>(T2COLE(txt)),<br />
0,0,0,IID_IPicture,<br />
reinterpret_cast<void **>(&ptmpPic)<br />
);<br />
<br />
if(hr==S_OK && ptmpPic)<br />
{<br />
pPic=ptmpPic;<br />
}<br />
else<br />
{<br />
throw 0;<br />
}<br />
<br />
OLE_XPOS_HIMETRIC cxSrc;<br />
OLE_YPOS_HIMETRIC cySrc;<br />
<br />
if(S_OK!=pPic->get_Width(&cxSrc))throw 0;<br />
if(S_OK!=pPic->get_Height(&cySrc))throw 0;<br />
<br />
Wid=cxSrc/26;<br />
Hig=cySrc/26;<br />
<br />
//рисуем<br />
if(S_OK !=pPic->Render(pDestDC->GetSafeHdc(),<br />
0,Hig,Wid,-Hig,0,0,cxSrc,cySrc,0))throw 0;<br />
}<br />
catch(...)<br />
{<br />
result=false;<br />
}<br />
<br />
if(pPic)<br />
{<br />
pPic->Release();<br />
pPic=0;<br />
}<br />
<br />
<br />
if(pWid)*pWid=Wid;<br />
if(pHig)*pHig=Hig;<br />
<br />
return result;<br />
}<br />
<br />
</pre><br />
===У меня модальное диалоговое окно, в нем поле редактирования мультилайновое, т.е. чтобы перейти на новую строку надо нажать ентер, но вызывается стандартный обработчик диалогового окна. Подскажите, что делать?===<br />
Нужно в редакторе ресурсов поставить для CEdit окошка галочку<br />
свойства WantReturn,<br />
<br />
или добавить ES_WANTRETURN при создании CEdit контрола динамически.<br />
===Как выводят картинку-логотип(splash screen) при запуске программы? То есть, когда загружается программа на экран выводится картинка, потом она исчезает(загрузка программы закончена) и пользователь может приступать к работе ===<br />
Для этого используется класс, производный от CDialog. Этот диалог после создания показывает себя на экран, выводя на себя рисунок. Также запускает таймер, по срабатывани которого диалог гасится. Создаётся диалог InitInstance приложения.<br />
<br />
В VC6++ также есть уже готовый компонент<br />
Project->Add To Project -> Components and Controls->(в папке "Visual C++ Components" есть SplashScreen.)<br />
<br />
===Как сделать, чтобы при выпадении списка у ComboBox была не одна строка, а больше, вроде все свойства покрутил, не помогает Вместо выпадающего списка одна строка и скролл...===<br />
В редакторе ресурсов надо щелкнуть в комбобоксе на треугольнике - появляется рамка для растягивания вниз - размер выпадающего списка.<br />
===В VC++.net, что делать после того, как на форму установил ActiveX ListView, как объявить класс и переменную для этого элемента?===<br />
Щёлкнуть правой кнопкой мыши на элементе, в меню - add variable или add class<br />
<br />
===Как вставить данные в буфер обмена (Clipboard)? Как их оттуда вытащить?===<br />
<br />
1) копирование в буфер обмена:<br />
<br />
1.Готовим данные<br />
а.Выделяем память из кучи, вызывая GlobalAlloc()<br />
б.Получаем указатель на выделенную память, вызывая GlobalLock()<br />
в.Заполняем данные<br />
г.Освобождаем указатель, вызывая GlobalUnlock();<br />
<br />
2.Открываем буфер обмена, вызывая OpenClipboard();<br />
3.Очищаем буфер, вызывая EmptyClipboard();<br />
4.Вызываем SetClipboardData() один раз для каждого формата<br />
вставляемых данных (имеется в виду - если одни и те же<br />
данные представлены в разных форматах, и приложение<br />
может эти форматы создать)<br />
5.Закрываем буфер, вызывая CloseClipboard();<br />
6.ВЫЗЫВАТЬ GlobalFree() НЕ НУЖНО, в этом случае это<br />
предоставлено системе<br />
<br />
Скажем, хотим поместить в буфер обмена текст.<br />
<pre><br />
//готовим данные<br />
//выделяем из кучи память для данных<br />
HANDLE hglbCopy = GlobalAlloc(GMEM_MOVEABLE,10);<br />
if(!hglbCopy)return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)return;<br />
<br />
//заполняем данные<br />
strcpy((char*)lpStr,"my text");<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
//очищаем<br />
EmptyClipboard();<br />
<br />
//текстовый формат<br />
SetClipboardData(CF_TEXT,hglbCopy);<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</pre><br />
2) извлечение из буфера обмена<br />
<br />
1.Проверяем, что поддерживается нужный формат данных,<br />
вызывая IsClipboardFormatAvailable()<br />
2.Открываем буфер обмена, вызывая OpenClipboard();<br />
3.Достаём данные<br />
а.Получаем из буфера хендл требуемого формата,<br />
вызывая GetClipboardData()<br />
б.Получаем указатель на выделенную память, вызывая GlobalLock()<br />
в.Работаем с данными<br />
г.Освобождаем указатель, вызывая GlobalUnlock();<br />
4.Закрываем буфер, вызывая CloseClipboard();<br />
<pre><br />
//Проверяем, что поддерживается нужный формат данных,<br />
if(!IsClipboardFormatAvailable(CF_TEXT))return;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
<br />
//достаём данные<br />
<br />
//текстовый формат<br />
HANDLE hglbCopy = GetClipboardData(CF_TEXT);<br />
if(!hglbCopy)return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)return;<br />
<br />
//читаем данные<br />
char data[10];<br />
memmove(data,lpStr,sizeof(data));<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</pre><br />
<br />
===Как получить полный путь к экзешнику из самой программы?===<br />
В командную строку первым параметром система всегда передаёт заключённый в кавычки полный путь к файлу запущенной программы. Достаём путь таким образом:<br />
<pre><br />
BOOL CMyApp::InitInstance()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName - содержит искомый путь<br />
<br />
//...<br />
//...<br />
}<br />
</pre><br />
<br />
===Каким способом exe файл может заменить самого себя? То есть, моя программа обновляется, например, через Internet, и хочет обновить свой exe-файл. Но так как он в данный момент запущен - это будет, естественно, запрещено. Как это можно проще всего сделать?===<br />
Один из способов - сделать копию экзешника и из него обновиться<br />
<pre><br />
<br />
#define def_exeNAMEup "c:\\myprog_update.exe"<br />
#define def_exeNAMEdnld "c:\\myprog_downloaded.exe"<br />
#define def_keyUdate "/update"<br />
<br />
void CTESTFAQApp::UpdateItself()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName - содержит искомый путь<br />
<br />
//делаем копию экзешника с другим именем<br />
CopyFile(csFullExeName,def_exeNAMEup,0);<br />
<br />
<br />
<br />
//передаём в параметры нового процесса ключ и путь к текущему файлу<br />
CString csParams=def_keyUdate;<br />
csParams+=" ";<br />
csParams+=csFullExeName;<br />
<br />
//запускаем копию<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(def_exeNAMEup,def_keyUdate,0,0,0,0,0,0,&si,&pi))<br />
{<br />
//завершаем текущий процесс<br />
ExitFromMyApp();<br />
}<br />
}<br />
<br />
void CTESTFAQApp::ExitFromMyApp()<br />
{<br />
exit(0);<br />
}<br />
<br />
BOOL CTESTFAQApp::InitInstance()<br />
{<br />
<br />
//смотрим, не запустили ли для апдейта?<br />
<br />
CString txt;<br />
txt=m_lpCmdLine;<br />
if(txt.Find(def_keyUdate)==0)<br />
{<br />
//делаем айдейт<br />
txt.Replace(def_keyUdate,"");<br />
txt.TrimLeft();<br />
<br />
CString csFullExeName=txt;<br />
<br />
//берём откуда то уже скачанный файл обновления<br />
//...<br />
CString csFull_Downloaded_ExeName=def_exeNAMEdnld;<br />
<br />
//копируем файл (обновляем старый то есть)<br />
CopyFile(csFull_Downloaded_ExeName,csFullExeName,0);<br />
<br />
//запускаем обновлённого мученника<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(csFullExeName,0,0,0,0,0,0,0,&si,&pi))<br />
<br />
ExitFromMyApp();<br />
<br />
}<br />
//...<br />
//...<br />
}<br />
</pre><br />
===Есть строка символов (страничка из Инета) в кодировке utf-8 (строка char*). Как мне ее получить в формате String или в char* в кодировке ANSI (cp 1251)?===<br />
<br />
Можно перевести строку из UTF8 в Unicode, затем из Unicode в 1251<br />
<br />
Ниже приведена структура, содержащая процедуры перекодирования,<br />
а также процедуру с примером использования<br />
<pre><br />
//описание структуры<br />
struct coder<br />
{<br />
//utf8->unicode<br />
static wchar_t* utf8_to_unicode__dontForgetDeleteArr(const char *utf8_string)<br />
{<br />
wchar_t* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len=MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,0,0);<br />
if(!res_len)return 0;<br />
<br />
//выделяем память<br />
pRes = new wchar_t[res_len];<br />
if(!pRes)return 0;<br />
<br />
//преобразование<br />
if(!MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,pRes,res_len))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//unicode->1251<br />
static char * unicode_to_1251__dontForgetDeleteArr(const wchar_t *unicode_string)<br />
{<br />
char* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len = WideCharToMultiByte(1251,0,unicode_string,-1,0,0,0,0);<br />
if(!res_len)return 0;<br />
<br />
//выделяем память<br />
pRes=new char[res_len];<br />
if(!pRes)return 0;<br />
<br />
//преобразование<br />
if(!WideCharToMultiByte(1251,0,unicode_string,-1,pRes,res_len,0,0))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//процедура с примером<br />
static void Example()<br />
{<br />
wchar_t* unicode_string=0;<br />
char* cp1251_string=0;<br />
<br />
//исходный текст<br />
char utf8_string[] = "UTF-8 + русский текст";<br />
<br />
for(;;)<br />
{<br />
<br />
unicode_string=utf8_to_unicode__dontForgetDeleteArr(utf8_string);<br />
if(!unicode_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать в unicode!");<br />
break;<br />
}<br />
<br />
cp1251_string = unicode_to_1251__dontForgetDeleteArr(unicode_string);<br />
<br />
if(!cp1251_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать из unicode!");<br />
break;<br />
}<br />
<br />
break;<br />
}<br />
<br />
//cp1251_string - результат<br />
AfxMessageBox(cp1251_string);<br />
<br />
<br />
//не забываем удалить массивы<br />
if(unicode_string)<br />
{<br />
delete [] unicode_string;<br />
unicode_string=0;<br />
}<br />
if(cp1251_string)<br />
{<br />
delete [] cp1251_string;<br />
cp1251_string=0;<br />
}<br />
}<br />
};<br />
<br />
//вызов примера<br />
coder::Example();<br />
</pre><br />
<br />
===Как организовать взаимодействие программы на VC.net с Access-овской базой данных?===<br />
Проще всего подключить ADO компоненты и сделать все на них.<br />
Компоненты ADO (ADODC,DATAGRID и т.п.) это ActiveX.<br />
В редакторе ресурсов, во всплывающем меню, есть Insert ActiveX Control -> открывается список всех компоент,<br />
зарегистрированых на машине. Нужно найти компоненты (Это компоненты от MS и они помечены (OLEDB)) и вставить их в диалог. Для того что бы иметь возможность управлять ими, нужно импортировать обертки для них, это делается при помощи ClassWisard, там есть импорт->класс->указать файл с компоентой (OSX).<br />
Появляется список всех классов, объявленых внутри.<br />
Проставляем галочки, нажимаем ОК.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_3&diff=603FAQ:WinAPI, VCPP Part 32008-10-08T18:10:19Z<p>Алексей1153++: /* Имеется класс Class1, содержащий мембер типа "указатель на Class2". В Class2 также имеется указатель на Class1. Компилятор выдаёт ошибку. Что надо де</p>
<hr />
<div><br />
<br />
=== Как узнать, что пользователь меняет текст в приложении на основе CRichEditView?===<br />
Нужно добавить обработчик сообщения EN_CHANGE. Сообщение генерируется CRichEditView каждый раз, когда пользователь изменяет текст в окне CRichEditView<br />
<br />
===Чем отличается метод CArray::GetSize от метода CArray::GetCount?===<br />
Эти методы абсолютно идентичны. Скорее всего, в более старых версиях библиотек функции, одинаковые по смыслу, имели разные имена. Поэтому в целях совместимости разработчики оставили обе функции)<br />
<br />
===Как загрузить текстовую строку из ресурса?===<br />
Пример:<br />
<syntaxhighlight><br />
CString m_Temp;<br />
m_Temp.LoadString(ID_MYSTRING);<br />
</syntaxhighlight><br />
<br />
===Как поменять иконку у элемента item в CListCtrl?===<br />
Пример:<br />
<syntaxhighlight><br />
//заполняем структуру LVITEM<br />
LVITEM lvItem;<br />
memset(&lvItem,0,sizeof(lvItem));<br />
<br />
lvItem.mask = LVIF_IMAGE;//меняться будет картинка<br />
lvItem.iItem = ...;// индекс элемента списка (Zero-based)<br />
lvItem.iSubItem = 0;<br />
lvItem.iImage = ...; //индекс иконки (из списка контрола)<br />
<br />
pList->SetItem(&lvItem);<br />
</syntaxhighlight><br />
<br />
===Имеется класс Class1, содержащий мембер типа "указатель на Class2". В Class2 также имеется указатель на Class1. Компилятор выдаёт ошибку. Что надо делать?===<br />
Перекрёстное определение обходится следкющим образом: код обоих классов разносится в пары файлов *.h и *.cpp, а перед каждым классом вписывается предопределение другого класса:<br />
<br />
файл "class1.h"<br />
<syntaxhighlight>class Class2;//предопределение Class2<br />
<br />
Class1<br />
{<br />
Class2* m_p2;//компилятор разрешит объявление указателя Class2*<br />
<br />
void F1(Class2* p);//компилятор разрешит объявление указателя Class2*<br />
void F2(Class1* p);<br />
};<br />
</syntaxhighlight><br />
<br />
файл "class1.cpp"<br />
<syntaxhighlight>#include "class1.h"<br />
#include "class2.h"<br />
<br />
void Class1::F1(Class2* p)<br />
{<br />
...<br />
}<br />
<br />
void Class1::F2(Class1* p)<br />
{<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
файл "class2.h"<br />
<syntaxhighlight>class Class1;//предопределение Class1<br />
<br />
Class2<br />
{<br />
Class1* m_p1;//компилятор разрешит объявление указателя Class1*<br />
<br />
void F3(Class1* p);//компилятор разрешит объявление указателя Class1*<br />
};<br />
</syntaxhighlight><br />
<br />
файл "class2.cpp"<br />
<syntaxhighlight>#include "class2.h"<br />
#include "class1.h"<br />
<br />
void Class2::F3(Class1* p)<br />
{<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
После предопределениея класса компилятор позволяет объявлять указатель на класс, так как переменная указателя на любой тип имеет всегда один и тот же размер.<br />
<br />
===Как переключить раскладку в другом (то есть в активном) процессе?===<br />
Для этого можно использовать функции<br />
<syntaxhighlight><br />
GetKeyboardLayout(...); // определить текущую раскладку<br />
LoadKeyboardLayout(...); // загрузить новую раскладку<br />
VerLanguageName(...); // получить строку с описанием языка<br />
</syntaxhighlight><br />
<br />
Подробности - в MSDN<br />
<br />
===Как получить хендл элемента управления, зная его идентификатор?===<br />
Пример:<br />
Пусть элемент Edit лежит на окне CMyWnd.<br />
Тогда:<br />
<syntaxhighlight><br />
void CMyWnd::некая_процедура()<br />
{<br />
//для MFC<br />
CEdit* ed=(CEdit* ) GetDlgItem(ID_EDIT1);<br />
HWND hwnd=ed->GetSafeHwnd();<br />
if(hwnd)<br />
{<br />
...<br />
}<br />
<br />
//для Win32 API<br />
HWND hwnd=GetDlgItem(m_hWnd,ID_EDIT1);<br />
if(hwnd)<br />
{<br />
...<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
===Как из дочернего окна закрыть приложение?===<br />
Для этого нужно послать родительскому окну сообщение WM_CLOSE:<br />
<br />
через указатель на родительское окно:<br />
<syntaxhighlight><br />
pParent->PostMessage(WM_CLOSE);<br />
</syntaxhighlight><br />
<br />
при помощи хендла рордительского окна:<br />
<syntaxhighlight><br />
::PostMessage(pParent->m_hWnd,WM_CLOSE,(WPARAM)0,(LPARAM)0);<br />
</syntaxhighlight><br />
<br />
===Как корректно перевести тип BSTR в CString и наоборот?===<br />
<br />
1) для конвертирования BSTR в CString нужно просто присвоить переменной типа CString переменную типа BSTR.<br />
Оператор "=" класса CString сам выполнит всю работу.<br />
<br />
2) для конвертирования BSTR в CString нужно выполнить код:<br />
<syntaxhighlight><br />
<br />
//указатель на будущий буфер с BSTR.<br />
BSTR bstrHE=0;<br />
// (По сути, BSTR определён как <br />
// typedef WCHAR* BSTR;<br />
// то есть указатель на 16-битный символ юникод)<br />
<br />
//строка для конвертации<br />
CString Str="мой текст";<br />
<br />
//Выделяем память и загружаем адрес блока в bstrHE<br />
bstrHE=Str.AllocSysString();<br />
<br />
//... <br />
//тут работаем с bstrHE[]<br />
//...<br />
<br />
//освобождаем память<br />
SysFreeString(bstrHE);<br />
</syntaxhighlight><br />
<br />
===Как получить доступ к графическим ресурсам элементов текущей темы оформления Windows?===<br />
<br />
Для этого нужно использовать функции<br />
<br />
<syntaxhighlight><br />
OpenThemeData(...);<br />
DrawThemeBackground(...);<br />
DrawFrameControl(...);<br />
CloseThemeData(...);<br />
</syntaxhighlight><br />
<br />
(подробности - в MSDN)<br />
<br />
===Имеется класс , производный от CDialog. Когда диалог в фокусе, нажатие на Enter или Esc приводит к закрытию диалога. Как это запретить?===<br />
При нажатии Enter происходит выполнение команды IDOK,при нажатии Esc - IDCANCEL.<br />
<br />
Нужно переопределить в классе виртуальные функции OnOk() и OnCancel(), которые соответственно вызываются для этих команд. При помощи визарда эти функции добавить можно так:<br />
<br />
Положить на диалог две кнопки с идентификаторами IDOK и IDCANCEL (при создании нового диалога они там есть сразу), затем двойной щелчок по кнопке добавит соответствующий обработчик. В обработчиках надо удалить вызовы СDialog::OnOK() и CDialog::OnCancel(), тогда диалог закрываться не будет.<br />
<br />
Однако тогда диалог станет невозможно закрыть кнопкой с крестиком. Это обходится так: добавляем обработчик сообщения WM_CLOSE - OnClose(), и в нём делаем вызов OnOk() или OnCancel():<br />
<syntaxhighlight><br />
void CPlayersPropsDialog::OnClose() <br />
{<br />
CDialog::OnClose();<br />
CDialog::OnCancel();//добавлено<br />
}<br />
</syntaxhighlight><br />
<br />
===Я написал в VC++ простейший макрос , где невозможно ошибиться, а компилятор всё же выдаёт ошибку. Не пойму, в чём дело?===<br />
<br />
Скорее всего после одного из символов соединения строк "\" имеется пробел или табуляция. Их надо удалить. Можно найти их "наощупь", а можно включить показ непечатных символов в студии. Найти эту команду можно так:<br />
<br />
Tools->Customize...->вкладка Commands. В окошке Category выбрать "Edit", и среди кнопок справа найти кнопку, на которой написано "a.b"<br />
<br />
Эту кнопку надо перетащить на одну из панелей инструментов студии.<br />
<br />
===Как получить список всех процесов, включая idle?===<br />
<br />
Использовать функции<br />
<syntaxhighlight><br />
Process32First(...);<br />
Precess32Next(...);<br />
</syntaxhighlight><br />
<br />
(подробности - в MSDN)<br />
<br />
===Как программно установить переменные окружения?===<br />
Чтобы добавить или изменить их программно, необходимо воспользоваться ключом реестра<br />
<syntaxhighlight><br />
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment<br />
</syntaxhighlight><br />
<br />
Затем нужно отправить широковещательное сообщение WM_SETTINGCHANGE (это позволит приложениям узнать об изменениях):<br />
<syntaxhighlight><br />
::SendMessage(HWND_BROADCAST,WM_SETTINGCHANGE,0,0);<br />
</syntaxhighlight><br />
<br />
<br />
===Как сделать, чтобы у окна был черный фон?===<br />
Нужно переопределить обработчик сообщения WM_CTLCOLOR - OnCtlColor() :<br />
<br />
<syntaxhighlight><br />
CBrush br(RGB(0,0,0)); //глобальная переменная или член класса CMyDlg,<br />
// инициализированный в OnInitDialog()<br />
<br />
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
HBRUSH hbr = CMyDlg::OnCtlColor(pDC, pWnd, nCtlColor);<br />
<br />
//фон диалога (или View)<br />
if(nCtlColor==CTLCOLOR_DLG)<br />
{<br />
return (HBRUSH)br;<br />
}<br />
<br />
//фон элементов SCtatic, лежащих на форме (если нужно)<br />
if(nCtlColor==CTLCOLOR_STATIC)<br />
{<br />
//делаем фон текста статика прозрачным<br />
pDC->SetBkMode(TRANSPARENT);<br />
return (HBRUSH)br;<br />
}<br />
<br />
return hbr;<br />
}<br />
</syntaxhighlight><br />
<br />
===Почему на моем компьютере экзешник, созданный в MFC запускается, а на других компьютерах - нет? Требует какую-то dll-ку.===<br />
Нужно выбирать режим Release :<br />
<br />
Menu->Build->Configurations...->Release,<br />
<br />
и экзешник, соответственно, брать из папки Release проекта<br />
===Как в диалог добавить меню?===<br />
Надо сделать в ресурсах меню, затем вставить в диалог:<br />
<br />
открыть в редакторе диалог, в свойствах (во вкладке General, окошко Menu) указать идентивикатор ресурса меню.<br />
При помощи визарда добавить для меню обработчики OnCommand() и OnUpdateСommand().<br />
===Я добавил визардом меню в диалог. Добавил обработчики для пунктов меню. Пункты работают, но OnUpdate для пунктов не вызывается - то есть не получается ни затенить, ни чек поставить. Что делать?===<br />
В диалоге у меню апдейта не происходит сам, в отличие от мейнфрейма.<br />
Для этого нужно сделать самим апдейт в обработчике сообщения WM_KICKIDLE.<br />
Визардом обработчик не добавляется, поэтому можно переопределить виртуальную DefWindowProc() и там обработать:<br />
<pre><br />
#include <afxpriv.h> //этот файл надо включить, там определёна WM_KICKIDLE<br />
<br />
LRESULT CMyDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
if(message==WM_KICKIDLE)<br />
{<br />
//делаем апдейт для всех пунктов меню<br />
CMenu* pMainMenu=GetMenu();<br />
if(pMainMenu)<br />
{<br />
CCmdUI cmdUI;<br />
for (UINT n=0; n < pMainMenu->GetMenuItemCount(); ++n)<br />
{<br />
CMenu* pSubMenu = pMainMenu->GetSubMenu(n);<br />
if(!pSubMenu)continue;<br />
<br />
cmdUI.m_nIndexMax = pSubMenu->GetMenuItemCount();<br />
for (UINT i = 0; i < cmdUI.m_nIndexMax;++i)<br />
{<br />
cmdUI.m_nIndex = i;<br />
cmdUI.m_nID = pSubMenu->GetMenuItemID(i);<br />
cmdUI.m_pMenu = pSubMenu;<br />
cmdUI.DoUpdate(this, FALSE);<br />
}<br />
}<br />
}<br />
}<br />
<br />
<br />
<br />
return CDialog::DefWindowProc(message, wParam, lParam);<br />
}<br />
</pre><br />
<br />
===Как на Visual C++ 6.0 в Главном окне отключить системное меню (в левом верхнем углу) и кнопки(в правом верхнем углу)?===<br />
При создании окна нужно убрать стиль WS_SYSMENU<br />
(теперь пользователь корректно может закрыть окно только Alt+F4,<br />
ну или если вы предоставите ему дополнительную возможность сделать это)<br />
<br />
<br />
Пример 1. (для SDI, MDI)<br />
<pre><br />
//этот обработчик уже добавлен визардом<br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
if( !CFrameWnd::PreCreateWindow(cs) )<br />
return FALSE;<br />
// TODO: Modify the Window class or styles here by modifying<br />
// the CREATESTRUCT cs<br />
<br />
///////////////////////////////<br />
//добавленная часть<br />
{<br />
//убираем стиль<br />
cs.style&=~WS_SYSMENU;<br />
}<br />
///////////////////////////////<br />
<br />
return TRUE;<br />
}<br />
</pre><br />
Пример 2. (для диалога)<br />
Если диалог описан в ресурсах, то в свойствах диалога убрать галочки<br />
"System menu"<br />
"Minimize box"<br />
"Maximize box"<br />
<br />
===Хочу сделать так, чтобы пользователь не мог нажать на кнопку, пока программа не разрешит.===<br />
Нужно применить метод класса CWnd::EnableWindow(...) для кнопки.<br />
Значение параметра 0 делает кнопку неактивной, 1 - делает активной.<br />
(кстате, не только для кнопки можно, а для любого класса, производного<br />
от класса CWnd)<br />
<br />
<br />
Пусть имеется некий диалог, на нём лежит кнопка c ID == IDC_1.<br />
в любом месте кода диалога (кроме конструктора и деструктора , хотя, если<br />
проверить наличие валидного хендла диалога, как в примере, то ничего<br />
страшного не будет и там)<br />
<pre><br />
//делаем кнопку неактивной<br />
if(m_hWnd)<br />
{<br />
CWnd* pw=0;<br />
pw=GetDlgItem(IDC_1);<br />
if(pw)pw->EnableWindow(0);<br />
}<br />
</pre><br />
<br />
===Что означают сообщения, которые студия выводит при компиляции, вроде таких : Loaded 'C:\WINDOWS\SYSTEM\WSOCK32.DLL', no matching symbolic information found. ===<br />
Это строка говорит о том, что студия не смогла найти отладочные<br />
символы для WSOCK32.DLL. В этом нет ничего страшного, просто при наличии<br />
отладочных символов в процессе отладки можно получить доступ к именам<br />
функции из системных DLL. Например, вместо<br />
KERNEL32! 0x77E8B184() -<br />
увидим<br />
KERNEL32!CreateThread.<br />
===Как обработать сообщения, которое приходит к некому контролу (скажем CEdit)?===<br />
Нужно произвести от CEdit свой класс, и в виртуальной процедуре класса WindowProc перехватить нужные сообщения.<br />
<pre><br />
virtual LRESULT WindowProc(<br />
UINT message,<br />
WPARAM wParam,<br />
LPARAM lParam <br />
);<br />
</pre><br />
Пример. Полностью выключаем, скажем, обработку сообщения WM_CHAR<br />
<pre><br />
LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
switch(message)<br />
{<br />
case WM_CHAR:<br />
{<br />
return 0;<br />
}<br />
break;<br />
}<br />
<br />
return CEdit::WindowProc(message, wParam, lParam);<br />
}<br />
</pre><br />
Чтобы связать экземпляр класса с контролом на форме, добавьте визардом для<br />
контрола переменную класса (выбрав не Value а Control).<br />
<br />
===Как настроить количество пробелов в табуляции?===<br />
Tools->Options->Tabs->Insert Spaces<br />
(или правой кнопкой мыши по тексту-> properties)<br />
===Как автоматически расставить отступы?===<br />
Выделить текст для форматирования, нажать Alt+F8<br />
<br />
Есть ещё программа Artistic Style, которая занимается<br />
переформатированием кода<br />
http://sourceforge.net/projects/astyle/<br />
===Поиск границ блока===<br />
"CTRL+ }" ищет парную фигурную скобку в тексте и переходит на неё<br />
===Вертикальное выделение текста===<br />
"Alt + выделение мышкой" - позволяет выделять вертикальные фрагменты текста<br />
===Как узнать количество установленных в CListCtrl столбцов?===<br />
<pre><br />
CListCtrl* pL=...; //указатель на переменную-контрол<br />
<br />
int count=pL->GetHeaderCtrl()->GetItemCount();<br />
</pre><br />
<br />
===Как получить иконку приложения?===<br />
Если приложение запущено, то нужно найти его главное окно и<br />
послать ему сообщение WM_GETICON.<br />
<pre><br />
//функция возвращант хендл иконки <br />
LRESULT SendMessage(hWnd, WM_GETICON, wParam, 0);<br />
<br />
//hWnd == хендл окна приложения<br />
//wParam == <br />
// 1)==ICON_BIG - получить большую иконку<br />
// 2)==ICON_SMALL - получить маленькую иконку<br />
// 3)==ICON_SMALL2 - получить маленькую иконку, если она определена<br />
// в приложении. Если её нет, то маленькую иконку, <br />
// сгенерированную системой из большой иконки<br />
</pre><br />
===Как в CString можно найти или вырезать часть строки?===<br />
есть такие методы в CString:<br />
<pre><br />
//вырезает кусок строки<br />
CString Mid(int nFirst) const;<br />
CString Mid(int nFirst, int nCount) const;<br />
<br />
//возвращает кусок строки (сначала или с конца)<br />
CString Left(int nCount ) const;<br />
CString Right(int nCount ) const;<br />
<br />
//возвращает начальный кусок строки, в котором есть только<br />
//символы из набора,представленного в lpszCharSet<br />
CString SpanIncluding(LPCTSTR lpszCharSet ) const;<br />
<br />
//возвращает начальный кусок строки, в котором нет<br />
//символов из набора,представленного в lpszCharSet<br />
CString SpanExcluding(LPCTSTR lpszCharSet ) const; <br />
<br />
//убирает "пробелоподобные" символы из самого начала строки<br />
//(то есть - пробел, табуляцию (\t) , возврат каретки, перевод строки (/r/n))<br />
void TrimLeft();<br />
//убирает все повторы символа из самого начала строки<br />
void TrimLeft(TCHAR chTarget );<br />
//убирает из самого начала строки все символа из набора lpszTargets <br />
void TrimLeft(LPCTSTR lpszTargets ); <br />
<br />
void TrimRight();<br />
void TrimRight(TCHAR chTarget );<br />
void TrimRight(LPCTSTR lpszTargets ); <br />
<br />
//поиск в строке<br />
int Find( TCHAR ch ) const;<br />
int Find( LPCTSTR lpszSub ) const;<br />
int Find( TCHAR ch, int nStart ) const;<br />
int Find( LPCTSTR pstr, int nStart ) const;<br />
<br />
//поиск, начиная с конца<br />
int ReverseFind( TCHAR ch ) const;<br />
<br />
//поиск позиции первого символа, одного из набора,<br />
// представленного в lpszCharSet<br />
int FindOneOf( LPCTSTR lpszCharSet ) const;<br />
</pre><br />
<br />
===Есть у меня CListBox и я в ходе выполнения программы добавляю в него строки. Но я не могу посмотреть что именно добавляется. Вывод результатов происходит в конце выполнения процедуры...===<br />
Если нужно делать принудительную перерисовку окна во время<br />
длительных вычислений, то нужно вызывать для окна, которое<br />
надо перерисовать метод<br />
RedrawWindow()<br />
с параметрами по умолчанию, или пару<br />
Invalidate(0);<br />
UpdateWindow();<br />
Это приводит к пометке всего окна к перерисовке и отправлению<br />
сообщения WM_PAINT в оконную процедуру в обход очереди<br />
сообщений, вызывая немедленную перерисовку окна.<br />
<pre><br />
CWnd* pw=...;//окно, которое надо перерисовывать<br />
<br />
for(int i=0;i<10000)<br />
{<br />
//меняется содержимое окна<br />
//...<br />
<br />
//немедленная перерисовка<br />
pw->Invalidate(0);<br />
pw->UpdateWindow();<br />
}<br />
</pre><br />
<br />
===Я написал DLL, которую используют несколько приложений. Всё вроде работает, но когда происходит очередной вызов функции из DLL, почему то данные в функции обнуляются. С чем это связано?===<br />
Переменные и массивы в DLL, содержимое которых должно использоваться несколькими процессами, должны объявляться статическими. Статическая переменная или массив инициализируются только один раз в момент загрузки DLL.<br />
Пример:<br />
<pre><br />
DWORD calltest()<br />
{<br />
//будет выполнено только при первом вызове<br />
static DWORD callcount=0;<br />
static DWORD str[1000]={0}; <br />
<br />
//будет выполняться каждый раз<br />
return ++callcount;<br />
}<br />
</pre><br />
<br />
===Как открыть проекцию файла в память и как с ней работать?===<br />
Создаем проекцию<br />
<pre><br />
HANDLE CreateFileMapping(<br />
HANDLE hFile, //хендл уже открытого файла<br />
LPSECURITY_ATTRIBUTES lpAttributes,<br />
DWORD flProtect, //способ открытия проекции<br />
DWORD dwMaximumSizeHigh, //размер файла (старшие 4 байта , обычно==0)<br />
DWORD dwMaximumSizeLow, //размер файла (младшие 4 байта)<br />
LPCTSTR lpName<br />
);<br />
</pre><br />
Доступ к созданной проекции производится процедурой<br />
<pre><br />
LPVOID MapViewOfFile(<br />
HANDLE hFileMappingObject, //хендл проекции<br />
DWORD dwDesiredAccess, //способ работы с проекцией<br />
DWORD dwFileOffsetHigh,<br />
DWORD dwFileOffsetLow, //смещение от начала файла (младшие 4 байта)<br />
SIZE_T dwNumberOfBytesToMap //длина в байтах (если ==0 - то весь файл)<br />
);<br />
</pre><br />
далее с файлом можно работать как с обычным массивом в памяти.<br />
<br />
После работы с проекцией, её надо освободить процедурой<br />
<pre><br />
BOOL UnmapViewOfFile(<br />
LPCVOID lpBaseAddress //адрес, который вернула процедура MapViewOfFile<br />
);<br />
</pre><br />
Пример.<br />
<pre><br />
HANDLE hMapFile=0;//для проекции<br />
<br />
HANDLE hFile=...;//хендл уже открытого файла<br />
DWORD dwdFileLen=...;//размер открытого файла<br />
<br />
//создаём проекцию "только для чтения"<br />
hMapFile=::CreateFileMapping(hFile,0,PAGE_READONLY,0,dwdFileLen,0);<br />
<br />
//хендл hFile можно закрыть уже здесь, в принципе,<br />
//но мы сделаем это позже<br />
<br />
//получаем доступ к проекции (тоже только для чтения)<br />
BYTE* pbyFile=(BYTE*)::MapViewOfFile(hMapFile,FILE_MAP_READ,0,0,0);<br />
<br />
///////////////////<br />
//тут работаем с массивом pbyFile[dwdFileLen] как с обычным,<br />
//только не забываем, что он открыт только для чтения<br />
//...<br />
//...<br />
//...<br />
///////////////////<br />
<br />
<br />
//отключаем файл данных от адресного пространства<br />
UnmapViewOfFile(pbyFile);<br />
<br />
//освобождаем хендл проекции<br />
CloseHandle(hMapFile)<br />
<br />
//освобождаем хендл открытого файла<br />
CloseHandle(hFile);<br />
</pre><br />
<br />
===Использую MFC Grid control 2.25, не получается отобразить картинку в ячейке. Как это делается?===<br />
Нужно создать список изображений (CImageList), затем передать указатель на список в контрол. Поскольку контрол лишь копирует указатель, список должен создаваться динамически, либо быть членом класса, экземпляр которого существует всё время работы контрола.<br />
<pre><br />
m_GridMarket<br />
CImageList m_ImageList;<br />
CGridCtrL m_Grid1<br />
...<br />
...<br />
//неким образом создаётся список<br />
m_ImageList.Create(...);<br />
//...<br />
<br />
//вставляем в контрол<br />
m_Grid1.SetImageList(&m_ImageList);<br />
<br />
//<br />
</pre><br />
<br />
===Как при помощи IPicture отобразить картинку из файла? ===<br />
Пример - несложная функция, отображающая картинку из файла<br />
<br />
поддерживаются форматы<br />
BMP, GIF, JPEG, PNG, TIFF, EMF<br />
<pre><br />
#include "atlconv.h"<br />
#define HandleIsValid(H) (H!=(HANDLE)-1 && H!=(HANDLE)0)<br />
<br />
//*pDestDC - CDC, на который предполагается вывод картинки<br />
//pchzFilePath - путь к файлу<br />
//pWid - (возвращает) ширина картинки<br />
//pHig - (возвращает) высота картинки<br />
bool DrawBitmapFromFile(CDC* pDestDC,const char* pchzFilePath,int *pWid=0,int *pHig=0)<br />
{<br />
bool result=false;<br />
<br />
if(pWid)*pWid=0;<br />
if(pHig)*pHig=0;<br />
<br />
int Wid=0;<br />
int Hig=0;<br />
<br />
IPicture* pPic=0;<br />
try<br />
{<br />
IPicture* ptmpPic=0;<br />
USES_CONVERSION;<br />
HRESULT hr;<br />
<br />
CString txt=pchzFilePath;<br />
hr= ::OleLoadPicturePath(<br />
const_cast<LPOLESTR>(T2COLE(txt)),<br />
0,0,0,IID_IPicture,<br />
reinterpret_cast<void **>(&ptmpPic)<br />
);<br />
<br />
if(hr==S_OK && ptmpPic)<br />
{<br />
pPic=ptmpPic;<br />
}<br />
else<br />
{<br />
throw 0;<br />
}<br />
<br />
OLE_XPOS_HIMETRIC cxSrc;<br />
OLE_YPOS_HIMETRIC cySrc;<br />
<br />
if(S_OK!=pPic->get_Width(&cxSrc))throw 0;<br />
if(S_OK!=pPic->get_Height(&cySrc))throw 0;<br />
<br />
Wid=cxSrc/26;<br />
Hig=cySrc/26;<br />
<br />
//рисуем<br />
if(S_OK !=pPic->Render(pDestDC->GetSafeHdc(),<br />
0,Hig,Wid,-Hig,0,0,cxSrc,cySrc,0))throw 0;<br />
}<br />
catch(...)<br />
{<br />
result=false;<br />
}<br />
<br />
if(pPic)<br />
{<br />
pPic->Release();<br />
pPic=0;<br />
}<br />
<br />
<br />
if(pWid)*pWid=Wid;<br />
if(pHig)*pHig=Hig;<br />
<br />
return result;<br />
}<br />
<br />
</pre><br />
===У меня модальное диалоговое окно, в нем поле редактирования мультилайновое, т.е. чтобы перейти на новую строку надо нажать ентер, но вызывается стандартный обработчик диалогового окна. Подскажите, что делать?===<br />
Нужно в редакторе ресурсов поставить для CEdit окошка галочку<br />
свойства WantReturn,<br />
<br />
или добавить ES_WANTRETURN при создании CEdit контрола динамически.<br />
===Как выводят картинку-логотип(splash screen) при запуске программы? То есть, когда загружается программа на экран выводится картинка, потом она исчезает(загрузка программы закончена) и пользователь может приступать к работе ===<br />
Для этого используется класс, производный от CDialog. Этот диалог после создания показывает себя на экран, выводя на себя рисунок. Также запускает таймер, по срабатывани которого диалог гасится. Создаётся диалог InitInstance приложения.<br />
<br />
В VC6++ также есть уже готовый компонент<br />
Project->Add To Project -> Components and Controls->(в папке "Visual C++ Components" есть SplashScreen.)<br />
<br />
===Как сделать, чтобы при выпадении списка у ComboBox была не одна строка, а больше, вроде все свойства покрутил, не помогает Вместо выпадающего списка одна строка и скролл...===<br />
В редакторе ресурсов надо щелкнуть в комбобоксе на треугольнике - появляется рамка для растягивания вниз - размер выпадающего списка.<br />
===В VC++.net, что делать после того, как на форму установил ActiveX ListView, как объявить класс и переменную для этого элемента?===<br />
Щёлкнуть правой кнопкой мыши на элементе, в меню - add variable или add class<br />
<br />
===Как вставить данные в буфер обмена (Clipboard)? Как их оттуда вытащить?===<br />
<br />
1) копирование в буфер обмена:<br />
<br />
1.Готовим данные<br />
а.Выделяем память из кучи, вызывая GlobalAlloc()<br />
б.Получаем указатель на выделенную память, вызывая GlobalLock()<br />
в.Заполняем данные<br />
г.Освобождаем указатель, вызывая GlobalUnlock();<br />
<br />
2.Открываем буфер обмена, вызывая OpenClipboard();<br />
3.Очищаем буфер, вызывая EmptyClipboard();<br />
4.Вызываем SetClipboardData() один раз для каждого формата<br />
вставляемых данных (имеется в виду - если одни и те же<br />
данные представлены в разных форматах, и приложение<br />
может эти форматы создать)<br />
5.Закрываем буфер, вызывая CloseClipboard();<br />
6.ВЫЗЫВАТЬ GlobalFree() НЕ НУЖНО, в этом случае это<br />
предоставлено системе<br />
<br />
Скажем, хотим поместить в буфер обмена текст.<br />
<pre><br />
//готовим данные<br />
//выделяем из кучи память для данных<br />
HANDLE hglbCopy = GlobalAlloc(GMEM_MOVEABLE,10);<br />
if(!hglbCopy)return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)return;<br />
<br />
//заполняем данные<br />
strcpy((char*)lpStr,"my text");<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
//очищаем<br />
EmptyClipboard();<br />
<br />
//текстовый формат<br />
SetClipboardData(CF_TEXT,hglbCopy);<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</pre><br />
2) извлечение из буфера обмена<br />
<br />
1.Проверяем, что поддерживается нужный формат данных,<br />
вызывая IsClipboardFormatAvailable()<br />
2.Открываем буфер обмена, вызывая OpenClipboard();<br />
3.Достаём данные<br />
а.Получаем из буфера хендл требуемого формата,<br />
вызывая GetClipboardData()<br />
б.Получаем указатель на выделенную память, вызывая GlobalLock()<br />
в.Работаем с данными<br />
г.Освобождаем указатель, вызывая GlobalUnlock();<br />
4.Закрываем буфер, вызывая CloseClipboard();<br />
<pre><br />
//Проверяем, что поддерживается нужный формат данных,<br />
if(!IsClipboardFormatAvailable(CF_TEXT))return;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
<br />
//достаём данные<br />
<br />
//текстовый формат<br />
HANDLE hglbCopy = GetClipboardData(CF_TEXT);<br />
if(!hglbCopy)return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)return;<br />
<br />
//читаем данные<br />
char data[10];<br />
memmove(data,lpStr,sizeof(data));<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</pre><br />
<br />
===Как получить полный путь к экзешнику из самой программы?===<br />
В командную строку первым параметром система всегда передаёт заключённый в кавычки полный путь к файлу запущенной программы. Достаём путь таким образом:<br />
<pre><br />
BOOL CMyApp::InitInstance()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName - содержит искомый путь<br />
<br />
//...<br />
//...<br />
}<br />
</pre><br />
<br />
===Каким способом exe файл может заменить самого себя? То есть, моя программа обновляется, например, через Internet, и хочет обновить свой exe-файл. Но так как он в данный момент запущен - это будет, естественно, запрещено. Как это можно проще всего сделать?===<br />
Один из способов - сделать копию экзешника и из него обновиться<br />
<pre><br />
<br />
#define def_exeNAMEup "c:\\myprog_update.exe"<br />
#define def_exeNAMEdnld "c:\\myprog_downloaded.exe"<br />
#define def_keyUdate "/update"<br />
<br />
void CTESTFAQApp::UpdateItself()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName - содержит искомый путь<br />
<br />
//делаем копию экзешника с другим именем<br />
CopyFile(csFullExeName,def_exeNAMEup,0);<br />
<br />
<br />
<br />
//передаём в параметры нового процесса ключ и путь к текущему файлу<br />
CString csParams=def_keyUdate;<br />
csParams+=" ";<br />
csParams+=csFullExeName;<br />
<br />
//запускаем копию<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(def_exeNAMEup,def_keyUdate,0,0,0,0,0,0,&si,&pi))<br />
{<br />
//завершаем текущий процесс<br />
ExitFromMyApp();<br />
}<br />
}<br />
<br />
void CTESTFAQApp::ExitFromMyApp()<br />
{<br />
exit(0);<br />
}<br />
<br />
BOOL CTESTFAQApp::InitInstance()<br />
{<br />
<br />
//смотрим, не запустили ли для апдейта?<br />
<br />
CString txt;<br />
txt=m_lpCmdLine;<br />
if(txt.Find(def_keyUdate)==0)<br />
{<br />
//делаем айдейт<br />
txt.Replace(def_keyUdate,"");<br />
txt.TrimLeft();<br />
<br />
CString csFullExeName=txt;<br />
<br />
//берём откуда то уже скачанный файл обновления<br />
//...<br />
CString csFull_Downloaded_ExeName=def_exeNAMEdnld;<br />
<br />
//копируем файл (обновляем старый то есть)<br />
CopyFile(csFull_Downloaded_ExeName,csFullExeName,0);<br />
<br />
//запускаем обновлённого мученника<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(csFullExeName,0,0,0,0,0,0,0,&si,&pi))<br />
<br />
ExitFromMyApp();<br />
<br />
}<br />
//...<br />
//...<br />
}<br />
</pre><br />
===Есть строка символов (страничка из Инета) в кодировке utf-8 (строка char*). Как мне ее получить в формате String или в char* в кодировке ANSI (cp 1251)?===<br />
<br />
Можно перевести строку из UTF8 в Unicode, затем из Unicode в 1251<br />
<br />
Ниже приведена структура, содержащая процедуры перекодирования,<br />
а также процедуру с примером использования<br />
<pre><br />
//описание структуры<br />
struct coder<br />
{<br />
//utf8->unicode<br />
static wchar_t* utf8_to_unicode__dontForgetDeleteArr(const char *utf8_string)<br />
{<br />
wchar_t* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len=MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,0,0);<br />
if(!res_len)return 0;<br />
<br />
//выделяем память<br />
pRes = new wchar_t[res_len];<br />
if(!pRes)return 0;<br />
<br />
//преобразование<br />
if(!MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,pRes,res_len))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//unicode->1251<br />
static char * unicode_to_1251__dontForgetDeleteArr(const wchar_t *unicode_string)<br />
{<br />
char* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len = WideCharToMultiByte(1251,0,unicode_string,-1,0,0,0,0);<br />
if(!res_len)return 0;<br />
<br />
//выделяем память<br />
pRes=new char[res_len];<br />
if(!pRes)return 0;<br />
<br />
//преобразование<br />
if(!WideCharToMultiByte(1251,0,unicode_string,-1,pRes,res_len,0,0))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//процедура с примером<br />
static void Example()<br />
{<br />
wchar_t* unicode_string=0;<br />
char* cp1251_string=0;<br />
<br />
//исходный текст<br />
char utf8_string[] = "UTF-8 + русский текст";<br />
<br />
for(;;)<br />
{<br />
<br />
unicode_string=utf8_to_unicode__dontForgetDeleteArr(utf8_string);<br />
if(!unicode_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать в unicode!");<br />
break;<br />
}<br />
<br />
cp1251_string = unicode_to_1251__dontForgetDeleteArr(unicode_string);<br />
<br />
if(!cp1251_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать из unicode!");<br />
break;<br />
}<br />
<br />
break;<br />
}<br />
<br />
//cp1251_string - результат<br />
AfxMessageBox(cp1251_string);<br />
<br />
<br />
//не забываем удалить массивы<br />
if(unicode_string)<br />
{<br />
delete [] unicode_string;<br />
unicode_string=0;<br />
}<br />
if(cp1251_string)<br />
{<br />
delete [] cp1251_string;<br />
cp1251_string=0;<br />
}<br />
}<br />
};<br />
<br />
//вызов примера<br />
coder::Example();<br />
</pre><br />
<br />
===Как организовать взаимодействие программы на VC.net с Access-овской базой данных?===<br />
Проще всего подключить ADO компоненты и сделать все на них.<br />
Компоненты ADO (ADODC,DATAGRID и т.п.) это ActiveX.<br />
В редакторе ресурсов, во всплывающем меню, есть Insert ActiveX Control -> открывается список всех компоент,<br />
зарегистрированых на машине. Нужно найти компоненты (Это компоненты от MS и они помечены (OLEDB)) и вставить их в диалог. Для того что бы иметь возможность управлять ими, нужно импортировать обертки для них, это делается при помощи ClassWisard, там есть импорт->класс->указать файл с компоентой (OSX).<br />
Появляется список всех классов, объявленых внутри.<br />
Проставляем галочки, нажимаем ОК.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_3&diff=602FAQ:WinAPI, VCPP Part 32008-10-08T18:08:50Z<p>Алексей1153++: </p>
<hr />
<div><br />
<br />
=== Как узнать, что пользователь меняет текст в приложении на основе CRichEditView?===<br />
Нужно добавить обработчик сообщения EN_CHANGE. Сообщение генерируется CRichEditView каждый раз, когда пользователь изменяет текст в окне CRichEditView<br />
<br />
===Чем отличается метод CArray::GetSize от метода CArray::GetCount?===<br />
Эти методы абсолютно идентичны. Скорее всего, в более старых версиях библиотек функции, одинаковые по смыслу, имели разные имена. Поэтому в целях совместимости разработчики оставили обе функции)<br />
<br />
===Как загрузить текстовую строку из ресурса?===<br />
Пример:<br />
<syntaxhighlight><br />
CString m_Temp;<br />
m_Temp.LoadString(ID_MYSTRING);<br />
</syntaxhighlight><br />
<br />
===Как поменять иконку у элемента item в CListCtrl?===<br />
Пример:<br />
<syntaxhighlight><br />
//заполняем структуру LVITEM<br />
LVITEM lvItem;<br />
memset(&lvItem,0,sizeof(lvItem));<br />
<br />
lvItem.mask = LVIF_IMAGE;//меняться будет картинка<br />
lvItem.iItem = ...;// индекс элемента списка (Zero-based)<br />
lvItem.iSubItem = 0;<br />
lvItem.iImage = ...; //индекс иконки (из списка контрола)<br />
<br />
pList->SetItem(&lvItem);<br />
</syntaxhighlight><br />
<br />
===Имеется класс Class1, содержащий мембер типа "указатель на Class2". В Class2 также имеется указатель на Class1. Компилятор выдаёт ошибку. Что надо делать?===<br />
Перекрёстное определение обходится следкющим образом: код обоих классов разносится в пары файлов *.h и *.cpp, а перед каждым классом вписывается предопределение другого класса:<br />
<br />
файл class1.h<br />
<syntaxhighlight><br />
class Class2;//предопределение Class2<br />
<br />
Class1<br />
{<br />
Class2* m_p2;//компилятор разрешит объявление указателя Class2*<br />
<br />
void F1(Class2* p);//компилятор разрешит объявление указателя Class2*<br />
void F2(Class1* p);<br />
};<br />
</syntaxhighlight><br />
<br />
файл class1.cpp<br />
<syntaxhighlight><br />
#include "class1.h"<br />
#include "class2.h"<br />
<br />
void Class1::F1(Class2* p)<br />
{<br />
...<br />
}<br />
<br />
void Class1::F2(Class1* p)<br />
{<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
файл class2.h<br />
<syntaxhighlight><br />
class Class1;//предопределение Class1<br />
<br />
Class2<br />
{<br />
Class1* m_p1;//компилятор разрешит объявление указателя Class1*<br />
<br />
void F3(Class1* p);//компилятор разрешит объявление указателя Class1*<br />
};<br />
</syntaxhighlight><br />
<br />
файл class2.cpp<br />
<syntaxhighlight><br />
#include "class2.h"<br />
#include "class1.h"<br />
<br />
void Class2::F3(Class1* p)<br />
{<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
После предопределениея класса компилятор позволяет объявлять указатель на класс, так как переменная указателя на любой тип имеет всегда один и тот же размер.<br />
<br />
===Как переключить раскладку в другом (то есть в активном) процессе?===<br />
Для этого можно использовать функции<br />
<syntaxhighlight><br />
GetKeyboardLayout(...); // определить текущую раскладку<br />
LoadKeyboardLayout(...); // загрузить новую раскладку<br />
VerLanguageName(...); // получить строку с описанием языка<br />
</syntaxhighlight><br />
<br />
Подробности - в MSDN<br />
<br />
===Как получить хендл элемента управления, зная его идентификатор?===<br />
Пример:<br />
Пусть элемент Edit лежит на окне CMyWnd.<br />
Тогда:<br />
<syntaxhighlight><br />
void CMyWnd::некая_процедура()<br />
{<br />
//для MFC<br />
CEdit* ed=(CEdit* ) GetDlgItem(ID_EDIT1);<br />
HWND hwnd=ed->GetSafeHwnd();<br />
if(hwnd)<br />
{<br />
...<br />
}<br />
<br />
//для Win32 API<br />
HWND hwnd=GetDlgItem(m_hWnd,ID_EDIT1);<br />
if(hwnd)<br />
{<br />
...<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
===Как из дочернего окна закрыть приложение?===<br />
Для этого нужно послать родительскому окну сообщение WM_CLOSE:<br />
<br />
через указатель на родительское окно:<br />
<syntaxhighlight><br />
pParent->PostMessage(WM_CLOSE);<br />
</syntaxhighlight><br />
<br />
при помощи хендла рордительского окна:<br />
<syntaxhighlight><br />
::PostMessage(pParent->m_hWnd,WM_CLOSE,(WPARAM)0,(LPARAM)0);<br />
</syntaxhighlight><br />
<br />
===Как корректно перевести тип BSTR в CString и наоборот?===<br />
<br />
1) для конвертирования BSTR в CString нужно просто присвоить переменной типа CString переменную типа BSTR.<br />
Оператор "=" класса CString сам выполнит всю работу.<br />
<br />
2) для конвертирования BSTR в CString нужно выполнить код:<br />
<syntaxhighlight><br />
<br />
//указатель на будущий буфер с BSTR.<br />
BSTR bstrHE=0;<br />
// (По сути, BSTR определён как <br />
// typedef WCHAR* BSTR;<br />
// то есть указатель на 16-битный символ юникод)<br />
<br />
//строка для конвертации<br />
CString Str="мой текст";<br />
<br />
//Выделяем память и загружаем адрес блока в bstrHE<br />
bstrHE=Str.AllocSysString();<br />
<br />
//... <br />
//тут работаем с bstrHE[]<br />
//...<br />
<br />
//освобождаем память<br />
SysFreeString(bstrHE);<br />
</syntaxhighlight><br />
<br />
===Как получить доступ к графическим ресурсам элементов текущей темы оформления Windows?===<br />
<br />
Для этого нужно использовать функции<br />
<br />
<syntaxhighlight><br />
OpenThemeData(...);<br />
DrawThemeBackground(...);<br />
DrawFrameControl(...);<br />
CloseThemeData(...);<br />
</syntaxhighlight><br />
<br />
(подробности - в MSDN)<br />
<br />
===Имеется класс , производный от CDialog. Когда диалог в фокусе, нажатие на Enter или Esc приводит к закрытию диалога. Как это запретить?===<br />
При нажатии Enter происходит выполнение команды IDOK,при нажатии Esc - IDCANCEL.<br />
<br />
Нужно переопределить в классе виртуальные функции OnOk() и OnCancel(), которые соответственно вызываются для этих команд. При помощи визарда эти функции добавить можно так:<br />
<br />
Положить на диалог две кнопки с идентификаторами IDOK и IDCANCEL (при создании нового диалога они там есть сразу), затем двойной щелчок по кнопке добавит соответствующий обработчик. В обработчиках надо удалить вызовы СDialog::OnOK() и CDialog::OnCancel(), тогда диалог закрываться не будет.<br />
<br />
Однако тогда диалог станет невозможно закрыть кнопкой с крестиком. Это обходится так: добавляем обработчик сообщения WM_CLOSE - OnClose(), и в нём делаем вызов OnOk() или OnCancel():<br />
<syntaxhighlight><br />
void CPlayersPropsDialog::OnClose() <br />
{<br />
CDialog::OnClose();<br />
CDialog::OnCancel();//добавлено<br />
}<br />
</syntaxhighlight><br />
<br />
===Я написал в VC++ простейший макрос , где невозможно ошибиться, а компилятор всё же выдаёт ошибку. Не пойму, в чём дело?===<br />
<br />
Скорее всего после одного из символов соединения строк "\" имеется пробел или табуляция. Их надо удалить. Можно найти их "наощупь", а можно включить показ непечатных символов в студии. Найти эту команду можно так:<br />
<br />
Tools->Customize...->вкладка Commands. В окошке Category выбрать "Edit", и среди кнопок справа найти кнопку, на которой написано "a.b"<br />
<br />
Эту кнопку надо перетащить на одну из панелей инструментов студии.<br />
<br />
===Как получить список всех процесов, включая idle?===<br />
<br />
Использовать функции<br />
<syntaxhighlight><br />
Process32First(...);<br />
Precess32Next(...);<br />
</syntaxhighlight><br />
<br />
(подробности - в MSDN)<br />
<br />
===Как программно установить переменные окружения?===<br />
Чтобы добавить или изменить их программно, необходимо воспользоваться ключом реестра<br />
<syntaxhighlight><br />
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment<br />
</syntaxhighlight><br />
<br />
Затем нужно отправить широковещательное сообщение WM_SETTINGCHANGE (это позволит приложениям узнать об изменениях):<br />
<syntaxhighlight><br />
::SendMessage(HWND_BROADCAST,WM_SETTINGCHANGE,0,0);<br />
</syntaxhighlight><br />
<br />
<br />
===Как сделать, чтобы у окна был черный фон?===<br />
Нужно переопределить обработчик сообщения WM_CTLCOLOR - OnCtlColor() :<br />
<br />
<syntaxhighlight><br />
CBrush br(RGB(0,0,0)); //глобальная переменная или член класса CMyDlg,<br />
// инициализированный в OnInitDialog()<br />
<br />
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
HBRUSH hbr = CMyDlg::OnCtlColor(pDC, pWnd, nCtlColor);<br />
<br />
//фон диалога (или View)<br />
if(nCtlColor==CTLCOLOR_DLG)<br />
{<br />
return (HBRUSH)br;<br />
}<br />
<br />
//фон элементов SCtatic, лежащих на форме (если нужно)<br />
if(nCtlColor==CTLCOLOR_STATIC)<br />
{<br />
//делаем фон текста статика прозрачным<br />
pDC->SetBkMode(TRANSPARENT);<br />
return (HBRUSH)br;<br />
}<br />
<br />
return hbr;<br />
}<br />
</syntaxhighlight><br />
<br />
===Почему на моем компьютере экзешник, созданный в MFC запускается, а на других компьютерах - нет? Требует какую-то dll-ку.===<br />
Нужно выбирать режим Release :<br />
<br />
Menu->Build->Configurations...->Release,<br />
<br />
и экзешник, соответственно, брать из папки Release проекта<br />
===Как в диалог добавить меню?===<br />
Надо сделать в ресурсах меню, затем вставить в диалог:<br />
<br />
открыть в редакторе диалог, в свойствах (во вкладке General, окошко Menu) указать идентивикатор ресурса меню.<br />
При помощи визарда добавить для меню обработчики OnCommand() и OnUpdateСommand().<br />
===Я добавил визардом меню в диалог. Добавил обработчики для пунктов меню. Пункты работают, но OnUpdate для пунктов не вызывается - то есть не получается ни затенить, ни чек поставить. Что делать?===<br />
В диалоге у меню апдейта не происходит сам, в отличие от мейнфрейма.<br />
Для этого нужно сделать самим апдейт в обработчике сообщения WM_KICKIDLE.<br />
Визардом обработчик не добавляется, поэтому можно переопределить виртуальную DefWindowProc() и там обработать:<br />
<pre><br />
#include <afxpriv.h> //этот файл надо включить, там определёна WM_KICKIDLE<br />
<br />
LRESULT CMyDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
if(message==WM_KICKIDLE)<br />
{<br />
//делаем апдейт для всех пунктов меню<br />
CMenu* pMainMenu=GetMenu();<br />
if(pMainMenu)<br />
{<br />
CCmdUI cmdUI;<br />
for (UINT n=0; n < pMainMenu->GetMenuItemCount(); ++n)<br />
{<br />
CMenu* pSubMenu = pMainMenu->GetSubMenu(n);<br />
if(!pSubMenu)continue;<br />
<br />
cmdUI.m_nIndexMax = pSubMenu->GetMenuItemCount();<br />
for (UINT i = 0; i < cmdUI.m_nIndexMax;++i)<br />
{<br />
cmdUI.m_nIndex = i;<br />
cmdUI.m_nID = pSubMenu->GetMenuItemID(i);<br />
cmdUI.m_pMenu = pSubMenu;<br />
cmdUI.DoUpdate(this, FALSE);<br />
}<br />
}<br />
}<br />
}<br />
<br />
<br />
<br />
return CDialog::DefWindowProc(message, wParam, lParam);<br />
}<br />
</pre><br />
<br />
===Как на Visual C++ 6.0 в Главном окне отключить системное меню (в левом верхнем углу) и кнопки(в правом верхнем углу)?===<br />
При создании окна нужно убрать стиль WS_SYSMENU<br />
(теперь пользователь корректно может закрыть окно только Alt+F4,<br />
ну или если вы предоставите ему дополнительную возможность сделать это)<br />
<br />
<br />
Пример 1. (для SDI, MDI)<br />
<pre><br />
//этот обработчик уже добавлен визардом<br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
if( !CFrameWnd::PreCreateWindow(cs) )<br />
return FALSE;<br />
// TODO: Modify the Window class or styles here by modifying<br />
// the CREATESTRUCT cs<br />
<br />
///////////////////////////////<br />
//добавленная часть<br />
{<br />
//убираем стиль<br />
cs.style&=~WS_SYSMENU;<br />
}<br />
///////////////////////////////<br />
<br />
return TRUE;<br />
}<br />
</pre><br />
Пример 2. (для диалога)<br />
Если диалог описан в ресурсах, то в свойствах диалога убрать галочки<br />
"System menu"<br />
"Minimize box"<br />
"Maximize box"<br />
<br />
===Хочу сделать так, чтобы пользователь не мог нажать на кнопку, пока программа не разрешит.===<br />
Нужно применить метод класса CWnd::EnableWindow(...) для кнопки.<br />
Значение параметра 0 делает кнопку неактивной, 1 - делает активной.<br />
(кстате, не только для кнопки можно, а для любого класса, производного<br />
от класса CWnd)<br />
<br />
<br />
Пусть имеется некий диалог, на нём лежит кнопка c ID == IDC_1.<br />
в любом месте кода диалога (кроме конструктора и деструктора , хотя, если<br />
проверить наличие валидного хендла диалога, как в примере, то ничего<br />
страшного не будет и там)<br />
<pre><br />
//делаем кнопку неактивной<br />
if(m_hWnd)<br />
{<br />
CWnd* pw=0;<br />
pw=GetDlgItem(IDC_1);<br />
if(pw)pw->EnableWindow(0);<br />
}<br />
</pre><br />
<br />
===Что означают сообщения, которые студия выводит при компиляции, вроде таких : Loaded 'C:\WINDOWS\SYSTEM\WSOCK32.DLL', no matching symbolic information found. ===<br />
Это строка говорит о том, что студия не смогла найти отладочные<br />
символы для WSOCK32.DLL. В этом нет ничего страшного, просто при наличии<br />
отладочных символов в процессе отладки можно получить доступ к именам<br />
функции из системных DLL. Например, вместо<br />
KERNEL32! 0x77E8B184() -<br />
увидим<br />
KERNEL32!CreateThread.<br />
===Как обработать сообщения, которое приходит к некому контролу (скажем CEdit)?===<br />
Нужно произвести от CEdit свой класс, и в виртуальной процедуре класса WindowProc перехватить нужные сообщения.<br />
<pre><br />
virtual LRESULT WindowProc(<br />
UINT message,<br />
WPARAM wParam,<br />
LPARAM lParam <br />
);<br />
</pre><br />
Пример. Полностью выключаем, скажем, обработку сообщения WM_CHAR<br />
<pre><br />
LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) <br />
{<br />
switch(message)<br />
{<br />
case WM_CHAR:<br />
{<br />
return 0;<br />
}<br />
break;<br />
}<br />
<br />
return CEdit::WindowProc(message, wParam, lParam);<br />
}<br />
</pre><br />
Чтобы связать экземпляр класса с контролом на форме, добавьте визардом для<br />
контрола переменную класса (выбрав не Value а Control).<br />
<br />
===Как настроить количество пробелов в табуляции?===<br />
Tools->Options->Tabs->Insert Spaces<br />
(или правой кнопкой мыши по тексту-> properties)<br />
===Как автоматически расставить отступы?===<br />
Выделить текст для форматирования, нажать Alt+F8<br />
<br />
Есть ещё программа Artistic Style, которая занимается<br />
переформатированием кода<br />
http://sourceforge.net/projects/astyle/<br />
===Поиск границ блока===<br />
"CTRL+ }" ищет парную фигурную скобку в тексте и переходит на неё<br />
===Вертикальное выделение текста===<br />
"Alt + выделение мышкой" - позволяет выделять вертикальные фрагменты текста<br />
===Как узнать количество установленных в CListCtrl столбцов?===<br />
<pre><br />
CListCtrl* pL=...; //указатель на переменную-контрол<br />
<br />
int count=pL->GetHeaderCtrl()->GetItemCount();<br />
</pre><br />
<br />
===Как получить иконку приложения?===<br />
Если приложение запущено, то нужно найти его главное окно и<br />
послать ему сообщение WM_GETICON.<br />
<pre><br />
//функция возвращант хендл иконки <br />
LRESULT SendMessage(hWnd, WM_GETICON, wParam, 0);<br />
<br />
//hWnd == хендл окна приложения<br />
//wParam == <br />
// 1)==ICON_BIG - получить большую иконку<br />
// 2)==ICON_SMALL - получить маленькую иконку<br />
// 3)==ICON_SMALL2 - получить маленькую иконку, если она определена<br />
// в приложении. Если её нет, то маленькую иконку, <br />
// сгенерированную системой из большой иконки<br />
</pre><br />
===Как в CString можно найти или вырезать часть строки?===<br />
есть такие методы в CString:<br />
<pre><br />
//вырезает кусок строки<br />
CString Mid(int nFirst) const;<br />
CString Mid(int nFirst, int nCount) const;<br />
<br />
//возвращает кусок строки (сначала или с конца)<br />
CString Left(int nCount ) const;<br />
CString Right(int nCount ) const;<br />
<br />
//возвращает начальный кусок строки, в котором есть только<br />
//символы из набора,представленного в lpszCharSet<br />
CString SpanIncluding(LPCTSTR lpszCharSet ) const;<br />
<br />
//возвращает начальный кусок строки, в котором нет<br />
//символов из набора,представленного в lpszCharSet<br />
CString SpanExcluding(LPCTSTR lpszCharSet ) const; <br />
<br />
//убирает "пробелоподобные" символы из самого начала строки<br />
//(то есть - пробел, табуляцию (\t) , возврат каретки, перевод строки (/r/n))<br />
void TrimLeft();<br />
//убирает все повторы символа из самого начала строки<br />
void TrimLeft(TCHAR chTarget );<br />
//убирает из самого начала строки все символа из набора lpszTargets <br />
void TrimLeft(LPCTSTR lpszTargets ); <br />
<br />
void TrimRight();<br />
void TrimRight(TCHAR chTarget );<br />
void TrimRight(LPCTSTR lpszTargets ); <br />
<br />
//поиск в строке<br />
int Find( TCHAR ch ) const;<br />
int Find( LPCTSTR lpszSub ) const;<br />
int Find( TCHAR ch, int nStart ) const;<br />
int Find( LPCTSTR pstr, int nStart ) const;<br />
<br />
//поиск, начиная с конца<br />
int ReverseFind( TCHAR ch ) const;<br />
<br />
//поиск позиции первого символа, одного из набора,<br />
// представленного в lpszCharSet<br />
int FindOneOf( LPCTSTR lpszCharSet ) const;<br />
</pre><br />
<br />
===Есть у меня CListBox и я в ходе выполнения программы добавляю в него строки. Но я не могу посмотреть что именно добавляется. Вывод результатов происходит в конце выполнения процедуры...===<br />
Если нужно делать принудительную перерисовку окна во время<br />
длительных вычислений, то нужно вызывать для окна, которое<br />
надо перерисовать метод<br />
RedrawWindow()<br />
с параметрами по умолчанию, или пару<br />
Invalidate(0);<br />
UpdateWindow();<br />
Это приводит к пометке всего окна к перерисовке и отправлению<br />
сообщения WM_PAINT в оконную процедуру в обход очереди<br />
сообщений, вызывая немедленную перерисовку окна.<br />
<pre><br />
CWnd* pw=...;//окно, которое надо перерисовывать<br />
<br />
for(int i=0;i<10000)<br />
{<br />
//меняется содержимое окна<br />
//...<br />
<br />
//немедленная перерисовка<br />
pw->Invalidate(0);<br />
pw->UpdateWindow();<br />
}<br />
</pre><br />
<br />
===Я написал DLL, которую используют несколько приложений. Всё вроде работает, но когда происходит очередной вызов функции из DLL, почему то данные в функции обнуляются. С чем это связано?===<br />
Переменные и массивы в DLL, содержимое которых должно использоваться несколькими процессами, должны объявляться статическими. Статическая переменная или массив инициализируются только один раз в момент загрузки DLL.<br />
Пример:<br />
<pre><br />
DWORD calltest()<br />
{<br />
//будет выполнено только при первом вызове<br />
static DWORD callcount=0;<br />
static DWORD str[1000]={0}; <br />
<br />
//будет выполняться каждый раз<br />
return ++callcount;<br />
}<br />
</pre><br />
<br />
===Как открыть проекцию файла в память и как с ней работать?===<br />
Создаем проекцию<br />
<pre><br />
HANDLE CreateFileMapping(<br />
HANDLE hFile, //хендл уже открытого файла<br />
LPSECURITY_ATTRIBUTES lpAttributes,<br />
DWORD flProtect, //способ открытия проекции<br />
DWORD dwMaximumSizeHigh, //размер файла (старшие 4 байта , обычно==0)<br />
DWORD dwMaximumSizeLow, //размер файла (младшие 4 байта)<br />
LPCTSTR lpName<br />
);<br />
</pre><br />
Доступ к созданной проекции производится процедурой<br />
<pre><br />
LPVOID MapViewOfFile(<br />
HANDLE hFileMappingObject, //хендл проекции<br />
DWORD dwDesiredAccess, //способ работы с проекцией<br />
DWORD dwFileOffsetHigh,<br />
DWORD dwFileOffsetLow, //смещение от начала файла (младшие 4 байта)<br />
SIZE_T dwNumberOfBytesToMap //длина в байтах (если ==0 - то весь файл)<br />
);<br />
</pre><br />
далее с файлом можно работать как с обычным массивом в памяти.<br />
<br />
После работы с проекцией, её надо освободить процедурой<br />
<pre><br />
BOOL UnmapViewOfFile(<br />
LPCVOID lpBaseAddress //адрес, который вернула процедура MapViewOfFile<br />
);<br />
</pre><br />
Пример.<br />
<pre><br />
HANDLE hMapFile=0;//для проекции<br />
<br />
HANDLE hFile=...;//хендл уже открытого файла<br />
DWORD dwdFileLen=...;//размер открытого файла<br />
<br />
//создаём проекцию "только для чтения"<br />
hMapFile=::CreateFileMapping(hFile,0,PAGE_READONLY,0,dwdFileLen,0);<br />
<br />
//хендл hFile можно закрыть уже здесь, в принципе,<br />
//но мы сделаем это позже<br />
<br />
//получаем доступ к проекции (тоже только для чтения)<br />
BYTE* pbyFile=(BYTE*)::MapViewOfFile(hMapFile,FILE_MAP_READ,0,0,0);<br />
<br />
///////////////////<br />
//тут работаем с массивом pbyFile[dwdFileLen] как с обычным,<br />
//только не забываем, что он открыт только для чтения<br />
//...<br />
//...<br />
//...<br />
///////////////////<br />
<br />
<br />
//отключаем файл данных от адресного пространства<br />
UnmapViewOfFile(pbyFile);<br />
<br />
//освобождаем хендл проекции<br />
CloseHandle(hMapFile)<br />
<br />
//освобождаем хендл открытого файла<br />
CloseHandle(hFile);<br />
</pre><br />
<br />
===Использую MFC Grid control 2.25, не получается отобразить картинку в ячейке. Как это делается?===<br />
Нужно создать список изображений (CImageList), затем передать указатель на список в контрол. Поскольку контрол лишь копирует указатель, список должен создаваться динамически, либо быть членом класса, экземпляр которого существует всё время работы контрола.<br />
<pre><br />
m_GridMarket<br />
CImageList m_ImageList;<br />
CGridCtrL m_Grid1<br />
...<br />
...<br />
//неким образом создаётся список<br />
m_ImageList.Create(...);<br />
//...<br />
<br />
//вставляем в контрол<br />
m_Grid1.SetImageList(&m_ImageList);<br />
<br />
//<br />
</pre><br />
<br />
===Как при помощи IPicture отобразить картинку из файла? ===<br />
Пример - несложная функция, отображающая картинку из файла<br />
<br />
поддерживаются форматы<br />
BMP, GIF, JPEG, PNG, TIFF, EMF<br />
<pre><br />
#include "atlconv.h"<br />
#define HandleIsValid(H) (H!=(HANDLE)-1 && H!=(HANDLE)0)<br />
<br />
//*pDestDC - CDC, на который предполагается вывод картинки<br />
//pchzFilePath - путь к файлу<br />
//pWid - (возвращает) ширина картинки<br />
//pHig - (возвращает) высота картинки<br />
bool DrawBitmapFromFile(CDC* pDestDC,const char* pchzFilePath,int *pWid=0,int *pHig=0)<br />
{<br />
bool result=false;<br />
<br />
if(pWid)*pWid=0;<br />
if(pHig)*pHig=0;<br />
<br />
int Wid=0;<br />
int Hig=0;<br />
<br />
IPicture* pPic=0;<br />
try<br />
{<br />
IPicture* ptmpPic=0;<br />
USES_CONVERSION;<br />
HRESULT hr;<br />
<br />
CString txt=pchzFilePath;<br />
hr= ::OleLoadPicturePath(<br />
const_cast<LPOLESTR>(T2COLE(txt)),<br />
0,0,0,IID_IPicture,<br />
reinterpret_cast<void **>(&ptmpPic)<br />
);<br />
<br />
if(hr==S_OK && ptmpPic)<br />
{<br />
pPic=ptmpPic;<br />
}<br />
else<br />
{<br />
throw 0;<br />
}<br />
<br />
OLE_XPOS_HIMETRIC cxSrc;<br />
OLE_YPOS_HIMETRIC cySrc;<br />
<br />
if(S_OK!=pPic->get_Width(&cxSrc))throw 0;<br />
if(S_OK!=pPic->get_Height(&cySrc))throw 0;<br />
<br />
Wid=cxSrc/26;<br />
Hig=cySrc/26;<br />
<br />
//рисуем<br />
if(S_OK !=pPic->Render(pDestDC->GetSafeHdc(),<br />
0,Hig,Wid,-Hig,0,0,cxSrc,cySrc,0))throw 0;<br />
}<br />
catch(...)<br />
{<br />
result=false;<br />
}<br />
<br />
if(pPic)<br />
{<br />
pPic->Release();<br />
pPic=0;<br />
}<br />
<br />
<br />
if(pWid)*pWid=Wid;<br />
if(pHig)*pHig=Hig;<br />
<br />
return result;<br />
}<br />
<br />
</pre><br />
===У меня модальное диалоговое окно, в нем поле редактирования мультилайновое, т.е. чтобы перейти на новую строку надо нажать ентер, но вызывается стандартный обработчик диалогового окна. Подскажите, что делать?===<br />
Нужно в редакторе ресурсов поставить для CEdit окошка галочку<br />
свойства WantReturn,<br />
<br />
или добавить ES_WANTRETURN при создании CEdit контрола динамически.<br />
===Как выводят картинку-логотип(splash screen) при запуске программы? То есть, когда загружается программа на экран выводится картинка, потом она исчезает(загрузка программы закончена) и пользователь может приступать к работе ===<br />
Для этого используется класс, производный от CDialog. Этот диалог после создания показывает себя на экран, выводя на себя рисунок. Также запускает таймер, по срабатывани которого диалог гасится. Создаётся диалог InitInstance приложения.<br />
<br />
В VC6++ также есть уже готовый компонент<br />
Project->Add To Project -> Components and Controls->(в папке "Visual C++ Components" есть SplashScreen.)<br />
<br />
===Как сделать, чтобы при выпадении списка у ComboBox была не одна строка, а больше, вроде все свойства покрутил, не помогает Вместо выпадающего списка одна строка и скролл...===<br />
В редакторе ресурсов надо щелкнуть в комбобоксе на треугольнике - появляется рамка для растягивания вниз - размер выпадающего списка.<br />
===В VC++.net, что делать после того, как на форму установил ActiveX ListView, как объявить класс и переменную для этого элемента?===<br />
Щёлкнуть правой кнопкой мыши на элементе, в меню - add variable или add class<br />
<br />
===Как вставить данные в буфер обмена (Clipboard)? Как их оттуда вытащить?===<br />
<br />
1) копирование в буфер обмена:<br />
<br />
1.Готовим данные<br />
а.Выделяем память из кучи, вызывая GlobalAlloc()<br />
б.Получаем указатель на выделенную память, вызывая GlobalLock()<br />
в.Заполняем данные<br />
г.Освобождаем указатель, вызывая GlobalUnlock();<br />
<br />
2.Открываем буфер обмена, вызывая OpenClipboard();<br />
3.Очищаем буфер, вызывая EmptyClipboard();<br />
4.Вызываем SetClipboardData() один раз для каждого формата<br />
вставляемых данных (имеется в виду - если одни и те же<br />
данные представлены в разных форматах, и приложение<br />
может эти форматы создать)<br />
5.Закрываем буфер, вызывая CloseClipboard();<br />
6.ВЫЗЫВАТЬ GlobalFree() НЕ НУЖНО, в этом случае это<br />
предоставлено системе<br />
<br />
Скажем, хотим поместить в буфер обмена текст.<br />
<pre><br />
//готовим данные<br />
//выделяем из кучи память для данных<br />
HANDLE hglbCopy = GlobalAlloc(GMEM_MOVEABLE,10);<br />
if(!hglbCopy)return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)return;<br />
<br />
//заполняем данные<br />
strcpy((char*)lpStr,"my text");<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
//очищаем<br />
EmptyClipboard();<br />
<br />
//текстовый формат<br />
SetClipboardData(CF_TEXT,hglbCopy);<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</pre><br />
2) извлечение из буфера обмена<br />
<br />
1.Проверяем, что поддерживается нужный формат данных,<br />
вызывая IsClipboardFormatAvailable()<br />
2.Открываем буфер обмена, вызывая OpenClipboard();<br />
3.Достаём данные<br />
а.Получаем из буфера хендл требуемого формата,<br />
вызывая GetClipboardData()<br />
б.Получаем указатель на выделенную память, вызывая GlobalLock()<br />
в.Работаем с данными<br />
г.Освобождаем указатель, вызывая GlobalUnlock();<br />
4.Закрываем буфер, вызывая CloseClipboard();<br />
<pre><br />
//Проверяем, что поддерживается нужный формат данных,<br />
if(!IsClipboardFormatAvailable(CF_TEXT))return;<br />
<br />
//открываем буфер обмена<br />
OpenClipboard();<br />
<br />
//достаём данные<br />
<br />
//текстовый формат<br />
HANDLE hglbCopy = GetClipboardData(CF_TEXT);<br />
if(!hglbCopy)return;<br />
<br />
//получаем указатель<br />
void* lpStr = GlobalLock(hglbCopy);<br />
if(!lpStr)return;<br />
<br />
//читаем данные<br />
char data[10];<br />
memmove(data,lpStr,sizeof(data));<br />
<br />
//освобождаем указатель<br />
GlobalUnlock(hglbCopy);<br />
lpStr=0;<br />
<br />
//закрываем буфер<br />
CloseClipboard();<br />
</pre><br />
<br />
===Как получить полный путь к экзешнику из самой программы?===<br />
В командную строку первым параметром система всегда передаёт заключённый в кавычки полный путь к файлу запущенной программы. Достаём путь таким образом:<br />
<pre><br />
BOOL CMyApp::InitInstance()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName - содержит искомый путь<br />
<br />
//...<br />
//...<br />
}<br />
</pre><br />
<br />
===Каким способом exe файл может заменить самого себя? То есть, моя программа обновляется, например, через Internet, и хочет обновить свой exe-файл. Но так как он в данный момент запущен - это будет, естественно, запрещено. Как это можно проще всего сделать?===<br />
Один из способов - сделать копию экзешника и из него обновиться<br />
<pre><br />
<br />
#define def_exeNAMEup "c:\\myprog_update.exe"<br />
#define def_exeNAMEdnld "c:\\myprog_downloaded.exe"<br />
#define def_keyUdate "/update"<br />
<br />
void CTESTFAQApp::UpdateItself()<br />
{<br />
//добыча полного имени экзешника<br />
CString csFullExeName;<br />
{<br />
CString csAppName=GetCommandLine();<br />
csAppName.Delete(0,1);<br />
csAppName.Replace('\"','\0');<br />
csFullExeName=(const char*)csAppName;<br />
}<br />
//теперь csFullExeName - содержит искомый путь<br />
<br />
//делаем копию экзешника с другим именем<br />
CopyFile(csFullExeName,def_exeNAMEup,0);<br />
<br />
<br />
<br />
//передаём в параметры нового процесса ключ и путь к текущему файлу<br />
CString csParams=def_keyUdate;<br />
csParams+=" ";<br />
csParams+=csFullExeName;<br />
<br />
//запускаем копию<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(def_exeNAMEup,def_keyUdate,0,0,0,0,0,0,&si,&pi))<br />
{<br />
//завершаем текущий процесс<br />
ExitFromMyApp();<br />
}<br />
}<br />
<br />
void CTESTFAQApp::ExitFromMyApp()<br />
{<br />
exit(0);<br />
}<br />
<br />
BOOL CTESTFAQApp::InitInstance()<br />
{<br />
<br />
//смотрим, не запустили ли для апдейта?<br />
<br />
CString txt;<br />
txt=m_lpCmdLine;<br />
if(txt.Find(def_keyUdate)==0)<br />
{<br />
//делаем айдейт<br />
txt.Replace(def_keyUdate,"");<br />
txt.TrimLeft();<br />
<br />
CString csFullExeName=txt;<br />
<br />
//берём откуда то уже скачанный файл обновления<br />
//...<br />
CString csFull_Downloaded_ExeName=def_exeNAMEdnld;<br />
<br />
//копируем файл (обновляем старый то есть)<br />
CopyFile(csFull_Downloaded_ExeName,csFullExeName,0);<br />
<br />
//запускаем обновлённого мученника<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
ZeroMemory(&si,sizeof(si));<br />
si.cb = sizeof(si);<br />
ZeroMemory(&pi,sizeof(pi));<br />
if(CreateProcess(csFullExeName,0,0,0,0,0,0,0,&si,&pi))<br />
<br />
ExitFromMyApp();<br />
<br />
}<br />
//...<br />
//...<br />
}<br />
</pre><br />
===Есть строка символов (страничка из Инета) в кодировке utf-8 (строка char*). Как мне ее получить в формате String или в char* в кодировке ANSI (cp 1251)?===<br />
<br />
Можно перевести строку из UTF8 в Unicode, затем из Unicode в 1251<br />
<br />
Ниже приведена структура, содержащая процедуры перекодирования,<br />
а также процедуру с примером использования<br />
<pre><br />
//описание структуры<br />
struct coder<br />
{<br />
//utf8->unicode<br />
static wchar_t* utf8_to_unicode__dontForgetDeleteArr(const char *utf8_string)<br />
{<br />
wchar_t* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len=MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,0,0);<br />
if(!res_len)return 0;<br />
<br />
//выделяем память<br />
pRes = new wchar_t[res_len];<br />
if(!pRes)return 0;<br />
<br />
//преобразование<br />
if(!MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,pRes,res_len))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//unicode->1251<br />
static char * unicode_to_1251__dontForgetDeleteArr(const wchar_t *unicode_string)<br />
{<br />
char* pRes=0;<br />
int res_len=0;<br />
<br />
//тест на возможность преобразования<br />
res_len = WideCharToMultiByte(1251,0,unicode_string,-1,0,0,0,0);<br />
if(!res_len)return 0;<br />
<br />
//выделяем память<br />
pRes=new char[res_len];<br />
if(!pRes)return 0;<br />
<br />
//преобразование<br />
if(!WideCharToMultiByte(1251,0,unicode_string,-1,pRes,res_len,0,0))<br />
{<br />
delete [] pRes;<br />
return 0;<br />
}<br />
<br />
return pRes;<br />
}<br />
<br />
//процедура с примером<br />
static void Example()<br />
{<br />
wchar_t* unicode_string=0;<br />
char* cp1251_string=0;<br />
<br />
//исходный текст<br />
char utf8_string[] = "UTF-8 + русский текст";<br />
<br />
for(;;)<br />
{<br />
<br />
unicode_string=utf8_to_unicode__dontForgetDeleteArr(utf8_string);<br />
if(!unicode_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать в unicode!");<br />
break;<br />
}<br />
<br />
cp1251_string = unicode_to_1251__dontForgetDeleteArr(unicode_string);<br />
<br />
if(!cp1251_string)<br />
{<br />
AfxMessageBox("Не удалось конвертировать из unicode!");<br />
break;<br />
}<br />
<br />
break;<br />
}<br />
<br />
//cp1251_string - результат<br />
AfxMessageBox(cp1251_string);<br />
<br />
<br />
//не забываем удалить массивы<br />
if(unicode_string)<br />
{<br />
delete [] unicode_string;<br />
unicode_string=0;<br />
}<br />
if(cp1251_string)<br />
{<br />
delete [] cp1251_string;<br />
cp1251_string=0;<br />
}<br />
}<br />
};<br />
<br />
//вызов примера<br />
coder::Example();<br />
</pre><br />
<br />
===Как организовать взаимодействие программы на VC.net с Access-овской базой данных?===<br />
Проще всего подключить ADO компоненты и сделать все на них.<br />
Компоненты ADO (ADODC,DATAGRID и т.п.) это ActiveX.<br />
В редакторе ресурсов, во всплывающем меню, есть Insert ActiveX Control -> открывается список всех компоент,<br />
зарегистрированых на машине. Нужно найти компоненты (Это компоненты от MS и они помечены (OLEDB)) и вставить их в диалог. Для того что бы иметь возможность управлять ими, нужно импортировать обертки для них, это делается при помощи ClassWisard, там есть импорт->класс->указать файл с компоентой (OSX).<br />
Появляется список всех классов, объявленых внутри.<br />
Проставляем галочки, нажимаем ОК.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_2&diff=601FAQ:WinAPI, VCPP Part 22008-10-08T17:20:31Z<p>Алексей1153++: /* Как в отладчике Visual С++ просмотреть содержимое std::vector ? */</p>
<hr />
<div><br />
<br />
=== Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу? ===<br />
<br />
Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand() :<br />
<syntaxhighlight><br />
BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam) <br />
{<br />
WORD wMess=(wParam>>16);//командное сообщение<br />
int nID=(int)(wParam &0x0000ffff));//ID контрола<br />
HWND hW=(HWND)lParam;//хендл контрола<br />
<br />
//смотрим, какой контрол<br />
switch(nID)<br />
{<br />
//кнопки<br />
case ID_BN1:<br />
case ID_BN2:<br />
case ID_BN3:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case BN_CLICKED:{ ... }break;<br />
}<br />
}<br />
break;<br />
<br />
//едиты<br />
case ID_ED1:<br />
case ID_ED2:<br />
case ID_ED3:<br />
case ID_ED4:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case EN_CHANGE:{ ... }break;<br />
case EN_KILLFOCUS:{ ... }break;<br />
}<br />
}<br />
break;<br />
}<br />
<br />
return CDialog::OnCommand(wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать? ===<br />
<br />
Лечится проблема так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются. <br />
<br />
=== Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы? ===<br />
<br />
Нужно использовать функцию GetModuleFileName(): <br />
<syntaxhighlight><br />
TCHAR pszFileName[MAX_PATH];<br />
pszFileName[0]=0;<br />
GetModuleFileName(NULL, pszFileName, MAX_PATH);<br />
CString stModulePath = pszFileName;<br />
//ищем первый слеш с конца и удаляем<br />
//его вместе с именем файла EXE<br />
int nEnd = stModulePath.ReverseFind('\\');<br />
stModulePath.Delete(nEnd, stModulePath.GetLength()-nEnd);<br />
<br />
//stModulePath - содержит путь<br />
</syntaxhighlight><br />
<br />
=== Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame? ===<br />
<br />
<syntaxhighlight><br />
#include "MainFrm.h"<br />
<br />
//CMyApp - класс вашего приложения. theApp - глобальная переменная,<br />
//поэтому для доступа к ней используем extern<br />
extern CMyApp theApp;<br />
<br />
void CMyView::F()<br />
{<br />
//Получаем главное окно приложения в любом месте программы<br />
CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);<br />
<br />
pMainFrame->m_wndDlgBar ....//Делаем что хотим<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как загрузить и показать один из стандартных курсоров? ===<br />
<br />
<syntaxhighlight><br />
HCURSOR hCursor;<br />
hCursor=AfxGetApp()->LoadStandardCursor(IDC_UPARROW);<br />
if(hCursor)SetCursor(hCursor);<br />
</syntaxhighlight><br />
идентификаторы стандартных курсоров:<br />
<br />
IDC_ARROW<br />
<br />
IDC_IBEAM<br />
<br />
IDC_WAIT<br />
<br />
IDC_CROSS<br />
<br />
IDC_UPARROW<br />
<br />
IDC_SIZENWSE<br />
<br />
IDC_SIZENESW<br />
<br />
IDC_SIZEWE<br />
<br />
IDC_SIZENS<br />
<br />
IDC_SIZEALL <br />
<br />
=== Как запретить пользователю закрыть программу нажатием на кнопку с крестиком? ===<br />
<br />
Для этого нужно добавить обработчик сообщения WM_CLOSE ( функция OnClose() в MFC) в главное окно программы. Для диалоговых приложений такое окно - это главный диалог, для одно- и много-документных приложений - это CMainFrame. <br />
<syntaxhighlight><br />
void CMainFrame::OnClose()<br />
{<br />
if(......)<br />
{<br />
//не разрешаем закрыть<br />
return;<br />
}<br />
<br />
CFrameWnd::OnClose();<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab? ===<br />
<br />
Последовательность действий следующая:<br />
<br />
1) кладём на форму нужное количество элементов RadioButton.<br />
<br />
2) у первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство.<br />
<br />
3) порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется.<br />
<br />
=== Где лучше устанавливать начальные значения элемента CComboBox? ===<br />
<br />
Это можно сделать парой способов:<br />
<br />
1) В редакторе форм - открыть свойства элемента CComboBox , "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter) <br />
<br />
2) В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView) <br />
<br />
=== Как перевести RichEdit в режим замены символов? ===<br />
<br />
Имеется несколько способов.<br />
<br />
1) Программно, если известен хендл элемента (hWnd), это делается так: <br />
<syntaxhighlight><br />
//помещаем в конец очереди сообющений контрола сообщение WM_KEYDOWN<br />
//с нужными параметрами<br />
::PostMessage(hWnd,WM_KEYDOWN,VK_INSERT,1);<br />
</syntaxhighlight><br />
<br />
2) Пользователь во время работы может нажать клавишу Insert.<br />
<br />
=== Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы? ===<br />
<br />
Это можно сделать так:<br />
<br />
<syntaxhighlight><br />
AfxGetApp()->m_pMainWnd-> ...; <br />
</syntaxhighlight><br />
<br />
или так<br />
<syntaxhighlight><br />
extern CMyAppXXX theApp;//здесь CMyAppXXX - название класса вашего приложения<br />
theApp.m_pMainWnd-> ...; <br />
</syntaxhighlight><br />
<br />
=== Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ? ===<br />
<br />
Это можно сделать методом SetScaleToFitSize():<br />
<syntaxhighlight><br />
void CMyView::OnInitialUpdate()<br />
{<br />
CFormView::OnInitialUpdate();<br />
<br />
//скрываем полосы прокрутки<br />
GetParentFrame()->RecalcLayout();<br />
ResizeParentToFit();//это уберёт полосы прокрутки со вьюхи<br />
SIZE s={0,0};<br />
SetScaleToFitSize(s);<br />
//далее вызовется обработчик OnPaint(), о котором ниже<br />
/////////<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
Также обратите внимание на одну особенность: в дебаг-версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s={0,0} происходит с ошибкой (программа при этом завершается).<br />
Обходится это так:<br />
<syntaxhighlight><br />
void CMyView::OnPaint() <br />
{<br />
#ifdef _DEBUG<br />
CPaintDC dc(this);<br />
#else<br />
CFormView::OnPaint();<br />
#endif<br />
}<br />
</syntaxhighlight><br />
<br />
или даже вообще так:<br />
<syntaxhighlight><br />
void CMyView::OnPaint() <br />
{<br />
CPaintDC dc(this);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как нарисовать прямоугольник с вертикальным цветовым градиентом? ===<br />
<br />
Нужно задасться граничными значениями цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников (а, значит, плавность гралдиента) задаётся точностью.<br />
Пример:<br />
<syntaxhighlight><br />
//вертикальный градиент<br />
//pdc - указатель на контекст устройства<br />
//pSize - указатель на структуру<br />
//SIZE с размером прямоугольника<br />
// dwdColor1, dwdColor2 - начальный и конечный цвет<br />
//bySteps - количество шагов градиента (1...255) <br />
void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps)<br />
{<br />
if(!bySteps)bySteps=1;<br />
WORD i;<br />
<br />
long W,H,x1,x2;<br />
BYTE R1,G1,B1,R2,G2,B2;<br />
float dh,dR,dG,dB,y1,y2,Rc,Gc,Bc;<br />
<br />
//ширина и высота<br />
W=pSize->cx;<br />
H=pSize->cy;<br />
<br />
//раскладываем цвета на их составляющие<br />
//для удобства дальнейших вычислений<br />
R1=(BYTE)((dwdColor1&0x000000ff));<br />
G1=(BYTE)((dwdColor1&0x0000ff00)>>8);<br />
B1=(BYTE)((dwdColor1&0x00ff0000)>>16);<br />
R2=(BYTE)((dwdColor2&0x000000ff));<br />
G2=(BYTE)((dwdColor2&0x0000ff00)>>8);<br />
B2=(BYTE)((dwdColor2&0x00ff0000)>>16);<br />
<br />
//высота разноцветных прямоугольников<br />
dh=((float)H)/((float)bySteps);<br />
//величина шагов составляющих цветов<br />
dR=(((float)R2)-((float)R1))/((float)bySteps);<br />
dG=(((float)G2)-((float)G1))/((float)bySteps);<br />
dB=(((float)B2)-((float)B1))/((float)bySteps);<br />
//выводим прямоугольники<br />
x1=0;x2=W;y1=0;y2=dh;<br />
Rc=R1;Gc=G1;Bc=B1;<br />
for(i=0;i<bySteps;i++)<br />
{<br />
//текущий цвет<br />
pdc->FillSolidRect(x1,(int)y1,x2-x1,(int)(y2-y1),RGB((BYTE)Rc,(BYTE)Gc,(BYTE)Bc));<br />
//следующий цвет и координаты<br />
y1+=dh;y2+=dh;<br />
Rc+=dR;Gc+=dG;Bc+=dB;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
пример вызова: <br />
<syntaxhighlight><br />
SIZE Size={100,100};<br />
sFillGradientRect(&dc,&Size, RGB(200,0,0), RGB(0,200,0),10);<br />
</syntaxhighlight><br />
<br />
=== Как под Windows отслеживать изменение файла? ===<br />
<br />
Нужно использовать функции: <br />
<br />
FindFirstChangeNotification<br />
<br />
FindNextChangeNotification<br />
<br />
FindCloseChangeNotification<br />
<br />
(подробности - в MSDN)<br />
<br />
=== Как конвертировать массив char[] в CString? ===<br />
Это можно сделать методами самого класса CString:<br />
<syntaxhighlight><br />
char buf[]="text";<br />
<br />
//строка должна обязательно заканчиваться нулём!!!<br />
<br />
//конвертируем так<br />
CString txt(buf);<br />
<br />
//или так<br />
CString txt;<br />
txt=buf;<br />
</syntaxhighlight><br />
<br />
=== Как зарезервировать в CString буфер нужной длины? ===<br />
<br />
Это можно сделать при помощи методов класса: <br />
<br />
<syntaxhighlight><br />
CString::GetBuffer(...)<br />
</syntaxhighlight><br />
и<br />
<syntaxhighlight><br />
CString::GetBufferSetLength(...)<br />
</syntaxhighlight><br />
<br />
Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку НЕ МЕНЬШЕ заданной длины, а второй возвращает строку точно равную заданной длине. Обе могут перераспределять память если надо. В обычных случаях лучше использовать GetBuffer. <br />
<br />
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем.<br />
<br />
=== Как передать больше одного параметр в процедуру потока? ===<br />
<br />
Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру.<br />
Пример:<br />
<syntaxhighlight><br />
struct mystr<br />
{<br />
CEdit* pEd;<br />
CDialog* pDlg;<br />
DWORD* pdwd;<br />
int *pn;<br />
};<br />
</syntaxhighlight><br />
<br />
запуск потока: <br />
<br />
<syntaxhighlight><br />
mystr *pparam=new mystr;//экземпляр не должен быть временным!!!<br />
<br />
memset(pparam,0,sizeof(*pparam));<br />
pparam->pEd=...;<br />
pparam->pdwd=...;<br />
<br />
::AfxBeginThread(thread,pparam); <br />
//тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как<br />
//он у нас удалиля в процедуре потока<br />
</syntaxhighlight><br />
<br />
процедура потока: <br />
<syntaxhighlight><br />
//поток: <br />
UINT threadLoader(LPVOID pParam) <br />
{ <br />
//копируем данные из структуры в локальную структуру<br />
mystr data=*((mystr*)pParam);<br />
//освобождаем память временной структуры<br />
delete ((mystr*)pParam);<br />
pParam=0;<br />
<br />
<br />
...<br />
data.pDlg->...;<br />
(*data.pdwd)=...;<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как убрать главное меню из окна CMainFrame? ===<br />
Это можно сделать в виртуальной функции PreCreateWindow:<br />
<syntaxhighlight><br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
//обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow<br />
cs.hMenu = 0;<br />
<br />
if(!CFrameWnd::PreCreateWindow(cs))<br />
return FALSE;<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как работающая программа может определить, что пользователь завершает работу Windows? ===<br />
<br />
Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу.<br />
<br />
=== Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ===<br />
<br />
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify) :<br />
<syntaxhighlight><br />
class CMyDlg:puplic CDialog<br />
{<br />
CToolTipCtrl m_ToolTip;//мембер класса CMyDlg<br />
};<br />
<br />
//массив, в котором перечислены идентификаторы<br />
//контролов и тексты подсказок к ним<br />
struct{int ID;const char* pch;} m_a_Tips[]=<br />
{<br />
{IDC_BUTTON1,"Кнопка"},<br />
{IDC_STATIC1,"Текст"},<br />
//<br />
{0,0},//признак конца массива<br />
};<br />
<br />
//в инициализации диалога (хотя, в принципе,<br />
//можно и не тут) создаём и привязываем подсказки<br />
BOOL CMyDlg::OnInitDialog() <br />
{<br />
CDialog::OnInitDialog();<br />
<br />
//создаём элемент TOOLTIP<br />
m_ToolTip.Create(this);<br />
<br />
//Привязка подсказок<br />
for(int i=0; m_a_Tips[i].ID; i++)<br />
{<br />
m_ToolTip.AddTool(<br />
GetDlgItem(m_a_Tips[i].ID),<br />
m_a_Tips[i].pch<br />
);<br />
}<br />
<br />
//включаем показ подсказок<br />
m_ToolTip.Activate(1);<br />
...<br />
...<br />
}<br />
<br />
//для того, чтобы подсказки отображались как реакция на движение<br />
//курсора мыши, транслируем получаемые окнами сообщения в<br />
//виртуальной PreTranslateMessage()<br />
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) <br />
{<br />
//транслируем<br />
if(m_ToolTip.m_hWnd)m_ToolTip.RelayEvent(pMsg);<br />
<br />
return CDialog::PreTranslateMessage(pMsg);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как в отладчике Visual С++ просмотреть содержимое std::vector<string> ?===<br />
<br />
Это можно сделать так. К примеру, имеется<br />
<syntaxhighlight><br />
std::vector<string> V;<br />
</syntaxhighlight><br />
<br />
режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения: <br />
<br />
V._Myfirst (- будет показан первый элемент V)<br />
<br />
V._Myfirst+1 (- второй элемент V)<br />
<br />
и т.д.<br />
<br />
=== Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах? ===<br />
<br />
Для этого нужно использовать процедуру API: <br />
<syntaxhighlight><br />
BOOL GetTextExtentPoint32(<br />
HDC hdc,// хендл контекста<br />
LPCTSTR lpString,// выводимая строка<br />
int cbString,// длина строки в символах<br />
LPSIZE lpSize// указатель на структуру SIZE, куда <br />
//будут помещены размеры<br />
);<br />
</syntaxhighlight><br />
<br />
Функция вычисляет длину лишь одной символов, оканчивающейся нулём. Поэтому, чтобы вычислить "размер" многострочнокго текста, текст вначале необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_2&diff=600FAQ:WinAPI, VCPP Part 22008-10-08T17:16:44Z<p>Алексей1153++: /* Как в отладчике Visual С++ просмотреть содержимое std::vector ? */</p>
<hr />
<div><br />
<br />
=== Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу? ===<br />
<br />
Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand() :<br />
<syntaxhighlight><br />
BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam) <br />
{<br />
WORD wMess=(wParam>>16);//командное сообщение<br />
int nID=(int)(wParam &0x0000ffff));//ID контрола<br />
HWND hW=(HWND)lParam;//хендл контрола<br />
<br />
//смотрим, какой контрол<br />
switch(nID)<br />
{<br />
//кнопки<br />
case ID_BN1:<br />
case ID_BN2:<br />
case ID_BN3:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case BN_CLICKED:{ ... }break;<br />
}<br />
}<br />
break;<br />
<br />
//едиты<br />
case ID_ED1:<br />
case ID_ED2:<br />
case ID_ED3:<br />
case ID_ED4:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case EN_CHANGE:{ ... }break;<br />
case EN_KILLFOCUS:{ ... }break;<br />
}<br />
}<br />
break;<br />
}<br />
<br />
return CDialog::OnCommand(wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать? ===<br />
<br />
Лечится проблема так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются. <br />
<br />
=== Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы? ===<br />
<br />
Нужно использовать функцию GetModuleFileName(): <br />
<syntaxhighlight><br />
TCHAR pszFileName[MAX_PATH];<br />
pszFileName[0]=0;<br />
GetModuleFileName(NULL, pszFileName, MAX_PATH);<br />
CString stModulePath = pszFileName;<br />
//ищем первый слеш с конца и удаляем<br />
//его вместе с именем файла EXE<br />
int nEnd = stModulePath.ReverseFind('\\');<br />
stModulePath.Delete(nEnd, stModulePath.GetLength()-nEnd);<br />
<br />
//stModulePath - содержит путь<br />
</syntaxhighlight><br />
<br />
=== Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame? ===<br />
<br />
<syntaxhighlight><br />
#include "MainFrm.h"<br />
<br />
//CMyApp - класс вашего приложения. theApp - глобальная переменная,<br />
//поэтому для доступа к ней используем extern<br />
extern CMyApp theApp;<br />
<br />
void CMyView::F()<br />
{<br />
//Получаем главное окно приложения в любом месте программы<br />
CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);<br />
<br />
pMainFrame->m_wndDlgBar ....//Делаем что хотим<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как загрузить и показать один из стандартных курсоров? ===<br />
<br />
<syntaxhighlight><br />
HCURSOR hCursor;<br />
hCursor=AfxGetApp()->LoadStandardCursor(IDC_UPARROW);<br />
if(hCursor)SetCursor(hCursor);<br />
</syntaxhighlight><br />
идентификаторы стандартных курсоров:<br />
<br />
IDC_ARROW<br />
<br />
IDC_IBEAM<br />
<br />
IDC_WAIT<br />
<br />
IDC_CROSS<br />
<br />
IDC_UPARROW<br />
<br />
IDC_SIZENWSE<br />
<br />
IDC_SIZENESW<br />
<br />
IDC_SIZEWE<br />
<br />
IDC_SIZENS<br />
<br />
IDC_SIZEALL <br />
<br />
=== Как запретить пользователю закрыть программу нажатием на кнопку с крестиком? ===<br />
<br />
Для этого нужно добавить обработчик сообщения WM_CLOSE ( функция OnClose() в MFC) в главное окно программы. Для диалоговых приложений такое окно - это главный диалог, для одно- и много-документных приложений - это CMainFrame. <br />
<syntaxhighlight><br />
void CMainFrame::OnClose()<br />
{<br />
if(......)<br />
{<br />
//не разрешаем закрыть<br />
return;<br />
}<br />
<br />
CFrameWnd::OnClose();<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab? ===<br />
<br />
Последовательность действий следующая:<br />
<br />
1) кладём на форму нужное количество элементов RadioButton.<br />
<br />
2) у первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство.<br />
<br />
3) порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется.<br />
<br />
=== Где лучше устанавливать начальные значения элемента CComboBox? ===<br />
<br />
Это можно сделать парой способов:<br />
<br />
1) В редакторе форм - открыть свойства элемента CComboBox , "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter) <br />
<br />
2) В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView) <br />
<br />
=== Как перевести RichEdit в режим замены символов? ===<br />
<br />
Имеется несколько способов.<br />
<br />
1) Программно, если известен хендл элемента (hWnd), это делается так: <br />
<syntaxhighlight><br />
//помещаем в конец очереди сообющений контрола сообщение WM_KEYDOWN<br />
//с нужными параметрами<br />
::PostMessage(hWnd,WM_KEYDOWN,VK_INSERT,1);<br />
</syntaxhighlight><br />
<br />
2) Пользователь во время работы может нажать клавишу Insert.<br />
<br />
=== Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы? ===<br />
<br />
Это можно сделать так:<br />
<br />
<syntaxhighlight><br />
AfxGetApp()->m_pMainWnd-> ...; <br />
</syntaxhighlight><br />
<br />
или так<br />
<syntaxhighlight><br />
extern CMyAppXXX theApp;//здесь CMyAppXXX - название класса вашего приложения<br />
theApp.m_pMainWnd-> ...; <br />
</syntaxhighlight><br />
<br />
=== Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ? ===<br />
<br />
Это можно сделать методом SetScaleToFitSize():<br />
<syntaxhighlight><br />
void CMyView::OnInitialUpdate()<br />
{<br />
CFormView::OnInitialUpdate();<br />
<br />
//скрываем полосы прокрутки<br />
GetParentFrame()->RecalcLayout();<br />
ResizeParentToFit();//это уберёт полосы прокрутки со вьюхи<br />
SIZE s={0,0};<br />
SetScaleToFitSize(s);<br />
//далее вызовется обработчик OnPaint(), о котором ниже<br />
/////////<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
Также обратите внимание на одну особенность: в дебаг-версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s={0,0} происходит с ошибкой (программа при этом завершается).<br />
Обходится это так:<br />
<syntaxhighlight><br />
void CMyView::OnPaint() <br />
{<br />
#ifdef _DEBUG<br />
CPaintDC dc(this);<br />
#else<br />
CFormView::OnPaint();<br />
#endif<br />
}<br />
</syntaxhighlight><br />
<br />
или даже вообще так:<br />
<syntaxhighlight><br />
void CMyView::OnPaint() <br />
{<br />
CPaintDC dc(this);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как нарисовать прямоугольник с вертикальным цветовым градиентом? ===<br />
<br />
Нужно задасться граничными значениями цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников (а, значит, плавность гралдиента) задаётся точностью.<br />
Пример:<br />
<syntaxhighlight><br />
//вертикальный градиент<br />
//pdc - указатель на контекст устройства<br />
//pSize - указатель на структуру<br />
//SIZE с размером прямоугольника<br />
// dwdColor1, dwdColor2 - начальный и конечный цвет<br />
//bySteps - количество шагов градиента (1...255) <br />
void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps)<br />
{<br />
if(!bySteps)bySteps=1;<br />
WORD i;<br />
<br />
long W,H,x1,x2;<br />
BYTE R1,G1,B1,R2,G2,B2;<br />
float dh,dR,dG,dB,y1,y2,Rc,Gc,Bc;<br />
<br />
//ширина и высота<br />
W=pSize->cx;<br />
H=pSize->cy;<br />
<br />
//раскладываем цвета на их составляющие<br />
//для удобства дальнейших вычислений<br />
R1=(BYTE)((dwdColor1&0x000000ff));<br />
G1=(BYTE)((dwdColor1&0x0000ff00)>>8);<br />
B1=(BYTE)((dwdColor1&0x00ff0000)>>16);<br />
R2=(BYTE)((dwdColor2&0x000000ff));<br />
G2=(BYTE)((dwdColor2&0x0000ff00)>>8);<br />
B2=(BYTE)((dwdColor2&0x00ff0000)>>16);<br />
<br />
//высота разноцветных прямоугольников<br />
dh=((float)H)/((float)bySteps);<br />
//величина шагов составляющих цветов<br />
dR=(((float)R2)-((float)R1))/((float)bySteps);<br />
dG=(((float)G2)-((float)G1))/((float)bySteps);<br />
dB=(((float)B2)-((float)B1))/((float)bySteps);<br />
//выводим прямоугольники<br />
x1=0;x2=W;y1=0;y2=dh;<br />
Rc=R1;Gc=G1;Bc=B1;<br />
for(i=0;i<bySteps;i++)<br />
{<br />
//текущий цвет<br />
pdc->FillSolidRect(x1,(int)y1,x2-x1,(int)(y2-y1),RGB((BYTE)Rc,(BYTE)Gc,(BYTE)Bc));<br />
//следующий цвет и координаты<br />
y1+=dh;y2+=dh;<br />
Rc+=dR;Gc+=dG;Bc+=dB;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
пример вызова: <br />
<syntaxhighlight><br />
SIZE Size={100,100};<br />
sFillGradientRect(&dc,&Size, RGB(200,0,0), RGB(0,200,0),10);<br />
</syntaxhighlight><br />
<br />
=== Как под Windows отслеживать изменение файла? ===<br />
<br />
Нужно использовать функции: <br />
<br />
FindFirstChangeNotification<br />
<br />
FindNextChangeNotification<br />
<br />
FindCloseChangeNotification<br />
<br />
(подробности - в MSDN)<br />
<br />
=== Как конвертировать массив char[] в CString? ===<br />
Это можно сделать методами самого класса CString:<br />
<syntaxhighlight><br />
char buf[]="text";<br />
<br />
//строка должна обязательно заканчиваться нулём!!!<br />
<br />
//конвертируем так<br />
CString txt(buf);<br />
<br />
//или так<br />
CString txt;<br />
txt=buf;<br />
</syntaxhighlight><br />
<br />
=== Как зарезервировать в CString буфер нужной длины? ===<br />
<br />
Это можно сделать при помощи методов класса: <br />
<br />
<syntaxhighlight><br />
CString::GetBuffer(...)<br />
</syntaxhighlight><br />
и<br />
<syntaxhighlight><br />
CString::GetBufferSetLength(...)<br />
</syntaxhighlight><br />
<br />
Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку НЕ МЕНЬШЕ заданной длины, а второй возвращает строку точно равную заданной длине. Обе могут перераспределять память если надо. В обычных случаях лучше использовать GetBuffer. <br />
<br />
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем.<br />
<br />
=== Как передать больше одного параметр в процедуру потока? ===<br />
<br />
Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру.<br />
Пример:<br />
<syntaxhighlight><br />
struct mystr<br />
{<br />
CEdit* pEd;<br />
CDialog* pDlg;<br />
DWORD* pdwd;<br />
int *pn;<br />
};<br />
</syntaxhighlight><br />
<br />
запуск потока: <br />
<br />
<syntaxhighlight><br />
mystr *pparam=new mystr;//экземпляр не должен быть временным!!!<br />
<br />
memset(pparam,0,sizeof(*pparam));<br />
pparam->pEd=...;<br />
pparam->pdwd=...;<br />
<br />
::AfxBeginThread(thread,pparam); <br />
//тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как<br />
//он у нас удалиля в процедуре потока<br />
</syntaxhighlight><br />
<br />
процедура потока: <br />
<syntaxhighlight><br />
//поток: <br />
UINT threadLoader(LPVOID pParam) <br />
{ <br />
//копируем данные из структуры в локальную структуру<br />
mystr data=*((mystr*)pParam);<br />
//освобождаем память временной структуры<br />
delete ((mystr*)pParam);<br />
pParam=0;<br />
<br />
<br />
...<br />
data.pDlg->...;<br />
(*data.pdwd)=...;<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как убрать главное меню из окна CMainFrame? ===<br />
Это можно сделать в виртуальной функции PreCreateWindow:<br />
<syntaxhighlight><br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
//обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow<br />
cs.hMenu = 0;<br />
<br />
if(!CFrameWnd::PreCreateWindow(cs))<br />
return FALSE;<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как работающая программа может определить, что пользователь завершает работу Windows? ===<br />
<br />
Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу.<br />
<br />
=== Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ===<br />
<br />
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify) :<br />
<syntaxhighlight><br />
class CMyDlg:puplic CDialog<br />
{<br />
CToolTipCtrl m_ToolTip;//мембер класса CMyDlg<br />
};<br />
<br />
//массив, в котором перечислены идентификаторы<br />
//контролов и тексты подсказок к ним<br />
struct{int ID;const char* pch;} m_a_Tips[]=<br />
{<br />
{IDC_BUTTON1,"Кнопка"},<br />
{IDC_STATIC1,"Текст"},<br />
//<br />
{0,0},//признак конца массива<br />
};<br />
<br />
//в инициализации диалога (хотя, в принципе,<br />
//можно и не тут) создаём и привязываем подсказки<br />
BOOL CMyDlg::OnInitDialog() <br />
{<br />
CDialog::OnInitDialog();<br />
<br />
//создаём элемент TOOLTIP<br />
m_ToolTip.Create(this);<br />
<br />
//Привязка подсказок<br />
for(int i=0; m_a_Tips[i].ID; i++)<br />
{<br />
m_ToolTip.AddTool(<br />
GetDlgItem(m_a_Tips[i].ID),<br />
m_a_Tips[i].pch<br />
);<br />
}<br />
<br />
//включаем показ подсказок<br />
m_ToolTip.Activate(1);<br />
...<br />
...<br />
}<br />
<br />
//для того, чтобы подсказки отображались как реакция на движение<br />
//курсора мыши, транслируем получаемые окнами сообщения в<br />
//виртуальной PreTranslateMessage()<br />
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) <br />
{<br />
//транслируем<br />
if(m_ToolTip.m_hWnd)m_ToolTip.RelayEvent(pMsg);<br />
<br />
return CDialog::PreTranslateMessage(pMsg);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как в отладчике Visual С++ просмотреть содержимое std::vector<string> ?===<br />
<br />
Это можно сделать так. К примеру, имеется<br />
<syntaxhighlight><br />
std::vector<string> V;<br />
</syntaxhighlight><br />
<br />
режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения: <br />
<br />
V._Myfirst (- будет показан первый элемент V)<br />
<br />
V._Myfirst+1 (- второй элемент V,)<br />
<br />
и т.д.<br />
<br />
=== Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах? ===<br />
<br />
Для этого нужно использовать процедуру API: <br />
<syntaxhighlight><br />
BOOL GetTextExtentPoint32(<br />
HDC hdc,// хендл контекста<br />
LPCTSTR lpString,// выводимая строка<br />
int cbString,// длина строки в символах<br />
LPSIZE lpSize// указатель на структуру SIZE, куда <br />
//будут помещены размеры<br />
);<br />
</syntaxhighlight><br />
<br />
Функция вычисляет длину лишь одной символов, оканчивающейся нулём. Поэтому, чтобы вычислить "размер" многострочнокго текста, текст вначале необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_2&diff=599FAQ:WinAPI, VCPP Part 22008-10-08T17:16:19Z<p>Алексей1153++: /* Как зарезервировать в CString буфер нужной длины? */</p>
<hr />
<div><br />
<br />
=== Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу? ===<br />
<br />
Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand() :<br />
<syntaxhighlight><br />
BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam) <br />
{<br />
WORD wMess=(wParam>>16);//командное сообщение<br />
int nID=(int)(wParam &0x0000ffff));//ID контрола<br />
HWND hW=(HWND)lParam;//хендл контрола<br />
<br />
//смотрим, какой контрол<br />
switch(nID)<br />
{<br />
//кнопки<br />
case ID_BN1:<br />
case ID_BN2:<br />
case ID_BN3:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case BN_CLICKED:{ ... }break;<br />
}<br />
}<br />
break;<br />
<br />
//едиты<br />
case ID_ED1:<br />
case ID_ED2:<br />
case ID_ED3:<br />
case ID_ED4:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case EN_CHANGE:{ ... }break;<br />
case EN_KILLFOCUS:{ ... }break;<br />
}<br />
}<br />
break;<br />
}<br />
<br />
return CDialog::OnCommand(wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать? ===<br />
<br />
Лечится проблема так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются. <br />
<br />
=== Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы? ===<br />
<br />
Нужно использовать функцию GetModuleFileName(): <br />
<syntaxhighlight><br />
TCHAR pszFileName[MAX_PATH];<br />
pszFileName[0]=0;<br />
GetModuleFileName(NULL, pszFileName, MAX_PATH);<br />
CString stModulePath = pszFileName;<br />
//ищем первый слеш с конца и удаляем<br />
//его вместе с именем файла EXE<br />
int nEnd = stModulePath.ReverseFind('\\');<br />
stModulePath.Delete(nEnd, stModulePath.GetLength()-nEnd);<br />
<br />
//stModulePath - содержит путь<br />
</syntaxhighlight><br />
<br />
=== Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame? ===<br />
<br />
<syntaxhighlight><br />
#include "MainFrm.h"<br />
<br />
//CMyApp - класс вашего приложения. theApp - глобальная переменная,<br />
//поэтому для доступа к ней используем extern<br />
extern CMyApp theApp;<br />
<br />
void CMyView::F()<br />
{<br />
//Получаем главное окно приложения в любом месте программы<br />
CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);<br />
<br />
pMainFrame->m_wndDlgBar ....//Делаем что хотим<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как загрузить и показать один из стандартных курсоров? ===<br />
<br />
<syntaxhighlight><br />
HCURSOR hCursor;<br />
hCursor=AfxGetApp()->LoadStandardCursor(IDC_UPARROW);<br />
if(hCursor)SetCursor(hCursor);<br />
</syntaxhighlight><br />
идентификаторы стандартных курсоров:<br />
<br />
IDC_ARROW<br />
<br />
IDC_IBEAM<br />
<br />
IDC_WAIT<br />
<br />
IDC_CROSS<br />
<br />
IDC_UPARROW<br />
<br />
IDC_SIZENWSE<br />
<br />
IDC_SIZENESW<br />
<br />
IDC_SIZEWE<br />
<br />
IDC_SIZENS<br />
<br />
IDC_SIZEALL <br />
<br />
=== Как запретить пользователю закрыть программу нажатием на кнопку с крестиком? ===<br />
<br />
Для этого нужно добавить обработчик сообщения WM_CLOSE ( функция OnClose() в MFC) в главное окно программы. Для диалоговых приложений такое окно - это главный диалог, для одно- и много-документных приложений - это CMainFrame. <br />
<syntaxhighlight><br />
void CMainFrame::OnClose()<br />
{<br />
if(......)<br />
{<br />
//не разрешаем закрыть<br />
return;<br />
}<br />
<br />
CFrameWnd::OnClose();<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab? ===<br />
<br />
Последовательность действий следующая:<br />
<br />
1) кладём на форму нужное количество элементов RadioButton.<br />
<br />
2) у первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство.<br />
<br />
3) порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется.<br />
<br />
=== Где лучше устанавливать начальные значения элемента CComboBox? ===<br />
<br />
Это можно сделать парой способов:<br />
<br />
1) В редакторе форм - открыть свойства элемента CComboBox , "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter) <br />
<br />
2) В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView) <br />
<br />
=== Как перевести RichEdit в режим замены символов? ===<br />
<br />
Имеется несколько способов.<br />
<br />
1) Программно, если известен хендл элемента (hWnd), это делается так: <br />
<syntaxhighlight><br />
//помещаем в конец очереди сообющений контрола сообщение WM_KEYDOWN<br />
//с нужными параметрами<br />
::PostMessage(hWnd,WM_KEYDOWN,VK_INSERT,1);<br />
</syntaxhighlight><br />
<br />
2) Пользователь во время работы может нажать клавишу Insert.<br />
<br />
=== Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы? ===<br />
<br />
Это можно сделать так:<br />
<br />
<syntaxhighlight><br />
AfxGetApp()->m_pMainWnd-> ...; <br />
</syntaxhighlight><br />
<br />
или так<br />
<syntaxhighlight><br />
extern CMyAppXXX theApp;//здесь CMyAppXXX - название класса вашего приложения<br />
theApp.m_pMainWnd-> ...; <br />
</syntaxhighlight><br />
<br />
=== Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ? ===<br />
<br />
Это можно сделать методом SetScaleToFitSize():<br />
<syntaxhighlight><br />
void CMyView::OnInitialUpdate()<br />
{<br />
CFormView::OnInitialUpdate();<br />
<br />
//скрываем полосы прокрутки<br />
GetParentFrame()->RecalcLayout();<br />
ResizeParentToFit();//это уберёт полосы прокрутки со вьюхи<br />
SIZE s={0,0};<br />
SetScaleToFitSize(s);<br />
//далее вызовется обработчик OnPaint(), о котором ниже<br />
/////////<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
Также обратите внимание на одну особенность: в дебаг-версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s={0,0} происходит с ошибкой (программа при этом завершается).<br />
Обходится это так:<br />
<syntaxhighlight><br />
void CMyView::OnPaint() <br />
{<br />
#ifdef _DEBUG<br />
CPaintDC dc(this);<br />
#else<br />
CFormView::OnPaint();<br />
#endif<br />
}<br />
</syntaxhighlight><br />
<br />
или даже вообще так:<br />
<syntaxhighlight><br />
void CMyView::OnPaint() <br />
{<br />
CPaintDC dc(this);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как нарисовать прямоугольник с вертикальным цветовым градиентом? ===<br />
<br />
Нужно задасться граничными значениями цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников (а, значит, плавность гралдиента) задаётся точностью.<br />
Пример:<br />
<syntaxhighlight><br />
//вертикальный градиент<br />
//pdc - указатель на контекст устройства<br />
//pSize - указатель на структуру<br />
//SIZE с размером прямоугольника<br />
// dwdColor1, dwdColor2 - начальный и конечный цвет<br />
//bySteps - количество шагов градиента (1...255) <br />
void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps)<br />
{<br />
if(!bySteps)bySteps=1;<br />
WORD i;<br />
<br />
long W,H,x1,x2;<br />
BYTE R1,G1,B1,R2,G2,B2;<br />
float dh,dR,dG,dB,y1,y2,Rc,Gc,Bc;<br />
<br />
//ширина и высота<br />
W=pSize->cx;<br />
H=pSize->cy;<br />
<br />
//раскладываем цвета на их составляющие<br />
//для удобства дальнейших вычислений<br />
R1=(BYTE)((dwdColor1&0x000000ff));<br />
G1=(BYTE)((dwdColor1&0x0000ff00)>>8);<br />
B1=(BYTE)((dwdColor1&0x00ff0000)>>16);<br />
R2=(BYTE)((dwdColor2&0x000000ff));<br />
G2=(BYTE)((dwdColor2&0x0000ff00)>>8);<br />
B2=(BYTE)((dwdColor2&0x00ff0000)>>16);<br />
<br />
//высота разноцветных прямоугольников<br />
dh=((float)H)/((float)bySteps);<br />
//величина шагов составляющих цветов<br />
dR=(((float)R2)-((float)R1))/((float)bySteps);<br />
dG=(((float)G2)-((float)G1))/((float)bySteps);<br />
dB=(((float)B2)-((float)B1))/((float)bySteps);<br />
//выводим прямоугольники<br />
x1=0;x2=W;y1=0;y2=dh;<br />
Rc=R1;Gc=G1;Bc=B1;<br />
for(i=0;i<bySteps;i++)<br />
{<br />
//текущий цвет<br />
pdc->FillSolidRect(x1,(int)y1,x2-x1,(int)(y2-y1),RGB((BYTE)Rc,(BYTE)Gc,(BYTE)Bc));<br />
//следующий цвет и координаты<br />
y1+=dh;y2+=dh;<br />
Rc+=dR;Gc+=dG;Bc+=dB;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
пример вызова: <br />
<syntaxhighlight><br />
SIZE Size={100,100};<br />
sFillGradientRect(&dc,&Size, RGB(200,0,0), RGB(0,200,0),10);<br />
</syntaxhighlight><br />
<br />
=== Как под Windows отслеживать изменение файла? ===<br />
<br />
Нужно использовать функции: <br />
<br />
FindFirstChangeNotification<br />
<br />
FindNextChangeNotification<br />
<br />
FindCloseChangeNotification<br />
<br />
(подробности - в MSDN)<br />
<br />
=== Как конвертировать массив char[] в CString? ===<br />
Это можно сделать методами самого класса CString:<br />
<syntaxhighlight><br />
char buf[]="text";<br />
<br />
//строка должна обязательно заканчиваться нулём!!!<br />
<br />
//конвертируем так<br />
CString txt(buf);<br />
<br />
//или так<br />
CString txt;<br />
txt=buf;<br />
</syntaxhighlight><br />
<br />
=== Как зарезервировать в CString буфер нужной длины? ===<br />
<br />
Это можно сделать при помощи методов класса: <br />
<br />
<syntaxhighlight><br />
CString::GetBuffer(...)<br />
</syntaxhighlight><br />
и<br />
<syntaxhighlight><br />
CString::GetBufferSetLength(...)<br />
</syntaxhighlight><br />
<br />
Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку НЕ МЕНЬШЕ заданной длины, а второй возвращает строку точно равную заданной длине. Обе могут перераспределять память если надо. В обычных случаях лучше использовать GetBuffer. <br />
<br />
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем.<br />
<br />
=== Как передать больше одного параметр в процедуру потока? ===<br />
<br />
Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру.<br />
Пример:<br />
<syntaxhighlight><br />
struct mystr<br />
{<br />
CEdit* pEd;<br />
CDialog* pDlg;<br />
DWORD* pdwd;<br />
int *pn;<br />
};<br />
</syntaxhighlight><br />
<br />
запуск потока: <br />
<br />
<syntaxhighlight><br />
mystr *pparam=new mystr;//экземпляр не должен быть временным!!!<br />
<br />
memset(pparam,0,sizeof(*pparam));<br />
pparam->pEd=...;<br />
pparam->pdwd=...;<br />
<br />
::AfxBeginThread(thread,pparam); <br />
//тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как<br />
//он у нас удалиля в процедуре потока<br />
</syntaxhighlight><br />
<br />
процедура потока: <br />
<syntaxhighlight><br />
//поток: <br />
UINT threadLoader(LPVOID pParam) <br />
{ <br />
//копируем данные из структуры в локальную структуру<br />
mystr data=*((mystr*)pParam);<br />
//освобождаем память временной структуры<br />
delete ((mystr*)pParam);<br />
pParam=0;<br />
<br />
<br />
...<br />
data.pDlg->...;<br />
(*data.pdwd)=...;<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как убрать главное меню из окна CMainFrame? ===<br />
Это можно сделать в виртуальной функции PreCreateWindow:<br />
<syntaxhighlight><br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
//обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow<br />
cs.hMenu = 0;<br />
<br />
if(!CFrameWnd::PreCreateWindow(cs))<br />
return FALSE;<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как работающая программа может определить, что пользователь завершает работу Windows? ===<br />
<br />
Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу.<br />
<br />
=== Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ===<br />
<br />
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify) :<br />
<syntaxhighlight><br />
class CMyDlg:puplic CDialog<br />
{<br />
CToolTipCtrl m_ToolTip;//мембер класса CMyDlg<br />
};<br />
<br />
//массив, в котором перечислены идентификаторы<br />
//контролов и тексты подсказок к ним<br />
struct{int ID;const char* pch;} m_a_Tips[]=<br />
{<br />
{IDC_BUTTON1,"Кнопка"},<br />
{IDC_STATIC1,"Текст"},<br />
//<br />
{0,0},//признак конца массива<br />
};<br />
<br />
//в инициализации диалога (хотя, в принципе,<br />
//можно и не тут) создаём и привязываем подсказки<br />
BOOL CMyDlg::OnInitDialog() <br />
{<br />
CDialog::OnInitDialog();<br />
<br />
//создаём элемент TOOLTIP<br />
m_ToolTip.Create(this);<br />
<br />
//Привязка подсказок<br />
for(int i=0; m_a_Tips[i].ID; i++)<br />
{<br />
m_ToolTip.AddTool(<br />
GetDlgItem(m_a_Tips[i].ID),<br />
m_a_Tips[i].pch<br />
);<br />
}<br />
<br />
//включаем показ подсказок<br />
m_ToolTip.Activate(1);<br />
...<br />
...<br />
}<br />
<br />
//для того, чтобы подсказки отображались как реакция на движение<br />
//курсора мыши, транслируем получаемые окнами сообщения в<br />
//виртуальной PreTranslateMessage()<br />
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) <br />
{<br />
//транслируем<br />
if(m_ToolTip.m_hWnd)m_ToolTip.RelayEvent(pMsg);<br />
<br />
return CDialog::PreTranslateMessage(pMsg);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как в отладчике Visual С++ просмотреть содержимое std::vector<string> ?===<br />
<br />
Это можно сделать так. К примеру, имеется<br />
<syntaxhighlight><br />
std::vector<string> V;<br />
</syntaxhighlight><br />
<br />
режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения: <br />
<br />
V._Myfirst (- будет показан первый элемент V)<br />
V._Myfirst+1 (- второй элемент V,)<br />
<br />
и т.д. <br />
<br />
=== Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах? ===<br />
<br />
Для этого нужно использовать процедуру API: <br />
<syntaxhighlight><br />
BOOL GetTextExtentPoint32(<br />
HDC hdc,// хендл контекста<br />
LPCTSTR lpString,// выводимая строка<br />
int cbString,// длина строки в символах<br />
LPSIZE lpSize// указатель на структуру SIZE, куда <br />
//будут помещены размеры<br />
);<br />
</syntaxhighlight><br />
<br />
Функция вычисляет длину лишь одной символов, оканчивающейся нулём. Поэтому, чтобы вычислить "размер" многострочнокго текста, текст вначале необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_2&diff=598FAQ:WinAPI, VCPP Part 22008-10-08T17:16:08Z<p>Алексей1153++: /* Как под Windows отслеживать изменение файла? */</p>
<hr />
<div><br />
<br />
=== Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу? ===<br />
<br />
Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand() :<br />
<syntaxhighlight><br />
BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam) <br />
{<br />
WORD wMess=(wParam>>16);//командное сообщение<br />
int nID=(int)(wParam &0x0000ffff));//ID контрола<br />
HWND hW=(HWND)lParam;//хендл контрола<br />
<br />
//смотрим, какой контрол<br />
switch(nID)<br />
{<br />
//кнопки<br />
case ID_BN1:<br />
case ID_BN2:<br />
case ID_BN3:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case BN_CLICKED:{ ... }break;<br />
}<br />
}<br />
break;<br />
<br />
//едиты<br />
case ID_ED1:<br />
case ID_ED2:<br />
case ID_ED3:<br />
case ID_ED4:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case EN_CHANGE:{ ... }break;<br />
case EN_KILLFOCUS:{ ... }break;<br />
}<br />
}<br />
break;<br />
}<br />
<br />
return CDialog::OnCommand(wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать? ===<br />
<br />
Лечится проблема так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются. <br />
<br />
=== Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы? ===<br />
<br />
Нужно использовать функцию GetModuleFileName(): <br />
<syntaxhighlight><br />
TCHAR pszFileName[MAX_PATH];<br />
pszFileName[0]=0;<br />
GetModuleFileName(NULL, pszFileName, MAX_PATH);<br />
CString stModulePath = pszFileName;<br />
//ищем первый слеш с конца и удаляем<br />
//его вместе с именем файла EXE<br />
int nEnd = stModulePath.ReverseFind('\\');<br />
stModulePath.Delete(nEnd, stModulePath.GetLength()-nEnd);<br />
<br />
//stModulePath - содержит путь<br />
</syntaxhighlight><br />
<br />
=== Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame? ===<br />
<br />
<syntaxhighlight><br />
#include "MainFrm.h"<br />
<br />
//CMyApp - класс вашего приложения. theApp - глобальная переменная,<br />
//поэтому для доступа к ней используем extern<br />
extern CMyApp theApp;<br />
<br />
void CMyView::F()<br />
{<br />
//Получаем главное окно приложения в любом месте программы<br />
CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);<br />
<br />
pMainFrame->m_wndDlgBar ....//Делаем что хотим<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как загрузить и показать один из стандартных курсоров? ===<br />
<br />
<syntaxhighlight><br />
HCURSOR hCursor;<br />
hCursor=AfxGetApp()->LoadStandardCursor(IDC_UPARROW);<br />
if(hCursor)SetCursor(hCursor);<br />
</syntaxhighlight><br />
идентификаторы стандартных курсоров:<br />
<br />
IDC_ARROW<br />
<br />
IDC_IBEAM<br />
<br />
IDC_WAIT<br />
<br />
IDC_CROSS<br />
<br />
IDC_UPARROW<br />
<br />
IDC_SIZENWSE<br />
<br />
IDC_SIZENESW<br />
<br />
IDC_SIZEWE<br />
<br />
IDC_SIZENS<br />
<br />
IDC_SIZEALL <br />
<br />
=== Как запретить пользователю закрыть программу нажатием на кнопку с крестиком? ===<br />
<br />
Для этого нужно добавить обработчик сообщения WM_CLOSE ( функция OnClose() в MFC) в главное окно программы. Для диалоговых приложений такое окно - это главный диалог, для одно- и много-документных приложений - это CMainFrame. <br />
<syntaxhighlight><br />
void CMainFrame::OnClose()<br />
{<br />
if(......)<br />
{<br />
//не разрешаем закрыть<br />
return;<br />
}<br />
<br />
CFrameWnd::OnClose();<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab? ===<br />
<br />
Последовательность действий следующая:<br />
<br />
1) кладём на форму нужное количество элементов RadioButton.<br />
<br />
2) у первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство.<br />
<br />
3) порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется.<br />
<br />
=== Где лучше устанавливать начальные значения элемента CComboBox? ===<br />
<br />
Это можно сделать парой способов:<br />
<br />
1) В редакторе форм - открыть свойства элемента CComboBox , "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter) <br />
<br />
2) В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView) <br />
<br />
=== Как перевести RichEdit в режим замены символов? ===<br />
<br />
Имеется несколько способов.<br />
<br />
1) Программно, если известен хендл элемента (hWnd), это делается так: <br />
<syntaxhighlight><br />
//помещаем в конец очереди сообющений контрола сообщение WM_KEYDOWN<br />
//с нужными параметрами<br />
::PostMessage(hWnd,WM_KEYDOWN,VK_INSERT,1);<br />
</syntaxhighlight><br />
<br />
2) Пользователь во время работы может нажать клавишу Insert.<br />
<br />
=== Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы? ===<br />
<br />
Это можно сделать так:<br />
<br />
<syntaxhighlight><br />
AfxGetApp()->m_pMainWnd-> ...; <br />
</syntaxhighlight><br />
<br />
или так<br />
<syntaxhighlight><br />
extern CMyAppXXX theApp;//здесь CMyAppXXX - название класса вашего приложения<br />
theApp.m_pMainWnd-> ...; <br />
</syntaxhighlight><br />
<br />
=== Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ? ===<br />
<br />
Это можно сделать методом SetScaleToFitSize():<br />
<syntaxhighlight><br />
void CMyView::OnInitialUpdate()<br />
{<br />
CFormView::OnInitialUpdate();<br />
<br />
//скрываем полосы прокрутки<br />
GetParentFrame()->RecalcLayout();<br />
ResizeParentToFit();//это уберёт полосы прокрутки со вьюхи<br />
SIZE s={0,0};<br />
SetScaleToFitSize(s);<br />
//далее вызовется обработчик OnPaint(), о котором ниже<br />
/////////<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
Также обратите внимание на одну особенность: в дебаг-версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s={0,0} происходит с ошибкой (программа при этом завершается).<br />
Обходится это так:<br />
<syntaxhighlight><br />
void CMyView::OnPaint() <br />
{<br />
#ifdef _DEBUG<br />
CPaintDC dc(this);<br />
#else<br />
CFormView::OnPaint();<br />
#endif<br />
}<br />
</syntaxhighlight><br />
<br />
или даже вообще так:<br />
<syntaxhighlight><br />
void CMyView::OnPaint() <br />
{<br />
CPaintDC dc(this);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как нарисовать прямоугольник с вертикальным цветовым градиентом? ===<br />
<br />
Нужно задасться граничными значениями цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников (а, значит, плавность гралдиента) задаётся точностью.<br />
Пример:<br />
<syntaxhighlight><br />
//вертикальный градиент<br />
//pdc - указатель на контекст устройства<br />
//pSize - указатель на структуру<br />
//SIZE с размером прямоугольника<br />
// dwdColor1, dwdColor2 - начальный и конечный цвет<br />
//bySteps - количество шагов градиента (1...255) <br />
void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps)<br />
{<br />
if(!bySteps)bySteps=1;<br />
WORD i;<br />
<br />
long W,H,x1,x2;<br />
BYTE R1,G1,B1,R2,G2,B2;<br />
float dh,dR,dG,dB,y1,y2,Rc,Gc,Bc;<br />
<br />
//ширина и высота<br />
W=pSize->cx;<br />
H=pSize->cy;<br />
<br />
//раскладываем цвета на их составляющие<br />
//для удобства дальнейших вычислений<br />
R1=(BYTE)((dwdColor1&0x000000ff));<br />
G1=(BYTE)((dwdColor1&0x0000ff00)>>8);<br />
B1=(BYTE)((dwdColor1&0x00ff0000)>>16);<br />
R2=(BYTE)((dwdColor2&0x000000ff));<br />
G2=(BYTE)((dwdColor2&0x0000ff00)>>8);<br />
B2=(BYTE)((dwdColor2&0x00ff0000)>>16);<br />
<br />
//высота разноцветных прямоугольников<br />
dh=((float)H)/((float)bySteps);<br />
//величина шагов составляющих цветов<br />
dR=(((float)R2)-((float)R1))/((float)bySteps);<br />
dG=(((float)G2)-((float)G1))/((float)bySteps);<br />
dB=(((float)B2)-((float)B1))/((float)bySteps);<br />
//выводим прямоугольники<br />
x1=0;x2=W;y1=0;y2=dh;<br />
Rc=R1;Gc=G1;Bc=B1;<br />
for(i=0;i<bySteps;i++)<br />
{<br />
//текущий цвет<br />
pdc->FillSolidRect(x1,(int)y1,x2-x1,(int)(y2-y1),RGB((BYTE)Rc,(BYTE)Gc,(BYTE)Bc));<br />
//следующий цвет и координаты<br />
y1+=dh;y2+=dh;<br />
Rc+=dR;Gc+=dG;Bc+=dB;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
пример вызова: <br />
<syntaxhighlight><br />
SIZE Size={100,100};<br />
sFillGradientRect(&dc,&Size, RGB(200,0,0), RGB(0,200,0),10);<br />
</syntaxhighlight><br />
<br />
=== Как под Windows отслеживать изменение файла? ===<br />
<br />
Нужно использовать функции: <br />
<br />
FindFirstChangeNotification<br />
<br />
FindNextChangeNotification<br />
<br />
FindCloseChangeNotification<br />
<br />
(подробности - в MSDN)<br />
<br />
=== Как конвертировать массив char[] в CString? ===<br />
Это можно сделать методами самого класса CString:<br />
<syntaxhighlight><br />
char buf[]="text";<br />
<br />
//строка должна обязательно заканчиваться нулём!!!<br />
<br />
//конвертируем так<br />
CString txt(buf);<br />
<br />
//или так<br />
CString txt;<br />
txt=buf;<br />
</syntaxhighlight><br />
<br />
=== Как зарезервировать в CString буфер нужной длины? ===<br />
<br />
Это можно сделать при помощи методов класса: <br />
<br />
<syntaxhighlight><br />
CString::GetBuffer(...)<br />
</syntaxhighlight><br />
и<br />
<syntaxhighlight><br />
CString::GetBufferSetLength(...)<br />
</syntaxhighlight><br />
<br />
Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку НЕ МЕНЬШЕ заданной длины, а второй возвращает строку точно равную заданной длине. Обе могут перераспределять память если надо. В обычных случаях лучше использовать GetBuffer. <br />
<br />
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем. <br />
<br />
=== Как передать больше одного параметр в процедуру потока? ===<br />
<br />
Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру.<br />
Пример:<br />
<syntaxhighlight><br />
struct mystr<br />
{<br />
CEdit* pEd;<br />
CDialog* pDlg;<br />
DWORD* pdwd;<br />
int *pn;<br />
};<br />
</syntaxhighlight><br />
<br />
запуск потока: <br />
<br />
<syntaxhighlight><br />
mystr *pparam=new mystr;//экземпляр не должен быть временным!!!<br />
<br />
memset(pparam,0,sizeof(*pparam));<br />
pparam->pEd=...;<br />
pparam->pdwd=...;<br />
<br />
::AfxBeginThread(thread,pparam); <br />
//тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как<br />
//он у нас удалиля в процедуре потока<br />
</syntaxhighlight><br />
<br />
процедура потока: <br />
<syntaxhighlight><br />
//поток: <br />
UINT threadLoader(LPVOID pParam) <br />
{ <br />
//копируем данные из структуры в локальную структуру<br />
mystr data=*((mystr*)pParam);<br />
//освобождаем память временной структуры<br />
delete ((mystr*)pParam);<br />
pParam=0;<br />
<br />
<br />
...<br />
data.pDlg->...;<br />
(*data.pdwd)=...;<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как убрать главное меню из окна CMainFrame? ===<br />
Это можно сделать в виртуальной функции PreCreateWindow:<br />
<syntaxhighlight><br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
//обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow<br />
cs.hMenu = 0;<br />
<br />
if(!CFrameWnd::PreCreateWindow(cs))<br />
return FALSE;<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как работающая программа может определить, что пользователь завершает работу Windows? ===<br />
<br />
Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу.<br />
<br />
=== Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ===<br />
<br />
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify) :<br />
<syntaxhighlight><br />
class CMyDlg:puplic CDialog<br />
{<br />
CToolTipCtrl m_ToolTip;//мембер класса CMyDlg<br />
};<br />
<br />
//массив, в котором перечислены идентификаторы<br />
//контролов и тексты подсказок к ним<br />
struct{int ID;const char* pch;} m_a_Tips[]=<br />
{<br />
{IDC_BUTTON1,"Кнопка"},<br />
{IDC_STATIC1,"Текст"},<br />
//<br />
{0,0},//признак конца массива<br />
};<br />
<br />
//в инициализации диалога (хотя, в принципе,<br />
//можно и не тут) создаём и привязываем подсказки<br />
BOOL CMyDlg::OnInitDialog() <br />
{<br />
CDialog::OnInitDialog();<br />
<br />
//создаём элемент TOOLTIP<br />
m_ToolTip.Create(this);<br />
<br />
//Привязка подсказок<br />
for(int i=0; m_a_Tips[i].ID; i++)<br />
{<br />
m_ToolTip.AddTool(<br />
GetDlgItem(m_a_Tips[i].ID),<br />
m_a_Tips[i].pch<br />
);<br />
}<br />
<br />
//включаем показ подсказок<br />
m_ToolTip.Activate(1);<br />
...<br />
...<br />
}<br />
<br />
//для того, чтобы подсказки отображались как реакция на движение<br />
//курсора мыши, транслируем получаемые окнами сообщения в<br />
//виртуальной PreTranslateMessage()<br />
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) <br />
{<br />
//транслируем<br />
if(m_ToolTip.m_hWnd)m_ToolTip.RelayEvent(pMsg);<br />
<br />
return CDialog::PreTranslateMessage(pMsg);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как в отладчике Visual С++ просмотреть содержимое std::vector<string> ?===<br />
<br />
Это можно сделать так. К примеру, имеется<br />
<syntaxhighlight><br />
std::vector<string> V;<br />
</syntaxhighlight><br />
<br />
режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения: <br />
<br />
V._Myfirst (- будет показан первый элемент V)<br />
V._Myfirst+1 (- второй элемент V,)<br />
<br />
и т.д. <br />
<br />
=== Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах? ===<br />
<br />
Для этого нужно использовать процедуру API: <br />
<syntaxhighlight><br />
BOOL GetTextExtentPoint32(<br />
HDC hdc,// хендл контекста<br />
LPCTSTR lpString,// выводимая строка<br />
int cbString,// длина строки в символах<br />
LPSIZE lpSize// указатель на структуру SIZE, куда <br />
//будут помещены размеры<br />
);<br />
</syntaxhighlight><br />
<br />
Функция вычисляет длину лишь одной символов, оканчивающейся нулём. Поэтому, чтобы вычислить "размер" многострочнокго текста, текст вначале необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_2&diff=597FAQ:WinAPI, VCPP Part 22008-10-08T17:15:31Z<p>Алексей1153++: </p>
<hr />
<div><br />
<br />
=== Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу? ===<br />
<br />
Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand() :<br />
<syntaxhighlight><br />
BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam) <br />
{<br />
WORD wMess=(wParam>>16);//командное сообщение<br />
int nID=(int)(wParam &0x0000ffff));//ID контрола<br />
HWND hW=(HWND)lParam;//хендл контрола<br />
<br />
//смотрим, какой контрол<br />
switch(nID)<br />
{<br />
//кнопки<br />
case ID_BN1:<br />
case ID_BN2:<br />
case ID_BN3:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case BN_CLICKED:{ ... }break;<br />
}<br />
}<br />
break;<br />
<br />
//едиты<br />
case ID_ED1:<br />
case ID_ED2:<br />
case ID_ED3:<br />
case ID_ED4:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case EN_CHANGE:{ ... }break;<br />
case EN_KILLFOCUS:{ ... }break;<br />
}<br />
}<br />
break;<br />
}<br />
<br />
return CDialog::OnCommand(wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать? ===<br />
<br />
Лечится проблема так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются. <br />
<br />
=== Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы? ===<br />
<br />
Нужно использовать функцию GetModuleFileName(): <br />
<syntaxhighlight><br />
TCHAR pszFileName[MAX_PATH];<br />
pszFileName[0]=0;<br />
GetModuleFileName(NULL, pszFileName, MAX_PATH);<br />
CString stModulePath = pszFileName;<br />
//ищем первый слеш с конца и удаляем<br />
//его вместе с именем файла EXE<br />
int nEnd = stModulePath.ReverseFind('\\');<br />
stModulePath.Delete(nEnd, stModulePath.GetLength()-nEnd);<br />
<br />
//stModulePath - содержит путь<br />
</syntaxhighlight><br />
<br />
=== Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame? ===<br />
<br />
<syntaxhighlight><br />
#include "MainFrm.h"<br />
<br />
//CMyApp - класс вашего приложения. theApp - глобальная переменная,<br />
//поэтому для доступа к ней используем extern<br />
extern CMyApp theApp;<br />
<br />
void CMyView::F()<br />
{<br />
//Получаем главное окно приложения в любом месте программы<br />
CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);<br />
<br />
pMainFrame->m_wndDlgBar ....//Делаем что хотим<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как загрузить и показать один из стандартных курсоров? ===<br />
<br />
<syntaxhighlight><br />
HCURSOR hCursor;<br />
hCursor=AfxGetApp()->LoadStandardCursor(IDC_UPARROW);<br />
if(hCursor)SetCursor(hCursor);<br />
</syntaxhighlight><br />
идентификаторы стандартных курсоров:<br />
<br />
IDC_ARROW<br />
<br />
IDC_IBEAM<br />
<br />
IDC_WAIT<br />
<br />
IDC_CROSS<br />
<br />
IDC_UPARROW<br />
<br />
IDC_SIZENWSE<br />
<br />
IDC_SIZENESW<br />
<br />
IDC_SIZEWE<br />
<br />
IDC_SIZENS<br />
<br />
IDC_SIZEALL <br />
<br />
=== Как запретить пользователю закрыть программу нажатием на кнопку с крестиком? ===<br />
<br />
Для этого нужно добавить обработчик сообщения WM_CLOSE ( функция OnClose() в MFC) в главное окно программы. Для диалоговых приложений такое окно - это главный диалог, для одно- и много-документных приложений - это CMainFrame. <br />
<syntaxhighlight><br />
void CMainFrame::OnClose()<br />
{<br />
if(......)<br />
{<br />
//не разрешаем закрыть<br />
return;<br />
}<br />
<br />
CFrameWnd::OnClose();<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab? ===<br />
<br />
Последовательность действий следующая:<br />
<br />
1) кладём на форму нужное количество элементов RadioButton.<br />
<br />
2) у первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство.<br />
<br />
3) порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется.<br />
<br />
=== Где лучше устанавливать начальные значения элемента CComboBox? ===<br />
<br />
Это можно сделать парой способов:<br />
<br />
1) В редакторе форм - открыть свойства элемента CComboBox , "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter) <br />
<br />
2) В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView) <br />
<br />
=== Как перевести RichEdit в режим замены символов? ===<br />
<br />
Имеется несколько способов.<br />
<br />
1) Программно, если известен хендл элемента (hWnd), это делается так: <br />
<syntaxhighlight><br />
//помещаем в конец очереди сообющений контрола сообщение WM_KEYDOWN<br />
//с нужными параметрами<br />
::PostMessage(hWnd,WM_KEYDOWN,VK_INSERT,1);<br />
</syntaxhighlight><br />
<br />
2) Пользователь во время работы может нажать клавишу Insert.<br />
<br />
=== Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы? ===<br />
<br />
Это можно сделать так:<br />
<br />
<syntaxhighlight><br />
AfxGetApp()->m_pMainWnd-> ...; <br />
</syntaxhighlight><br />
<br />
или так<br />
<syntaxhighlight><br />
extern CMyAppXXX theApp;//здесь CMyAppXXX - название класса вашего приложения<br />
theApp.m_pMainWnd-> ...; <br />
</syntaxhighlight><br />
<br />
=== Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ? ===<br />
<br />
Это можно сделать методом SetScaleToFitSize():<br />
<syntaxhighlight><br />
void CMyView::OnInitialUpdate()<br />
{<br />
CFormView::OnInitialUpdate();<br />
<br />
//скрываем полосы прокрутки<br />
GetParentFrame()->RecalcLayout();<br />
ResizeParentToFit();//это уберёт полосы прокрутки со вьюхи<br />
SIZE s={0,0};<br />
SetScaleToFitSize(s);<br />
//далее вызовется обработчик OnPaint(), о котором ниже<br />
/////////<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
Также обратите внимание на одну особенность: в дебаг-версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s={0,0} происходит с ошибкой (программа при этом завершается).<br />
Обходится это так:<br />
<syntaxhighlight><br />
void CMyView::OnPaint() <br />
{<br />
#ifdef _DEBUG<br />
CPaintDC dc(this);<br />
#else<br />
CFormView::OnPaint();<br />
#endif<br />
}<br />
</syntaxhighlight><br />
<br />
или даже вообще так:<br />
<syntaxhighlight><br />
void CMyView::OnPaint() <br />
{<br />
CPaintDC dc(this);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как нарисовать прямоугольник с вертикальным цветовым градиентом? ===<br />
<br />
Нужно задасться граничными значениями цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников (а, значит, плавность гралдиента) задаётся точностью.<br />
Пример:<br />
<syntaxhighlight><br />
//вертикальный градиент<br />
//pdc - указатель на контекст устройства<br />
//pSize - указатель на структуру<br />
//SIZE с размером прямоугольника<br />
// dwdColor1, dwdColor2 - начальный и конечный цвет<br />
//bySteps - количество шагов градиента (1...255) <br />
void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps)<br />
{<br />
if(!bySteps)bySteps=1;<br />
WORD i;<br />
<br />
long W,H,x1,x2;<br />
BYTE R1,G1,B1,R2,G2,B2;<br />
float dh,dR,dG,dB,y1,y2,Rc,Gc,Bc;<br />
<br />
//ширина и высота<br />
W=pSize->cx;<br />
H=pSize->cy;<br />
<br />
//раскладываем цвета на их составляющие<br />
//для удобства дальнейших вычислений<br />
R1=(BYTE)((dwdColor1&0x000000ff));<br />
G1=(BYTE)((dwdColor1&0x0000ff00)>>8);<br />
B1=(BYTE)((dwdColor1&0x00ff0000)>>16);<br />
R2=(BYTE)((dwdColor2&0x000000ff));<br />
G2=(BYTE)((dwdColor2&0x0000ff00)>>8);<br />
B2=(BYTE)((dwdColor2&0x00ff0000)>>16);<br />
<br />
//высота разноцветных прямоугольников<br />
dh=((float)H)/((float)bySteps);<br />
//величина шагов составляющих цветов<br />
dR=(((float)R2)-((float)R1))/((float)bySteps);<br />
dG=(((float)G2)-((float)G1))/((float)bySteps);<br />
dB=(((float)B2)-((float)B1))/((float)bySteps);<br />
//выводим прямоугольники<br />
x1=0;x2=W;y1=0;y2=dh;<br />
Rc=R1;Gc=G1;Bc=B1;<br />
for(i=0;i<bySteps;i++)<br />
{<br />
//текущий цвет<br />
pdc->FillSolidRect(x1,(int)y1,x2-x1,(int)(y2-y1),RGB((BYTE)Rc,(BYTE)Gc,(BYTE)Bc));<br />
//следующий цвет и координаты<br />
y1+=dh;y2+=dh;<br />
Rc+=dR;Gc+=dG;Bc+=dB;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
пример вызова: <br />
<syntaxhighlight><br />
SIZE Size={100,100};<br />
sFillGradientRect(&dc,&Size, RGB(200,0,0), RGB(0,200,0),10);<br />
</syntaxhighlight><br />
<br />
=== Как под Windows отслеживать изменение файла? ===<br />
<br />
Нужно использовать функции: <br />
<br />
FindFirstChangeNotification<br />
<br />
FindNextChangeNotification<br />
<br />
FindCloseChangeNotification<br />
<br />
(подробности - в MSDN)<br />
<br />
=== Как конвертировать массив char[] в CString? ===<br />
Это можно сделать методами самого класса CString:<br />
<syntaxhighlight><br />
char buf[]="text";<br />
<br />
//строка должна обязательно заканчиваться нулём!!!<br />
<br />
//конвертируем так<br />
CString txt(buf);<br />
<br />
//или так<br />
CString txt;<br />
txt=buf;<br />
</syntaxhighlight><br />
<br />
=== Как зарезервировать в CString буфер нужной длины? ===<br />
<br />
Это можно сделать при помощи методов класса: <br />
<br />
<syntaxhighlight><br />
CString::GetBuffer(...)<br />
</syntaxhighlight><br />
и<br />
<syntaxhighlight><br />
CString::GetBufferSetLength(...)<br />
</syntaxhighlight><br />
<br />
Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку НЕ МЕНЬШЕ заданной длины, а второй возвращает строку точно равную заданной длине. Обе могут перераспределять память если надо. В обычных случаях лучше использовать GetBuffer. <br />
<br />
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем. <br />
<br />
=== Как передать больше одного параметр в процедуру потока? ===<br />
<br />
Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру.<br />
Пример:<br />
<syntaxhighlight><br />
struct mystr<br />
{<br />
CEdit* pEd;<br />
CDialog* pDlg;<br />
DWORD* pdwd;<br />
int *pn;<br />
};<br />
</syntaxhighlight><br />
<br />
запуск потока: <br />
<br />
<syntaxhighlight><br />
mystr *pparam=new mystr;//экземпляр не должен быть временным!!!<br />
<br />
memset(pparam,0,sizeof(*pparam));<br />
pparam->pEd=...;<br />
pparam->pdwd=...;<br />
<br />
::AfxBeginThread(thread,pparam); <br />
//тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как<br />
//он у нас удалиля в процедуре потока<br />
</syntaxhighlight><br />
<br />
процедура потока: <br />
<syntaxhighlight><br />
//поток: <br />
UINT threadLoader(LPVOID pParam) <br />
{ <br />
//копируем данные из структуры в локальную структуру<br />
mystr data=*((mystr*)pParam);<br />
//освобождаем память временной структуры<br />
delete ((mystr*)pParam);<br />
pParam=0;<br />
<br />
<br />
...<br />
data.pDlg->...;<br />
(*data.pdwd)=...;<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как убрать главное меню из окна CMainFrame? ===<br />
Это можно сделать в виртуальной функции PreCreateWindow:<br />
<syntaxhighlight><br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
//обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow<br />
cs.hMenu = 0;<br />
<br />
if(!CFrameWnd::PreCreateWindow(cs))<br />
return FALSE;<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как работающая программа может определить, что пользователь завершает работу Windows? ===<br />
<br />
Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу.<br />
<br />
=== Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ===<br />
<br />
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify) :<br />
<syntaxhighlight><br />
class CMyDlg:puplic CDialog<br />
{<br />
CToolTipCtrl m_ToolTip;//мембер класса CMyDlg<br />
};<br />
<br />
//массив, в котором перечислены идентификаторы<br />
//контролов и тексты подсказок к ним<br />
struct{int ID;const char* pch;} m_a_Tips[]=<br />
{<br />
{IDC_BUTTON1,"Кнопка"},<br />
{IDC_STATIC1,"Текст"},<br />
//<br />
{0,0},//признак конца массива<br />
};<br />
<br />
//в инициализации диалога (хотя, в принципе,<br />
//можно и не тут) создаём и привязываем подсказки<br />
BOOL CMyDlg::OnInitDialog() <br />
{<br />
CDialog::OnInitDialog();<br />
<br />
//создаём элемент TOOLTIP<br />
m_ToolTip.Create(this);<br />
<br />
//Привязка подсказок<br />
for(int i=0; m_a_Tips[i].ID; i++)<br />
{<br />
m_ToolTip.AddTool(<br />
GetDlgItem(m_a_Tips[i].ID),<br />
m_a_Tips[i].pch<br />
);<br />
}<br />
<br />
//включаем показ подсказок<br />
m_ToolTip.Activate(1);<br />
...<br />
...<br />
}<br />
<br />
//для того, чтобы подсказки отображались как реакция на движение<br />
//курсора мыши, транслируем получаемые окнами сообщения в<br />
//виртуальной PreTranslateMessage()<br />
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) <br />
{<br />
//транслируем<br />
if(m_ToolTip.m_hWnd)m_ToolTip.RelayEvent(pMsg);<br />
<br />
return CDialog::PreTranslateMessage(pMsg);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как в отладчике Visual С++ просмотреть содержимое std::vector<string> ?===<br />
<br />
Это можно сделать так. К примеру, имеется<br />
<syntaxhighlight><br />
std::vector<string> V;<br />
</syntaxhighlight><br />
<br />
режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения: <br />
<br />
V._Myfirst (- будет показан первый элемент V)<br />
V._Myfirst+1 (- второй элемент V,)<br />
<br />
и т.д. <br />
<br />
=== Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах? ===<br />
<br />
Для этого нужно использовать процедуру API: <br />
<syntaxhighlight><br />
BOOL GetTextExtentPoint32(<br />
HDC hdc,// хендл контекста<br />
LPCTSTR lpString,// выводимая строка<br />
int cbString,// длина строки в символах<br />
LPSIZE lpSize// указатель на структуру SIZE, куда <br />
//будут помещены размеры<br />
);<br />
</syntaxhighlight><br />
<br />
Функция вычисляет длину лишь одной символов, оканчивающейся нулём. Поэтому, чтобы вычислить "размер" многострочнокго текста, текст вначале необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_2&diff=596FAQ:WinAPI, VCPP Part 22008-10-08T17:11:05Z<p>Алексей1153++: </p>
<hr />
<div><br />
<br />
<br />
=== Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу? ===<br />
<br />
Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand() :<br />
<syntaxhighlight><br />
BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam) <br />
{<br />
WORD wMess=(wParam>>16);//командное сообщение<br />
int nID=(int)(wParam &0x0000ffff));//ID контрола<br />
HWND hW=(HWND)lParam;//хендл контрола<br />
<br />
//смотрим, какой контрол<br />
switch(nID)<br />
{<br />
//кнопки<br />
case ID_BN1:<br />
case ID_BN2:<br />
case ID_BN3:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case BN_CLICKED:{ ... }break;<br />
}<br />
}<br />
break;<br />
<br />
//едиты<br />
case ID_ED1:<br />
case ID_ED2:<br />
case ID_ED3:<br />
case ID_ED4:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case EN_CHANGE:{ ... }break;<br />
case EN_KILLFOCUS:{ ... }break;<br />
}<br />
}<br />
break;<br />
}<br />
<br />
return CDialog::OnCommand(wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать? ===<br />
<br />
Лечится проблема так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются. <br />
<br />
=== Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы? ===<br />
<br />
Нужно использовать функцию GetModuleFileName(): <br />
<syntaxhighlight><br />
TCHAR pszFileName[MAX_PATH];<br />
pszFileName[0]=0;<br />
GetModuleFileName(NULL, pszFileName, MAX_PATH);<br />
CString stModulePath = pszFileName;<br />
//ищем первый слеш с конца и удаляем<br />
//его вместе с именем файла EXE<br />
int nEnd = stModulePath.ReverseFind('\\');<br />
stModulePath.Delete(nEnd, stModulePath.GetLength()-nEnd);<br />
<br />
//stModulePath - содержит путь<br />
</syntaxhighlight><br />
<br />
=== Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame? ===<br />
<br />
<syntaxhighlight><br />
#include "MainFrm.h"<br />
<br />
//CMyApp - класс вашего приложения. theApp - глобальная переменная,<br />
//поэтому для доступа к ней используем extern<br />
extern CMyApp theApp;<br />
<br />
void CMyView::F()<br />
{<br />
//Получаем главное окно приложения в любом месте программы<br />
CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);<br />
<br />
pMainFrame->m_wndDlgBar ....//Делаем что хотим<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как загрузить и показать один из стандартных курсоров? ===<br />
<br />
<syntaxhighlight><br />
HCURSOR hCursor;<br />
hCursor=AfxGetApp()->LoadStandardCursor(IDC_UPARROW);<br />
if(hCursor)SetCursor(hCursor);<br />
</syntaxhighlight><br />
идентификаторы стандартных курсоров:<br />
<syntaxhighlight><br />
IDC_ARROW<br />
IDC_IBEAM<br />
IDC_WAIT<br />
IDC_CROSS<br />
IDC_UPARROW<br />
IDC_SIZENWSE<br />
IDC_SIZENESW<br />
IDC_SIZEWE<br />
IDC_SIZENS<br />
IDC_SIZEALL <br />
</syntaxhighlight><br />
<br />
=== Как запретить пользователю закрыть программу нажатием на кнопку с крестиком? ===<br />
<br />
Для этого нужно добавить обработчик сообщения WM_CLOSE ( функция OnClose() в MFC) в главное окно программы. Для диалоговых приложений такое окно - это главный диалог, для одно- и много-документных приложений - это CMainFrame. <br />
<syntaxhighlight><br />
void CMainFrame::OnClose()<br />
{<br />
if(......)<br />
{<br />
//не разрешаем закрыть<br />
return;<br />
}<br />
<br />
CFrameWnd::OnClose();<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab? ===<br />
<br />
Последовательность действий следующая:<br />
1) кладём на форму нужное количество элементов RadioButton.<br />
2) у первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство.<br />
3) порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется.<br />
<br />
=== Где лучше устанавливать начальные значения элемента CComboBox? ===<br />
<br />
Это можно сделать парой способов:<br />
<br />
1) В редакторе форм - открыть свойства элемента CComboBox , "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter) <br />
2) В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView) <br />
<br />
=== Как перевести RichEdit в режим замены символов? ===<br />
<br />
Имеется несколько способов.<br />
<br />
1) Программно, если известен хендл элемента (hWnd), это делается так: <br />
<syntaxhighlight><br />
//помещаем в конец очереди сообющений контрола сообщение WM_KEYDOWN<br />
//с нужными параметрами<br />
::PostMessage(hWnd,WM_KEYDOWN,VK_INSERT,1);<br />
</syntaxhighlight><br />
<br />
2) Пользователь во время работы может нажать клавишу Insert.<br />
<br />
=== Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы? ===<br />
<br />
Это можно сделать так:<br />
<br />
<syntaxhighlight><br />
AfxGetApp()->m_pMainWnd-> ...; <br />
</syntaxhighlight><br />
<br />
или так<br />
<syntaxhighlight><br />
extern CMyAppXXX theApp;//здесь CMyAppXXX - название класса вашего приложения<br />
theApp.m_pMainWnd-> ...; <br />
</syntaxhighlight><br />
<br />
=== Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ? ===<br />
<br />
Это можно сделать методом SetScaleToFitSize():<br />
<syntaxhighlight><br />
void CMyView::OnInitialUpdate()<br />
{<br />
CFormView::OnInitialUpdate();<br />
<br />
//скрываем полосы прокрутки<br />
GetParentFrame()->RecalcLayout();<br />
ResizeParentToFit();//это уберёт полосы прокрутки со вьюхи<br />
SIZE s={0,0};<br />
SetScaleToFitSize(s);<br />
//далее вызовется обработчик OnPaint(), о котором ниже<br />
/////////<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
Также обратите внимание на одну особенность: в дебаг-версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s={0,0} происходит с ошибкой (программа при этом завершается).<br />
Обходится это так:<br />
<syntaxhighlight><br />
void CMyView::OnPaint() <br />
{<br />
#ifdef _DEBUG<br />
CPaintDC dc(this);<br />
#else<br />
CFormView::OnPaint();<br />
#endif<br />
}<br />
</syntaxhighlight><br />
<br />
или даже вообще так:<br />
<syntaxhighlight><br />
void CMyView::OnPaint() <br />
{<br />
CPaintDC dc(this);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как нарисовать прямоугольник с вертикальным цветовым градиентом? ===<br />
<br />
Нужно задасться граничными значениями цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников (а, значит, плавность гралдиента) задаётся точностью.<br />
Пример:<br />
<syntaxhighlight><br />
//вертикальный градиент<br />
//pdc - указатель на контекст устройства<br />
//pSize - указатель на структуру<br />
//SIZE с размером прямоугольника<br />
// dwdColor1, dwdColor2 - начальный и конечный цвет<br />
//bySteps - количество шагов градиента (1...255) <br />
void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps)<br />
{<br />
if(!bySteps)bySteps=1;<br />
WORD i;<br />
<br />
long W,H,x1,x2;<br />
BYTE R1,G1,B1,R2,G2,B2;<br />
float dh,dR,dG,dB,y1,y2,Rc,Gc,Bc;<br />
<br />
//ширина и высота<br />
W=pSize->cx;<br />
H=pSize->cy;<br />
<br />
//раскладываем цвета на их составляющие<br />
//для удобства дальнейших вычислений<br />
R1=(BYTE)((dwdColor1&0x000000ff));<br />
G1=(BYTE)((dwdColor1&0x0000ff00)>>8);<br />
B1=(BYTE)((dwdColor1&0x00ff0000)>>16);<br />
R2=(BYTE)((dwdColor2&0x000000ff));<br />
G2=(BYTE)((dwdColor2&0x0000ff00)>>8);<br />
B2=(BYTE)((dwdColor2&0x00ff0000)>>16);<br />
<br />
//высота разноцветных прямоугольников<br />
dh=((float)H)/((float)bySteps);<br />
//величина шагов составляющих цветов<br />
dR=(((float)R2)-((float)R1))/((float)bySteps);<br />
dG=(((float)G2)-((float)G1))/((float)bySteps);<br />
dB=(((float)B2)-((float)B1))/((float)bySteps);<br />
//выводим прямоугольники<br />
x1=0;x2=W;y1=0;y2=dh;<br />
Rc=R1;Gc=G1;Bc=B1;<br />
for(i=0;i<bySteps;i++)<br />
{<br />
//текущий цвет<br />
pdc->FillSolidRect(x1,(int)y1,x2-x1,(int)(y2-y1),RGB((BYTE)Rc,(BYTE)Gc,(BYTE)Bc));<br />
//следующий цвет и координаты<br />
y1+=dh;y2+=dh;<br />
Rc+=dR;Gc+=dG;Bc+=dB;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
пример вызова: <br />
<syntaxhighlight><br />
SIZE Size={100,100};<br />
sFillGradientRect(&dc,&Size, RGB(200,0,0), RGB(0,200,0),10);<br />
</syntaxhighlight><br />
<br />
=== Как под Windows отслеживать изменение файла? ===<br />
<br />
Нужно использовать функции: <br />
<br />
FindFirstChangeNotification<br />
FindNextChangeNotification<br />
FindCloseChangeNotification<br />
<br />
(подробности - в MSDN)<br />
<br />
=== Как конвертировать массив char[] в CString? ===<br />
Это можно сделать методами самого класса CString:<br />
<syntaxhighlight><br />
char buf[]="text";<br />
<br />
//строка должна обязательно заканчиваться нулём!!!<br />
<br />
//конвертируем так<br />
CString txt(buf);<br />
<br />
//или так<br />
CString txt;<br />
txt=buf;<br />
</syntaxhighlight><br />
<br />
=== Как зарезервировать в CString буфер нужной длины? ===<br />
<br />
Это можно сделать при помощи методов класса: <br />
<br />
<syntaxhighlight><br />
CString::GetBuffer(...)<br />
</syntaxhighlight><br />
и<br />
<syntaxhighlight><br />
CString::GetBufferSetLength(...)<br />
</syntaxhighlight><br />
<br />
Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку НЕ МЕНЬШЕ заданной длины, а второй возвращает строку точно равную заданной длине. Обе могут перераспределять память если надо. В обычных случаях лучше использовать GetBuffer. <br />
<br />
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем. <br />
<br />
=== Как передать больше одного параметр в процедуру потока? ===<br />
<br />
Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру.<br />
Пример:<br />
<syntaxhighlight><br />
struct mystr<br />
{<br />
CEdit* pEd;<br />
CDialog* pDlg;<br />
DWORD* pdwd;<br />
int *pn;<br />
};<br />
</syntaxhighlight><br />
<br />
запуск потока: <br />
<br />
<syntaxhighlight><br />
mystr *pparam=new mystr;//экземпляр не должен быть временным!!!<br />
<br />
memset(pparam,0,sizeof(*pparam));<br />
pparam->pEd=...;<br />
pparam->pdwd=...;<br />
<br />
::AfxBeginThread(thread,pparam); <br />
//тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как<br />
//он у нас удалиля в процедуре потока<br />
</syntaxhighlight><br />
<br />
процедура потока: <br />
<syntaxhighlight><br />
//поток: <br />
UINT threadLoader(LPVOID pParam) <br />
{ <br />
//копируем данные из структуры в локальную структуру<br />
mystr data=*((mystr*)pParam);<br />
//освобождаем память временной структуры<br />
delete ((mystr*)pParam);<br />
pParam=0;<br />
<br />
<br />
...<br />
data.pDlg->...;<br />
(*data.pdwd)=...;<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как убрать главное меню из окна CMainFrame? ===<br />
Это можно сделать в виртуальной функции PreCreateWindow:<br />
<syntaxhighlight><br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
//обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow<br />
cs.hMenu = 0;<br />
<br />
if(!CFrameWnd::PreCreateWindow(cs))<br />
return FALSE;<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как работающая программа может определить, что пользователь завершает работу Windows? ===<br />
<br />
Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу.<br />
<br />
=== Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ===<br />
<br />
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify) :<br />
<syntaxhighlight><br />
class CMyDlg:puplic CDialog<br />
{<br />
CToolTipCtrl m_ToolTip;//мембер класса CMyDlg<br />
};<br />
<br />
//массив, в котором перечислены идентификаторы<br />
//контролов и тексты подсказок к ним<br />
struct{int ID;const char* pch;} m_a_Tips[]=<br />
{<br />
{IDC_BUTTON1,"Кнопка"},<br />
{IDC_STATIC1,"Текст"},<br />
//<br />
{0,0},//признак конца массива<br />
};<br />
<br />
//в инициализации диалога (хотя, в принципе,<br />
//можно и не тут) создаём и привязываем подсказки<br />
BOOL CMyDlg::OnInitDialog() <br />
{<br />
CDialog::OnInitDialog();<br />
<br />
//создаём элемент TOOLTIP<br />
m_ToolTip.Create(this);<br />
<br />
//Привязка подсказок<br />
for(int i=0; m_a_Tips[i].ID; i++)<br />
{<br />
m_ToolTip.AddTool(<br />
GetDlgItem(m_a_Tips[i].ID),<br />
m_a_Tips[i].pch<br />
);<br />
}<br />
<br />
//включаем показ подсказок<br />
m_ToolTip.Activate(1);<br />
...<br />
...<br />
}<br />
<br />
//для того, чтобы подсказки отображались как реакция на движение<br />
//курсора мыши, транслируем получаемые окнами сообщения в<br />
//виртуальной PreTranslateMessage()<br />
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) <br />
{<br />
//транслируем<br />
if(m_ToolTip.m_hWnd)m_ToolTip.RelayEvent(pMsg);<br />
<br />
return CDialog::PreTranslateMessage(pMsg);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как в отладчике Visual С++ просмотреть содержимое std::vector<string> ?===<br />
<br />
Это можно сделать так. К примеру, имеется<br />
<syntaxhighlight><br />
std::vector<string> V;<br />
</syntaxhighlight><br />
<br />
режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения: <br />
<br />
V._Myfirst (- будет показан первый элемент V)<br />
V._Myfirst+1 (- второй элемент V,)<br />
<br />
и т.д. <br />
<br />
=== Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах? ===<br />
<br />
Для этого нужно использовать процедуру API: <br />
<syntaxhighlight><br />
BOOL GetTextExtentPoint32(<br />
HDC hdc,// хендл контекста<br />
LPCTSTR lpString,// выводимая строка<br />
int cbString,// длина строки в символах<br />
LPSIZE lpSize// указатель на структуру SIZE, куда <br />
//будут помещены размеры<br />
);<br />
</syntaxhighlight><br />
<br />
Функция вычисляет длину лишь одной символов, оканчивающейся нулём. Поэтому, чтобы вычислить "размер" многострочнокго текста, текст вначале необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_2&diff=595FAQ:WinAPI, VCPP Part 22008-10-08T17:10:12Z<p>Алексей1153++: </p>
<hr />
<div><br />
<br />
<br />
<br />
=== Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу? ===<br />
<br />
Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand() :<br />
<syntaxhighlight><br />
BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam) <br />
{<br />
WORD wMess=(wParam>>16);//командное сообщение<br />
int nID=(int)(wParam &0x0000ffff));//ID контрола<br />
HWND hW=(HWND)lParam;//хендл контрола<br />
<br />
//смотрим, какой контрол<br />
switch(nID)<br />
{<br />
//кнопки<br />
case ID_BN1:<br />
case ID_BN2:<br />
case ID_BN3:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case BN_CLICKED:{ ... }break;<br />
}<br />
}<br />
break;<br />
<br />
//едиты<br />
case ID_ED1:<br />
case ID_ED2:<br />
case ID_ED3:<br />
case ID_ED4:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case EN_CHANGE:{ ... }break;<br />
case EN_KILLFOCUS:{ ... }break;<br />
}<br />
}<br />
break;<br />
}<br />
<br />
return CDialog::OnCommand(wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать? ===<br />
<br />
Лечится проблема так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются. <br />
<br />
=== Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы? ===<br />
<br />
Нужно использовать функцию GetModuleFileName(): <br />
<syntaxhighlight><br />
TCHAR pszFileName[MAX_PATH];<br />
pszFileName[0]=0;<br />
GetModuleFileName(NULL, pszFileName, MAX_PATH);<br />
CString stModulePath = pszFileName;<br />
//ищем первый слеш с конца и удаляем<br />
//его вместе с именем файла EXE<br />
int nEnd = stModulePath.ReverseFind('\\');<br />
stModulePath.Delete(nEnd, stModulePath.GetLength()-nEnd);<br />
<br />
//stModulePath - содержит путь<br />
</syntaxhighlight><br />
<br />
=== Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame? ===<br />
<br />
<syntaxhighlight><br />
#include "MainFrm.h"<br />
<br />
//CMyApp - класс вашего приложения. theApp - глобальная переменная,<br />
//поэтому для доступа к ней используем extern<br />
extern CMyApp theApp;<br />
<br />
void CMyView::F()<br />
{<br />
//Получаем главное окно приложения в любом месте программы<br />
CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);<br />
<br />
pMainFrame->m_wndDlgBar ....//Делаем что хотим<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как загрузить и показать один из стандартных курсоров? ===<br />
<br />
<syntaxhighlight><br />
HCURSOR hCursor;<br />
hCursor=AfxGetApp()->LoadStandardCursor(IDC_UPARROW);<br />
if(hCursor)SetCursor(hCursor);<br />
</syntaxhighlight><br />
идентификаторы стандартных курсоров:<br />
IDC_ARROW<br />
IDC_IBEAM<br />
IDC_WAIT<br />
IDC_CROSS<br />
IDC_UPARROW<br />
IDC_SIZENWSE<br />
IDC_SIZENESW<br />
IDC_SIZEWE<br />
IDC_SIZENS<br />
IDC_SIZEALL <br />
<br />
=== Как запретить пользователю закрыть программу нажатием на кнопку с крестиком? ===<br />
<br />
Для этого нужно добавить обработчик сообщения WM_CLOSE ( функция OnClose() в MFC) в главное окно программы. Для диалоговых приложений такое окно - это главный диалог, для одно- и много-документных приложений - это CMainFrame. <br />
<syntaxhighlight><br />
void CMainFrame::OnClose()<br />
{<br />
if(......)<br />
{<br />
//не разрешаем закрыть<br />
return;<br />
}<br />
<br />
CFrameWnd::OnClose();<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab? ===<br />
<br />
Последовательность действий следующая:<br />
1) кладём на форму нужное количество элементов RadioButton.<br />
2) у первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство.<br />
3) порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется.<br />
<br />
=== Где лучше устанавливать начальные значения элемента CComboBox? ===<br />
<br />
Это можно сделать парой способов:<br />
<br />
1) В редакторе форм - открыть свойства элемента CComboBox , "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter) <br />
2) В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView) <br />
<br />
=== Как перевести RichEdit в режим замены символов? ===<br />
<br />
Имеется несколько способов.<br />
<br />
1) Программно, если известен хендл элемента (hWnd), это делается так: <br />
<syntaxhighlight><br />
//помещаем в конец очереди сообющений контрола сообщение WM_KEYDOWN<br />
//с нужными параметрами<br />
::PostMessage(hWnd,WM_KEYDOWN,VK_INSERT,1);<br />
</syntaxhighlight><br />
<br />
2) Пользователь во время работы может нажать клавишу Insert.<br />
<br />
=== Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы? ===<br />
<br />
Это можно сделать так:<br />
<br />
<syntaxhighlight><br />
AfxGetApp()->m_pMainWnd-> ...; <br />
</syntaxhighlight><br />
<br />
или так<br />
<syntaxhighlight><br />
extern CMyAppXXX theApp;//здесь CMyAppXXX - название класса вашего приложения<br />
theApp.m_pMainWnd-> ...; <br />
</syntaxhighlight><br />
<br />
=== Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ? ===<br />
<br />
Это можно сделать методом SetScaleToFitSize():<br />
<syntaxhighlight><br />
void CMyView::OnInitialUpdate()<br />
{<br />
CFormView::OnInitialUpdate();<br />
<br />
//скрываем полосы прокрутки<br />
GetParentFrame()->RecalcLayout();<br />
ResizeParentToFit();//это уберёт полосы прокрутки со вьюхи<br />
SIZE s={0,0};<br />
SetScaleToFitSize(s);<br />
//далее вызовется обработчик OnPaint(), о котором ниже<br />
/////////<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
Также обратите внимание на одну особенность: в дебаг-версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s={0,0} происходит с ошибкой (программа при этом завершается).<br />
Обходится это так:<br />
<syntaxhighlight><br />
void CMyView::OnPaint() <br />
{<br />
#ifdef _DEBUG<br />
CPaintDC dc(this);<br />
#else<br />
CFormView::OnPaint();<br />
#endif<br />
}<br />
</syntaxhighlight><br />
<br />
или даже вообще так:<br />
<syntaxhighlight><br />
void CMyView::OnPaint() <br />
{<br />
CPaintDC dc(this);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как нарисовать прямоугольник с вертикальным цветовым градиентом? ===<br />
<br />
Нужно задасться граничными значениями цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников (а, значит, плавность гралдиента) задаётся точностью.<br />
Пример:<br />
<syntaxhighlight><br />
//вертикальный градиент<br />
//pdc - указатель на контекст устройства<br />
//pSize - указатель на структуру<br />
//SIZE с размером прямоугольника<br />
// dwdColor1, dwdColor2 - начальный и конечный цвет<br />
//bySteps - количество шагов градиента (1...255) <br />
void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps)<br />
{<br />
if(!bySteps)bySteps=1;<br />
WORD i;<br />
<br />
long W,H,x1,x2;<br />
BYTE R1,G1,B1,R2,G2,B2;<br />
float dh,dR,dG,dB,y1,y2,Rc,Gc,Bc;<br />
<br />
//ширина и высота<br />
W=pSize->cx;<br />
H=pSize->cy;<br />
<br />
//раскладываем цвета на их составляющие<br />
//для удобства дальнейших вычислений<br />
R1=(BYTE)((dwdColor1&0x000000ff));<br />
G1=(BYTE)((dwdColor1&0x0000ff00)>>8);<br />
B1=(BYTE)((dwdColor1&0x00ff0000)>>16);<br />
R2=(BYTE)((dwdColor2&0x000000ff));<br />
G2=(BYTE)((dwdColor2&0x0000ff00)>>8);<br />
B2=(BYTE)((dwdColor2&0x00ff0000)>>16);<br />
<br />
//высота разноцветных прямоугольников<br />
dh=((float)H)/((float)bySteps);<br />
//величина шагов составляющих цветов<br />
dR=(((float)R2)-((float)R1))/((float)bySteps);<br />
dG=(((float)G2)-((float)G1))/((float)bySteps);<br />
dB=(((float)B2)-((float)B1))/((float)bySteps);<br />
//выводим прямоугольники<br />
x1=0;x2=W;y1=0;y2=dh;<br />
Rc=R1;Gc=G1;Bc=B1;<br />
for(i=0;i<bySteps;i++)<br />
{<br />
//текущий цвет<br />
pdc->FillSolidRect(x1,(int)y1,x2-x1,(int)(y2-y1),RGB((BYTE)Rc,(BYTE)Gc,(BYTE)Bc));<br />
//следующий цвет и координаты<br />
y1+=dh;y2+=dh;<br />
Rc+=dR;Gc+=dG;Bc+=dB;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
пример вызова: <br />
<syntaxhighlight><br />
SIZE Size={100,100};<br />
sFillGradientRect(&dc,&Size, RGB(200,0,0), RGB(0,200,0),10);<br />
</syntaxhighlight><br />
<br />
=== Как под Windows отслеживать изменение файла? ===<br />
<br />
Нужно использовать функции: <br />
<br />
FindFirstChangeNotification<br />
FindNextChangeNotification<br />
FindCloseChangeNotification<br />
<br />
(подробности - в MSDN)<br />
<br />
=== Как конвертировать массив char[] в CString? ===<br />
Это можно сделать методами самого класса CString:<br />
<syntaxhighlight><br />
char buf[]="text";<br />
<br />
//строка должна обязательно заканчиваться нулём!!!<br />
<br />
//конвертируем так<br />
CString txt(buf);<br />
<br />
//или так<br />
CString txt;<br />
txt=buf;<br />
</syntaxhighlight><br />
<br />
=== Как зарезервировать в CString буфер нужной длины? ===<br />
<br />
Это можно сделать при помощи методов класса: <br />
<br />
<syntaxhighlight><br />
CString::GetBuffer(...)<br />
</syntaxhighlight><br />
и<br />
<syntaxhighlight><br />
CString::GetBufferSetLength(...)<br />
</syntaxhighlight><br />
<br />
Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку НЕ МЕНЬШЕ заданной длины, а второй возвращает строку точно равную заданной длине. Обе могут перераспределять память если надо. В обычных случаях лучше использовать GetBuffer. <br />
<br />
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем. <br />
<br />
=== Как передать больше одного параметр в процедуру потока? ===<br />
<br />
Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру.<br />
Пример:<br />
<syntaxhighlight><br />
struct mystr<br />
{<br />
CEdit* pEd;<br />
CDialog* pDlg;<br />
DWORD* pdwd;<br />
int *pn;<br />
};<br />
</syntaxhighlight><br />
<br />
запуск потока: <br />
<br />
<syntaxhighlight><br />
mystr *pparam=new mystr;//экземпляр не должен быть временным!!!<br />
<br />
memset(pparam,0,sizeof(*pparam));<br />
pparam->pEd=...;<br />
pparam->pdwd=...;<br />
<br />
::AfxBeginThread(thread,pparam); <br />
//тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как<br />
//он у нас удалиля в процедуре потока<br />
</syntaxhighlight><br />
<br />
процедура потока: <br />
<syntaxhighlight><br />
//поток: <br />
UINT threadLoader(LPVOID pParam) <br />
{ <br />
//копируем данные из структуры в локальную структуру<br />
mystr data=*((mystr*)pParam);<br />
//освобождаем память временной структуры<br />
delete ((mystr*)pParam);<br />
pParam=0;<br />
<br />
<br />
...<br />
data.pDlg->...;<br />
(*data.pdwd)=...;<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как убрать главное меню из окна CMainFrame? ===<br />
Это можно сделать в виртуальной функции PreCreateWindow:<br />
<syntaxhighlight><br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
//обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow<br />
cs.hMenu = 0;<br />
<br />
if(!CFrameWnd::PreCreateWindow(cs))<br />
return FALSE;<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как работающая программа может определить, что пользователь завершает работу Windows? ===<br />
<br />
Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу.<br />
<br />
=== Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ===<br />
<br />
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify) :<br />
<syntaxhighlight><br />
class CMyDlg:puplic CDialog<br />
{<br />
CToolTipCtrl m_ToolTip;//мембер класса CMyDlg<br />
};<br />
<br />
//массив, в котором перечислены идентификаторы<br />
//контролов и тексты подсказок к ним<br />
struct{int ID;const char* pch;} m_a_Tips[]=<br />
{<br />
{IDC_BUTTON1,"Кнопка"},<br />
{IDC_STATIC1,"Текст"},<br />
//<br />
{0,0},//признак конца массива<br />
};<br />
<br />
//в инициализации диалога (хотя, в принципе,<br />
//можно и не тут) создаём и привязываем подсказки<br />
BOOL CMyDlg::OnInitDialog() <br />
{<br />
CDialog::OnInitDialog();<br />
<br />
//создаём элемент TOOLTIP<br />
m_ToolTip.Create(this);<br />
<br />
//Привязка подсказок<br />
for(int i=0; m_a_Tips[i].ID; i++)<br />
{<br />
m_ToolTip.AddTool(<br />
GetDlgItem(m_a_Tips[i].ID),<br />
m_a_Tips[i].pch<br />
);<br />
}<br />
<br />
//включаем показ подсказок<br />
m_ToolTip.Activate(1);<br />
...<br />
...<br />
}<br />
<br />
//для того, чтобы подсказки отображались как реакция на движение<br />
//курсора мыши, транслируем получаемые окнами сообщения в<br />
//виртуальной PreTranslateMessage()<br />
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) <br />
{<br />
//транслируем<br />
if(m_ToolTip.m_hWnd)m_ToolTip.RelayEvent(pMsg);<br />
<br />
return CDialog::PreTranslateMessage(pMsg);<br />
}<br />
</syntaxhighlight><br />
<br />
=== Как в отладчике Visual С++ просмотреть содержимое std::vector<string> ?===<br />
<br />
Это можно сделать так. К примеру, имеется<br />
<syntaxhighlight><br />
std::vector<string> V;<br />
</syntaxhighlight><br />
<br />
режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения: <br />
<br />
V._Myfirst (- будет показан первый элемент V)<br />
V._Myfirst+1 (- второй элемент V,)<br />
<br />
и т.д. <br />
<br />
=== Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах? ===<br />
<br />
Для этого нужно использовать процедуру API: <br />
<syntaxhighlight><br />
BOOL GetTextExtentPoint32(<br />
HDC hdc,// хендл контекста<br />
LPCTSTR lpString,// выводимая строка<br />
int cbString,// длина строки в символах<br />
LPSIZE lpSize// указатель на структуру SIZE, куда <br />
//будут помещены размеры<br />
);<br />
</syntaxhighlight><br />
<br />
Функция вычисляет длину лишь одной символов, оканчивающейся нулём. Поэтому, чтобы вычислить "размер" многострочнокго текста, текст вначале необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки.<br />
<br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_2&diff=594FAQ:WinAPI, VCPP Part 22008-10-08T15:40:44Z<p>Алексей1153++: тег pre -> code , &amp;, &lt; ,&gt -> $, <, ></p>
<hr />
<div><br />
<br />
<br />
<br />
=== Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу? ===<br />
<br />
Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand() :<br />
<syntaxhighlight>BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam) <br />
{<br />
WORD wMess=(wParam>>16);//командное сообщение<br />
int nID=(int)(wParam &0x0000ffff));//ID контрола<br />
HWND hW=(HWND)lParam;//хендл контрола<br />
<br />
//смотрим, какой контрол<br />
switch(nID)<br />
{<br />
//кнопки<br />
case ID_BN1:<br />
case ID_BN2:<br />
case ID_BN3:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case BN_CLICKED:{ ... }break;<br />
}<br />
}<br />
break;<br />
<br />
//едиты<br />
case ID_ED1:<br />
case ID_ED2:<br />
case ID_ED3:<br />
case ID_ED4:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case EN_CHANGE:{ ... }break;<br />
case EN_KILLFOCUS:{ ... }break;<br />
}<br />
}<br />
break;<br />
}<br />
<br />
return CDialog::OnCommand(wParam, lParam);<br />
}<br />
</syntaxhighlight><br />
=== Когда запускаю программу, то все надписи на русском языке теряются - показываются вопросики. Что делать? ===<br />
<br />
Лечится так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются. <br />
<br />
=== Как в проекте VC6 MFC получить путь, откуда запущен ЕХЕ? ===<br />
<br />
Использовать GetModuleFileName(): <br />
<syntaxhighlight> TCHAR pszFileName[MAX_PATH];<br />
pszFileName[0]=0;<br />
GetModuleFileName(NULL, pszFileName, MAX_PATH);<br />
CString stModulePath = pszFileName;<br />
//ищем первый слеш с конца и удаляем<br />
//его вместе с именем файла EXE<br />
int nEnd = stModulePath.ReverseFind('\\');<br />
stModulePath.Delete(nEnd, stModulePath.GetLength()-nEnd);<br />
<br />
//stModulePath - содержит путь<br />
</syntaxhighlight><br />
=== Как получить доступ к контролам на панели CReBar, принадлежащей классу MainFrame? ===<br />
<syntaxhighlight>#include "MainFrm.h"<br />
<br />
//CMyApp - класс вашего приложения. theApp - глобальная переменная,<br />
//поэтому для доступа к ней используем extern<br />
extern CMyApp theApp;<br />
<br />
void CMyView::F()<br />
{<br />
//Получаем главное окно приложения в любом месте программы<br />
CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);<br />
pMainFrame->m_wndDlgBar ....//Делаем что хотим<br />
...<br />
}<br />
</syntaxhighlight><br />
=== Как загрузить и показать один из стандартных курсоров? ===<br />
<syntaxhighlight>HCURSOR hCursor;<br />
hCursor=AfxGetApp()->LoadStandardCursor(IDC_UPARROW);<br />
if(hCursor)SetCursor(hCursor);<br />
</syntaxhighlight><br />
идентификаторы стандартных курсоров: IDC_ARROW IDC_IBEAM IDC_WAIT IDC_CROSS IDC_UPARROW IDC_SIZENWSE IDC_SIZENESW IDC_SIZEWE IDC_SIZENS IDC_SIZEALL <br />
<br />
=== Как запретить пользователю закрыть программу нажатием на крестик? ===<br />
<br />
Нужно добавить обработчик сообщений WM_CLOSE - OnClose() - в главное окно программы. Для диалоговых приложений - это главный диалог, для одно- и много-документных - это CMainFrame. <br />
<syntaxhighlight>void CMainFrame::OnClose()<br />
{<br />
if(......)<br />
{<br />
//не разрешаем закрыть<br />
return;<br />
}<br />
<br />
CFrameWnd::OnClose();<br />
}<br />
</syntaxhighlight><br />
=== Как создать на диалоге группу RadioButton-ов и как задать порядок их обхода клавишей Tab? ===<br />
<br />
Кладём на форму N контролов RadioButton. Затем у первого из группы ставим свойство Group, у остальных в группе - убираем это свойство. Порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется. <br />
<br />
=== Где лучше устанавливать начальные значения CComboBox? ===<br />
<br />
1) В визарде (новая строка данных - Ctrl+Enter) <br />
<br />
2) В функции OnInitDialog (для диалога) или OnInitialUpdate (для CView) <br />
<br />
=== Как перевести RichEdit в режим замены символов? ===<br />
<br />
1) Программно, зная хендл контрола (hWnd): <br />
<br />
::PostMessage(hWnd,WM_KEYDOWN,VK_INSERT,1);<br />
<br />
2) Пользователь может нажать Insert. <br />
<br />
=== Как вызвать метод класса CMainFrame (главное окно) из любого места программы? ===<br />
<br />
AfxGetApp()->m_pMainWnd-> ...; <br />
<br />
=== Как запретить появление полос прокруток на CFormView, когда пользователь делает размер главного окна меньше размера окна CFormView ? ===<br />
<br />
методом SetScaleToFitSize(): <br />
<syntaxhighlight>void CMyView::OnInitialUpdate()<br />
{<br />
CFormView::OnInitialUpdate();<br />
/////////<br />
GetParentFrame()->RecalcLayout();<br />
ResizeParentToFit();<br />
SIZE s={0,0};<br />
SetScaleToFitSize(s);<br />
/////////<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
=== Как нарисовать прямоугольник с вертикальным цветовым градиентом? ===<br />
<br />
pdc - указатель на контекст устройства pSize - указатель на структуру SIZE с размером прямоугольника dwdColor1, dwdColor2 - начальный и конечный цвет bySteps - количество шагов градиента (1...255) <br />
<syntaxhighlight>//вертикальный градиент<br />
void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps)<br />
{<br />
if(!bySteps)bySteps=1;<br />
WORD i;<br />
<br />
long W,H,x1,x2;<br />
BYTE R1,G1,B1,R2,G2,B2;<br />
float dh,dR,dG,dB,y1,y2,Rc,Gc,Bc;<br />
<br />
//ширина и высота<br />
W=pSize->cx;<br />
H=pSize->cy;<br />
<br />
//раскладываем цвета на их составляющие<br />
R1=(BYTE)((dwdColor1&0x000000ff));<br />
G1=(BYTE)((dwdColor1&0x0000ff00)>>8);<br />
B1=(BYTE)((dwdColor1&0x00ff0000)>>16);<br />
R2=(BYTE)((dwdColor2&0x000000ff));<br />
G2=(BYTE)((dwdColor2&0x0000ff00)>>8);<br />
B2=(BYTE)((dwdColor2&0x00ff0000)>>16);<br />
<br />
//высота разноцветных прямоугольников<br />
dh=((float)H)/((float)bySteps);<br />
//величина шагов составляющих цветов<br />
dR=(((float)R2)-((float)R1))/((float)bySteps);<br />
dG=(((float)G2)-((float)G1))/((float)bySteps);<br />
dB=(((float)B2)-((float)B1))/((float)bySteps);<br />
//выводим прямоугольники<br />
x1=0;x2=W;y1=0;y2=dh;<br />
Rc=R1;Gc=G1;Bc=B1;<br />
for(i=0;i<bySteps;i++)<br />
{<br />
//текущий цвет<br />
pdc->FillSolidRect(x1,(int)y1,x2-x1,(int)(y2-y1),RGB((BYTE)Rc,(BYTE)Gc,(BYTE)Bc));<br />
//следующий цвет и координаты<br />
y1+=dh;y2+=dh;<br />
Rc+=dR;Gc+=dG;Bc+=dB;<br />
}<br />
}<br />
</syntaxhighlight><br />
пример вызова: <br />
<syntaxhighlight> SIZE Size={100,100};<br />
sFillGradientRect(&dc,&Size, RGB(200,0,0), RGB(0,200,0),10);<br />
</syntaxhighlight><br />
=== Как под Windows отслеживать изменение файла? ===<br />
<br />
Использовать функции: <br />
<br />
FindFirstChangeNotification<br />
FindNextChangeNotification<br />
FindCloseChangeNotification<br />
<br />
=== Есть массив char[], как конвертировать его в CString? ===<br />
<syntaxhighlight> char buf[]="text";<br />
<br />
//строка должна обязательно заканчиваться нулём.<br />
<br />
//конвертируем так<br />
CString txt(buf);<br />
<br />
//или так<br />
CString txt;<br />
txt=buf;<br />
</syntaxhighlight><br />
=== Как зарезервировать в CString буфер нужной длины? ===<br />
<br />
при помощи методов класса: <br />
<br />
CString::GetBuffer<br />
и<br />
CString::GetBufferSetLength<br />
<br />
Разница между CString::GetBuffer(nLen) и CString::GetBufferSetLength(nLen) в том, что первый возвращает строку не меньше заданной длины, а второй возвращает строку точно равную заданной длине. Обе могут перераспределять память если надо. В обычных случаях лучше GetBuffer. <br />
<br />
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем. <br />
<br />
=== Как передать больше одного параметр в процедуру потока? ===<br />
<br />
Определить структуру с указателями на всё любое, например: <br />
<syntaxhighlight>struct mystr<br />
{<br />
CEdit* pEd;<br />
CDialog* pDlg;<br />
DWORD* pdwd;<br />
int *pn;<br />
};<br />
</syntaxhighlight><br />
запуск потока: <br />
<syntaxhighlight>mystr *pparam=new mystr;//экземпляр не должен быть временным!!!<br />
memset(pparam,0,sizeof(*pparam));<br />
pparam->pEd=...;<br />
pparam->pdwd=...;<br />
<br />
::AfxBeginThread(thread,pparam); <br />
//тут экземпляр *(pparam) уже нельзя использовать!!!<br />
//он удалиться в потоке<br />
</syntaxhighlight><br />
в потоке: <br />
<syntaxhighlight>//поток: <br />
UINT threadLoader(LPVOID pParam) <br />
{ <br />
mystr data=*((mystr*)pParam);<br />
delete ((mystr*)pParam);//подчищаем память<br />
<br />
...<br />
data.pDlg->...;<br />
(*data.pdwd)=...;<br />
...<br />
}<br />
</syntaxhighlight><br />
=== Как убрать главное меню из CMainFrame? ===<br />
<syntaxhighlight>BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />
{<br />
//обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow<br />
cs.hMenu = 0;<br />
<br />
if(!CFrameWnd::PreCreateWindow(cs))<br />
return FALSE;<br />
...<br />
...<br />
}<br />
</syntaxhighlight><br />
=== Как работающая программа может определить, что юзер завершает работу Windows? ===<br />
<br />
В этот момент всем процессам посылается сообщение WM_QUERYENDSESSION - его и нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу. <br />
<br />
=== Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ===<br />
<br />
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для контролов. (для CStatic контролов не забудьте поставить свойство Notify) <br />
<syntaxhighlight>class CMyDlg:puplic CDialog<br />
{<br />
CToolTipCtrl m_ToolTip;//мембер класса CMyDlg<br />
//<br />
};<br />
<br />
//массив, в котором перечислены идентификаторы<br />
//контролов и тексты подсказок к ним<br />
struct{int ID;const char* pch;} m_a_Tips[]=<br />
{<br />
{IDC_BUTTON1,"КЫнопка"},<br />
{IDC_STATIC1,"Текст"},<br />
//<br />
{0,0},//признак конца массива<br />
};<br />
<br />
//в инициализации диалога (хотя, в принципе,<br />
//можно и не тут) создаём и привязываем подсказки<br />
BOOL CMyDlg::OnInitDialog() <br />
{<br />
CDialog::OnInitDialog();<br />
//<br />
//создаём<br />
m_ToolTip.Create(this);<br />
//Привязка подсказок<br />
for(int i=0; m_a_Tips[i].ID; i++)<br />
{<br />
m_ToolTip.AddTool(<br />
GetDlgItem(m_a_Tips[i].ID),<br />
m_a_Tips[i].pch);<br />
}<br />
<br />
//включаем показ подсказок<br />
m_ToolTip.Activate(1);<br />
...<br />
...<br />
}<br />
<br />
//для того, чтобы подсказки отображались как реакция на движение<br />
//курсора мыши, транслируем получаемые окнами сообщения в<br />
//виртуальной PreTranslateMessage()<br />
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) <br />
{<br />
//транслируем<br />
if(m_ToolTip.m_hWnd)m_ToolTip.RelayEvent(pMsg);<br />
<br />
...<br />
...<br />
return CDialog::PreTranslateMessage(pMsg);<br />
}<br />
</syntaxhighlight><br />
=== Как в отладчике VС просмотреть содержимое std::vector<string> V ===<br />
<br />
В режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения: <br />
<br />
V._Myfirst - будет показан первый элемент V._Myfirst+1 - второй V._Myfirst+2 - и т.д. <br />
<br />
=== Я вывожу на контекст устройства текст. Как определить в пикселах ширину и высоту выведенных символов текста? ===<br />
<br />
использовать процедуру API: <br />
<syntaxhighlight>BOOL GetTextExtentPoint32(<br />
HDC hdc,// хендл контекста<br />
LPCTSTR lpString,// выводимая строка<br />
int cbString,// длина строки в символах<br />
LPSIZE lpSize// указатель на структуру SIZE, куда <br />
//будут помещены размеры<br />
);<br />
</syntaxhighlight><br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%B4%D0%BB%D1%8F_%D0%B2%D1%8B%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%D0%B0/%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B8%D0%B7_%D1%81%D0%B2%D0%BE%D0%B5%D0%B9_%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_DLL&diff=530FAQ:WinAPI VCPP:значение переменной для вызывающего процесса/потока из своей собственной DLL2008-10-03T20:04:07Z<p>Алексей1153++: </p>
<hr />
<div>=== Каким образом можно установить значение переменной для вызывающего процесса/потока из своей собственной DLL? Проблема заключается в том, что несмотря на то, что все линкуется нормально, значение переменной процесса не изменяется, когда я его устанавливаю вручную в библиотеке. ===<br />
<br />
Проблема вызвана тем, что каждая влинкованная libc (одна линкуется в исполняемый файл, ещё одна в dll) содержит свою копию переменной. <br />
<br />
1) Можно воспользоваться динамически подгружаемой библиотекой С runtime. Для этого приложение и dll надо компилировать с ключом /MD (или MDd для отладки). В таком случае переменная будет общей для приложения и dll. <br />
<br />
2) Можно в основном модуле программы (тот, который станет .exe) сделать "дырку" (backdoor), через которую присваивать переменной (int errno) значение: <br />
<pre>__declspec(dllexport) void set_errno(int code)<br />
{<br />
errno = code;<br />
}<br />
</pre><br />
В dll при подключении к процессу надо извлечь из модуля программы указатель на эту функцию. <br />
<pre> typedef void (*SETINT)(int);<br />
SETINT g_set_errno=0;<br />
void set_errno_in_exe(int code)<br />
{<br />
if(g_set_errno) g_set_errno(code);<br />
}<br />
<br />
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )<br />
{<br />
HANDLE hModule; // Handle to the main module<br />
if(fdwReason == DLL_PROCESS_ATTACH )<br />
{<br />
hModule = GetModuleHandle(NULL);<br />
if (hModule == NULL) return FALSE;<br />
g_set_errno = (SETINT) GetProcAddress(hModule, "set_errno");<br />
}<br />
return TRUE;<br />
}<br />
</pre><br />
В нужном месте в dll вместо присваивания errno нужно вызывать внешнюю функцию <br />
<pre>void inside_dll_func()<br />
{<br />
...<br />
...<br />
set_errno_in_exe(ERROR_CODE);<br />
...<br />
}<br />
</pre></div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_2&diff=528FAQ:WinAPI, VCPP Part 22008-10-03T19:59:01Z<p>Алексей1153++: </p>
<hr />
<div><br><br />
<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%B3%D0%B4%D0%B5_%D0%BD%D0%B0%D0%B9%D1%82%D0%B8_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5_nmake_%D0%B4%D0%BB%D1%8F_VC%2B%2B6|1 где найти описание nmake для VC++6?]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%B4%D0%BB%D1%8F_%D0%B2%D1%8B%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%D0%B0/%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B8%D0%B7_%D1%81%D0%B2%D0%BE%D0%B5%D0%B9_%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_DLL|2 значение переменной для вызывающего процесса/потока из своей собственной DLL]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D1%82%D1%8C_%D1%84%D0%BE%D0%BD_%D0%BE%D0%BA%D0%BD%D0%B0_CWnd|3 Как закрасить фон окна CWnd?]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C_%2C_%D1%87%D1%82%D0%BE_%D0%BA%D1%83%D1%80%D1%81%D0%BE%D1%80_%D0%BC%D1%8B%D1%88%D0%B8_%D0%B2%D1%8B%D1%88%D0%B5%D0%BB_%D0%B7%D0%B0_%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D1%83_%D0%BE%D0%BA%D0%BD%D0%B0|4 Как определить , что курсор мыши вышел за границу окна?]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:%D0%9A%D0%BE%D0%B3%D0%B4%D0%B0_%D1%80%D0%B0%D0%B7%D0%BC%D0%B5%D1%89%D0%B0%D1%8E_%D0%BA%D0%BE%D0%BC%D0%BF%D0%BE%D0%BD%D0%B5%D0%BD%D1%82_RichEdit_%D0%BD%D0%B0_%D1%84%D0%BE%D1%80%D0%BC%D1%83%2C_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0_%D0%B7%D0%B0%D0%BF%D1%83%D1%81%D0%BA%D0%B0%D0%B5%D1%82%D1%81%D1%8F_%D0%B8_%D1%82%D1%83%D1%82_%D0%B6%D0%B5_%D0%B7%D0%B0%D0%BA%D1%80%D1%8B%D0%B2%D0%B0%D0%B5%D1%82%D1%81%D1%8F|5 Когда размещаю компонент RichEdit на форму, программа запускается и тут же закрывается. Что здесь не так?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%BE%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA_%D1%81%D0%BE%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B4%D0%BB%D1%8F_%D0%BD%D0%B5%D1%81%D0%BA%D0%BE%D0%BB%D1%8C%D0%BA%D0%B8%D1%85_%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BE%D0%B2_%D1%81%D1%80%D0%B0%D0%B7%D1%83|6 Как сделать обработчик сообщения для нескольких контролов сразу?]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%B2%D1%81%D0%B5_%D0%BD%D0%B0%D0%B4%D0%BF%D0%B8%D1%81%D0%B8_%D0%BD%D0%B0_%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D0%BC_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B5_%D1%82%D0%B5%D1%80%D1%8F%D1%8E%D1%82%D1%81%D1%8F_-_%D0%BF%D0%BE%D0%BA%D0%B0%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%82%D1%81%D1%8F_%D0%B2%D0%BE%D0%BF%D1%80%D0%BE%D1%81%D0%B8%D0%BA%D0%B8|7 Когда запускаю программу, то все надписи на русском языке теряются - показываются вопросики. Что делать?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B2_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B5_VC6_MFC_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C_%D0%BF%D1%83%D1%82%D1%8C%2C_%D0%BE%D1%82%D0%BA%D1%83%D0%B4%D0%B0_%D0%B7%D0%B0%D0%BF%D1%83%D1%89%D0%B5%D0%BD_%D0%95%D0%A5%D0%95|8 Как в проекте VC6 MFC получить путь, откуда запущен ЕХЕ?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C_%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF_%D0%BA_%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%B0%D0%BC_%D0%BD%D0%B0_%D0%BF%D0%B0%D0%BD%D0%B5%D0%BB%D0%B8_CReBar%2C_%D0%BF%D1%80%D0%B8%D0%BD%D0%B0%D0%B4%D0%BB%D0%B5%D0%B6%D0%B0%D1%89%D0%B5%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D1%83_MainFrame|9 Как получить доступ к контролам на панели CReBar, принадлежащей классу MainFrame?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%B8%D1%82%D1%8C_%D0%B8_%D0%BF%D0%BE%D0%BA%D0%B0%D0%B7%D0%B0%D1%82%D1%8C_%D0%BE%D0%B4%D0%B8%D0%BD_%D0%B8%D0%B7_%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D1%85_%D0%BA%D1%83%D1%80%D1%81%D0%BE%D1%80%D0%BE%D0%B2|10 Как загрузить и показать один из стандартных курсоров?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D0%BF%D1%80%D0%B5%D1%82%D0%B8%D1%82%D1%8C_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8E_%D0%B7%D0%B0%D0%BA%D1%80%D1%8B%D1%82%D1%8C_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D1%83_%D0%BD%D0%B0%D0%B6%D0%B0%D1%82%D0%B8%D0%B5%D0%BC_%D0%BD%D0%B0_%D0%BA%D1%80%D0%B5%D1%81%D1%82%D0%B8%D0%BA|11 Как запретить пользователю закрыть программу нажатием на крестик?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D1%8C_%D0%BD%D0%B0_%D0%B4%D0%B8%D0%B0%D0%BB%D0%BE%D0%B3%D0%B5_%D0%B3%D1%80%D1%83%D0%BF%D0%BF%D1%83_RadioButton-%D0%BE%D0%B2_%D0%B8_%D0%BA%D0%B0%D0%BA_%D0%B7%D0%B0%D0%B4%D0%B0%D1%82%D1%8C_%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D0%BA_%D0%B8%D1%85_%D0%BE%D0%B1%D1%85%D0%BE%D0%B4%D0%B0_%D0%BA%D0%BB%D0%B0%D0%B2%D0%B8%D1%88%D0%B5%D0%B9_Tab|12 Как создать на диалоге группу RadioButton-ов и как задать порядок их обхода клавишей Tab?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%93%D0%B4%D0%B5_%D0%BB%D1%83%D1%87%D1%88%D0%B5_%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%B0%D0%B2%D0%BB%D0%B8%D0%B2%D0%B0%D1%82%D1%8C_%D0%BD%D0%B0%D1%87%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B5_%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_CComboBox|13 Где лучше устанавливать начальные значения CComboBox?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BF%D0%B5%D1%80%D0%B5%D0%B2%D0%B5%D1%81%D1%82%D0%B8_RichEdit_%D0%B2_%D1%80%D0%B5%D0%B6%D0%B8%D0%BC_%D0%B7%D0%B0%D0%BC%D0%B5%D0%BD%D1%8B_%D1%81%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB%D0%BE%D0%B2|14 Как перевести RichEdit в режим замены символов?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B2%D1%8B%D0%B7%D0%B2%D0%B0%D1%82%D1%8C_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B0_CMainFrame_%28%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%BE%D0%B5_%D0%BE%D0%BA%D0%BD%D0%BE%29_%D0%B8%D0%B7_%D0%BB%D1%8E%D0%B1%D0%BE%D0%B3%D0%BE_%D0%BC%D0%B5%D1%81%D1%82%D0%B0_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D1%8B|15 Как вызвать метод класса CMainFrame (главное окно) из любого места программы?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D0%BF%D1%80%D0%B5%D1%82%D0%B8%D1%82%D1%8C_%D0%BF%D0%BE%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%BB%D0%BE%D1%81_%D0%BF%D1%80%D0%BE%D0%BA%D1%80%D1%83%D1%82%D0%BE%D0%BA_%D0%BD%D0%B0_CFormView%2C_%D0%BA%D0%BE%D0%B3%D0%B4%D0%B0_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C_%D0%B4%D0%B5%D0%BB%D0%B0%D0%B5%D1%82_%D1%80%D0%B0%D0%B7%D0%BC%D0%B5%D1%80_%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%BA%D0%BD%D0%B0_%D0%BC%D0%B5%D0%BD%D1%8C%D1%88%D0%B5_%D1%80%D0%B0%D0%B7%D0%BC%D0%B5%D1%80%D0%B0_%D0%BE%D0%BA%D0%BD%D0%B0_CFormView|16 Как запретить появление полос прокруток на CFormView, когда пользователь делает размер главного окна меньше размера окна CFormView&nbsp;?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BD%D0%B0%D1%80%D0%B8%D1%81%D0%BE%D0%B2%D0%B0%D1%82%D1%8C_%D0%BF%D1%80%D1%8F%D0%BC%D0%BE%D1%83%D0%B3%D0%BE%D0%BB%D1%8C%D0%BD%D0%B8%D0%BA_%D1%81_%D0%B2%D0%B5%D1%80%D1%82%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%BC_%D1%86%D0%B2%D0%B5%D1%82%D0%BE%D0%B2%D1%8B%D0%BC_%D0%B3%D1%80%D0%B0%D0%B4%D0%B8%D0%B5%D0%BD%D1%82%D0%BE%D0%BC|17 Как нарисовать прямоугольник с вертикальным цветовым градиентом?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BF%D0%BE%D0%B4_Windows_%D0%BE%D1%82%D1%81%D0%BB%D0%B5%D0%B6%D0%B8%D0%B2%D0%B0%D1%82%D1%8C_%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D1%84%D0%B0%D0%B9%D0%BB%D0%B0|18 Как под Windows отслеживать изменение файла?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%95%D1%81%D1%82%D1%8C_%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2_char%2C_%D0%BA%D0%B0%D0%BA_%D0%BA%D0%BE%D0%BD%D0%B2%D0%B5%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C_%D0%B5%D0%B3%D0%BE_%D0%B2_CString|19 Есть массив char, как конвертировать его в CString?]]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D1%80%D0%B5%D0%B7%D0%B5%D1%80%D0%B2%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C_%D0%B2_CString_%D0%B1%D1%83%D1%84%D0%B5%D1%80_%D0%BD%D1%83%D0%B6%D0%BD%D0%BE%D0%B9_%D0%B4%D0%BB%D0%B8%D0%BD%D1%8B|20 Как зарезервировать в CString буфер нужной длины?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BF%D0%B5%D1%80%D0%B5%D0%B4%D0%B0%D1%82%D1%8C_%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B5_%D0%BE%D0%B4%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80_%D0%B2_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D0%B4%D1%83%D1%80%D1%83_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0|21 Как передать больше одного параметр в процедуру потока?]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D1%83%D0%B1%D1%80%D0%B0%D1%82%D1%8C_%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%BE%D0%B5_%D0%BC%D0%B5%D0%BD%D1%8E_%D0%B8%D0%B7_CMainFrame|22 Как убрать главное меню из CMainFrame?]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D1%8E%D1%89%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0_%D0%BC%D0%BE%D0%B6%D0%B5%D1%82_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C%2C_%D1%87%D1%82%D0%BE_%D1%8E%D0%B7%D0%B5%D1%80_%D0%B7%D0%B0%D0%B2%D0%B5%D1%80%D1%88%D0%B0%D0%B5%D1%82_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%83_Windows|23 Как работающая программа может определить, что юзер завершает работу Windows?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C_%D0%B2%D1%81%D0%BF%D0%BB%D1%8B%D0%B2%D0%B0%D1%8E%D1%89%D1%83%D1%8E_%D0%BF%D0%BE%D0%B4%D1%81%D0%BA%D0%B0%D0%B7%D0%BA%D1%83_%D0%B4%D0%BB%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B0_CWnd_%D0%B8_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%BE%D0%B2%2C_%D0%BE%D1%82_%D0%BD%D0%B5%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B8%D0%B7%D0%B2%D0%BE%D0%B4%D0%BD%D1%8B%D1%85|24 Как сделать всплывающую подсказку для класса CWnd и классов, от него производных?]]<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B2_%D0%BE%D1%82%D0%BB%D0%B0%D0%B4%D1%87%D0%B8%D0%BA%D0%B5_V%D0%A1_%D0%BF%D1%80%D0%BE%D1%81%D0%BC%D0%BE%D1%82%D1%80%D0%B5%D1%82%D1%8C_%D1%81%D0%BE%D0%B4%D0%B5%D1%80%D0%B6%D0%B8%D0%BC%D0%BE%D0%B5_std::vector-string-_V|25 Как в отладчике VС просмотреть содержимое std::vector-string- V]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%AF_%D0%B2%D1%8B%D0%B2%D0%BE%D0%B6%D1%83_%D0%BD%D0%B0_%D0%BA%D0%BE%D0%BD%D1%82%D0%B5%D0%BA%D1%81%D1%82_%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1%81%D1%82%D0%B2%D0%B0_%D1%82%D0%B5%D0%BA%D1%81%D1%82._%D0%9A%D0%B0%D0%BA_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C_%D0%B2_%D0%BF%D0%B8%D0%BA%D1%81%D0%B5%D0%BB%D0%B0%D1%85_%D1%88%D0%B8%D1%80%D0%B8%D0%BD%D1%83_%D0%B8_%D0%B2%D1%8B%D1%81%D0%BE%D1%82%D1%83_%D0%B2%D1%8B%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D1%81%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB%D0%BE%D0%B2_%D1%82%D0%B5%D0%BA%D1%81%D1%82%D0%B0|26 Я вывожу на контекст устройства текст. Как определить в пикселах ширину и высоту выведенных символов текста?]]<br />
<br />
<br><br />
<br />
<br><br />
<br />
----<br />
<br />
=== где найти описание nmake для VC++6? ===<br />
<br />
В MSDN http://msdn.microsoft.com/library/en-us/vcug98/html/_asug_overview.3a_.nmake_reference.asp <br />
<br />
=== Каким образом можно установить значение переменной для вызывающего процесса/потока из своей собственной DLL? Проблема заключается в том, что несмотря на то, что все линкуется нормально, значение переменной процесса не изменяется, когда я его устанавливаю вручную в библиотеке. ===<br />
<br />
Проблема вызвана тем, что каждая влинкованная libc (одна линкуется в исполняемый файл, ещё одна в dll) содержит свою копию переменной. <br />
<br />
1) Можно воспользоваться динамически подгружаемой библиотекой С runtime. Для этого приложение и dll надо компилировать с ключом /MD (или MDd для отладки). В таком случае переменная будет общей для приложения и dll. <br />
<br />
2) Можно в основном модуле программы (тот, который станет .exe) сделать "дырку" (backdoor), через которую присваивать переменной (int errno) значение: <br />
<pre>__declspec(dllexport) void set_errno(int code)<br />
{<br />
errno = code;<br />
}<br />
</pre><br />
В dll при подключении к процессу надо извлечь из модуля программы указатель на эту функцию. <br />
<pre> typedef void (*SETINT)(int);<br />
SETINT g_set_errno=0;<br />
void set_errno_in_exe(int code)<br />
{<br />
if(g_set_errno) g_set_errno(code);<br />
}<br />
<br />
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )<br />
{<br />
HANDLE hModule; // Handle to the main module<br />
if(fdwReason == DLL_PROCESS_ATTACH )<br />
{<br />
hModule = GetModuleHandle(NULL);<br />
if (hModule == NULL) return FALSE;<br />
g_set_errno = (SETINT) GetProcAddress(hModule, "set_errno");<br />
}<br />
return TRUE;<br />
}<br />
</pre><br />
В нужном месте в dll вместо присваивания errno нужно вызывать внешнюю функцию <br />
<pre>void inside_dll_func()<br />
{<br />
...<br />
...<br />
set_errno_in_exe(ERROR_CODE);<br />
...<br />
}<br />
</pre><br />
=== Как закрасить фон окна CWnd? ===<br />
<br />
Нужно добавить обработчик сообщения WM_CTLCOLOR <br />
<pre>class CMyDialog&nbsp;: public CDialog<br />
{<br />
//<br />
CBrush m_back_brush;<br />
...<br />
...<br />
};<br />
<br />
//конструктор<br />
CMyDialog::CMyDialog(): CDialog(CMyDialog::IDD)<br />
{<br />
//создаём кисть фона<br />
m_back_brush.CreateSolidBrush(RGB(192,186,207));<br />
}<br />
</pre><pre>HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
switch(nCtlColor)<br />
{<br />
//CStatic-контрол<br />
case WM_CTLCOLORSTATIC:<br />
{<br />
//у статиков делаем прозрачный фон<br />
pDC-&gt;SetBkMode(TRANSPARENT);<br />
//и красный цвет текста<br />
pDC-&gt;SetTextColor(RGB(255,0,0));<br />
<br />
//надо же что-то вернуть&nbsp;:)<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
//диалог<br />
case WM_CTLCOLORDLG:<br />
{<br />
//возвращаем хендл кисти нужного фона<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
}<br />
<br />
//фон по умолчанию<br />
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br />
}<br />
<br />
</pre><br />
=== Как определить , что курсор мыши вышел за границу окна? ===<br />
<br />
1) Использовать функцию _TrackMouseEvent. Например, есть класс MyST <br />
<pre>class MyST&nbsp;: public CStatic<br />
{<br />
bool m_bTrackingNow;<br />
...<br />
...<br />
};<br />
<br />
//в конструкторе<br />
MyST:MyST()<br />
{<br />
m_bTrackingNow=false;<br />
}<br />
<br />
//в обработчике OnMouseMove запускаем отслеживание<br />
void MyST::OnMouseMove(UINT nFlags, CPoint point)<br />
{<br />
if(!m_bTrackingNow)<br />
{<br />
m_bTrackingNow=true;<br />
TRACKMOUSEEVENT tme;<br />
tme.cbSize=sizeof(tme);<br />
tme.dwFlags=TME_LEAVE;//отслеживаем выход курсора<br />
tme.hwndTrack = m_hWnd;//из этого окна<br />
<br />
::_TrackMouseEvent(&amp;tme);//"запуск" отслеживания<br />
//при выходе курсора за границу окна будет<br />
//будет сгенерировано сообщение WM_MOUSELEAVE<br />
}<br />
...<br />
...<br />
CStatic::OnMouseMove(nFlags,point);<br />
}<br />
<br />
//ловим сообщение WM_MOUSELEAVE, для этого<br />
//переопределяем виртуальную PreTranslateMessage()<br />
BOOL MyST::PreTranslateMessage(MSG* pMsg)<br />
{<br />
if(pMsg-&gt;message==WM_MOUSELEAVE)<br />
{<br />
//тут обрабатываем<br />
...<br />
...<br />
m_bTrackingNow=false;<br />
}<br />
...<br />
...<br />
return CStatic::PreTranslateMessage(pMsg);<br />
}<br />
</pre><br />
2) Для случая, когда надо регулировать время "реакции" на выход за границу <br />
<pre>enum<br />
{<br />
def_TrackTimer_ID = 1000, //ID таймера<br />
def_TrackTimer_value = 50, //миллисекунд<br />
};<br />
<br />
MyST::MyST()<br />
{<br />
m_bTrackingNow=false;<br />
}<br />
<br />
//в обработчике OnMouseMove запускаем таймер<br />
void MyST::OnMouseMove(UINT nFlags, CPoint point)<br />
{<br />
//перезапуск таймера<br />
SetTimer(def_TrackTimer_ID,def_TrackTimer_value,0);<br />
m_bTrackingNow=true;<br />
...<br />
...<br />
CStatic::OnMouseMove(nFlags,point);<br />
}<br />
<br />
void MyST::OnTimer(UINT nIDEvent)<br />
{<br />
if(nIDEvent==def_TrackTimer_ID)<br />
{<br />
KillTimer(def_TrackTimer_ID);//таймер гасит сам себя<br />
//смотрим, где курсор<br />
POINT pnt;<br />
if(GetCursorPos(&amp;pnt))<br />
{<br />
if(WindowFromPoint(pnt)!=this)<br />
{<br />
m_bTrackingNow=false;//вышли за окно<br />
}<br />
}<br />
}<br />
CStatic::OnTimer(nIDEvent);<br />
}<br />
</pre><br />
=== Когда размещаю компонент RichEdit на форму, программа запускается и тут же закрывается. Что здесь не так? ===<br />
<br />
Необходимо до начала использования контрола инициализировать работу с классом: <br />
<br />
для RichEdit необходимо вызвать функцию AfxInitRichEdit(), для RichEdit2 - AfxInitRichEdit2(). <br />
<br />
Вызывать надо в InitInstance() приложения (в случае для MFC). <br />
<br />
=== Как сделать обработчик сообщения для нескольких контролов сразу? ===<br />
<br />
Если без помощи визарда, то переопределить виртуальную OnCommand() <br />
<pre>BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam) <br />
{<br />
WORD wMess=(wParam&gt;&gt;16);//командное сообщение<br />
int nID=(int)(wParam &amp;0x0000ffff));//ID контрола<br />
HWND hW=(HWND)lParam;//хендл контрола<br />
<br />
//смотрим, какой контрол<br />
switch(nID)<br />
{<br />
//кнопки<br />
case ID_BN1:<br />
case ID_BN2:<br />
case ID_BN3:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case BN_CLICKED:{ ... }break;<br />
}<br />
}<br />
break;<br />
<br />
//едиты<br />
case ID_ED1:<br />
case ID_ED2:<br />
case ID_ED3:<br />
case ID_ED4:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case EN_CHANGE:{ ... }break;<br />
case EN_KILLFOCUS:{ ... }break;<br />
}<br />
}<br />
break;<br />
}<br />
<br />
return CDialog::OnCommand(wParam, lParam);<br />
}<br />
</pre><br />
=== Когда запускаю программу, то все надписи на русском языке теряются - показываются вопросики. Что делать? ===<br />
<br />
Лечится так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются. <br />
<br />
=== Как в проекте VC6 MFC получить путь, откуда запущен ЕХЕ? ===<br />
<br />
Использовать GetModuleFileName(): <br />
<pre> TCHAR pszFileName[MAX_PATH];<br />
pszFileName[0]=0;<br />
GetModuleFileName(NULL, pszFileName, MAX_PATH);<br />
CString stModulePath = pszFileName;<br />
//ищем первый слеш с конца и удаляем<br />
//его вместе с именем файла EXE<br />
int nEnd = stModulePath.ReverseFind('\\');<br />
stModulePath.Delete(nEnd, stModulePath.GetLength()-nEnd);<br />
<br />
//stModulePath - содержит путь<br />
</pre><br />
=== Как получить доступ к контролам на панели CReBar, принадлежащей классу MainFrame? ===<br />
<pre>#include "MainFrm.h"<br />
<br />
//CMyApp - класс вашего приложения. theApp - глобальная переменная,<br />
//поэтому для доступа к ней используем extern<br />
extern CMyApp theApp;<br />
<br />
void CMyView::F()<br />
{<br />
//Получаем главное окно приложения в любом месте программы<br />
CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);<br />
pMainFrame-&gt;m_wndDlgBar ....//Делаем что хотим<br />
...<br />
}<br />
</pre><br />
=== Как загрузить и показать один из стандартных курсоров? ===<br />
<pre>HCURSOR hCursor;<br />
hCursor=AfxGetApp()-&gt;LoadStandardCursor(IDC_UPARROW);<br />
if(hCursor)SetCursor(hCursor);<br />
</pre><br />
идентификаторы стандартных курсоров: IDC_ARROW IDC_IBEAM IDC_WAIT IDC_CROSS IDC_UPARROW IDC_SIZENWSE IDC_SIZENESW IDC_SIZEWE IDC_SIZENS IDC_SIZEALL <br />
<br />
=== Как запретить пользователю закрыть программу нажатием на крестик? ===<br />
<br />
Нужно добавить обработчик сообщений WM_CLOSE - OnClose() - в главное окно программы. Для диалоговых приложений - это главный диалог, для одно- и много-документных - это CMainFrame. <br />
<pre>void CMainFrame::OnClose()<br />
{<br />
if(......)<br />
{<br />
//не разрешаем закрыть<br />
return;<br />
}<br />
<br />
CFrameWnd::OnClose();<br />
}<br />
</pre><br />
=== Как создать на диалоге группу RadioButton-ов и как задать порядок их обхода клавишей Tab? ===<br />
<br />
Кладём на форму N контролов RadioButton. Затем у первого из группы ставим свойство Group, у остальных в группе - убираем это свойство. Порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется. <br />
<br />
=== Где лучше устанавливать начальные значения CComboBox? ===<br />
<br />
1) В визарде (новая строка данных - Ctrl+Enter) <br />
<br />
2) В функции OnInitDialog (для диалога) или OnInitialUpdate (для CView) <br />
<br />
=== Как перевести RichEdit в режим замены символов? ===<br />
<br />
1) Программно, зная хендл контрола (hWnd): <br />
<br />
::PostMessage(hWnd,WM_KEYDOWN,VK_INSERT,1);<br />
<br />
2) Пользователь может нажать Insert. <br />
<br />
=== Как вызвать метод класса CMainFrame (главное окно) из любого места программы? ===<br />
<br />
AfxGetApp()-&gt;m_pMainWnd-&gt; ...&nbsp;; <br />
<br />
=== Как запретить появление полос прокруток на CFormView, когда пользователь делает размер главного окна меньше размера окна CFormView&nbsp;? ===<br />
<br />
методом SetScaleToFitSize(): <br />
<pre>void CMyView::OnInitialUpdate()<br />
{<br />
CFormView::OnInitialUpdate();<br />
/////////<br />
GetParentFrame()-&gt;RecalcLayout();<br />
ResizeParentToFit();<br />
SIZE s={0,0};<br />
SetScaleToFitSize(s);<br />
/////////<br />
...<br />
...<br />
}<br />
</pre><br />
=== Как нарисовать прямоугольник с вертикальным цветовым градиентом? ===<br />
<br />
pdc - указатель на контекст устройства pSize - указатель на структуру SIZE с размером прямоугольника dwdColor1, dwdColor2 - начальный и конечный цвет bySteps - количество шагов градиента (1...255) <br />
<pre>//вертикальный градиент<br />
void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps)<br />
{<br />
if(!bySteps)bySteps=1;<br />
WORD i;<br />
<br />
long W,H,x1,x2;<br />
BYTE R1,G1,B1,R2,G2,B2;<br />
float dh,dR,dG,dB,y1,y2,Rc,Gc,Bc;<br />
<br />
//ширина и высота<br />
W=pSize-&gt;cx;<br />
H=pSize-&gt;cy;<br />
<br />
//раскладываем цвета на их составляющие<br />
R1=(BYTE)((dwdColor1&amp;0x000000ff));<br />
G1=(BYTE)((dwdColor1&amp;0x0000ff00)&gt;&gt;8);<br />
B1=(BYTE)((dwdColor1&amp;0x00ff0000)&gt;&gt;16);<br />
R2=(BYTE)((dwdColor2&amp;0x000000ff));<br />
G2=(BYTE)((dwdColor2&amp;0x0000ff00)&gt;&gt;8);<br />
B2=(BYTE)((dwdColor2&amp;0x00ff0000)&gt;&gt;16);<br />
<br />
//высота разноцветных прямоугольников<br />
dh=((float)H)/((float)bySteps);<br />
//величина шагов составляющих цветов<br />
dR=(((float)R2)-((float)R1))/((float)bySteps);<br />
dG=(((float)G2)-((float)G1))/((float)bySteps);<br />
dB=(((float)B2)-((float)B1))/((float)bySteps);<br />
//выводим прямоугольники<br />
x1=0;x2=W;y1=0;y2=dh;<br />
Rc=R1;Gc=G1;Bc=B1;<br />
for(i=0;i&lt;bySteps;i++)<br />
{<br />
//текущий цвет<br />
pdc-&gt;FillSolidRect(x1,(int)y1,x2-x1,(int)(y2-y1),RGB((BYTE)Rc,(BYTE)Gc,(BYTE)Bc));<br />
//следующий цвет и координаты<br />
y1+=dh;y2+=dh;<br />
Rc+=dR;Gc+=dG;Bc+=dB;<br />
}<br />
}<br />
</pre><br />
пример вызова: <br />
<pre> SIZE Size={100,100};<br />
sFillGradientRect(&amp;dc,&amp;Size, RGB(200,0,0), RGB(0,200,0),10);<br />
</pre><br />
=== Как под Windows отслеживать изменение файла? ===<br />
<br />
Использовать функции: <br />
<br />
FindFirstChangeNotification<br />
FindNextChangeNotification<br />
FindCloseChangeNotification<br />
<br />
=== Есть массив char[], как конвертировать его в CString? ===<br />
<pre> char buf[]="text";<br />
<br />
//строка должна обязательно заканчиваться нулём.<br />
<br />
//конвертируем так<br />
CString txt(buf);<br />
<br />
//или так<br />
CString txt;<br />
txt=buf;<br />
</pre><br />
=== Как зарезервировать в CString буфер нужной длины? ===<br />
<br />
при помощи методов класса: <br />
<br />
CString::GetBuffer<br />
и<br />
CString::GetBufferSetLength<br />
<br />
Разница между CString::GetBuffer(nLen) и CString::GetBufferSetLength(nLen) в том, что первый возвращает строку не меньше заданной длины, а второй возвращает строку точно равную заданной длине. Обе могут перераспределять память если надо. В обычных случаях лучше GetBuffer. <br />
<br />
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем. <br />
<br />
=== Как передать больше одного параметр в процедуру потока? ===<br />
<br />
Определить структуру с указателями на всё любое, например: <br />
<pre>struct mystr<br />
{<br />
CEdit* pEd;<br />
CDialog* pDlg;<br />
DWORD* pdwd;<br />
int *pn;<br />
};<br />
</pre><br />
запуск потока: <br />
<pre>mystr *pparam=new mystr;//экземпляр не должен быть временным!!!<br />
memset(pparam,0,sizeof(*pparam));<br />
pparam-&gt;pEd=...;<br />
pparam-&gt;pdwd=...;<br />
<br />
::AfxBeginThread(thread,pparam); <br />
//тут экземпляр *(pparam) уже нельзя использовать!!!<br />
//он удалиться в потоке<br />
</pre><br />
в потоке: <br />
<pre>//поток: <br />
UINT threadLoader(LPVOID pParam) <br />
{ <br />
mystr data=*((mystr*)pParam);<br />
delete ((mystr*)pParam);//подчищаем память<br />
<br />
...<br />
data.pDlg-&gt;...;<br />
(*data.pdwd)=...;<br />
...<br />
}<br />
</pre><br />
=== Как убрать главное меню из CMainFrame? ===<br />
<pre>BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&amp; cs)<br />
{<br />
//обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow<br />
cs.hMenu = 0;<br />
<br />
if(&nbsp;!CFrameWnd::PreCreateWindow(cs) )<br />
return FALSE;<br />
...<br />
...<br />
}<br />
</pre><br />
=== Как работающая программа может определить, что юзер завершает работу Windows? ===<br />
<br />
В этот момент всем процессам посылается сообщение WM_QUERYENDSESSION - его и нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу. <br />
<br />
=== Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ===<br />
<br />
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для контролов. (для CStatic контролов не забудьте поставить свойство Notify) <br />
<pre>class CMyDlg:puplic CDialog<br />
{<br />
CToolTipCtrl m_ToolTip;//мембер класса CMyDlg<br />
//<br />
};<br />
<br />
//массив, в котором перечислены идентификаторы<br />
//контролов и тексты подсказок к ним<br />
struct{int ID;const char* pch;} m_a_Tips[]=<br />
{<br />
{IDC_BUTTON1,"КЫнопка"},<br />
{IDC_STATIC1,"Текст"},<br />
//<br />
{0,0},//признак конца массива<br />
};<br />
<br />
//в инициализации диалога (хотя, в принципе,<br />
//можно и не тут) создаём и привязываем подсказки<br />
BOOL CMyDlg::OnInitDialog() <br />
{<br />
CDialog::OnInitDialog();<br />
//<br />
//создаём<br />
m_ToolTip.Create(this);<br />
//Привязка подсказок<br />
for(int i=0; m_a_Tips[i].ID; i++)<br />
{<br />
m_ToolTip.AddTool(<br />
GetDlgItem(m_a_Tips[i].ID),<br />
m_a_Tips[i].pch);<br />
}<br />
<br />
//включаем показ подсказок<br />
m_ToolTip.Activate(1);<br />
...<br />
...<br />
}<br />
<br />
//для того, чтобы подсказки отображались как реакция на движение<br />
//курсора мыши, транслируем получаемые окнами сообщения в<br />
//виртуальной PreTranslateMessage()<br />
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) <br />
{<br />
//транслируем<br />
if(m_ToolTip.m_hWnd)m_ToolTip.RelayEvent(pMsg);<br />
<br />
...<br />
...<br />
return CDialog::PreTranslateMessage(pMsg);<br />
}<br />
</pre><br />
=== Как в отладчике VС просмотреть содержимое std::vector&lt;string&gt; V ===<br />
<br />
В режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения: <br />
<br />
V._Myfirst - будет показан первый элемент V._Myfirst+1 - второй V._Myfirst+2 - и т.д. <br />
<br />
=== Я вывожу на контекст устройства текст. Как определить в пикселах ширину и высоту выведенных символов текста? ===<br />
<br />
использовать процедуру API: <br />
<pre>BOOL GetTextExtentPoint32(<br />
HDC hdc,// хендл контекста<br />
LPCTSTR lpString,// выводимая строка<br />
int cbString,// длина строки в символах<br />
LPSIZE lpSize// указатель на структуру SIZE, куда <br />
//будут помещены размеры<br />
);<br />
</pre><br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_2&diff=527FAQ:WinAPI, VCPP Part 22008-10-03T19:48:48Z<p>Алексей1153++: </p>
<hr />
<div><br><br />
<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%B3%D0%B4%D0%B5_%D0%BD%D0%B0%D0%B9%D1%82%D0%B8_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5_nmake_%D0%B4%D0%BB%D1%8F_VC%2B%2B6|1 где найти описание nmake для VC++6?]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%B4%D0%BB%D1%8F_%D0%B2%D1%8B%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%D0%B0/%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B8%D0%B7_%D1%81%D0%B2%D0%BE%D0%B5%D0%B9_%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_DLL|2 значение переменной для вызывающего процесса/потока из своей собственной DLL]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D1%82%D1%8C_%D1%84%D0%BE%D0%BD_%D0%BE%D0%BA%D0%BD%D0%B0_CWnd|3 Как закрасить фон окна CWnd?]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C_%2C_%D1%87%D1%82%D0%BE_%D0%BA%D1%83%D1%80%D1%81%D0%BE%D1%80_%D0%BC%D1%8B%D1%88%D0%B8_%D0%B2%D1%8B%D1%88%D0%B5%D0%BB_%D0%B7%D0%B0_%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D1%83_%D0%BE%D0%BA%D0%BD%D0%B0|4 Как определить , что курсор мыши вышел за границу окна?]<br />
#[http://wiki.shelek.ru/index.php/FAQ:%D0%9A%D0%BE%D0%B3%D0%B4%D0%B0_%D1%80%D0%B0%D0%B7%D0%BC%D0%B5%D1%89%D0%B0%D1%8E_%D0%BA%D0%BE%D0%BC%D0%BF%D0%BE%D0%BD%D0%B5%D0%BD%D1%82_RichEdit_%D0%BD%D0%B0_%D1%84%D0%BE%D1%80%D0%BC%D1%83%2C_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0_%D0%B7%D0%B0%D0%BF%D1%83%D1%81%D0%BA%D0%B0%D0%B5%D1%82%D1%81%D1%8F_%D0%B8_%D1%82%D1%83%D1%82_%D0%B6%D0%B5_%D0%B7%D0%B0%D0%BA%D1%80%D1%8B%D0%B2%D0%B0%D0%B5%D1%82%D1%81%D1%8F|5 Когда размещаю компонент RichEdit на форму, программа запускается и тут же закрывается. Что здесь не так? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%BE%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA_%D1%81%D0%BE%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B4%D0%BB%D1%8F_%D0%BD%D0%B5%D1%81%D0%BA%D0%BE%D0%BB%D1%8C%D0%BA%D0%B8%D1%85_%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BE%D0%B2_%D1%81%D1%80%D0%B0%D0%B7%D1%83|6 Как сделать обработчик сообщения для нескольких контролов сразу?]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%B2%D1%81%D0%B5_%D0%BD%D0%B0%D0%B4%D0%BF%D0%B8%D1%81%D0%B8_%D0%BD%D0%B0_%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D0%BC_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B5_%D1%82%D0%B5%D1%80%D1%8F%D1%8E%D1%82%D1%81%D1%8F_-_%D0%BF%D0%BE%D0%BA%D0%B0%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%82%D1%81%D1%8F_%D0%B2%D0%BE%D0%BF%D1%80%D0%BE%D1%81%D0%B8%D0%BA%D0%B8|7 Когда запускаю программу, то все надписи на русском языке теряются - показываются вопросики. Что делать? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B2_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B5_VC6_MFC_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C_%D0%BF%D1%83%D1%82%D1%8C%2C_%D0%BE%D1%82%D0%BA%D1%83%D0%B4%D0%B0_%D0%B7%D0%B0%D0%BF%D1%83%D1%89%D0%B5%D0%BD_%D0%95%D0%A5%D0%95|8 Как в проекте VC6 MFC получить путь, откуда запущен ЕХЕ? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C_%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF_%D0%BA_%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%B0%D0%BC_%D0%BD%D0%B0_%D0%BF%D0%B0%D0%BD%D0%B5%D0%BB%D0%B8_CReBar%2C_%D0%BF%D1%80%D0%B8%D0%BD%D0%B0%D0%B4%D0%BB%D0%B5%D0%B6%D0%B0%D1%89%D0%B5%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D1%83_MainFrame|9 Как получить доступ к контролам на панели CReBar, принадлежащей классу MainFrame? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%B8%D1%82%D1%8C_%D0%B8_%D0%BF%D0%BE%D0%BA%D0%B0%D0%B7%D0%B0%D1%82%D1%8C_%D0%BE%D0%B4%D0%B8%D0%BD_%D0%B8%D0%B7_%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D1%85_%D0%BA%D1%83%D1%80%D1%81%D0%BE%D1%80%D0%BE%D0%B2|10 Как загрузить и показать один из стандартных курсоров? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D0%BF%D1%80%D0%B5%D1%82%D0%B8%D1%82%D1%8C_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8E_%D0%B7%D0%B0%D0%BA%D1%80%D1%8B%D1%82%D1%8C_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D1%83_%D0%BD%D0%B0%D0%B6%D0%B0%D1%82%D0%B8%D0%B5%D0%BC_%D0%BD%D0%B0_%D0%BA%D1%80%D0%B5%D1%81%D1%82%D0%B8%D0%BA|11 Как запретить пользователю закрыть программу нажатием на крестик? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D1%8C_%D0%BD%D0%B0_%D0%B4%D0%B8%D0%B0%D0%BB%D0%BE%D0%B3%D0%B5_%D0%B3%D1%80%D1%83%D0%BF%D0%BF%D1%83_RadioButton-%D0%BE%D0%B2_%D0%B8_%D0%BA%D0%B0%D0%BA_%D0%B7%D0%B0%D0%B4%D0%B0%D1%82%D1%8C_%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D0%BA_%D0%B8%D1%85_%D0%BE%D0%B1%D1%85%D0%BE%D0%B4%D0%B0_%D0%BA%D0%BB%D0%B0%D0%B2%D0%B8%D1%88%D0%B5%D0%B9_Tab|12 Как создать на диалоге группу RadioButton-ов и как задать порядок их обхода клавишей Tab? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%93%D0%B4%D0%B5_%D0%BB%D1%83%D1%87%D1%88%D0%B5_%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%B0%D0%B2%D0%BB%D0%B8%D0%B2%D0%B0%D1%82%D1%8C_%D0%BD%D0%B0%D1%87%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B5_%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_CComboBox|13 Где лучше устанавливать начальные значения CComboBox? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BF%D0%B5%D1%80%D0%B5%D0%B2%D0%B5%D1%81%D1%82%D0%B8_RichEdit_%D0%B2_%D1%80%D0%B5%D0%B6%D0%B8%D0%BC_%D0%B7%D0%B0%D0%BC%D0%B5%D0%BD%D1%8B_%D1%81%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB%D0%BE%D0%B2|14 Как перевести RichEdit в режим замены символов? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B2%D1%8B%D0%B7%D0%B2%D0%B0%D1%82%D1%8C_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B0_CMainFrame_%28%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%BE%D0%B5_%D0%BE%D0%BA%D0%BD%D0%BE%29_%D0%B8%D0%B7_%D0%BB%D1%8E%D0%B1%D0%BE%D0%B3%D0%BE_%D0%BC%D0%B5%D1%81%D1%82%D0%B0_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D1%8B|15 Как вызвать метод класса CMainFrame (главное окно) из любого места программы? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D0%BF%D1%80%D0%B5%D1%82%D0%B8%D1%82%D1%8C_%D0%BF%D0%BE%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%BB%D0%BE%D1%81_%D0%BF%D1%80%D0%BE%D0%BA%D1%80%D1%83%D1%82%D0%BE%D0%BA_%D0%BD%D0%B0_CFormView%2C_%D0%BA%D0%BE%D0%B3%D0%B4%D0%B0_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C_%D0%B4%D0%B5%D0%BB%D0%B0%D0%B5%D1%82_%D1%80%D0%B0%D0%B7%D0%BC%D0%B5%D1%80_%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%BA%D0%BD%D0%B0_%D0%BC%D0%B5%D0%BD%D1%8C%D1%88%D0%B5_%D1%80%D0%B0%D0%B7%D0%BC%D0%B5%D1%80%D0%B0_%D0%BE%D0%BA%D0%BD%D0%B0_CFormView|16 Как запретить появление полос прокруток на CFormView, когда пользователь делает размер главного окна меньше размера окна CFormView ? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BD%D0%B0%D1%80%D0%B8%D1%81%D0%BE%D0%B2%D0%B0%D1%82%D1%8C_%D0%BF%D1%80%D1%8F%D0%BC%D0%BE%D1%83%D0%B3%D0%BE%D0%BB%D1%8C%D0%BD%D0%B8%D0%BA_%D1%81_%D0%B2%D0%B5%D1%80%D1%82%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%BC_%D1%86%D0%B2%D0%B5%D1%82%D0%BE%D0%B2%D1%8B%D0%BC_%D0%B3%D1%80%D0%B0%D0%B4%D0%B8%D0%B5%D0%BD%D1%82%D0%BE%D0%BC|17 Как нарисовать прямоугольник с вертикальным цветовым градиентом? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BF%D0%BE%D0%B4_Windows_%D0%BE%D1%82%D1%81%D0%BB%D0%B5%D0%B6%D0%B8%D0%B2%D0%B0%D1%82%D1%8C_%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D1%84%D0%B0%D0%B9%D0%BB%D0%B0|18 Как под Windows отслеживать изменение файла? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%95%D1%81%D1%82%D1%8C_%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2_char%2C_%D0%BA%D0%B0%D0%BA_%D0%BA%D0%BE%D0%BD%D0%B2%D0%B5%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C_%D0%B5%D0%B3%D0%BE_%D0%B2_CString|19 Есть массив char, как конвертировать его в CString? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D1%80%D0%B5%D0%B7%D0%B5%D1%80%D0%B2%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C_%D0%B2_CString_%D0%B1%D1%83%D1%84%D0%B5%D1%80_%D0%BD%D1%83%D0%B6%D0%BD%D0%BE%D0%B9_%D0%B4%D0%BB%D0%B8%D0%BD%D1%8B|20 Как зарезервировать в CString буфер нужной длины? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BF%D0%B5%D1%80%D0%B5%D0%B4%D0%B0%D1%82%D1%8C_%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B5_%D0%BE%D0%B4%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80_%D0%B2_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D0%B4%D1%83%D1%80%D1%83_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0|21 Как передать больше одного параметр в процедуру потока?]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D1%83%D0%B1%D1%80%D0%B0%D1%82%D1%8C_%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%BE%D0%B5_%D0%BC%D0%B5%D0%BD%D1%8E_%D0%B8%D0%B7_CMainFrame|22 Как убрать главное меню из CMainFrame?]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D1%8E%D1%89%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0_%D0%BC%D0%BE%D0%B6%D0%B5%D1%82_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C%2C_%D1%87%D1%82%D0%BE_%D1%8E%D0%B7%D0%B5%D1%80_%D0%B7%D0%B0%D0%B2%D0%B5%D1%80%D1%88%D0%B0%D0%B5%D1%82_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%83_Windows|23 Как работающая программа может определить, что юзер завершает работу Windows? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C_%D0%B2%D1%81%D0%BF%D0%BB%D1%8B%D0%B2%D0%B0%D1%8E%D1%89%D1%83%D1%8E_%D0%BF%D0%BE%D0%B4%D1%81%D0%BA%D0%B0%D0%B7%D0%BA%D1%83_%D0%B4%D0%BB%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B0_CWnd_%D0%B8_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%BE%D0%B2%2C_%D0%BE%D1%82_%D0%BD%D0%B5%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B8%D0%B7%D0%B2%D0%BE%D0%B4%D0%BD%D1%8B%D1%85|24 Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B2_%D0%BE%D1%82%D0%BB%D0%B0%D0%B4%D1%87%D0%B8%D0%BA%D0%B5_V%D0%A1_%D0%BF%D1%80%D0%BE%D1%81%D0%BC%D0%BE%D1%82%D1%80%D0%B5%D1%82%D1%8C_%D1%81%D0%BE%D0%B4%D0%B5%D1%80%D0%B6%D0%B8%D0%BC%D0%BE%D0%B5_std::vector-string-_V|25 Как в отладчике VС просмотреть содержимое std::vector-string- V]<br />
#[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%AF_%D0%B2%D1%8B%D0%B2%D0%BE%D0%B6%D1%83_%D0%BD%D0%B0_%D0%BA%D0%BE%D0%BD%D1%82%D0%B5%D0%BA%D1%81%D1%82_%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1%81%D1%82%D0%B2%D0%B0_%D1%82%D0%B5%D0%BA%D1%81%D1%82._%D0%9A%D0%B0%D0%BA_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C_%D0%B2_%D0%BF%D0%B8%D0%BA%D1%81%D0%B5%D0%BB%D0%B0%D1%85_%D1%88%D0%B8%D1%80%D0%B8%D0%BD%D1%83_%D0%B8_%D0%B2%D1%8B%D1%81%D0%BE%D1%82%D1%83_%D0%B2%D1%8B%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D1%81%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB%D0%BE%D0%B2_%D1%82%D0%B5%D0%BA%D1%81%D1%82%D0%B0|26 Я вывожу на контекст устройства текст. Как определить в пикселах ширину и высоту выведенных символов текста?]<br />
<br />
<br />
<br />
<br><br />
<br />
----<br />
<br />
=== где найти описание nmake для VC++6? ===<br />
<br />
В MSDN http://msdn.microsoft.com/library/en-us/vcug98/html/_asug_overview.3a_.nmake_reference.asp <br />
<br />
=== Каким образом можно установить значение переменной для вызывающего процесса/потока из своей собственной DLL? Проблема заключается в том, что несмотря на то, что все линкуется нормально, значение переменной процесса не изменяется, когда я его устанавливаю вручную в библиотеке. ===<br />
<br />
Проблема вызвана тем, что каждая влинкованная libc (одна линкуется в исполняемый файл, ещё одна в dll) содержит свою копию переменной. <br />
<br />
1) Можно воспользоваться динамически подгружаемой библиотекой С runtime. Для этого приложение и dll надо компилировать с ключом /MD (или MDd для отладки). В таком случае переменная будет общей для приложения и dll. <br />
<br />
2) Можно в основном модуле программы (тот, который станет .exe) сделать "дырку" (backdoor), через которую присваивать переменной (int errno) значение: <br />
<pre>__declspec(dllexport) void set_errno(int code)<br />
{<br />
errno = code;<br />
}<br />
</pre><br />
В dll при подключении к процессу надо извлечь из модуля программы указатель на эту функцию. <br />
<pre> typedef void (*SETINT)(int);<br />
SETINT g_set_errno=0;<br />
void set_errno_in_exe(int code)<br />
{<br />
if(g_set_errno) g_set_errno(code);<br />
}<br />
<br />
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )<br />
{<br />
HANDLE hModule; // Handle to the main module<br />
if(fdwReason == DLL_PROCESS_ATTACH )<br />
{<br />
hModule = GetModuleHandle(NULL);<br />
if (hModule == NULL) return FALSE;<br />
g_set_errno = (SETINT) GetProcAddress(hModule, "set_errno");<br />
}<br />
return TRUE;<br />
}<br />
</pre><br />
В нужном месте в dll вместо присваивания errno нужно вызывать внешнюю функцию <br />
<pre>void inside_dll_func()<br />
{<br />
...<br />
...<br />
set_errno_in_exe(ERROR_CODE);<br />
...<br />
}<br />
</pre><br />
=== Как закрасить фон окна CWnd? ===<br />
<br />
Нужно добавить обработчик сообщения WM_CTLCOLOR <br />
<pre>class CMyDialog&nbsp;: public CDialog<br />
{<br />
//<br />
CBrush m_back_brush;<br />
...<br />
...<br />
};<br />
<br />
//конструктор<br />
CMyDialog::CMyDialog(): CDialog(CMyDialog::IDD)<br />
{<br />
//создаём кисть фона<br />
m_back_brush.CreateSolidBrush(RGB(192,186,207));<br />
}<br />
</pre><pre>HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
switch(nCtlColor)<br />
{<br />
//CStatic-контрол<br />
case WM_CTLCOLORSTATIC:<br />
{<br />
//у статиков делаем прозрачный фон<br />
pDC-&gt;SetBkMode(TRANSPARENT);<br />
//и красный цвет текста<br />
pDC-&gt;SetTextColor(RGB(255,0,0));<br />
<br />
//надо же что-то вернуть&nbsp;:)<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
//диалог<br />
case WM_CTLCOLORDLG:<br />
{<br />
//возвращаем хендл кисти нужного фона<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
}<br />
<br />
//фон по умолчанию<br />
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br />
}<br />
<br />
</pre><br />
=== Как определить , что курсор мыши вышел за границу окна? ===<br />
<br />
1) Использовать функцию _TrackMouseEvent. Например, есть класс MyST <br />
<pre>class MyST&nbsp;: public CStatic<br />
{<br />
bool m_bTrackingNow;<br />
...<br />
...<br />
};<br />
<br />
//в конструкторе<br />
MyST:MyST()<br />
{<br />
m_bTrackingNow=false;<br />
}<br />
<br />
//в обработчике OnMouseMove запускаем отслеживание<br />
void MyST::OnMouseMove(UINT nFlags, CPoint point)<br />
{<br />
if(!m_bTrackingNow)<br />
{<br />
m_bTrackingNow=true;<br />
TRACKMOUSEEVENT tme;<br />
tme.cbSize=sizeof(tme);<br />
tme.dwFlags=TME_LEAVE;//отслеживаем выход курсора<br />
tme.hwndTrack = m_hWnd;//из этого окна<br />
<br />
::_TrackMouseEvent(&amp;tme);//"запуск" отслеживания<br />
//при выходе курсора за границу окна будет<br />
//будет сгенерировано сообщение WM_MOUSELEAVE<br />
}<br />
...<br />
...<br />
CStatic::OnMouseMove(nFlags,point);<br />
}<br />
<br />
//ловим сообщение WM_MOUSELEAVE, для этого<br />
//переопределяем виртуальную PreTranslateMessage()<br />
BOOL MyST::PreTranslateMessage(MSG* pMsg)<br />
{<br />
if(pMsg-&gt;message==WM_MOUSELEAVE)<br />
{<br />
//тут обрабатываем<br />
...<br />
...<br />
m_bTrackingNow=false;<br />
}<br />
...<br />
...<br />
return CStatic::PreTranslateMessage(pMsg);<br />
}<br />
</pre><br />
2) Для случая, когда надо регулировать время "реакции" на выход за границу <br />
<pre>enum<br />
{<br />
def_TrackTimer_ID = 1000, //ID таймера<br />
def_TrackTimer_value = 50, //миллисекунд<br />
};<br />
<br />
MyST::MyST()<br />
{<br />
m_bTrackingNow=false;<br />
}<br />
<br />
//в обработчике OnMouseMove запускаем таймер<br />
void MyST::OnMouseMove(UINT nFlags, CPoint point)<br />
{<br />
//перезапуск таймера<br />
SetTimer(def_TrackTimer_ID,def_TrackTimer_value,0);<br />
m_bTrackingNow=true;<br />
...<br />
...<br />
CStatic::OnMouseMove(nFlags,point);<br />
}<br />
<br />
void MyST::OnTimer(UINT nIDEvent)<br />
{<br />
if(nIDEvent==def_TrackTimer_ID)<br />
{<br />
KillTimer(def_TrackTimer_ID);//таймер гасит сам себя<br />
//смотрим, где курсор<br />
POINT pnt;<br />
if(GetCursorPos(&amp;pnt))<br />
{<br />
if(WindowFromPoint(pnt)!=this)<br />
{<br />
m_bTrackingNow=false;//вышли за окно<br />
}<br />
}<br />
}<br />
CStatic::OnTimer(nIDEvent);<br />
}<br />
</pre><br />
=== Когда размещаю компонент RichEdit на форму, программа запускается и тут же закрывается. Что здесь не так? ===<br />
<br />
Необходимо до начала использования контрола инициализировать работу с классом: <br />
<br />
для RichEdit необходимо вызвать функцию AfxInitRichEdit(), для RichEdit2 - AfxInitRichEdit2(). <br />
<br />
Вызывать надо в InitInstance() приложения (в случае для MFC). <br />
<br />
=== Как сделать обработчик сообщения для нескольких контролов сразу? ===<br />
<br />
Если без помощи визарда, то переопределить виртуальную OnCommand() <br />
<pre>BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam) <br />
{<br />
WORD wMess=(wParam&gt;&gt;16);//командное сообщение<br />
int nID=(int)(wParam &amp;0x0000ffff));//ID контрола<br />
HWND hW=(HWND)lParam;//хендл контрола<br />
<br />
//смотрим, какой контрол<br />
switch(nID)<br />
{<br />
//кнопки<br />
case ID_BN1:<br />
case ID_BN2:<br />
case ID_BN3:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case BN_CLICKED:{ ... }break;<br />
}<br />
}<br />
break;<br />
<br />
//едиты<br />
case ID_ED1:<br />
case ID_ED2:<br />
case ID_ED3:<br />
case ID_ED4:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case EN_CHANGE:{ ... }break;<br />
case EN_KILLFOCUS:{ ... }break;<br />
}<br />
}<br />
break;<br />
}<br />
<br />
return CDialog::OnCommand(wParam, lParam);<br />
}<br />
</pre><br />
=== Когда запускаю программу, то все надписи на русском языке теряются - показываются вопросики. Что делать? ===<br />
<br />
Лечится так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются. <br />
<br />
=== Как в проекте VC6 MFC получить путь, откуда запущен ЕХЕ? ===<br />
<br />
Использовать GetModuleFileName(): <br />
<pre> TCHAR pszFileName[MAX_PATH];<br />
pszFileName[0]=0;<br />
GetModuleFileName(NULL, pszFileName, MAX_PATH);<br />
CString stModulePath = pszFileName;<br />
//ищем первый слеш с конца и удаляем<br />
//его вместе с именем файла EXE<br />
int nEnd = stModulePath.ReverseFind('\\');<br />
stModulePath.Delete(nEnd, stModulePath.GetLength()-nEnd);<br />
<br />
//stModulePath - содержит путь<br />
</pre><br />
=== Как получить доступ к контролам на панели CReBar, принадлежащей классу MainFrame? ===<br />
<pre>#include "MainFrm.h"<br />
<br />
//CMyApp - класс вашего приложения. theApp - глобальная переменная,<br />
//поэтому для доступа к ней используем extern<br />
extern CMyApp theApp;<br />
<br />
void CMyView::F()<br />
{<br />
//Получаем главное окно приложения в любом месте программы<br />
CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);<br />
pMainFrame-&gt;m_wndDlgBar ....//Делаем что хотим<br />
...<br />
}<br />
</pre><br />
=== Как загрузить и показать один из стандартных курсоров? ===<br />
<pre>HCURSOR hCursor;<br />
hCursor=AfxGetApp()-&gt;LoadStandardCursor(IDC_UPARROW);<br />
if(hCursor)SetCursor(hCursor);<br />
</pre><br />
идентификаторы стандартных курсоров: IDC_ARROW IDC_IBEAM IDC_WAIT IDC_CROSS IDC_UPARROW IDC_SIZENWSE IDC_SIZENESW IDC_SIZEWE IDC_SIZENS IDC_SIZEALL <br />
<br />
=== Как запретить пользователю закрыть программу нажатием на крестик? ===<br />
<br />
Нужно добавить обработчик сообщений WM_CLOSE - OnClose() - в главное окно программы. Для диалоговых приложений - это главный диалог, для одно- и много-документных - это CMainFrame. <br />
<pre>void CMainFrame::OnClose()<br />
{<br />
if(......)<br />
{<br />
//не разрешаем закрыть<br />
return;<br />
}<br />
<br />
CFrameWnd::OnClose();<br />
}<br />
</pre><br />
=== Как создать на диалоге группу RadioButton-ов и как задать порядок их обхода клавишей Tab? ===<br />
<br />
Кладём на форму N контролов RadioButton. Затем у первого из группы ставим свойство Group, у остальных в группе - убираем это свойство. Порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется. <br />
<br />
=== Где лучше устанавливать начальные значения CComboBox? ===<br />
<br />
1) В визарде (новая строка данных - Ctrl+Enter) <br />
<br />
2) В функции OnInitDialog (для диалога) или OnInitialUpdate (для CView) <br />
<br />
=== Как перевести RichEdit в режим замены символов? ===<br />
<br />
1) Программно, зная хендл контрола (hWnd): <br />
<br />
::PostMessage(hWnd,WM_KEYDOWN,VK_INSERT,1);<br />
<br />
2) Пользователь может нажать Insert. <br />
<br />
=== Как вызвать метод класса CMainFrame (главное окно) из любого места программы? ===<br />
<br />
AfxGetApp()-&gt;m_pMainWnd-&gt; ...&nbsp;; <br />
<br />
=== Как запретить появление полос прокруток на CFormView, когда пользователь делает размер главного окна меньше размера окна CFormView&nbsp;? ===<br />
<br />
методом SetScaleToFitSize(): <br />
<pre>void CMyView::OnInitialUpdate()<br />
{<br />
CFormView::OnInitialUpdate();<br />
/////////<br />
GetParentFrame()-&gt;RecalcLayout();<br />
ResizeParentToFit();<br />
SIZE s={0,0};<br />
SetScaleToFitSize(s);<br />
/////////<br />
...<br />
...<br />
}<br />
</pre><br />
=== Как нарисовать прямоугольник с вертикальным цветовым градиентом? ===<br />
<br />
pdc - указатель на контекст устройства pSize - указатель на структуру SIZE с размером прямоугольника dwdColor1, dwdColor2 - начальный и конечный цвет bySteps - количество шагов градиента (1...255) <br />
<pre>//вертикальный градиент<br />
void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps)<br />
{<br />
if(!bySteps)bySteps=1;<br />
WORD i;<br />
<br />
long W,H,x1,x2;<br />
BYTE R1,G1,B1,R2,G2,B2;<br />
float dh,dR,dG,dB,y1,y2,Rc,Gc,Bc;<br />
<br />
//ширина и высота<br />
W=pSize-&gt;cx;<br />
H=pSize-&gt;cy;<br />
<br />
//раскладываем цвета на их составляющие<br />
R1=(BYTE)((dwdColor1&amp;0x000000ff));<br />
G1=(BYTE)((dwdColor1&amp;0x0000ff00)&gt;&gt;8);<br />
B1=(BYTE)((dwdColor1&amp;0x00ff0000)&gt;&gt;16);<br />
R2=(BYTE)((dwdColor2&amp;0x000000ff));<br />
G2=(BYTE)((dwdColor2&amp;0x0000ff00)&gt;&gt;8);<br />
B2=(BYTE)((dwdColor2&amp;0x00ff0000)&gt;&gt;16);<br />
<br />
//высота разноцветных прямоугольников<br />
dh=((float)H)/((float)bySteps);<br />
//величина шагов составляющих цветов<br />
dR=(((float)R2)-((float)R1))/((float)bySteps);<br />
dG=(((float)G2)-((float)G1))/((float)bySteps);<br />
dB=(((float)B2)-((float)B1))/((float)bySteps);<br />
//выводим прямоугольники<br />
x1=0;x2=W;y1=0;y2=dh;<br />
Rc=R1;Gc=G1;Bc=B1;<br />
for(i=0;i&lt;bySteps;i++)<br />
{<br />
//текущий цвет<br />
pdc-&gt;FillSolidRect(x1,(int)y1,x2-x1,(int)(y2-y1),RGB((BYTE)Rc,(BYTE)Gc,(BYTE)Bc));<br />
//следующий цвет и координаты<br />
y1+=dh;y2+=dh;<br />
Rc+=dR;Gc+=dG;Bc+=dB;<br />
}<br />
}<br />
</pre><br />
пример вызова: <br />
<pre> SIZE Size={100,100};<br />
sFillGradientRect(&amp;dc,&amp;Size, RGB(200,0,0), RGB(0,200,0),10);<br />
</pre><br />
=== Как под Windows отслеживать изменение файла? ===<br />
<br />
Использовать функции: <br />
<br />
FindFirstChangeNotification<br />
FindNextChangeNotification<br />
FindCloseChangeNotification<br />
<br />
=== Есть массив char[], как конвертировать его в CString? ===<br />
<pre> char buf[]="text";<br />
<br />
//строка должна обязательно заканчиваться нулём.<br />
<br />
//конвертируем так<br />
CString txt(buf);<br />
<br />
//или так<br />
CString txt;<br />
txt=buf;<br />
</pre><br />
=== Как зарезервировать в CString буфер нужной длины? ===<br />
<br />
при помощи методов класса: <br />
<br />
CString::GetBuffer<br />
и<br />
CString::GetBufferSetLength<br />
<br />
Разница между CString::GetBuffer(nLen) и CString::GetBufferSetLength(nLen) в том, что первый возвращает строку не меньше заданной длины, а второй возвращает строку точно равную заданной длине. Обе могут перераспределять память если надо. В обычных случаях лучше GetBuffer. <br />
<br />
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем. <br />
<br />
=== Как передать больше одного параметр в процедуру потока? ===<br />
<br />
Определить структуру с указателями на всё любое, например: <br />
<pre>struct mystr<br />
{<br />
CEdit* pEd;<br />
CDialog* pDlg;<br />
DWORD* pdwd;<br />
int *pn;<br />
};<br />
</pre><br />
запуск потока: <br />
<pre>mystr *pparam=new mystr;//экземпляр не должен быть временным!!!<br />
memset(pparam,0,sizeof(*pparam));<br />
pparam-&gt;pEd=...;<br />
pparam-&gt;pdwd=...;<br />
<br />
::AfxBeginThread(thread,pparam); <br />
//тут экземпляр *(pparam) уже нельзя использовать!!!<br />
//он удалиться в потоке<br />
</pre><br />
в потоке: <br />
<pre>//поток: <br />
UINT threadLoader(LPVOID pParam) <br />
{ <br />
mystr data=*((mystr*)pParam);<br />
delete ((mystr*)pParam);//подчищаем память<br />
<br />
...<br />
data.pDlg-&gt;...;<br />
(*data.pdwd)=...;<br />
...<br />
}<br />
</pre><br />
=== Как убрать главное меню из CMainFrame? ===<br />
<pre>BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&amp; cs)<br />
{<br />
//обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow<br />
cs.hMenu = 0;<br />
<br />
if(&nbsp;!CFrameWnd::PreCreateWindow(cs) )<br />
return FALSE;<br />
...<br />
...<br />
}<br />
</pre><br />
=== Как работающая программа может определить, что юзер завершает работу Windows? ===<br />
<br />
В этот момент всем процессам посылается сообщение WM_QUERYENDSESSION - его и нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу. <br />
<br />
=== Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ===<br />
<br />
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для контролов. (для CStatic контролов не забудьте поставить свойство Notify) <br />
<pre>class CMyDlg:puplic CDialog<br />
{<br />
CToolTipCtrl m_ToolTip;//мембер класса CMyDlg<br />
//<br />
};<br />
<br />
//массив, в котором перечислены идентификаторы<br />
//контролов и тексты подсказок к ним<br />
struct{int ID;const char* pch;} m_a_Tips[]=<br />
{<br />
{IDC_BUTTON1,"КЫнопка"},<br />
{IDC_STATIC1,"Текст"},<br />
//<br />
{0,0},//признак конца массива<br />
};<br />
<br />
//в инициализации диалога (хотя, в принципе,<br />
//можно и не тут) создаём и привязываем подсказки<br />
BOOL CMyDlg::OnInitDialog() <br />
{<br />
CDialog::OnInitDialog();<br />
//<br />
//создаём<br />
m_ToolTip.Create(this);<br />
//Привязка подсказок<br />
for(int i=0; m_a_Tips[i].ID; i++)<br />
{<br />
m_ToolTip.AddTool(<br />
GetDlgItem(m_a_Tips[i].ID),<br />
m_a_Tips[i].pch);<br />
}<br />
<br />
//включаем показ подсказок<br />
m_ToolTip.Activate(1);<br />
...<br />
...<br />
}<br />
<br />
//для того, чтобы подсказки отображались как реакция на движение<br />
//курсора мыши, транслируем получаемые окнами сообщения в<br />
//виртуальной PreTranslateMessage()<br />
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) <br />
{<br />
//транслируем<br />
if(m_ToolTip.m_hWnd)m_ToolTip.RelayEvent(pMsg);<br />
<br />
...<br />
...<br />
return CDialog::PreTranslateMessage(pMsg);<br />
}<br />
</pre><br />
=== Как в отладчике VС просмотреть содержимое std::vector&lt;string&gt; V ===<br />
<br />
В режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения: <br />
<br />
V._Myfirst - будет показан первый элемент V._Myfirst+1 - второй V._Myfirst+2 - и т.д. <br />
<br />
=== Я вывожу на контекст устройства текст. Как определить в пикселах ширину и высоту выведенных символов текста? ===<br />
<br />
использовать процедуру API: <br />
<pre>BOOL GetTextExtentPoint32(<br />
HDC hdc,// хендл контекста<br />
LPCTSTR lpString,// выводимая строка<br />
int cbString,// длина строки в символах<br />
LPSIZE lpSize// указатель на структуру SIZE, куда <br />
//будут помещены размеры<br />
);<br />
</pre><br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI,_VCPP_Part_2&diff=526FAQ:WinAPI, VCPP Part 22008-10-03T19:46:35Z<p>Алексей1153++: </p>
<hr />
<div><br><br />
<br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%B3%D0%B4%D0%B5_%D0%BD%D0%B0%D0%B9%D1%82%D0%B8_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5_nmake_%D0%B4%D0%BB%D1%8F_VC%2B%2B6|1 где найти описание nmake для VC++6?]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%B4%D0%BB%D1%8F_%D0%B2%D1%8B%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%D0%B0/%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B8%D0%B7_%D1%81%D0%B2%D0%BE%D0%B5%D0%B9_%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_DLL|2 значение переменной для вызывающего процесса/потока из своей собственной DLL]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D1%82%D1%8C_%D1%84%D0%BE%D0%BD_%D0%BE%D0%BA%D0%BD%D0%B0_CWnd|3 Как закрасить фон окна CWnd?]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C_%2C_%D1%87%D1%82%D0%BE_%D0%BA%D1%83%D1%80%D1%81%D0%BE%D1%80_%D0%BC%D1%8B%D1%88%D0%B8_%D0%B2%D1%8B%D1%88%D0%B5%D0%BB_%D0%B7%D0%B0_%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D1%83_%D0%BE%D0%BA%D0%BD%D0%B0|4 Как определить , что курсор мыши вышел за границу окна?]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:%D0%9A%D0%BE%D0%B3%D0%B4%D0%B0_%D1%80%D0%B0%D0%B7%D0%BC%D0%B5%D1%89%D0%B0%D1%8E_%D0%BA%D0%BE%D0%BC%D0%BF%D0%BE%D0%BD%D0%B5%D0%BD%D1%82_RichEdit_%D0%BD%D0%B0_%D1%84%D0%BE%D1%80%D0%BC%D1%83%2C_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0_%D0%B7%D0%B0%D0%BF%D1%83%D1%81%D0%BA%D0%B0%D0%B5%D1%82%D1%81%D1%8F_%D0%B8_%D1%82%D1%83%D1%82_%D0%B6%D0%B5_%D0%B7%D0%B0%D0%BA%D1%80%D1%8B%D0%B2%D0%B0%D0%B5%D1%82%D1%81%D1%8F|5 Когда размещаю компонент RichEdit на форму, программа запускается и тут же закрывается. Что здесь не так? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%BE%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA_%D1%81%D0%BE%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B4%D0%BB%D1%8F_%D0%BD%D0%B5%D1%81%D0%BA%D0%BE%D0%BB%D1%8C%D0%BA%D0%B8%D1%85_%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BE%D0%B2_%D1%81%D1%80%D0%B0%D0%B7%D1%83|6 Как сделать обработчик сообщения для нескольких контролов сразу?]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%B2%D1%81%D0%B5_%D0%BD%D0%B0%D0%B4%D0%BF%D0%B8%D1%81%D0%B8_%D0%BD%D0%B0_%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D0%BC_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B5_%D1%82%D0%B5%D1%80%D1%8F%D1%8E%D1%82%D1%81%D1%8F_-_%D0%BF%D0%BE%D0%BA%D0%B0%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%82%D1%81%D1%8F_%D0%B2%D0%BE%D0%BF%D1%80%D0%BE%D1%81%D0%B8%D0%BA%D0%B8|7 Когда запускаю программу, то все надписи на русском языке теряются - показываются вопросики. Что делать? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B2_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B5_VC6_MFC_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C_%D0%BF%D1%83%D1%82%D1%8C%2C_%D0%BE%D1%82%D0%BA%D1%83%D0%B4%D0%B0_%D0%B7%D0%B0%D0%BF%D1%83%D1%89%D0%B5%D0%BD_%D0%95%D0%A5%D0%95|8 Как в проекте VC6 MFC получить путь, откуда запущен ЕХЕ? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C_%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF_%D0%BA_%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%B0%D0%BC_%D0%BD%D0%B0_%D0%BF%D0%B0%D0%BD%D0%B5%D0%BB%D0%B8_CReBar%2C_%D0%BF%D1%80%D0%B8%D0%BD%D0%B0%D0%B4%D0%BB%D0%B5%D0%B6%D0%B0%D1%89%D0%B5%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D1%83_MainFrame|9 Как получить доступ к контролам на панели CReBar, принадлежащей классу MainFrame? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%B8%D1%82%D1%8C_%D0%B8_%D0%BF%D0%BE%D0%BA%D0%B0%D0%B7%D0%B0%D1%82%D1%8C_%D0%BE%D0%B4%D0%B8%D0%BD_%D0%B8%D0%B7_%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D1%85_%D0%BA%D1%83%D1%80%D1%81%D0%BE%D1%80%D0%BE%D0%B2|10 Как загрузить и показать один из стандартных курсоров? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D0%BF%D1%80%D0%B5%D1%82%D0%B8%D1%82%D1%8C_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8E_%D0%B7%D0%B0%D0%BA%D1%80%D1%8B%D1%82%D1%8C_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D1%83_%D0%BD%D0%B0%D0%B6%D0%B0%D1%82%D0%B8%D0%B5%D0%BC_%D0%BD%D0%B0_%D0%BA%D1%80%D0%B5%D1%81%D1%82%D0%B8%D0%BA|11 Как запретить пользователю закрыть программу нажатием на крестик? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D1%8C_%D0%BD%D0%B0_%D0%B4%D0%B8%D0%B0%D0%BB%D0%BE%D0%B3%D0%B5_%D0%B3%D1%80%D1%83%D0%BF%D0%BF%D1%83_RadioButton-%D0%BE%D0%B2_%D0%B8_%D0%BA%D0%B0%D0%BA_%D0%B7%D0%B0%D0%B4%D0%B0%D1%82%D1%8C_%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D0%BA_%D0%B8%D1%85_%D0%BE%D0%B1%D1%85%D0%BE%D0%B4%D0%B0_%D0%BA%D0%BB%D0%B0%D0%B2%D0%B8%D1%88%D0%B5%D0%B9_Tab|12 Как создать на диалоге группу RadioButton-ов и как задать порядок их обхода клавишей Tab? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%93%D0%B4%D0%B5_%D0%BB%D1%83%D1%87%D1%88%D0%B5_%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%B0%D0%B2%D0%BB%D0%B8%D0%B2%D0%B0%D1%82%D1%8C_%D0%BD%D0%B0%D1%87%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B5_%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_CComboBox|13 Где лучше устанавливать начальные значения CComboBox? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BF%D0%B5%D1%80%D0%B5%D0%B2%D0%B5%D1%81%D1%82%D0%B8_RichEdit_%D0%B2_%D1%80%D0%B5%D0%B6%D0%B8%D0%BC_%D0%B7%D0%B0%D0%BC%D0%B5%D0%BD%D1%8B_%D1%81%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB%D0%BE%D0%B2|14 Как перевести RichEdit в режим замены символов? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B2%D1%8B%D0%B7%D0%B2%D0%B0%D1%82%D1%8C_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B0_CMainFrame_%28%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%BE%D0%B5_%D0%BE%D0%BA%D0%BD%D0%BE%29_%D0%B8%D0%B7_%D0%BB%D1%8E%D0%B1%D0%BE%D0%B3%D0%BE_%D0%BC%D0%B5%D1%81%D1%82%D0%B0_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D1%8B|15 Как вызвать метод класса CMainFrame (главное окно) из любого места программы? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D0%BF%D1%80%D0%B5%D1%82%D0%B8%D1%82%D1%8C_%D0%BF%D0%BE%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%BB%D0%BE%D1%81_%D0%BF%D1%80%D0%BE%D0%BA%D1%80%D1%83%D1%82%D0%BE%D0%BA_%D0%BD%D0%B0_CFormView%2C_%D0%BA%D0%BE%D0%B3%D0%B4%D0%B0_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C_%D0%B4%D0%B5%D0%BB%D0%B0%D0%B5%D1%82_%D1%80%D0%B0%D0%B7%D0%BC%D0%B5%D1%80_%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%BA%D0%BD%D0%B0_%D0%BC%D0%B5%D0%BD%D1%8C%D1%88%D0%B5_%D1%80%D0%B0%D0%B7%D0%BC%D0%B5%D1%80%D0%B0_%D0%BE%D0%BA%D0%BD%D0%B0_CFormView|16 Как запретить появление полос прокруток на CFormView, когда пользователь делает размер главного окна меньше размера окна CFormView ? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BD%D0%B0%D1%80%D0%B8%D1%81%D0%BE%D0%B2%D0%B0%D1%82%D1%8C_%D0%BF%D1%80%D1%8F%D0%BC%D0%BE%D1%83%D0%B3%D0%BE%D0%BB%D1%8C%D0%BD%D0%B8%D0%BA_%D1%81_%D0%B2%D0%B5%D1%80%D1%82%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%BC_%D1%86%D0%B2%D0%B5%D1%82%D0%BE%D0%B2%D1%8B%D0%BC_%D0%B3%D1%80%D0%B0%D0%B4%D0%B8%D0%B5%D0%BD%D1%82%D0%BE%D0%BC|17 Как нарисовать прямоугольник с вертикальным цветовым градиентом? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BF%D0%BE%D0%B4_Windows_%D0%BE%D1%82%D1%81%D0%BB%D0%B5%D0%B6%D0%B8%D0%B2%D0%B0%D1%82%D1%8C_%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D1%84%D0%B0%D0%B9%D0%BB%D0%B0|18 Как под Windows отслеживать изменение файла? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%95%D1%81%D1%82%D1%8C_%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2_char%2C_%D0%BA%D0%B0%D0%BA_%D0%BA%D0%BE%D0%BD%D0%B2%D0%B5%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C_%D0%B5%D0%B3%D0%BE_%D0%B2_CString|19 Есть массив char, как конвертировать его в CString? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B7%D0%B0%D1%80%D0%B5%D0%B7%D0%B5%D1%80%D0%B2%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C_%D0%B2_CString_%D0%B1%D1%83%D1%84%D0%B5%D1%80_%D0%BD%D1%83%D0%B6%D0%BD%D0%BE%D0%B9_%D0%B4%D0%BB%D0%B8%D0%BD%D1%8B|20 Как зарезервировать в CString буфер нужной длины? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%BF%D0%B5%D1%80%D0%B5%D0%B4%D0%B0%D1%82%D1%8C_%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B5_%D0%BE%D0%B4%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80_%D0%B2_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D0%B4%D1%83%D1%80%D1%83_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0|21 Как передать больше одного параметр в процедуру потока?]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D1%83%D0%B1%D1%80%D0%B0%D1%82%D1%8C_%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%BE%D0%B5_%D0%BC%D0%B5%D0%BD%D1%8E_%D0%B8%D0%B7_CMainFrame|22 Как убрать главное меню из CMainFrame?]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D1%8E%D1%89%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0_%D0%BC%D0%BE%D0%B6%D0%B5%D1%82_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C%2C_%D1%87%D1%82%D0%BE_%D1%8E%D0%B7%D0%B5%D1%80_%D0%B7%D0%B0%D0%B2%D0%B5%D1%80%D1%88%D0%B0%D0%B5%D1%82_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%83_Windows|23 Как работающая программа может определить, что юзер завершает работу Windows? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C_%D0%B2%D1%81%D0%BF%D0%BB%D1%8B%D0%B2%D0%B0%D1%8E%D1%89%D1%83%D1%8E_%D0%BF%D0%BE%D0%B4%D1%81%D0%BA%D0%B0%D0%B7%D0%BA%D1%83_%D0%B4%D0%BB%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B0_CWnd_%D0%B8_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%BE%D0%B2%2C_%D0%BE%D1%82_%D0%BD%D0%B5%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B8%D0%B7%D0%B2%D0%BE%D0%B4%D0%BD%D1%8B%D1%85|24 Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%9A%D0%B0%D0%BA_%D0%B2_%D0%BE%D1%82%D0%BB%D0%B0%D0%B4%D1%87%D0%B8%D0%BA%D0%B5_V%D0%A1_%D0%BF%D1%80%D0%BE%D1%81%D0%BC%D0%BE%D1%82%D1%80%D0%B5%D1%82%D1%8C_%D1%81%D0%BE%D0%B4%D0%B5%D1%80%D0%B6%D0%B8%D0%BC%D0%BE%D0%B5_std::vector-string-_V|25 Как в отладчике VС просмотреть содержимое std::vector-string- V]] <br />
#[[http://wiki.shelek.ru/index.php/FAQ:WinAPI%2C_VCPP_Part_2:%D0%AF_%D0%B2%D1%8B%D0%B2%D0%BE%D0%B6%D1%83_%D0%BD%D0%B0_%D0%BA%D0%BE%D0%BD%D1%82%D0%B5%D0%BA%D1%81%D1%82_%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1%81%D1%82%D0%B2%D0%B0_%D1%82%D0%B5%D0%BA%D1%81%D1%82._%D0%9A%D0%B0%D0%BA_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C_%D0%B2_%D0%BF%D0%B8%D0%BA%D1%81%D0%B5%D0%BB%D0%B0%D1%85_%D1%88%D0%B8%D1%80%D0%B8%D0%BD%D1%83_%D0%B8_%D0%B2%D1%8B%D1%81%D0%BE%D1%82%D1%83_%D0%B2%D1%8B%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D1%81%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB%D0%BE%D0%B2_%D1%82%D0%B5%D0%BA%D1%81%D1%82%D0%B0|26 Я вывожу на контекст устройства текст. Как определить в пикселах ширину и высоту выведенных символов текста?]] <br />
<br />
<br />
<br><br />
<br />
<br />
----<br />
<br />
=== где найти описание nmake для VC++6? ===<br />
<br />
В MSDN http://msdn.microsoft.com/library/en-us/vcug98/html/_asug_overview.3a_.nmake_reference.asp <br />
<br />
=== Каким образом можно установить значение переменной для вызывающего процесса/потока из своей собственной DLL? Проблема заключается в том, что несмотря на то, что все линкуется нормально, значение переменной процесса не изменяется, когда я его устанавливаю вручную в библиотеке. ===<br />
<br />
Проблема вызвана тем, что каждая влинкованная libc (одна линкуется в исполняемый файл, ещё одна в dll) содержит свою копию переменной. <br />
<br />
1) Можно воспользоваться динамически подгружаемой библиотекой С runtime. Для этого приложение и dll надо компилировать с ключом /MD (или MDd для отладки). В таком случае переменная будет общей для приложения и dll. <br />
<br />
2) Можно в основном модуле программы (тот, который станет .exe) сделать "дырку" (backdoor), через которую присваивать переменной (int errno) значение: <br />
<pre>__declspec(dllexport) void set_errno(int code)<br />
{<br />
errno = code;<br />
}<br />
</pre><br />
В dll при подключении к процессу надо извлечь из модуля программы указатель на эту функцию. <br />
<pre> typedef void (*SETINT)(int);<br />
SETINT g_set_errno=0;<br />
void set_errno_in_exe(int code)<br />
{<br />
if(g_set_errno) g_set_errno(code);<br />
}<br />
<br />
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )<br />
{<br />
HANDLE hModule; // Handle to the main module<br />
if(fdwReason == DLL_PROCESS_ATTACH )<br />
{<br />
hModule = GetModuleHandle(NULL);<br />
if (hModule == NULL) return FALSE;<br />
g_set_errno = (SETINT) GetProcAddress(hModule, "set_errno");<br />
}<br />
return TRUE;<br />
}<br />
</pre><br />
В нужном месте в dll вместо присваивания errno нужно вызывать внешнюю функцию <br />
<pre>void inside_dll_func()<br />
{<br />
...<br />
...<br />
set_errno_in_exe(ERROR_CODE);<br />
...<br />
}<br />
</pre><br />
=== Как закрасить фон окна CWnd? ===<br />
<br />
Нужно добавить обработчик сообщения WM_CTLCOLOR <br />
<pre>class CMyDialog&nbsp;: public CDialog<br />
{<br />
//<br />
CBrush m_back_brush;<br />
...<br />
...<br />
};<br />
<br />
//конструктор<br />
CMyDialog::CMyDialog(): CDialog(CMyDialog::IDD)<br />
{<br />
//создаём кисть фона<br />
m_back_brush.CreateSolidBrush(RGB(192,186,207));<br />
}<br />
</pre><pre>HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
switch(nCtlColor)<br />
{<br />
//CStatic-контрол<br />
case WM_CTLCOLORSTATIC:<br />
{<br />
//у статиков делаем прозрачный фон<br />
pDC-&gt;SetBkMode(TRANSPARENT);<br />
//и красный цвет текста<br />
pDC-&gt;SetTextColor(RGB(255,0,0));<br />
<br />
//надо же что-то вернуть&nbsp;:)<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
//диалог<br />
case WM_CTLCOLORDLG:<br />
{<br />
//возвращаем хендл кисти нужного фона<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
}<br />
<br />
//фон по умолчанию<br />
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br />
}<br />
<br />
</pre><br />
=== Как определить , что курсор мыши вышел за границу окна? ===<br />
<br />
1) Использовать функцию _TrackMouseEvent. Например, есть класс MyST <br />
<pre>class MyST&nbsp;: public CStatic<br />
{<br />
bool m_bTrackingNow;<br />
...<br />
...<br />
};<br />
<br />
//в конструкторе<br />
MyST:MyST()<br />
{<br />
m_bTrackingNow=false;<br />
}<br />
<br />
//в обработчике OnMouseMove запускаем отслеживание<br />
void MyST::OnMouseMove(UINT nFlags, CPoint point)<br />
{<br />
if(!m_bTrackingNow)<br />
{<br />
m_bTrackingNow=true;<br />
TRACKMOUSEEVENT tme;<br />
tme.cbSize=sizeof(tme);<br />
tme.dwFlags=TME_LEAVE;//отслеживаем выход курсора<br />
tme.hwndTrack = m_hWnd;//из этого окна<br />
<br />
::_TrackMouseEvent(&amp;tme);//"запуск" отслеживания<br />
//при выходе курсора за границу окна будет<br />
//будет сгенерировано сообщение WM_MOUSELEAVE<br />
}<br />
...<br />
...<br />
CStatic::OnMouseMove(nFlags,point);<br />
}<br />
<br />
//ловим сообщение WM_MOUSELEAVE, для этого<br />
//переопределяем виртуальную PreTranslateMessage()<br />
BOOL MyST::PreTranslateMessage(MSG* pMsg)<br />
{<br />
if(pMsg-&gt;message==WM_MOUSELEAVE)<br />
{<br />
//тут обрабатываем<br />
...<br />
...<br />
m_bTrackingNow=false;<br />
}<br />
...<br />
...<br />
return CStatic::PreTranslateMessage(pMsg);<br />
}<br />
</pre><br />
2) Для случая, когда надо регулировать время "реакции" на выход за границу <br />
<pre>enum<br />
{<br />
def_TrackTimer_ID = 1000, //ID таймера<br />
def_TrackTimer_value = 50, //миллисекунд<br />
};<br />
<br />
MyST::MyST()<br />
{<br />
m_bTrackingNow=false;<br />
}<br />
<br />
//в обработчике OnMouseMove запускаем таймер<br />
void MyST::OnMouseMove(UINT nFlags, CPoint point)<br />
{<br />
//перезапуск таймера<br />
SetTimer(def_TrackTimer_ID,def_TrackTimer_value,0);<br />
m_bTrackingNow=true;<br />
...<br />
...<br />
CStatic::OnMouseMove(nFlags,point);<br />
}<br />
<br />
void MyST::OnTimer(UINT nIDEvent)<br />
{<br />
if(nIDEvent==def_TrackTimer_ID)<br />
{<br />
KillTimer(def_TrackTimer_ID);//таймер гасит сам себя<br />
//смотрим, где курсор<br />
POINT pnt;<br />
if(GetCursorPos(&amp;pnt))<br />
{<br />
if(WindowFromPoint(pnt)!=this)<br />
{<br />
m_bTrackingNow=false;//вышли за окно<br />
}<br />
}<br />
}<br />
CStatic::OnTimer(nIDEvent);<br />
}<br />
</pre><br />
=== Когда размещаю компонент RichEdit на форму, программа запускается и тут же закрывается. Что здесь не так? ===<br />
<br />
Необходимо до начала использования контрола инициализировать работу с классом: <br />
<br />
для RichEdit необходимо вызвать функцию AfxInitRichEdit(), для RichEdit2 - AfxInitRichEdit2(). <br />
<br />
Вызывать надо в InitInstance() приложения (в случае для MFC). <br />
<br />
=== Как сделать обработчик сообщения для нескольких контролов сразу? ===<br />
<br />
Если без помощи визарда, то переопределить виртуальную OnCommand() <br />
<pre>BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam) <br />
{<br />
WORD wMess=(wParam&gt;&gt;16);//командное сообщение<br />
int nID=(int)(wParam &amp;0x0000ffff));//ID контрола<br />
HWND hW=(HWND)lParam;//хендл контрола<br />
<br />
//смотрим, какой контрол<br />
switch(nID)<br />
{<br />
//кнопки<br />
case ID_BN1:<br />
case ID_BN2:<br />
case ID_BN3:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case BN_CLICKED:{ ... }break;<br />
}<br />
}<br />
break;<br />
<br />
//едиты<br />
case ID_ED1:<br />
case ID_ED2:<br />
case ID_ED3:<br />
case ID_ED4:<br />
{<br />
//смотрим, какое сообщение<br />
switch(wMess)<br />
{<br />
case EN_CHANGE:{ ... }break;<br />
case EN_KILLFOCUS:{ ... }break;<br />
}<br />
}<br />
break;<br />
}<br />
<br />
return CDialog::OnCommand(wParam, lParam);<br />
}<br />
</pre><br />
=== Когда запускаю программу, то все надписи на русском языке теряются - показываются вопросики. Что делать? ===<br />
<br />
Лечится так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются. <br />
<br />
=== Как в проекте VC6 MFC получить путь, откуда запущен ЕХЕ? ===<br />
<br />
Использовать GetModuleFileName(): <br />
<pre> TCHAR pszFileName[MAX_PATH];<br />
pszFileName[0]=0;<br />
GetModuleFileName(NULL, pszFileName, MAX_PATH);<br />
CString stModulePath = pszFileName;<br />
//ищем первый слеш с конца и удаляем<br />
//его вместе с именем файла EXE<br />
int nEnd = stModulePath.ReverseFind('\\');<br />
stModulePath.Delete(nEnd, stModulePath.GetLength()-nEnd);<br />
<br />
//stModulePath - содержит путь<br />
</pre><br />
=== Как получить доступ к контролам на панели CReBar, принадлежащей классу MainFrame? ===<br />
<pre>#include "MainFrm.h"<br />
<br />
//CMyApp - класс вашего приложения. theApp - глобальная переменная,<br />
//поэтому для доступа к ней используем extern<br />
extern CMyApp theApp;<br />
<br />
void CMyView::F()<br />
{<br />
//Получаем главное окно приложения в любом месте программы<br />
CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);<br />
pMainFrame-&gt;m_wndDlgBar ....//Делаем что хотим<br />
...<br />
}<br />
</pre><br />
=== Как загрузить и показать один из стандартных курсоров? ===<br />
<pre>HCURSOR hCursor;<br />
hCursor=AfxGetApp()-&gt;LoadStandardCursor(IDC_UPARROW);<br />
if(hCursor)SetCursor(hCursor);<br />
</pre><br />
идентификаторы стандартных курсоров: IDC_ARROW IDC_IBEAM IDC_WAIT IDC_CROSS IDC_UPARROW IDC_SIZENWSE IDC_SIZENESW IDC_SIZEWE IDC_SIZENS IDC_SIZEALL <br />
<br />
=== Как запретить пользователю закрыть программу нажатием на крестик? ===<br />
<br />
Нужно добавить обработчик сообщений WM_CLOSE - OnClose() - в главное окно программы. Для диалоговых приложений - это главный диалог, для одно- и много-документных - это CMainFrame. <br />
<pre>void CMainFrame::OnClose()<br />
{<br />
if(......)<br />
{<br />
//не разрешаем закрыть<br />
return;<br />
}<br />
<br />
CFrameWnd::OnClose();<br />
}<br />
</pre><br />
=== Как создать на диалоге группу RadioButton-ов и как задать порядок их обхода клавишей Tab? ===<br />
<br />
Кладём на форму N контролов RadioButton. Затем у первого из группы ставим свойство Group, у остальных в группе - убираем это свойство. Порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется. <br />
<br />
=== Где лучше устанавливать начальные значения CComboBox? ===<br />
<br />
1) В визарде (новая строка данных - Ctrl+Enter) <br />
<br />
2) В функции OnInitDialog (для диалога) или OnInitialUpdate (для CView) <br />
<br />
=== Как перевести RichEdit в режим замены символов? ===<br />
<br />
1) Программно, зная хендл контрола (hWnd): <br />
<br />
::PostMessage(hWnd,WM_KEYDOWN,VK_INSERT,1);<br />
<br />
2) Пользователь может нажать Insert. <br />
<br />
=== Как вызвать метод класса CMainFrame (главное окно) из любого места программы? ===<br />
<br />
AfxGetApp()-&gt;m_pMainWnd-&gt; ...&nbsp;; <br />
<br />
=== Как запретить появление полос прокруток на CFormView, когда пользователь делает размер главного окна меньше размера окна CFormView&nbsp;? ===<br />
<br />
методом SetScaleToFitSize(): <br />
<pre>void CMyView::OnInitialUpdate()<br />
{<br />
CFormView::OnInitialUpdate();<br />
/////////<br />
GetParentFrame()-&gt;RecalcLayout();<br />
ResizeParentToFit();<br />
SIZE s={0,0};<br />
SetScaleToFitSize(s);<br />
/////////<br />
...<br />
...<br />
}<br />
</pre><br />
=== Как нарисовать прямоугольник с вертикальным цветовым градиентом? ===<br />
<br />
pdc - указатель на контекст устройства pSize - указатель на структуру SIZE с размером прямоугольника dwdColor1, dwdColor2 - начальный и конечный цвет bySteps - количество шагов градиента (1...255) <br />
<pre>//вертикальный градиент<br />
void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps)<br />
{<br />
if(!bySteps)bySteps=1;<br />
WORD i;<br />
<br />
long W,H,x1,x2;<br />
BYTE R1,G1,B1,R2,G2,B2;<br />
float dh,dR,dG,dB,y1,y2,Rc,Gc,Bc;<br />
<br />
//ширина и высота<br />
W=pSize-&gt;cx;<br />
H=pSize-&gt;cy;<br />
<br />
//раскладываем цвета на их составляющие<br />
R1=(BYTE)((dwdColor1&amp;0x000000ff));<br />
G1=(BYTE)((dwdColor1&amp;0x0000ff00)&gt;&gt;8);<br />
B1=(BYTE)((dwdColor1&amp;0x00ff0000)&gt;&gt;16);<br />
R2=(BYTE)((dwdColor2&amp;0x000000ff));<br />
G2=(BYTE)((dwdColor2&amp;0x0000ff00)&gt;&gt;8);<br />
B2=(BYTE)((dwdColor2&amp;0x00ff0000)&gt;&gt;16);<br />
<br />
//высота разноцветных прямоугольников<br />
dh=((float)H)/((float)bySteps);<br />
//величина шагов составляющих цветов<br />
dR=(((float)R2)-((float)R1))/((float)bySteps);<br />
dG=(((float)G2)-((float)G1))/((float)bySteps);<br />
dB=(((float)B2)-((float)B1))/((float)bySteps);<br />
//выводим прямоугольники<br />
x1=0;x2=W;y1=0;y2=dh;<br />
Rc=R1;Gc=G1;Bc=B1;<br />
for(i=0;i&lt;bySteps;i++)<br />
{<br />
//текущий цвет<br />
pdc-&gt;FillSolidRect(x1,(int)y1,x2-x1,(int)(y2-y1),RGB((BYTE)Rc,(BYTE)Gc,(BYTE)Bc));<br />
//следующий цвет и координаты<br />
y1+=dh;y2+=dh;<br />
Rc+=dR;Gc+=dG;Bc+=dB;<br />
}<br />
}<br />
</pre><br />
пример вызова: <br />
<pre> SIZE Size={100,100};<br />
sFillGradientRect(&amp;dc,&amp;Size, RGB(200,0,0), RGB(0,200,0),10);<br />
</pre><br />
=== Как под Windows отслеживать изменение файла? ===<br />
<br />
Использовать функции: <br />
<br />
FindFirstChangeNotification<br />
FindNextChangeNotification<br />
FindCloseChangeNotification<br />
<br />
=== Есть массив char[], как конвертировать его в CString? ===<br />
<pre> char buf[]="text";<br />
<br />
//строка должна обязательно заканчиваться нулём.<br />
<br />
//конвертируем так<br />
CString txt(buf);<br />
<br />
//или так<br />
CString txt;<br />
txt=buf;<br />
</pre><br />
=== Как зарезервировать в CString буфер нужной длины? ===<br />
<br />
при помощи методов класса: <br />
<br />
CString::GetBuffer<br />
и<br />
CString::GetBufferSetLength<br />
<br />
Разница между CString::GetBuffer(nLen) и CString::GetBufferSetLength(nLen) в том, что первый возвращает строку не меньше заданной длины, а второй возвращает строку точно равную заданной длине. Обе могут перераспределять память если надо. В обычных случаях лучше GetBuffer. <br />
<br />
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем. <br />
<br />
=== Как передать больше одного параметр в процедуру потока? ===<br />
<br />
Определить структуру с указателями на всё любое, например: <br />
<pre>struct mystr<br />
{<br />
CEdit* pEd;<br />
CDialog* pDlg;<br />
DWORD* pdwd;<br />
int *pn;<br />
};<br />
</pre><br />
запуск потока: <br />
<pre>mystr *pparam=new mystr;//экземпляр не должен быть временным!!!<br />
memset(pparam,0,sizeof(*pparam));<br />
pparam-&gt;pEd=...;<br />
pparam-&gt;pdwd=...;<br />
<br />
::AfxBeginThread(thread,pparam); <br />
//тут экземпляр *(pparam) уже нельзя использовать!!!<br />
//он удалиться в потоке<br />
</pre><br />
в потоке: <br />
<pre>//поток: <br />
UINT threadLoader(LPVOID pParam) <br />
{ <br />
mystr data=*((mystr*)pParam);<br />
delete ((mystr*)pParam);//подчищаем память<br />
<br />
...<br />
data.pDlg-&gt;...;<br />
(*data.pdwd)=...;<br />
...<br />
}<br />
</pre><br />
=== Как убрать главное меню из CMainFrame? ===<br />
<pre>BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&amp; cs)<br />
{<br />
//обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow<br />
cs.hMenu = 0;<br />
<br />
if(&nbsp;!CFrameWnd::PreCreateWindow(cs) )<br />
return FALSE;<br />
...<br />
...<br />
}<br />
</pre><br />
=== Как работающая программа может определить, что юзер завершает работу Windows? ===<br />
<br />
В этот момент всем процессам посылается сообщение WM_QUERYENDSESSION - его и нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу. <br />
<br />
=== Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ===<br />
<br />
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для контролов. (для CStatic контролов не забудьте поставить свойство Notify) <br />
<pre>class CMyDlg:puplic CDialog<br />
{<br />
CToolTipCtrl m_ToolTip;//мембер класса CMyDlg<br />
//<br />
};<br />
<br />
//массив, в котором перечислены идентификаторы<br />
//контролов и тексты подсказок к ним<br />
struct{int ID;const char* pch;} m_a_Tips[]=<br />
{<br />
{IDC_BUTTON1,"КЫнопка"},<br />
{IDC_STATIC1,"Текст"},<br />
//<br />
{0,0},//признак конца массива<br />
};<br />
<br />
//в инициализации диалога (хотя, в принципе,<br />
//можно и не тут) создаём и привязываем подсказки<br />
BOOL CMyDlg::OnInitDialog() <br />
{<br />
CDialog::OnInitDialog();<br />
//<br />
//создаём<br />
m_ToolTip.Create(this);<br />
//Привязка подсказок<br />
for(int i=0; m_a_Tips[i].ID; i++)<br />
{<br />
m_ToolTip.AddTool(<br />
GetDlgItem(m_a_Tips[i].ID),<br />
m_a_Tips[i].pch);<br />
}<br />
<br />
//включаем показ подсказок<br />
m_ToolTip.Activate(1);<br />
...<br />
...<br />
}<br />
<br />
//для того, чтобы подсказки отображались как реакция на движение<br />
//курсора мыши, транслируем получаемые окнами сообщения в<br />
//виртуальной PreTranslateMessage()<br />
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) <br />
{<br />
//транслируем<br />
if(m_ToolTip.m_hWnd)m_ToolTip.RelayEvent(pMsg);<br />
<br />
...<br />
...<br />
return CDialog::PreTranslateMessage(pMsg);<br />
}<br />
</pre><br />
=== Как в отладчике VС просмотреть содержимое std::vector&lt;string&gt; V ===<br />
<br />
В режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения: <br />
<br />
V._Myfirst - будет показан первый элемент V._Myfirst+1 - второй V._Myfirst+2 - и т.д. <br />
<br />
=== Я вывожу на контекст устройства текст. Как определить в пикселах ширину и высоту выведенных символов текста? ===<br />
<br />
использовать процедуру API: <br />
<pre>BOOL GetTextExtentPoint32(<br />
HDC hdc,// хендл контекста<br />
LPCTSTR lpString,// выводимая строка<br />
int cbString,// длина строки в символах<br />
LPSIZE lpSize// указатель на структуру SIZE, куда <br />
//будут помещены размеры<br />
);<br />
</pre><br />
[[Category:FAQ]]</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B8%D0%BD%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_RichEdit_%D0%BF%D1%80%D0%B8_%D0%B7%D0%B0%D0%BF%D1%83%D1%81%D0%BA%D0%B5_%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F&diff=504FAQ:WinAPI VCPP:инциализация RichEdit при запуске приложения2008-10-03T17:49:23Z<p>Алексей1153++: Новая: === Когда размещаю компонент RichEdit на форму, программа запускается и тут же закрывается. Что здесь не та...</p>
<hr />
<div>=== Когда размещаю компонент RichEdit на форму, программа запускается и тут же закрывается. Что здесь не так? ===<br />
<br />
Необходимо до начала использования контрола инициализировать работу с классом: <br />
<br />
для RichEdit необходимо вызвать функцию AfxInitRichEdit(), для RichEdit2 - AfxInitRichEdit2(). <br />
<br />
Вызывать надо в InitInstance() приложения (в случае для MFC).</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C_%D0%B2%D1%8B%D1%85%D0%BE%D0%B4_%D0%BA%D1%83%D1%80%D1%81%D0%BE%D1%80%D0%B0_%D0%BC%D1%8B%D1%88%D0%B8_%D0%B7%D0%B0_%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D1%83_%D0%BE%D0%BA%D0%BD%D0%B0&diff=503FAQ:WinAPI VCPP:определить выход курсора мыши за границу окна2008-10-03T17:48:21Z<p>Алексей1153++: Новая: === Как определить , что курсор мыши вышел за границу окна? === 1) Использовать функцию _TrackMouseEvent. Например...</p>
<hr />
<div>=== Как определить , что курсор мыши вышел за границу окна? ===<br />
<br />
1) Использовать функцию _TrackMouseEvent. Например, есть класс MyST <br />
<pre>class MyST&nbsp;: public CStatic<br />
{<br />
bool m_bTrackingNow;<br />
...<br />
...<br />
};<br />
<br />
//в конструкторе<br />
MyST:MyST()<br />
{<br />
m_bTrackingNow=false;<br />
}<br />
<br />
//в обработчике OnMouseMove запускаем отслеживание<br />
void MyST::OnMouseMove(UINT nFlags, CPoint point)<br />
{<br />
if(!m_bTrackingNow)<br />
{<br />
m_bTrackingNow=true;<br />
TRACKMOUSEEVENT tme;<br />
tme.cbSize=sizeof(tme);<br />
tme.dwFlags=TME_LEAVE;//отслеживаем выход курсора<br />
tme.hwndTrack = m_hWnd;//из этого окна<br />
<br />
::_TrackMouseEvent(&amp;tme);//"запуск" отслеживания<br />
//при выходе курсора за границу окна будет<br />
//будет сгенерировано сообщение WM_MOUSELEAVE<br />
}<br />
...<br />
...<br />
CStatic::OnMouseMove(nFlags,point);<br />
}<br />
<br />
//ловим сообщение WM_MOUSELEAVE, для этого<br />
//переопределяем виртуальную PreTranslateMessage()<br />
BOOL MyST::PreTranslateMessage(MSG* pMsg)<br />
{<br />
if(pMsg-&gt;message==WM_MOUSELEAVE)<br />
{<br />
//тут обрабатываем<br />
...<br />
...<br />
m_bTrackingNow=false;<br />
}<br />
...<br />
...<br />
return CStatic::PreTranslateMessage(pMsg);<br />
}<br />
</pre><br />
2) Для случая, когда надо регулировать время "реакции" на выход за границу <br />
<pre>enum<br />
{<br />
def_TrackTimer_ID = 1000, //ID таймера<br />
def_TrackTimer_value = 50, //миллисекунд<br />
};<br />
<br />
MyST::MyST()<br />
{<br />
m_bTrackingNow=false;<br />
}<br />
<br />
//в обработчике OnMouseMove запускаем таймер<br />
void MyST::OnMouseMove(UINT nFlags, CPoint point)<br />
{<br />
//перезапуск таймера<br />
SetTimer(def_TrackTimer_ID,def_TrackTimer_value,0);<br />
m_bTrackingNow=true;<br />
...<br />
...<br />
CStatic::OnMouseMove(nFlags,point);<br />
}<br />
<br />
void MyST::OnTimer(UINT nIDEvent)<br />
{<br />
if(nIDEvent==def_TrackTimer_ID)<br />
{<br />
KillTimer(def_TrackTimer_ID);//таймер гасит сам себя<br />
//смотрим, где курсор<br />
POINT pnt;<br />
if(GetCursorPos(&amp;pnt))<br />
{<br />
if(WindowFromPoint(pnt)!=this)<br />
{<br />
m_bTrackingNow=false;//вышли за окно<br />
}<br />
}<br />
}<br />
CStatic::OnTimer(nIDEvent);<br />
}<br />
</pre></div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%B0%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D1%82%D1%8C_%D1%84%D0%BE%D0%BD_%D0%BE%D0%BA%D0%BD%D0%B0_CWnd&diff=502FAQ:WinAPI VCPP:закрасить фон окна CWnd2008-10-03T17:45:24Z<p>Алексей1153++: </p>
<hr />
<div>=== Как закрасить фон окна CWnd? ===<br />
<br />
Нужно добавить обработчик сообщения WM_CTLCOLOR <br />
<pre>class CMyDialog&nbsp;: public CDialog<br />
{<br />
//<br />
CBrush m_back_brush;<br />
...<br />
...<br />
};<br />
<br />
//конструктор<br />
CMyDialog::CMyDialog(): CDialog(CMyDialog::IDD)<br />
{<br />
//создаём кисть фона<br />
m_back_brush.CreateSolidBrush(RGB(192,186,207));<br />
}<br />
</pre><pre>HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
switch(nCtlColor)<br />
{<br />
//CStatic-контрол<br />
case WM_CTLCOLORSTATIC:<br />
{<br />
//у статиков делаем прозрачный фон<br />
pDC-&gt;SetBkMode(TRANSPARENT);<br />
//и красный цвет текста<br />
pDC-&gt;SetTextColor(RGB(255,0,0));<br />
<br />
//надо же что-то вернуть&nbsp;:)<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
//диалог<br />
case WM_CTLCOLORDLG:<br />
{<br />
//возвращаем хендл кисти нужного фона<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
}<br />
<br />
//фон по умолчанию<br />
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br />
}<br />
<br />
</pre></div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%B0%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D1%82%D1%8C_%D1%84%D0%BE%D0%BD_%D0%BE%D0%BA%D0%BD%D0%B0_CWnd&diff=501FAQ:WinAPI VCPP:закрасить фон окна CWnd2008-10-03T17:42:19Z<p>Алексей1153++: </p>
<hr />
<div>=== Как закрасить фон окна CWnd? ===<br />
<br />
<br>Нужно добавить обработчик сообщения WM_CTLCOLOR&nbsp; <br />
<br />
<br><br />
<pre>class CMyDialog&nbsp;: public CDialog<br />
{<br />
//<br />
CBrush m_back_brush;<br />
...<br />
...<br />
};<br />
<br />
//конструктор<br />
CMyDialog::CMyDialog(): CDialog(CMyDialog::IDD)<br />
{<br />
//создаём кисть фона<br />
m_back_brush.CreateSolidBrush(RGB(192,186,207));<br />
}</pre><pre>HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)<br />
{<br />
<br />
switch(nCtlColor)<br />
{<br />
//CStatic-контрол<br />
<br />
case WM_CTLCOLORSTATIC:<br />
{<br />
//у статиков делаем прозрачный фон<br />
pDC-&gt;SetBkMode(TRANSPARENT);<br />
//и красный цвет текста<br />
pDC-&gt;SetTextColor(RGB(255,0,0));<br />
//надо же что-то вернуть&nbsp;:)<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
//диалог<br />
case WM_CTLCOLORDLG:<br />
{<br />
//возвращаем хендл кисти нужного фона<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
}<br />
//фон по умолчанию<br />
<br />
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br />
<br />
}</pre><br />
<br></div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%B0%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D1%82%D1%8C_%D1%84%D0%BE%D0%BD_%D0%BE%D0%BA%D0%BD%D0%B0_CWnd&diff=500FAQ:WinAPI VCPP:закрасить фон окна CWnd2008-10-03T17:41:44Z<p>Алексей1153++: </p>
<hr />
<div>=== Как закрасить фон окна CWnd? ===<br />
<br />
<br>Нужно добавить обработчик сообщения WM_CTLCOLOR&nbsp; <br />
<br />
<br><br />
<pre>class CMyDialog&nbsp;: public CDialog<br />
{<br />
//<br />
CBrush m_back_brush;<br />
...<br />
...<br />
};<br />
<br />
//конструктор<br />
CMyDialog::CMyDialog(): CDialog(CMyDialog::IDD)<br />
{<br />
//создаём кисть фона<br />
m_back_brush.CreateSolidBrush(RGB(192,186,207));<br />
}</pre><pre>HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)<br />
{<br />
<br />
switch(nCtlColor)<br />
{<br />
//CStatic-контрол<br />
case WM_CTLCOLORSTATIC:<br />
{<br />
//у статиков делаем прозрачный фон<br />
pDC-&gt;SetBkMode(TRANSPARENT);<br />
//и красный цвет текста<br />
pDC-&gt;SetTextColor(RGB(255,0,0));<br />
//надо же что-то вернуть&nbsp;:)<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
//диалог<br />
case WM_CTLCOLORDLG:<br />
{<br />
//возвращаем хендл кисти нужного фона<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
}<br />
//фон по умолчанию<br />
<br />
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br />
<br />
}</pre><br />
<br></div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%B0%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D1%82%D1%8C_%D1%84%D0%BE%D0%BD_%D0%BE%D0%BA%D0%BD%D0%B0_CWnd&diff=499FAQ:WinAPI VCPP:закрасить фон окна CWnd2008-10-03T17:41:28Z<p>Алексей1153++: </p>
<hr />
<div>=== Как закрасить фон окна CWnd? ===<br />
<br />
<br>Нужно добавить обработчик сообщения WM_CTLCOLOR&nbsp; <br />
<br />
<br><br />
<pre>class CMyDialog&nbsp;: public CDialog<br />
{<br />
//<br />
CBrush m_back_brush;<br />
...<br />
...<br />
};<br />
<br />
//конструктор<br />
CMyDialog::CMyDialog(): CDialog(CMyDialog::IDD)<br />
{<br />
//создаём кисть фона<br />
m_back_brush.CreateSolidBrush(RGB(192,186,207));<br />
}</pre><pre>HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)<br />
{<br />
<br />
switch(nCtlColor)<br />
{<br />
//CStatic-контрол<br />
case WM_CTLCOLORSTATIC:<br />
{<br />
//у статиков делаем прозрачный фон<br />
pDC-&gt;SetBkMode(TRANSPARENT);<br />
//и красный цвет текста<br />
pDC-&gt;SetTextColor(RGB(255,0,0));<br />
//надо же что-то вернуть&nbsp;:)<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
//диалог<br />
case WM_CTLCOLORDLG:<br />
{<br />
//возвращаем хендл кисти нужного фона<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
}<br />
//фон по умолчанию<br />
<br />
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br />
}</pre><br />
<br></div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%B0%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D1%82%D1%8C_%D1%84%D0%BE%D0%BD_%D0%BE%D0%BA%D0%BD%D0%B0_CWnd&diff=498FAQ:WinAPI VCPP:закрасить фон окна CWnd2008-10-03T17:40:26Z<p>Алексей1153++: </p>
<hr />
<div>=== Как закрасить фон окна CWnd? ===<br />
<br />
<br>Нужно добавить обработчик сообщения WM_CTLCOLOR&nbsp; <br />
<br />
<br><br />
<pre>class CMyDialog&nbsp;: public CDialog<br />
{<br />
//<br />
CBrush m_back_brush;<br />
...<br />
...<br />
};<br />
<br />
//конструктор<br />
CMyDialog::CMyDialog(): CDialog(CMyDialog::IDD)<br />
{<br />
//создаём кисть фона<br />
m_back_brush.CreateSolidBrush(RGB(192,186,207));<br />
}</pre><pre>HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)<br />
{<br />
<br />
switch(nCtlColor)<br />
{<br />
//CStatic-контрол<br />
case WM_CTLCOLORSTATIC:<br />
{<br />
//у статиков делаем прозрачный фон<br />
pDC-&gt;SetBkMode(TRANSPARENT);<br />
//и красный цвет текста<br />
pDC-&gt;SetTextColor(RGB(255,0,0));<br />
//надо же что-то вернуть&nbsp;:)<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
&nbsp;<br />
<br />
//диалог<br />
case WM_CTLCOLORDLG:<br />
{<br />
//возвращаем хендл кисти нужного фона<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
}<br />
//фон по умолчанию<br />
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br />
}</pre><br />
<br></div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%B0%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D1%82%D1%8C_%D1%84%D0%BE%D0%BD_%D0%BE%D0%BA%D0%BD%D0%B0_CWnd&diff=497FAQ:WinAPI VCPP:закрасить фон окна CWnd2008-10-03T17:39:32Z<p>Алексей1153++: </p>
<hr />
<div>=== Как закрасить фон окна CWnd? ===<br />
<br />
<br>Нужно добавить обработчик сообщения WM_CTLCOLOR&nbsp; <br />
<br />
<br><br />
<pre>class CMyDialog&nbsp;: public CDialog<br />
{<br />
//<br />
CBrush m_back_brush;<br />
...<br />
...<br />
};<br />
<br />
//конструктор<br />
CMyDialog::CMyDialog(): CDialog(CMyDialog::IDD)<br />
{<br />
//создаём кисть фона<br />
m_back_brush.CreateSolidBrush(RGB(192,186,207));<br />
}</pre><pre>HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)<br />
{<br />
<br />
switch(nCtlColor)<br />
{<br />
//CStatic-контрол<br />
case WM_CTLCOLORSTATIC:<br />
{<br />
//у статиков делаем прозрачный фон<br />
pDC-&gt;SetBkMode(TRANSPARENT);<br />
//и красный цвет текста<br />
pDC-&gt;SetTextColor(RGB(255,0,0));<br />
//надо же что-то вернуть&nbsp;:)<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
//диалог<br />
case WM_CTLCOLORDLG:<br />
{<br />
//возвращаем хендл кисти нужного фона<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
}<br />
<br />
<br />
<br />
//фон по умолчанию<br />
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br />
<br />
}</pre><br />
<br></div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%B0%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D1%82%D1%8C_%D1%84%D0%BE%D0%BD_%D0%BE%D0%BA%D0%BD%D0%B0_CWnd&diff=496FAQ:WinAPI VCPP:закрасить фон окна CWnd2008-10-03T17:38:29Z<p>Алексей1153++: </p>
<hr />
<div>=== Как закрасить фон окна CWnd? ===<br />
<br />
<br>Нужно добавить обработчик сообщения WM_CTLCOLOR&nbsp; <br />
<br />
<br><br />
<pre>class CMyDialog&nbsp;: public CDialog<br />
{<br />
//<br />
CBrush m_back_brush;<br />
...<br />
<span id="fck_dom_range_temp_1223055208671_173" /> ...<br />
};<br />
<br />
//конструктор<br />
CMyDialog::CMyDialog(): CDialog(CMyDialog::IDD)<br />
{<br />
//создаём кисть фона<br />
m_back_brush.CreateSolidBrush(RGB(192,186,207));<br />
}</pre><pre>HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)<br />
{<br />
switch(nCtlColor)<br />
{<br />
//CStatic-контрол<br />
case WM_CTLCOLORSTATIC:<br />
{<br />
//у статиков делаем прозрачный фон<br />
pDC-&gt;SetBkMode(TRANSPARENT);<br />
//и красный цвет текста<br />
pDC-&gt;SetTextColor(RGB(255,0,0));<br />
//надо же что-то вернуть&nbsp;:)<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
//диалог<br />
case WM_CTLCOLORDLG:<br />
{<br />
//возвращаем хендл кисти нужного фона<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
}<br />
<br />
//фон по умолчанию<br />
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br />
}</pre><br />
<br></div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%B0%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D1%82%D1%8C_%D1%84%D0%BE%D0%BD_%D0%BE%D0%BA%D0%BD%D0%B0_CWnd&diff=495FAQ:WinAPI VCPP:закрасить фон окна CWnd2008-10-03T17:33:06Z<p>Алексей1153++: </p>
<hr />
<div>=== Как закрасить фон окна CWnd? ===<br />
<br />
<br>Нужно добавить обработчик сообщения WM_CTLCOLOR&nbsp; <br />
<br />
<br><br />
<pre> class CMyDialog&nbsp;: public CDialog<br />
{<br />
//<br />
CBrush m_back_brush;<br />
...<br />
...<br />
};<br />
<br />
//конструктор<br />
CMyDialog::CMyDialog(): CDialog(CMyDialog::IDD)<br />
{<br />
//создаём кисть фона<br />
m_back_brush.CreateSolidBrush(RGB(192,186,207));<br />
}</pre><pre>HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
switch(nCtlColor)<br />
{<br />
//CStatic-контрол<br />
case WM_CTLCOLORSTATIC:<br />
{<br />
//у статиков делаем прозрачный фон<br />
pDC-&gt;SetBkMode(TRANSPARENT);<br />
//и красный цвет текста<br />
pDC-&gt;SetTextColor(RGB(255,0,0));<br />
//надо же что-то вернуть&nbsp;:)<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
//диалог<br />
case WM_CTLCOLORDLG:<br />
{<br />
//возвращаем хендл кисти нужного фона<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
}<br />
//фон по умолчанию<br />
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br />
<br />
}</pre><br />
<br></div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%B0%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D1%82%D1%8C_%D1%84%D0%BE%D0%BD_%D0%BE%D0%BA%D0%BD%D0%B0_CWnd&diff=494FAQ:WinAPI VCPP:закрасить фон окна CWnd2008-10-03T17:32:33Z<p>Алексей1153++: </p>
<hr />
<div>=== Как закрасить фон окна CWnd? ===<br />
<br />
<br>Нужно добавить обработчик сообщения WM_CTLCOLOR&nbsp; <br />
<br />
<br><br />
<pre> class CMyDialog&nbsp;: public CDialog<br />
{<br />
//<br />
CBrush m_back_brush;<br />
...<br />
...<br />
};<br />
<br />
//конструктор<br />
CMyDialog::CMyDialog(): CDialog(CMyDialog::IDD)<br />
{<br />
//создаём кисть фона<br />
m_back_brush.CreateSolidBrush(RGB(192,186,207));<br />
}</pre><pre>HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
switch(nCtlColor)<br />
{<br />
//CStatic-контрол<br />
case WM_CTLCOLORSTATIC:<br />
{<br />
//у статиков делаем прозрачный фон<br />
pDC-&gt;SetBkMode(TRANSPARENT);<br />
//и красный цвет текста<br />
pDC-&gt;SetTextColor(RGB(255,0,0));<br />
//надо же что-то вернуть&nbsp;:)<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
//диалог<br />
case WM_CTLCOLORDLG:<br />
{<br />
//возвращаем хендл кисти нужного фона<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
}<br />
//фон по умолчанию<br />
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br />
<br />
}</pre><br />
<br></div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%B0%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D1%82%D1%8C_%D1%84%D0%BE%D0%BD_%D0%BE%D0%BA%D0%BD%D0%B0_CWnd&diff=493FAQ:WinAPI VCPP:закрасить фон окна CWnd2008-10-03T17:30:39Z<p>Алексей1153++: </p>
<hr />
<div>=== Как закрасить фон окна CWnd? ===<br />
<br />
<br>Нужно добавить обработчик сообщения WM_CTLCOLOR&nbsp;<br />
<br />
<br />
<pre>class CMyDialog : public CDialog<br />
{<br />
//<br />
CBrush m_back_brush;<br />
...<br />
...<br />
};<br />
<br />
//конструктор<br />
CMyDialog::CMyDialog(): CDialog(CMyDialog::IDD)<br />
{<br />
//создаём кисть фона<br />
m_back_brush.CreateSolidBrush(RGB(192,186,207));<br />
}</pre><pre>HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
switch(nCtlColor)<br />
{<br />
//CStatic-контрол<br />
case WM_CTLCOLORSTATIC:<br />
{<br />
//у статиков делаем прозрачный фон<br />
pDC-&gt;SetBkMode(TRANSPARENT);<br />
//и красный цвет текста<br />
pDC-&gt;SetTextColor(RGB(255,0,0));<br />
//надо же что-то вернуть :)<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
//диалог<br />
case WM_CTLCOLORDLG:<br />
{<br />
//возвращаем хендл кисти нужного фона<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
}<br />
//фон по умолчанию<br />
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br />
}</pre><br />
<br></div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%B0%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D1%82%D1%8C_%D1%84%D0%BE%D0%BD_%D0%BE%D0%BA%D0%BD%D0%B0_CWnd&diff=492FAQ:WinAPI VCPP:закрасить фон окна CWnd2008-10-03T17:25:42Z<p>Алексей1153++: Новая: Как закрасить фон окна CWnd? Нужно добавить обработчик сообщения WM_CTLCOLOR class CMyDialog : public CDialog { // CBrush m_back_br...</p>
<hr />
<div>Как закрасить фон окна CWnd?<br />
Нужно добавить обработчик сообщения WM_CTLCOLOR <br />
<br />
class CMyDialog : public CDialog<br />
{<br />
//<br />
CBrush m_back_brush;<br />
...<br />
...<br />
};<br />
<br />
//конструктор<br />
CMyDialog::CMyDialog(): CDialog(CMyDialog::IDD)<br />
{<br />
//создаём кисть фона<br />
m_back_brush.CreateSolidBrush(RGB(192,186,207));<br />
}<br />
<br />
HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />
{<br />
switch(nCtlColor)<br />
{<br />
//CStatic-контрол<br />
case WM_CTLCOLORSTATIC:<br />
{<br />
//у статиков делаем прозрачный фон<br />
pDC->SetBkMode(TRANSPARENT);<br />
//и красный цвет текста<br />
pDC->SetTextColor(RGB(255,0,0));<br />
<br />
//надо же что-то вернуть :)<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
<br />
//диалог<br />
case WM_CTLCOLORDLG:<br />
{<br />
//возвращаем хендл кисти нужного фона<br />
return (HBRUSH) (m_back_brush.m_hObject);<br />
}<br />
break;<br />
}<br />
<br />
//фон по умолчанию<br />
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br />
}</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%B4%D0%BB%D1%8F_%D0%B2%D1%8B%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%D0%B0/%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B8%D0%B7_%D1%81%D0%B2%D0%BE%D0%B5%D0%B9_%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_DLL&diff=491FAQ:WinAPI VCPP:значение переменной для вызывающего процесса/потока из своей собственной DLL2008-10-03T17:17:45Z<p>Алексей1153++: </p>
<hr />
<div>=== Каким образом можно установить значение переменной для вызывающего процесса/потока из своей собственной DLL? Проблема заключается в том, что несмотря на то, что все линкуется нормально, значение переменной процесса не изменяется, когда я его устанавливаю вручную в библиотеке. ===<br />
<br />
Проблема вызвана тем, что каждая влинкованная libc (одна линкуется в исполняемый файл, ещё одна в dll) содержит свою копию переменной. <br />
<br />
1) Можно воспользоваться динамически подгружаемой библиотекой С runtime. Для этого приложение и dll надо компилировать с ключом /MD (или MDd для отладки). В таком случае переменная будет общей для приложения и dll. <br />
<br />
2) Можно в основном модуле программы (тот, который станет .exe) сделать "дырку" (backdoor), через которую присваивать переменной (int errno) значение: <br />
<pre>__declspec(dllexport) void set_errno(int code)<br />
{<br />
errno = code;<br />
}<br />
</pre><br />
В dll при подключении к процессу надо извлечь из модуля программы указатель на эту функцию. <br />
<pre>typedef void (*SETINT)(int);<br />
SETINT g_set_errno=0;<br />
void set_errno_in_exe(int code)<br />
{<br />
if(g_set_errno) g_set_errno(code);<br />
}<br />
<br />
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )<br />
{<br />
HANDLE hModule; // Handle to the main module<br />
if(fdwReason == DLL_PROCESS_ATTACH )<br />
{<br />
hModule = GetModuleHandle(NULL);<br />
if (hModule == NULL) return FALSE;<br />
g_set_errno = (SETINT) GetProcAddress(hModule, "set_errno");<br />
}<br />
return TRUE;<br />
} </pre><br />
В нужном месте в dll вместо присваивания errno нужно вызывать внешнюю функцию <br />
<pre>void inside_dll_func()<br />
{<br />
...<br />
...<br />
set_errno_in_exe(ERROR_CODE);<br />
...<br />
}&nbsp;</pre></div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%B4%D0%BB%D1%8F_%D0%B2%D1%8B%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%D0%B0/%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B8%D0%B7_%D1%81%D0%B2%D0%BE%D0%B5%D0%B9_%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_DLL&diff=490FAQ:WinAPI VCPP:значение переменной для вызывающего процесса/потока из своей собственной DLL2008-10-03T17:16:23Z<p>Алексей1153++: </p>
<hr />
<div>=== Каким образом можно установить значение переменной для вызывающего процесса/потока из своей собственной DLL? Проблема заключается в том, что несмотря на то, что все линкуется нормально, значение переменной процесса не изменяется, когда я его устанавливаю вручную в библиотеке. ===<br />
<br />
Проблема вызвана тем, что каждая влинкованная libc (одна линкуется в исполняемый файл, ещё одна в dll) содержит свою копию переменной. <br />
<br />
1) Можно воспользоваться динамически подгружаемой библиотекой С runtime. Для этого приложение и dll надо компилировать с ключом /MD (или MDd для отладки). В таком случае переменная будет общей для приложения и dll. <br />
<br />
2) Можно в основном модуле программы (тот, который станет .exe) сделать "дырку" (backdoor), через которую присваивать переменной (int errno) значение:<br />
<pre>&nbsp;__declspec(dllexport) void set_errno(int code)<br />
{<br />
errno = code;<br />
}<br />
</pre><br />
В dll при подключении к процессу надо извлечь из модуля программы указатель на эту функцию. <br />
<pre>typedef void (*SETINT)(int);<br />
SETINT g_set_errno=0;<br />
void set_errno_in_exe(int code)<br />
{<br />
if(g_set_errno) g_set_errno(code);<br />
}<br />
<br />
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )<br />
{<br />
HANDLE hModule; // Handle to the main module<br />
if(fdwReason == DLL_PROCESS_ATTACH )<br />
{<br />
hModule = GetModuleHandle(NULL);<br />
if (hModule == NULL) return FALSE;<br />
g_set_errno = (SETINT) GetProcAddress(hModule, "set_errno");<br />
}<br />
return TRUE;<br />
} </pre><br />
В нужном месте в dll вместо присваивания errno нужно вызывать внешнюю функцию <br />
<pre>void inside_dll_func()<br />
{<br />
...<br />
...<br />
set_errno_in_exe(ERROR_CODE);<br />
...<br />
}&nbsp;</pre></div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%B4%D0%BB%D1%8F_%D0%B2%D1%8B%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%D0%B0/%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B8%D0%B7_%D1%81%D0%B2%D0%BE%D0%B5%D0%B9_%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_DLL&diff=489FAQ:WinAPI VCPP:значение переменной для вызывающего процесса/потока из своей собственной DLL2008-10-03T17:11:59Z<p>Алексей1153++: </p>
<hr />
<div>=== Каким образом можно установить значение переменной для вызывающего процесса/потока из своей собственной DLL? Проблема заключается в том, что несмотря на то, что все линкуется нормально, значение переменной процесса не изменяется, когда я его устанавливаю вручную в библиотеке. ===<br />
<br />
Проблема вызвана тем, что каждая влинкованная libc (одна линкуется в исполняемый файл, ещё одна в dll) содержит свою копию переменной. <br />
<br />
1) Можно воспользоваться динамически подгружаемой библиотекой С runtime. Для этого приложение и dll надо компилировать с ключом /MD (или MDd для отладки). В таком случае переменная будет общей для приложения и dll. <br />
<br />
2) Можно в основном модуле программы (тот, который станет .exe) сделать "дырку" (backdoor), через которую присваивать переменной (int errno) значение: <br>&lt;pre&gt;<br />
<br />
__declspec(dllexport) void set_errno(int code)<br>{<br>errno = code;<br>}<br>&lt;/pre&gt;<br>В dll при подключении к процессу надо извлечь из модуля программы указатель на эту функцию. <br>&lt;pre&gt; typedef void (*SETINT)(int);<br>SETINT g_set_errno=0;<br>void set_errno_in_exe(int code)<br>{<br>if(g_set_errno) g_set_errno(code);<br>}<br><br>BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )<br>{<br>HANDLE hModule; // Handle to the main module<br>if(fdwReason == DLL_PROCESS_ATTACH )<br>{<br>hModule = GetModuleHandle(NULL);<br>if (hModule == NULL) return FALSE;<br>g_set_errno = (SETINT) GetProcAddress(hModule, "set_errno");<br>}<br>return TRUE;<br>}<br>&lt;/pre&gt;<br>В нужном месте в dll вместо присваивания errno нужно вызывать внешнюю функцию <br>&lt;pre&gt;void inside_dll_func()<br>{<br>...<br>...<br>set_errno_in_exe(ERROR_CODE);<br>...<br>}<br>&lt;/pre&gt;</div>Алексей1153++https://wiki.shelek.ru/index.php?title=FAQ:WinAPI_VCPP:%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%B4%D0%BB%D1%8F_%D0%B2%D1%8B%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%D0%B0/%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B8%D0%B7_%D1%81%D0%B2%D0%BE%D0%B5%D0%B9_%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_DLL&diff=488FAQ:WinAPI VCPP:значение переменной для вызывающего процесса/потока из своей собственной DLL2008-10-03T17:10:52Z<p>Алексей1153++: Новая: === Каким образом можно установить значение переменной для вызывающего процесса/потока из своей собст...</p>
<hr />
<div>=== Каким образом можно установить значение переменной для вызывающего процесса/потока из своей собственной DLL? Проблема заключается в том, что несмотря на то, что все линкуется нормально, значение переменной процесса не изменяется, когда я его устанавливаю вручную в библиотеке. ===<br />
<br />
Проблема вызвана тем, что каждая влинкованная libc (одна линкуется в исполняемый файл, ещё одна в dll) содержит свою копию переменной. <br />
<br />
1) Можно воспользоваться динамически подгружаемой библиотекой С runtime. Для этого приложение и dll надо компилировать с ключом /MD (или MDd для отладки). В таком случае переменная будет общей для приложения и dll. <br />
<br />
2) Можно в основном модуле программы (тот, который станет .exe) сделать "дырку" (backdoor), через которую присваивать переменной (int errno) значение: <br>&lt;pre&gt;__declspec(dllexport) void set_errno(int code)<br>{<br>errno = code;<br>}<br>&lt;/pre&gt;<br>В dll при подключении к процессу надо извлечь из модуля программы указатель на эту функцию. <br>&lt;pre&gt; typedef void (*SETINT)(int);<br>SETINT g_set_errno=0;<br>void set_errno_in_exe(int code)<br>{<br>if(g_set_errno) g_set_errno(code);<br>}<br><br>BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )<br>{<br>HANDLE hModule; // Handle to the main module<br>if(fdwReason == DLL_PROCESS_ATTACH )<br>{<br>hModule = GetModuleHandle(NULL);<br>if (hModule == NULL) return FALSE;<br>g_set_errno = (SETINT) GetProcAddress(hModule, "set_errno");<br>}<br>return TRUE;<br>}<br>&lt;/pre&gt;<br>В нужном месте в dll вместо присваивания errno нужно вызывать внешнюю функцию <br>&lt;pre&gt;void inside_dll_func()<br>{<br>...<br>...<br>set_errno_in_exe(ERROR_CODE);<br>...<br>}<br>&lt;/pre&gt;</div>Алексей1153++https://wiki.shelek.ru/index.php?title=%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%BE%D0%B2%D0%BE%D0%B9_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D1%8B&diff=487Создание новой страницы2008-10-03T17:06:56Z<p>Алексей1153++: длинна -> длина</p>
<hr />
<div>===Используя Wikilinks===<br />
Новую страницу можно легко создать с помощью стандартных [[Форматирование ссылок|ссылок]], если кто-либо создал ссылку на несуществующую статью ссылка будет отображаться красным цветом. При переходе по такой ссылке откроется окно редактирования новой статьи. После создания статьи ссылка будет отображаться синим цветом.<br />
===С помощью URL===<br />
Новую страницу можно создать, указав ее название непосредственно в адресной строке браузера, обычно это выглядит следующим образом:<br />
*<nowiki>http://www.my-wiki.org/index.php/Название новой статьи</nowiki><br />
*<nowiki>http://www.my-wiki.org/wiki/Название новой статьи</nowiki><br />
===С помощью поиска===<br />
Если использовать кнопку "Перейти" для поиска и заданное имя страницы не найдено, появиться ссылка "Создать страницу". (ссылки не будет, если использовать кнопку "Поиск")<br />
=== Допустимые имена страниц ===<br />
<br />
Изначально для использования в именах страниц запрещены следующие символы: <br />
<br />
<nowiki># < > [ ] | { } +</nowiki><br />
<br />
<br />
Символ "+" можно разрешить, добавив строку <br />
<br />
$wgLegalTitleChars .='+';<br />
<br />
к локальному конфигурационному файлу. <br />
<br />
Дополнительные параметры задаются через обратный слэш ("\"). <br />
<br />
Пространство имен указывается перед названием статьи, через двоеточие. При этом максимальная длина названия состовляет 255 байт (не включая длину названия пространства имен). При использовании символов в кодировке utf-8 под один символ может резервироваться несколько байт. <br />
<br />
Пробелы в названии статей равноценны подчеркиваниям ("_"). <br />
<br />
[[Category:Язык_разметки]]</div>Алексей1153++