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

Материал из Весельчак У
Перейти к: навигация, поиск
(Создан редирект на FAQ:WinAPI_VCPP. Оптимизация для поисковых систем.)
 
(не показано 18 промежуточных версий 2 участников)
Строка 1: Строка 1:
−
 
+
#REDIRECT [[FAQ:WinAPI_VCPP]]
−
 
+
−
 
+
−
 
+
−
=== Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу?  ===
+
−
 
+
−
Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand() :
+
−
<syntaxhighlight>
+
−
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);
+
−
}
+
−
</syntaxhighlight>
+
−
 
+
−
=== Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать?  ===
+
−
 
+
−
Лечится проблема так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются.
+
−
 
+
−
=== Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы?  ===
+
−
 
+
−
Нужно использовать функцию GetModuleFileName():
+
−
<syntaxhighlight>
+
−
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 - содержит путь
+
−
</syntaxhighlight>
+
−
 
+
−
=== Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame?  ===
+
−
 
+
−
<syntaxhighlight>
+
−
#include "MainFrm.h"
+
−
 
+
−
//CMyApp - класс вашего приложения. theApp - глобальная переменная,
+
−
//поэтому для доступа к ней используем extern
+
−
extern CMyApp theApp;
+
−
 
+
−
void CMyView::F()
+
−
{
+
−
//Получаем главное окно приложения в любом месте программы
+
−
CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);
+
−
 
+
−
pMainFrame->m_wndDlgBar ....//Делаем что хотим
+
−
...
+
−
}
+
−
</syntaxhighlight>
+
−
 
+
−
=== Как загрузить и показать один из стандартных курсоров?  ===
+
−
 
+
−
<syntaxhighlight>
+
−
HCURSOR hCursor;
+
−
hCursor=AfxGetApp()->LoadStandardCursor(IDC_UPARROW);
+
−
if(hCursor)SetCursor(hCursor);
+
−
</syntaxhighlight>
+
−
идентификаторы стандартных курсоров:
+
−
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.
+
−
<syntaxhighlight>
+
−
void CMainFrame::OnClose()
+
−
{
+
−
if(......)
+
−
{
+
−
//не разрешаем закрыть
+
−
return;
+
−
}
+
−
+
−
CFrameWnd::OnClose();
+
−
}
+
−
</syntaxhighlight>
+
−
 
+
−
=== Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab?  ===
+
−
 
+
−
Последовательность действий следующая:
+
−
1) кладём на форму нужное количество элементов RadioButton.
+
−
2) у первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство.
+
−
3) порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется.
+
−
 
+
−
=== Где лучше устанавливать начальные значения элемента CComboBox?  ===
+
−
 
+
−
Это можно сделать парой способов:
+
−
 
+
−
1) В редакторе форм - открыть свойства элемента CComboBox , "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter)
+
−
2) В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView)
+
−
 
+
−
=== Как перевести RichEdit в режим замены символов?  ===
+
−
 
+
−
Имеется несколько способов.
+
−
 
+
−
1) Программно, если известен хендл элемента (hWnd), это делается так:
+
−
<syntaxhighlight>
+
−
//помещаем в конец очереди сообющений контрола сообщение WM_KEYDOWN
+
−
//с нужными параметрами
+
−
::PostMessage(hWnd,WM_KEYDOWN,VK_INSERT,1);
+
−
</syntaxhighlight>
+
−
 
+
−
2) Пользователь во время работы может нажать клавишу Insert.
+
−
 
+
−
=== Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы?  ===
+
−
 
+
−
Это можно сделать так:
+
−
 
+
−
<syntaxhighlight>
+
−
AfxGetApp()->m_pMainWnd-> ...;
+
−
</syntaxhighlight>
+
−
 
+
−
или так
+
−
<syntaxhighlight>
+
−
extern CMyAppXXX theApp;//здесь CMyAppXXX - название класса вашего приложения
+
−
theApp.m_pMainWnd-> ...;
+
−
</syntaxhighlight>
+
−
 
+
−
=== Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ?  ===
+
−
 
+
−
Это можно сделать методом SetScaleToFitSize():
+
−
<syntaxhighlight>
+
−
void CMyView::OnInitialUpdate()
+
−
{
+
−
CFormView::OnInitialUpdate();
+
−
 
+
−
//скрываем полосы прокрутки
+
−
GetParentFrame()->RecalcLayout();
+
−
ResizeParentToFit();//это уберёт полосы прокрутки со вьюхи
+
−
SIZE s={0,0};
+
−
SetScaleToFitSize(s);
+
−
//далее вызовется обработчик OnPaint(), о котором ниже
+
−
/////////
+
−
...
+
−
...
+
−
}
+
−
</syntaxhighlight>
+
−
 
+
−
Также обратите внимание на одну особенность: в дебаг-версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s={0,0} происходит с ошибкой (программа при этом завершается).
+
−
Обходится это так:
+
−
<syntaxhighlight>
+
−
void CMyView::OnPaint()
+
−
{
+
−
#ifdef _DEBUG
+
−
CPaintDC dc(this);
+
−
#else
+
−
CFormView::OnPaint();
+
−
#endif
+
−
}
+
−
</syntaxhighlight>
+
−
 
+
−
или даже вообще так:
+
−
<syntaxhighlight>
+
−
void CMyView::OnPaint()
+
−
{
+
−
CPaintDC dc(this);
+
−
}
+
−
</syntaxhighlight>
+
−
 
+
−
=== Как нарисовать прямоугольник с вертикальным цветовым градиентом?  ===
+
−
 
+
−
Нужно задасться граничными значениями цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников (а, значит, плавность гралдиента) задаётся точностью.
+
−
Пример:
+
−
<syntaxhighlight>
+
−
//вертикальный градиент
+
−
//pdc - указатель на контекст устройства
+
−
//pSize - указатель на структуру
+
−
//SIZE с размером прямоугольника
+
−
// dwdColor1, dwdColor2 - начальный и конечный цвет
+
−
//bySteps - количество шагов градиента (1...255)
+
−
void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps)
+
−
{
+
−
if(!bySteps)bySteps=1;
+
−
WORD i;
+
−
+
−
long W,H,x1,x2;
+
−
BYTE R1,G1,B1,R2,G2,B2;
+
−
float dh,dR,dG,dB,y1,y2,Rc,Gc,Bc;
+
−
+
−
//ширина и высота
+
−
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;
+
−
}
+
−
}
+
−
</syntaxhighlight>
+
−
 
+
−
пример вызова:
+
−
<syntaxhighlight>
+
−
SIZE Size={100,100};
+
−
sFillGradientRect(&dc,&Size, RGB(200,0,0), RGB(0,200,0),10);
+
−
</syntaxhighlight>
+
−
 
+
−
=== Как под Windows отслеживать изменение файла?  ===
+
−
 
+
−
Нужно использовать функции:
+
−
 
+
−
  FindFirstChangeNotification
+
−
  FindNextChangeNotification
+
−
  FindCloseChangeNotification
+
−
 
+
−
  (подробности - в MSDN)
+
−
 
+
−
=== Как конвертировать массив char[] в CString?  ===
+
−
Это можно сделать методами самого класса CString:
+
−
<syntaxhighlight>
+
−
char buf[]="text";
+
−
 
+
−
//строка должна обязательно заканчиваться нулём!!!
+
−
 
+
−
//конвертируем так
+
−
CString txt(buf);
+
−
 
+
−
//или так
+
−
CString txt;
+
−
txt=buf;
+
−
</syntaxhighlight>
+
−
 
+
−
=== Как зарезервировать в CString буфер нужной длины?  ===
+
−
 
+
−
Это можно сделать при помощи методов класса:  
+
−
 
+
−
<syntaxhighlight>
+
−
  CString::GetBuffer(...)
+
−
</syntaxhighlight>
+
−
  и
+
−
<syntaxhighlight>
+
−
  CString::GetBufferSetLength(...)
+
−
</syntaxhighlight>
+
−
 
+
−
Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку НЕ МЕНЬШЕ заданной длины, а второй возвращает строку точно равную заданной длине. Обе могут перераспределять память если надо. В обычных случаях лучше использовать GetBuffer.
+
−
 
+
−
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем.
+
−
 
+
−
=== Как передать больше одного параметр в процедуру потока?  ===
+
−
 
+
−
Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру.
+
−
Пример:
+
−
<syntaxhighlight>
+
−
struct mystr
+
−
{
+
−
CEdit* pEd;
+
−
CDialog* pDlg;
+
−
DWORD* pdwd;
+
−
int *pn;
+
−
};
+
−
</syntaxhighlight>
+
−
 
+
−
запуск потока:
+
−
 
+
−
<syntaxhighlight>
+
−
mystr *pparam=new mystr;//экземпляр не должен быть временным!!!
+
−
 
+
−
memset(pparam,0,sizeof(*pparam));
+
−
pparam->pEd=...;
+
−
pparam->pdwd=...;
+
−
 
+
−
::AfxBeginThread(thread,pparam);
+
−
//тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как
+
−
//он у нас удалиля в процедуре потока
+
−
</syntaxhighlight>
+
−
 
+
−
процедура потока:
+
−
<syntaxhighlight>
+
−
//поток:
+
−
UINT threadLoader(LPVOID pParam)
+
−
{
+
−
//копируем данные из структуры в локальную структуру
+
−
mystr data=*((mystr*)pParam);
+
−
//освобождаем память временной структуры
+
−
delete ((mystr*)pParam);
+
−
pParam=0;
+
−
+
−
 
+
−
...
+
−
data.pDlg->...;
+
−
(*data.pdwd)=...;
+
−
...
+
−
}
+
−
</syntaxhighlight>
+
−
 
+
−
=== Как убрать главное меню из окна CMainFrame?  ===
+
−
Это можно сделать в виртуальной функции PreCreateWindow:
+
−
<syntaxhighlight>
+
−
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
+
−
{
+
−
//обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow
+
−
cs.hMenu = 0;
+
−
+
−
if(!CFrameWnd::PreCreateWindow(cs))
+
−
return FALSE;
+
−
...
+
−
...
+
−
}
+
−
</syntaxhighlight>
+
−
 
+
−
=== Как работающая программа может определить, что пользователь завершает работу Windows?  ===
+
−
 
+
−
Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу.
+
−
 
+
−
=== Как сделать всплывающую подсказку для класса CWnd и классов, от него производных?  ===
+
−
 
+
−
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify) :
+
−
<syntaxhighlight>
+
−
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);
+
−
}
+
−
</syntaxhighlight>
+
−
 
+
−
=== Как в отладчике Visual С++ просмотреть содержимое std::vector<string> ?===
+
−
 
+
−
Это можно сделать так. К примеру, имеется
+
−
<syntaxhighlight>
+
−
std::vector<string> V;
+
−
</syntaxhighlight>
+
−
 
+
−
режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения:
+
−
 
+
−
V._Myfirst  (-  будет показан первый элемент V)
+
−
V._Myfirst+1  (- второй элемент V,)
+
−
 
+
−
и т.д.
+
−
 
+
−
=== Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах?  ===
+
−
 
+
−
Для этого нужно использовать процедуру API:
+
−
<syntaxhighlight>
+
−
BOOL GetTextExtentPoint32(
+
−
  HDC hdc,// хендл контекста
+
−
  LPCTSTR lpString,// выводимая строка
+
−
  int cbString,// длина строки в символах
+
−
  LPSIZE lpSize// указатель на структуру SIZE, куда
+
−
  //будут помещены размеры
+
−
);
+
−
</syntaxhighlight>
+
−
 
+
−
Функция вычисляет длину лишь одной символов, оканчивающейся нулём. Поэтому, чтобы вычислить "размер" многострочнокго текста, текст вначале необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки.
+
−
 
+
−
[[Category:FAQ]]
+

Текущая версия на 02:30, 9 ноября 2008

Перенаправление на: