FAQ:WinAPI, VCPP Part 2 — различия между версиями

Материал из Весельчак У
Перейти к: навигация, поиск
(Как в отладчике Visual С++ просмотреть содержимое std::vector ?)
м (Форматирование.)
Строка 1: Строка 1:
 +
===Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу?===
  
 +
Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand():
  
=== Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу?  ===
+
<syntaxhighlight lang="cpp">
 
+
BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam)
Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand() :
+
<syntaxhighlight>
+
BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam)  
+
 
{
 
{
WORD wMess=(wParam>>16);//командное сообщение
+
WORD wMess = (wParam >> 16); //командное сообщение
int nID=(int)(wParam &0x0000ffff));//ID контрола
+
int nID = (int)(wParam &0x0000ffff)); //ID контрола
HWND hW=(HWND)lParam;//хендл контрола
+
HWND hW = (HWND)lParam; //хендл контрола
 
 
//смотрим, какой контрол
+
// смотрим, какой контрол
switch(nID)
+
switch (nID)
 
{
 
{
 
//кнопки
 
//кнопки
Строка 20: Строка 19:
 
{
 
{
 
//смотрим, какое сообщение
 
//смотрим, какое сообщение
switch(wMess)
+
switch (wMess)
 
{
 
{
case BN_CLICKED:{ ... }break;
+
case BN_CLICKED: { ... } break;
 
}
 
}
 
}
 
}
 
break;
 
break;
 
 
//едиты
+
// едиты
 
case ID_ED1:
 
case ID_ED1:
 
case ID_ED2:
 
case ID_ED2:
Строка 33: Строка 32:
 
case ID_ED4:
 
case ID_ED4:
 
{
 
{
//смотрим, какое сообщение
+
// смотрим, какое сообщение
switch(wMess)
+
switch (wMess)
 
{
 
{
case EN_CHANGE:{ ... }break;
+
case EN_CHANGE: { ... } break;
case EN_KILLFOCUS:{ ... }break;
+
case EN_KILLFOCUS: { ... } break;
 
}
 
}
 
}
 
}
Строка 47: Строка 46:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать? ===
+
===Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать?===
 +
 
 +
Лечится проблема так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются.
  
Лечится проблема так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются.
+
===Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы?===
  
=== Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы?  ===
+
Нужно использовать функцию GetModuleFileName():
  
Нужно использовать функцию GetModuleFileName():
 
 
<syntaxhighlight>
 
<syntaxhighlight>
 
TCHAR pszFileName[MAX_PATH];
 
TCHAR pszFileName[MAX_PATH];
pszFileName[0]=0;
+
pszFileName[0] = 0;
 +
 
 
GetModuleFileName(NULL, pszFileName, MAX_PATH);
 
GetModuleFileName(NULL, pszFileName, MAX_PATH);
CString stModulePath = pszFileName;
+
CString stModulePath = pszFileName;
//ищем первый слеш с конца и удаляем
+
 
//его вместе с именем файла EXE
+
// ищем первый слеш с конца и удаляем
 +
// его вместе с именем файла EXE
 
int nEnd = stModulePath.ReverseFind('\\');
 
int nEnd = stModulePath.ReverseFind('\\');
stModulePath.Delete(nEnd, stModulePath.GetLength()-nEnd);
+
stModulePath.Delete(nEnd, stModulePath.GetLength() - nEnd);
  
//stModulePath - содержит путь
+
// stModulePath - содержит путь
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame? ===
+
===Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame?===
  
<syntaxhighlight>
+
<syntaxhighlight lang="cpp">
 
#include "MainFrm.h"
 
#include "MainFrm.h"
  
//CMyApp - класс вашего приложения. theApp - глобальная переменная,
+
// CMyApp - класс вашего приложения. theApp - глобальная переменная,
//поэтому для доступа к ней используем extern
+
// поэтому для доступа к ней используем extern
 +
 
 
extern CMyApp theApp;
 
extern CMyApp theApp;
  
 
void CMyView::F()
 
void CMyView::F()
 
{
 
{
//Получаем главное окно приложения в любом месте программы
+
// Получаем главное окно приложения в любом месте программы
CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);
+
CMainFrame* pMainFrame = (CMainFrame*)(theApp.m_pMainWnd);
  
pMainFrame->m_wndDlgBar ....//Делаем что хотим
+
pMainFrame->m_wndDlgBar ....; // Делаем что хотим
 
...
 
...
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Как загрузить и показать один из стандартных курсоров? ===
+
===Как загрузить и показать один из стандартных курсоров?===
  
<syntaxhighlight>
+
<syntaxhighlight lang="cpp">
 
HCURSOR hCursor;
 
HCURSOR hCursor;
hCursor=AfxGetApp()->LoadStandardCursor(IDC_UPARROW);
 
if(hCursor)SetCursor(hCursor);
 
</syntaxhighlight>
 
идентификаторы стандартных курсоров:
 
  
IDC_ARROW
+
hCursor = AfxGetApp()->LoadStandardCursor(IDC_UPARROW);
  
IDC_IBEAM
+
if (hCursor)
 +
SetCursor(hCursor);
 +
</syntaxhighlight>
  
IDC_WAIT
+
Идентификаторы стандартных курсоров:
 +
* IDC_ARROW
 +
* IDC_IBEAM
 +
* IDC_WAIT
 +
* IDC_CROSS
 +
* IDC_UPARROW
 +
* IDC_SIZENWSE
 +
* IDC_SIZENESW
 +
* IDC_SIZEWE
 +
* IDC_SIZENS
 +
* IDC_SIZEALL
  
IDC_CROSS
+
===Как запретить пользователю закрыть программу нажатием на кнопку с крестиком?===
  
IDC_UPARROW
+
Для этого нужно добавить обработчик сообщения WM_CLOSE (функция OnClose() в MFC) в главное окно программы. Для диалоговых приложений такое окно - это главный диалог, для одно- и много-документных приложений - это CMainFrame.
  
IDC_SIZENWSE
+
<syntaxhighlight lang="cpp">
 
+
IDC_SIZENESW
+
 
+
IDC_SIZEWE
+
 
+
IDC_SIZENS
+
 
+
IDC_SIZEALL
+
 
+
=== Как запретить пользователю закрыть программу нажатием на кнопку с крестиком?  ===
+
 
+
Для этого нужно добавить обработчик сообщения WM_CLOSE ( функция OnClose() в MFC) в главное окно программы. Для диалоговых приложений такое окно - это главный диалог, для одно- и много-документных приложений - это CMainFrame.
+
<syntaxhighlight>
+
 
void CMainFrame::OnClose()
 
void CMainFrame::OnClose()
 
{
 
{
if(......)
+
if (....)
 
{
 
{
//не разрешаем закрыть
+
// не разрешаем закрыть
 
return;
 
return;
 
}
 
}
Строка 131: Строка 129:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab? ===
+
===Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab?===
  
 
Последовательность действий следующая:
 
Последовательность действий следующая:
 +
# Помещаем на форму нужное количество элементов RadioButton;
 +
# У первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство;
 +
# Порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется.
  
1) кладём на форму нужное количество элементов RadioButton.
+
===Где лучше устанавливать начальные значения элемента CComboBox?===
 
+
2) у первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство.
+
 
+
3) порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется.
+
 
+
=== Где лучше устанавливать начальные значения элемента CComboBox? ===
+
  
 
Это можно сделать парой способов:
 
Это можно сделать парой способов:
 +
# В редакторе форм - открыть свойства элемента CComboBox, "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter);
 +
# В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView).
  
1) В редакторе форм - открыть свойства элемента CComboBox , "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter)
+
===Как перевести RichEdit в режим замены символов?===
  
2) В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView)
+
Имеется несколько способов.
  
=== Как перевести RichEdit в режим замены символов?  ===
+
1. Программно, если известен хендл элемента (hWnd), это делается так:
  
Имеется несколько способов.
+
<syntaxhighlight lang="cpp">
 
+
// помещаем в конец очереди сообющений контрола сообщение WM_KEYDOWN
1) Программно, если известен хендл элемента (hWnd), это делается так:
+
// с нужными параметрами
<syntaxhighlight>
+
::PostMessage(hWnd, WM_KEYDOWN, VK_INSERT, 1);
//помещаем в конец очереди сообющений контрола сообщение WM_KEYDOWN
+
//с нужными параметрами
+
::PostMessage(hWnd,WM_KEYDOWN,VK_INSERT,1);
+
 
</syntaxhighlight>
 
</syntaxhighlight>
  
2) Пользователь во время работы может нажать клавишу Insert.
+
2. Пользователь во время работы может нажать клавишу Insert.
  
=== Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы? ===
+
===Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы?===
  
 
Это можно сделать так:
 
Это можно сделать так:
  
<syntaxhighlight>
+
<syntaxhighlight lang="cpp">
AfxGetApp()->m_pMainWnd-> ...;  
+
AfxGetApp()->m_pMainWnd-> ...;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
или так
 
или так
<syntaxhighlight>
+
<syntaxhighlight lang="cpp">
extern CMyAppXXX theApp;//здесь CMyAppXXX - название класса вашего приложения
+
extern CMyAppXXX theApp; // здесь CMyAppXXX - название класса вашего приложения
theApp.m_pMainWnd-> ...;  
+
theApp.m_pMainWnd-> ...;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ? ===
+
===Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ?===
  
 
Это можно сделать методом SetScaleToFitSize():
 
Это можно сделать методом SetScaleToFitSize():
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="cpp">
 
void CMyView::OnInitialUpdate()
 
void CMyView::OnInitialUpdate()
 
{
 
{
 
CFormView::OnInitialUpdate();
 
CFormView::OnInitialUpdate();
  
//скрываем полосы прокрутки
+
// скрываем полосы прокрутки
 
GetParentFrame()->RecalcLayout();
 
GetParentFrame()->RecalcLayout();
ResizeParentToFit();//это уберёт полосы прокрутки со вьюхи
+
ResizeParentToFit(); // это уберёт полосы прокрутки со вьюхи
SIZE s={0,0};
+
SIZE s = {0, 0};
 
SetScaleToFitSize(s);
 
SetScaleToFitSize(s);
 
//далее вызовется обработчик OnPaint(), о котором ниже
 
//далее вызовется обработчик OnPaint(), о котором ниже
/////////
+
 
...
+
// ...
...
+
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Также обратите внимание на одну особенность: в дебаг-версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s={0,0} происходит с ошибкой (программа при этом завершается).
+
Также обратите внимание на одну особенность: в отладочной версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s = {0, 0} происходит с ошибкой (программа при этом завершается).
 
Обходится это так:
 
Обходится это так:
<syntaxhighlight>
+
 
void CMyView::OnPaint()  
+
<syntaxhighlight lang="cpp">
 +
void CMyView::OnPaint()
 
{
 
{
 
#ifdef _DEBUG
 
#ifdef _DEBUG
Строка 209: Строка 204:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
или даже вообще так:
+
Или так:
<syntaxhighlight>
+
 
void CMyView::OnPaint()  
+
<syntaxhighlight lang="cpp">
 +
void CMyView::OnPaint()
 
{
 
{
 
CPaintDC dc(this);
 
CPaintDC dc(this);
Строка 217: Строка 213:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Как нарисовать прямоугольник с вертикальным цветовым градиентом? ===
+
===Как нарисовать прямоугольник с вертикальным цветовым градиентом?===
 +
 
 +
Нужно задасть граничные значения цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников, а, значит - плавность градиента, задаётся точностью.
  
Нужно задасться граничными значениями цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников (а, значит, плавность гралдиента) задаётся точностью.
 
 
Пример:
 
Пример:
<syntaxhighlight>
+
 
//вертикальный градиент
+
<syntaxhighlight lang="cpp">
//pdc - указатель на контекст устройства
+
// вертикальный градиент
//pSize - указатель на структуру
+
// pdc - указатель на контекст устройства
//SIZE с размером прямоугольника
+
// pSize - указатель на структуру
 +
// SIZE с размером прямоугольника
 
// dwdColor1, dwdColor2 - начальный и конечный цвет
 
// dwdColor1, dwdColor2 - начальный и конечный цвет
//bySteps - количество шагов градиента (1...255)  
+
// bySteps - количество шагов градиента (1...255)
void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps)
+
void sFillVertGradientRect(CDC* pdc, SIZE *pSize, COLORREF dwdColor1,
 +
COLORREF dwdColor2, BYTE bySteps)
 
{
 
{
if(!bySteps)bySteps=1;
 
 
WORD i;
 
WORD i;
 +
long W, H, x1, x2;
 +
BYTE R1, G1, B1, R2, G2, B2;
 +
float dh, dR, dG, dB, y1, y2, Rc, Gc, Bc;
 
 
long W,H,x1,x2;
+
if (!bySteps)
BYTE R1,G1,B1,R2,G2,B2;
+
bySteps = 1;
float dh,dR,dG,dB,y1,y2,Rc,Gc,Bc;
+
 
+
 
//ширина и высота
 
//ширина и высота
W=pSize->cx;
+
W = pSize->cx;
H=pSize->cy;
+
H = pSize->cy;
 
 
//раскладываем цвета на их составляющие
+
// раскладываем цвета на их составляющие
//для удобства дальнейших вычислений
+
// для удобства дальнейших вычислений
R1=(BYTE)((dwdColor1&0x000000ff));
+
R1 = (BYTE)((dwdColor1 & 0x000000ff));
G1=(BYTE)((dwdColor1&0x0000ff00)>>8);
+
G1 = (BYTE)((dwdColor1 & 0x0000ff00) >> 8);
B1=(BYTE)((dwdColor1&0x00ff0000)>>16);
+
B1 = (BYTE)((dwdColor1 & 0x00ff0000) >> 16);
R2=(BYTE)((dwdColor2&0x000000ff));
+
R2 = (BYTE)((dwdColor2 & 0x000000ff));
G2=(BYTE)((dwdColor2&0x0000ff00)>>8);
+
G2 = (BYTE)((dwdColor2 & 0x0000ff00) >> 8);
B2=(BYTE)((dwdColor2&0x00ff0000)>>16);
+
B2 = (BYTE)((dwdColor2 & 0x00ff0000) >> 16);
 
 
//высота разноцветных прямоугольников
+
// высота разноцветных прямоугольников
dh=((float)H)/((float)bySteps);
+
dh = ((float)H) / ((float)bySteps);
//величина шагов составляющих цветов
+
 
dR=(((float)R2)-((float)R1))/((float)bySteps);
+
// величина шагов составляющих цветов
dG=(((float)G2)-((float)G1))/((float)bySteps);
+
dR = (((float)R2) - ((float)R1)) / ((float)bySteps);
dB=(((float)B2)-((float)B1))/((float)bySteps);
+
dG = (((float)G2) - ((float)G1)) / ((float)bySteps);
//выводим прямоугольники
+
dB = (((float)B2) - ((float)B1)) / ((float)bySteps);
x1=0;x2=W;y1=0;y2=dh;
+
 
Rc=R1;Gc=G1;Bc=B1;
+
// выводим прямоугольники
for(i=0;i<bySteps;i++)
+
x1 = 0;
 +
x2 = W;
 +
y1 = 0;
 +
y2 = dh;
 +
Rc = R1;
 +
Gc = G1;
 +
Bc = B1;
 +
 
 +
for (i = 0; i < bySteps; i++)
 
{
 
{
//текущий цвет
+
// текущий цвет
pdc->FillSolidRect(x1,(int)y1,x2-x1,(int)(y2-y1),RGB((BYTE)Rc,(BYTE)Gc,(BYTE)Bc));
+
pdc->FillSolidRect(
//следующий цвет и координаты
+
x1,
y1+=dh;y2+=dh;
+
(int)y1, x2 - x1,
Rc+=dR;Gc+=dG;Bc+=dB;
+
(int)(y2 - y1),
 +
RGB((BYTE)Rc,
 +
(BYTE)Gc,
 +
(BYTE)Bc)
 +
);
 +
 
 +
// следующий цвет и координаты
 +
y1 += dh;
 +
y2 += dh;
 +
Rc += dR;
 +
Gc += dG;
 +
Bc += dB;
 
}
 
}
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
пример вызова:  
+
Пример вызова:
<syntaxhighlight>
+
 
SIZE Size={100,100};
+
<syntaxhighlight lang="cpp">
sFillGradientRect(&dc,&Size, RGB(200,0,0), RGB(0,200,0),10);
+
SIZE Size = {100, 100};
 +
sFillGradientRect(&dc, &Size, RGB(200, 0, 0), RGB(0, 200, 0), 10);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Как под Windows отслеживать изменение файла? ===
+
===Как под Windows отслеживать изменение файла?===
  
Нужно использовать функции:  
+
Нужно использовать функции:
 
+
* FindFirstChangeNotification
FindFirstChangeNotification
+
* FindNextChangeNotification
 
+
* FindCloseChangeNotification
FindNextChangeNotification
+
 
+
FindCloseChangeNotification
+
  
 
(подробности - в MSDN)
 
(подробности - в MSDN)
  
=== Как конвертировать массив char[] в CString? ===
+
===Как конвертировать массив char[] в CString?===
 +
 
 
Это можно сделать методами самого класса CString:
 
Это можно сделать методами самого класса CString:
<syntaxhighlight>
 
char buf[]="text";
 
  
//строка должна обязательно заканчиваться нулём!!!
+
<syntaxhighlight lang="cpp">
 +
char buf[] = "text";
 +
// строка должна обязательно заканчиваться нулём!!!
  
//конвертируем так
+
// конвертируем так
 
CString txt(buf);
 
CString txt(buf);
  
//или так
+
// или так
 
CString txt;
 
CString txt;
txt=buf;
+
txt = buf;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Как зарезервировать в CString буфер нужной длины? ===
+
===Как зарезервировать в CString буфер нужной длины?===
  
Это можно сделать при помощи методов класса:  
+
Это можно сделать при помощи методов класса:
  
<syntaxhighlight>
+
<syntaxhighlight lang="cpp">
   CString::GetBuffer(...)
+
   CString::GetBuffer(...);
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
и
 
и
<syntaxhighlight>
+
 
   CString::GetBufferSetLength(...)
+
<syntaxhighlight lang="cpp">
 +
   CString::GetBufferSetLength(...);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку НЕ МЕНЬШЕ заданной длины, а второй возвращает строку точно равную заданной длине. Обе могут перераспределять память если надо. В обычных случаях лучше использовать GetBuffer.  
+
Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку ''не меньше'' заданной длины, а второй возвращает строку, точно равную заданной длине. Обе могут перераспределять память, если необходимо. В обычных случаях лучше использовать GetBuffer.
  
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем.
+
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе. "-1" удобно использовать, если известно, что строка заканчивается нулем.
  
=== Как передать больше одного параметр в процедуру потока? ===
+
===Как передать больше одного параметр в процедуру потока?===
  
 
Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру.
 
Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру.
 +
 
Пример:
 
Пример:
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="cpp">
 
struct mystr
 
struct mystr
 
{
 
{
Строка 333: Строка 355:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
запуск потока:  
+
запуск потока:
  
<syntaxhighlight>
+
<syntaxhighlight lang="cpp">
mystr *pparam=new mystr;//экземпляр не должен быть временным!!!
+
mystr *pparam = new mystr; // экземпляр не должен быть временным!!!
  
memset(pparam,0,sizeof(*pparam));
+
memset(pparam, 0, sizeof(*pparam));
pparam->pEd=...;
+
pparam->pEd = ...;
pparam->pdwd=...;
+
pparam->pdwd = ...;
  
::AfxBeginThread(thread,pparam);  
+
::AfxBeginThread(thread, pparam);
//тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как
+
// тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как
//он у нас удалиля в процедуре потока
+
// он у нас удалиля в процедуре потока
 
</syntaxhighlight>
 
</syntaxhighlight>
  
процедура потока:  
+
Процедура потока:
<syntaxhighlight>
+
 
//поток:  
+
<syntaxhighlight lang="cpp">
UINT threadLoader(LPVOID pParam)  
+
// поток:
{  
+
UINT threadLoader(LPVOID pParam)
//копируем данные из структуры в локальную структуру
+
{
mystr data=*((mystr*)pParam);
+
// копируем данные из структуры в локальную структуру
//освобождаем память временной структуры
+
mystr data = *((mystr*)pParam);
 +
// освобождаем память временной структуры
 
delete ((mystr*)pParam);
 
delete ((mystr*)pParam);
pParam=0;
+
pParam = 0;
+
  
 
...
 
...
 
data.pDlg->...;
 
data.pDlg->...;
(*data.pdwd)=...;
+
(*data.pdwd) = ...;
 
...
 
...
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Как убрать главное меню из окна CMainFrame? ===
+
===Как убрать главное меню из окна CMainFrame?===
 +
 
 
Это можно сделать в виртуальной функции PreCreateWindow:
 
Это можно сделать в виртуальной функции PreCreateWindow:
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="cpp">
 
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
 
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
 
{
 
{
//обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow
+
// обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow
 
cs.hMenu = 0;
 
cs.hMenu = 0;
 
 
if(!CFrameWnd::PreCreateWindow(cs))
+
if (!CFrameWnd::PreCreateWindow(cs))
 
return FALSE;
 
return FALSE;
...
+
 
 
...
 
...
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Как работающая программа может определить, что пользователь завершает работу Windows? ===
+
===Как работающая программа может определить, что пользователь завершает работу Windows?===
  
 
Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу.
 
Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу.
  
=== Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ===
+
===Как сделать всплывающую подсказку для класса CWnd и классов, от него производных?===
  
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify) :
+
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify):
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="cpp">
 
class CMyDlg:puplic CDialog
 
class CMyDlg:puplic CDialog
 
{
 
{
CToolTipCtrl m_ToolTip;//мембер класса CMyDlg
+
CToolTipCtrl m_ToolTip; // мембер класса CMyDlg
 
};
 
};
+
 
//массив, в котором перечислены идентификаторы
+
// массив, в котором перечислены идентификаторы
//контролов и тексты подсказок к ним
+
// контролов и тексты подсказок к ним
struct{int ID;const char* pch;} m_a_Tips[]=
+
struct
 +
{
 +
int ID;
 +
const char* pch;
 +
}
 +
m_a_Tips[] =
 
{
 
{
{IDC_BUTTON1,"Кнопка"},
+
{IDC_BUTTON1, "Кнопка"},
{IDC_STATIC1,"Текст"},
+
{IDC_STATIC1, "Текст"},
//
+
{0, 0} // признак конца массива
{0,0},//признак конца массива
+
 
};
 
};
+
 
//в инициализации диалога (хотя, в принципе,
+
// в инициализации диалога (хотя, в принципе,
//можно и не тут) создаём и привязываем подсказки
+
// можно и не тут) создаём и привязываем подсказки
BOOL CMyDlg::OnInitDialog()  
+
BOOL CMyDlg::OnInitDialog()
 
{
 
{
 
CDialog::OnInitDialog();
 
CDialog::OnInitDialog();
  
//создаём элемент TOOLTIP
+
// создаём элемент TOOLTIP
 
m_ToolTip.Create(this);
 
m_ToolTip.Create(this);
  
//Привязка подсказок
+
// Привязка подсказок
for(int i=0; m_a_Tips[i].ID; i++)
+
for (int i = 0; m_a_Tips[i].ID; i++)
 
{
 
{
 
m_ToolTip.AddTool(
 
m_ToolTip.AddTool(
 
GetDlgItem(m_a_Tips[i].ID),
 
GetDlgItem(m_a_Tips[i].ID),
 
m_a_Tips[i].pch
 
m_a_Tips[i].pch
);
+
);
 
}
 
}
 
 
//включаем показ подсказок
+
// включаем показ подсказок
 
m_ToolTip.Activate(1);
 
m_ToolTip.Activate(1);
...
+
 
 
...
 
...
 
}
 
}
+
 
//для того, чтобы подсказки отображались как реакция на движение
+
// для того, чтобы подсказки отображались как реакция на движение
//курсора мыши, транслируем получаемые окнами сообщения в
+
// курсора мыши, транслируем получаемые окнами сообщения в
//виртуальной PreTranslateMessage()
+
// виртуальной PreTranslateMessage()
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg)  
+
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg)
 
{
 
{
//транслируем
+
// транслируем
if(m_ToolTip.m_hWnd)m_ToolTip.RelayEvent(pMsg);
+
if (m_ToolTip.m_hWnd)
+
m_ToolTip.RelayEvent(pMsg);
 +
 
 
return CDialog::PreTranslateMessage(pMsg);
 
return CDialog::PreTranslateMessage(pMsg);
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Как в отладчике Visual С++ просмотреть содержимое std::vector<string> ?===
+
===Как в отладчике Visual С++ просмотреть содержимое std::vector<string>?===
  
Это можно сделать так. К примеру, имеется
+
Это можно сделать так: к примеру, имеется:
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="cpp">
 
std::vector<string> V;
 
std::vector<string> V;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения:  
+
В режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения:
 +
* "V._Myfirst" - будет показан первый элемент V
 +
* "V._Myfirst+1" - второй элемент V
 +
и т.д.
  
V._Myfirst    (-  будет показан первый элемент V)
+
===Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах?===
  
V._Myfirst+1  (- второй элемент V)
+
Для этого нужно использовать процедуру API:
  
и т.д.
+
<syntaxhighlight lang="cpp">
 
+
=== Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах?  ===
+
 
+
Для этого нужно использовать процедуру API:
+
<syntaxhighlight>
+
 
BOOL GetTextExtentPoint32(
 
BOOL GetTextExtentPoint32(
  HDC hdc,// хендл контекста
+
HDC hdc, // хендл контекста
  LPCTSTR lpString,// выводимая строка
+
LPCTSTR lpString, // выводимая строка
  int cbString,// длина строки в символах
+
int cbString, // длина строки в символах
  LPSIZE lpSize// указатель на структуру SIZE, куда  
+
LPSIZE lpSize // указатель на структуру SIZE, куда будут помещены размеры
  //будут помещены размеры
+
 
);
 
);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Функция вычисляет длину лишь одной символов, оканчивающейся нулём. Поэтому, чтобы вычислить "размер" многострочнокго текста, текст вначале необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки.
+
Функция вычисляет ширину строки символов, оканчивающейся нулём. Поэтому, чтобы вычислить габариты многострочного текста, текст, в начале, необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки.
  
 
[[Category:FAQ]]
 
[[Category:FAQ]]

Версия 11:05, 18 октября 2008

Содержание

Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу?

Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand():

BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam)
{
	WORD wMess = (wParam >> 16); //командное сообщение
	int nID = (int)(wParam &0x0000ffff)); //ID контрола
	HWND hW = (HWND)lParam; //хендл контрола
 
	// смотрим, какой контрол
	switch (nID)
	{
		//кнопки
		case ID_BN1:
		case ID_BN2:
		case ID_BN3:
		{
			//смотрим, какое сообщение
			switch (wMess)
			{
				case BN_CLICKED: { ... } break;
			}
		}
		break;
 
			// едиты
		case ID_ED1:
		case ID_ED2:
		case ID_ED3:
		case ID_ED4:
		{
			// смотрим, какое сообщение
			switch (wMess)
			{
				case EN_CHANGE: { ... } break;
				case EN_KILLFOCUS: { ... } break;
			}
		}
		break;
	}
 
	return CDialog::OnCommand(wParam, lParam);
}

Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать?

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

Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы?

Нужно использовать функцию GetModuleFileName():

Указан неподдерживаемый язык.

Вы должны указать язык следующим образом: <source lang="html4strict">...</source>

Поддерживаемые языки:

4cs, 6502acme, 6502kickass, 6502tasm, 68000devpac, abap, actionscript, actionscript3, ada, aimms, algol68, apache, applescript, arm, asm, asp, asymptote, autoconf, autohotkey, autoit, avisynth, awk, bascomavr, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, caddcl, cadlisp, cfdg, cfm, chaiscript, chapel, cil, clojure, cmake, cobol, coffeescript, cpp, csharp, css, cuesheet, d, dart, dcl, dcpu16, dcs, delphi, diff, div, dos, dot, e, ecmascript, eiffel, email, epc, erlang, euphoria, ezt, f1, falcon, fo, fortran, freebasic, freeswitch, fsharp, gambas, gdb, genero, genie, gettext, glsl, gml, gnuplot, go, groovy, gwbasic, haskell, haxe, hicest, hq9plus, html4strict, html5, icon, idl, ini, inno, intercal, io, ispfpanel, j, java, java5, javascript, jcl, jquery, kixtart, klonec, klonecpp, latex, lb, ldif, lisp, llvm, locobasic, logtalk, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, magiksf, make, mapbasic, matlab, mirc, mmix, modula2, modula3, mpasm, mxml, mysql, nagios, netrexx, newlisp, nginx, nimrod, nsis, oberon2, objc, objeck, ocaml, octave, oobas, oorexx, oracle11, oracle8, oxygene, oz, parasail, parigp, pascal, pcre, per, perl, perl6, pf, php, pic16, pike, pixelbender, pli, plsql, postgresql, postscript, povray, powerbuilder, powershell, proftpd, progress, prolog, properties, providex, purebasic, pycon, pys60, python, q, qbasic, qml, racket, rails, rbs, rebol, reg, rexx, robots, rpmspec, rsplus, ruby, rust, sas, scala, scheme, scilab, scl, sdlbasic, smalltalk, smarty, spark, sparql, sql, standardml, stonescript, systemverilog, tcl, teraterm, text, thinbasic, tsql, typoscript, unicon, upc, urbi, uscript, vala, vb, vbnet, vbscript, vedit, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, whois, winbatch, xbasic, xml, xpp, yaml, z80, zxbasic


TCHAR pszFileName[MAX_PATH];
pszFileName[0] = 0;

GetModuleFileName(NULL, pszFileName, MAX_PATH);
CString stModulePath = pszFileName;

// ищем первый слеш с конца и удаляем
// его вместе с именем файла EXE
int nEnd = stModulePath.ReverseFind('\\');
stModulePath.Delete(nEnd, stModulePath.GetLength() - nEnd);

// stModulePath - содержит путь

Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame?

#include "MainFrm.h"
 
// CMyApp - класс вашего приложения. theApp - глобальная переменная,
// поэтому для доступа к ней используем extern
 
extern CMyApp theApp;
 
void CMyView::F()
{
	// Получаем главное окно приложения в любом месте программы
	CMainFrame* pMainFrame = (CMainFrame*)(theApp.m_pMainWnd);
 
	pMainFrame->m_wndDlgBar ....; // Делаем что хотим
	...
}

Как загрузить и показать один из стандартных курсоров?

HCURSOR hCursor;
 
hCursor = AfxGetApp()->LoadStandardCursor(IDC_UPARROW);
 
if (hCursor)
	SetCursor(hCursor);

Идентификаторы стандартных курсоров:

  • IDC_ARROW
  • IDC_IBEAM
  • IDC_WAIT
  • IDC_CROSS
  • IDC_UPARROW
  • IDC_SIZENWSE
  • IDC_SIZENESW
  • IDC_SIZEWE
  • IDC_SIZENS
  • IDC_SIZEALL

Как запретить пользователю закрыть программу нажатием на кнопку с крестиком?

Для этого нужно добавить обработчик сообщения WM_CLOSE (функция OnClose() в MFC) в главное окно программы. Для диалоговых приложений такое окно - это главный диалог, для одно- и много-документных приложений - это CMainFrame.

void CMainFrame::OnClose()
{
	if (....)
	{
		// не разрешаем закрыть
		return;
	}
 
	CFrameWnd::OnClose();
}

Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab?

Последовательность действий следующая:

  1. Помещаем на форму нужное количество элементов RadioButton;
  2. У первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство;
  3. Порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется.

Где лучше устанавливать начальные значения элемента CComboBox?

Это можно сделать парой способов:

  1. В редакторе форм - открыть свойства элемента CComboBox, "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter);
  2. В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView).

Как перевести RichEdit в режим замены символов?

Имеется несколько способов.

1. Программно, если известен хендл элемента (hWnd), это делается так:

// помещаем в конец очереди сообющений контрола сообщение WM_KEYDOWN
// с нужными параметрами
::PostMessage(hWnd, WM_KEYDOWN, VK_INSERT, 1);

2. Пользователь во время работы может нажать клавишу Insert.

Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы?

Это можно сделать так:

AfxGetApp()->m_pMainWnd-> ...;

или так

extern CMyAppXXX theApp; // здесь CMyAppXXX - название класса вашего приложения
theApp.m_pMainWnd-> ...;

Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ?

Это можно сделать методом SetScaleToFitSize():

void CMyView::OnInitialUpdate()
{
	CFormView::OnInitialUpdate();
 
	// скрываем полосы прокрутки
	GetParentFrame()->RecalcLayout();
	ResizeParentToFit(); // это уберёт полосы прокрутки со вьюхи
	SIZE s = {0, 0};
	SetScaleToFitSize(s);
	//далее вызовется обработчик OnPaint(), о котором ниже
 
	// ...
}

Также обратите внимание на одну особенность: в отладочной версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s = {0, 0} происходит с ошибкой (программа при этом завершается). Обходится это так:

void CMyView::OnPaint()
{
	#ifdef _DEBUG
		CPaintDC dc(this);
	#else
		CFormView::OnPaint();
	#endif
}

Или так:

void CMyView::OnPaint()
{
	CPaintDC dc(this);
}

Как нарисовать прямоугольник с вертикальным цветовым градиентом?

Нужно задасть граничные значения цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников, а, значит - плавность градиента, задаётся точностью.

Пример:

// вертикальный градиент
// pdc - указатель на контекст устройства
// pSize - указатель на структуру
// SIZE с размером прямоугольника
// dwdColor1, dwdColor2 - начальный и конечный цвет
// bySteps - количество шагов градиента (1...255)
void sFillVertGradientRect(CDC* pdc, SIZE *pSize, COLORREF dwdColor1,
	COLORREF dwdColor2, BYTE bySteps)
{
	WORD i;
	long W, H, x1, x2;
	BYTE R1, G1, B1, R2, G2, B2;
	float dh, dR, dG, dB, y1, y2, Rc, Gc, Bc;
 
	if (!bySteps)
		bySteps = 1;
 
	//ширина и высота
	W = pSize->cx;
	H = pSize->cy;
 
	// раскладываем цвета на их составляющие
	// для удобства дальнейших вычислений
	R1 = (BYTE)((dwdColor1 & 0x000000ff));
	G1 = (BYTE)((dwdColor1 & 0x0000ff00) >> 8);
	B1 = (BYTE)((dwdColor1 & 0x00ff0000) >> 16);
	R2 = (BYTE)((dwdColor2 & 0x000000ff));
	G2 = (BYTE)((dwdColor2 & 0x0000ff00) >> 8);
	B2 = (BYTE)((dwdColor2 & 0x00ff0000) >> 16);
 
	// высота разноцветных прямоугольников
	dh = ((float)H) / ((float)bySteps);
 
	// величина шагов составляющих цветов
	dR = (((float)R2) - ((float)R1)) / ((float)bySteps);
	dG = (((float)G2) - ((float)G1)) / ((float)bySteps);
	dB = (((float)B2) - ((float)B1)) / ((float)bySteps);
 
	// выводим прямоугольники
	x1 = 0;
	x2 = W;
	y1 = 0;
	y2 = dh;
	Rc = R1;
	Gc = G1;
	Bc = B1;
 
	for (i = 0; i < bySteps; i++)
	{
		// текущий цвет
		pdc->FillSolidRect(
			x1,
			(int)y1, x2 - x1,
			(int)(y2 - y1),
			RGB((BYTE)Rc,
			(BYTE)Gc,
			(BYTE)Bc)
		);
 
		// следующий цвет и координаты
		y1 += dh;
		y2 += dh;
		Rc += dR;
		Gc += dG;
		Bc += dB;
	}
}

Пример вызова:

SIZE Size = {100, 100};
sFillGradientRect(&dc, &Size, RGB(200, 0, 0), RGB(0, 200, 0), 10);

Как под Windows отслеживать изменение файла?

Нужно использовать функции:

  • FindFirstChangeNotification
  • FindNextChangeNotification
  • FindCloseChangeNotification

(подробности - в MSDN)

Как конвертировать массив char[] в CString?

Это можно сделать методами самого класса CString:

char buf[] = "text";
// строка должна обязательно заканчиваться нулём!!!
 
// конвертируем так
CString txt(buf);
 
// или так
CString txt;
txt = buf;

Как зарезервировать в CString буфер нужной длины?

Это можно сделать при помощи методов класса:

   CString::GetBuffer(...);

и

   CString::GetBufferSetLength(...);

Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку не меньше заданной длины, а второй возвращает строку, точно равную заданной длине. Обе могут перераспределять память, если необходимо. В обычных случаях лучше использовать GetBuffer.

Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе. "-1" удобно использовать, если известно, что строка заканчивается нулем.

Как передать больше одного параметр в процедуру потока?

Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру.

Пример:

struct mystr
{
	CEdit* pEd;
	CDialog* pDlg;
	DWORD* pdwd;
	int *pn;
};

запуск потока:

mystr *pparam = new mystr; // экземпляр не должен быть временным!!!
 
memset(pparam, 0, sizeof(*pparam));
pparam->pEd = ...;
pparam->pdwd = ...;
 
::AfxBeginThread(thread, pparam);
// тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как
// он у нас удалиля в процедуре потока

Процедура потока:

// поток:
UINT threadLoader(LPVOID pParam)
{
	// копируем данные из структуры в локальную структуру
	mystr data = *((mystr*)pParam);
	// освобождаем память временной структуры
	delete ((mystr*)pParam);
	pParam = 0;
 
	...
	data.pDlg->...;
	(*data.pdwd) = ...;
	...
}

Как убрать главное меню из окна CMainFrame?

Это можно сделать в виртуальной функции PreCreateWindow:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	// обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow
	cs.hMenu = 0;
 
	if (!CFrameWnd::PreCreateWindow(cs))
		return FALSE;
 
	...
}

Как работающая программа может определить, что пользователь завершает работу Windows?

Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу.

Как сделать всплывающую подсказку для класса CWnd и классов, от него производных?

Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify):

class CMyDlg:puplic CDialog
{
	CToolTipCtrl m_ToolTip; // мембер класса CMyDlg
};
 
// массив, в котором перечислены идентификаторы
// контролов и тексты подсказок к ним
struct
{
	int ID;
	const char* pch;
}
m_a_Tips[] =
{
	{IDC_BUTTON1, "Кнопка"},
	{IDC_STATIC1, "Текст"},
	{0, 0} // признак конца массива
};
 
// в инициализации диалога (хотя, в принципе,
// можно и не тут) создаём и привязываем подсказки
BOOL CMyDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
 
	// создаём элемент TOOLTIP
	m_ToolTip.Create(this);
 
	// Привязка подсказок
	for (int i = 0; m_a_Tips[i].ID; i++)
	{
		m_ToolTip.AddTool(
			GetDlgItem(m_a_Tips[i].ID),
			m_a_Tips[i].pch
		);
	}
 
	// включаем показ подсказок
	m_ToolTip.Activate(1);
 
	...
}
 
// для того, чтобы подсказки отображались как реакция на движение
// курсора мыши, транслируем получаемые окнами сообщения в
// виртуальной PreTranslateMessage()
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg)
{
	// транслируем
	if (m_ToolTip.m_hWnd)
		m_ToolTip.RelayEvent(pMsg);
 
	return CDialog::PreTranslateMessage(pMsg);
}

Как в отладчике Visual С++ просмотреть содержимое std::vector<string>?

Это можно сделать так: к примеру, имеется:

std::vector<string> V;

В режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения:

  • "V._Myfirst" - будет показан первый элемент V
  • "V._Myfirst+1" - второй элемент V

и т.д.

Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах?

Для этого нужно использовать процедуру API:

BOOL GetTextExtentPoint32(
	HDC hdc, // хендл контекста
	LPCTSTR lpString, // выводимая строка
	int cbString, // длина строки в символах
	LPSIZE lpSize // указатель на структуру SIZE, куда будут помещены размеры
);

Функция вычисляет ширину строки символов, оканчивающейся нулём. Поэтому, чтобы вычислить габариты многострочного текста, текст, в начале, необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки.