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

Материал из Весельчак У
Перейти к: навигация, поиск
м (Множественные правки: форматирование кода, перефразировка вопросов, редактирование орфографии. (Остановился на "КОПИРОВАНИЕ В БУФЕР ОБ)
Строка 1: Строка 1:
 
=== Как узнать, что пользователь меняет текст в приложении на основе CRichEditView?===
 
=== Как узнать, что пользователь меняет текст в приложении на основе CRichEditView?===
Нужно добавить обработчик сообщения EN_CHANGE. Сообщение генерируется CRichEditView каждый раз, когда пользователь изменяет текст в окне CRichEditView
+
 
 +
Нужно добавить обработчик сообщения EN_CHANGE. Сообщение генерируется CRichEditView каждый раз, когда пользователь изменяет текст в окне CRichEditView.
  
 
===Чем отличается метод CArray::GetSize от метода CArray::GetCount?===
 
===Чем отличается метод CArray::GetSize от метода CArray::GetCount?===
Эти методы абсолютно идентичны. Скорее всего, в более старых версиях библиотек функции, одинаковые по смыслу, имели разные имена. Поэтому в целях совместимости разработчики оставили обе функции)
+
 
 +
Эти методы абсолютно идентичны. Скорее всего, в более старых версиях библиотек функции, одинаковые по смыслу, имели разные имена. Поэтому в целях совместимости разработчики оставили обе функции.
  
 
===Как загрузить текстовую строку из ресурса?===
 
===Как загрузить текстовую строку из ресурса?===
 +
 
Пример:
 
Пример:
 +
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
CString m_Temp;
 
CString m_Temp;
 +
 
m_Temp.LoadString(ID_MYSTRING);
 
m_Temp.LoadString(ID_MYSTRING);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
===Как поменять иконку у элемента item в CListCtrl?===
 
===Как поменять иконку у элемента item в CListCtrl?===
 +
 
Пример:
 
Пример:
 +
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
//заполняем структуру LVITEM
+
// заполняем структуру LVITEM
 
LVITEM lvItem;
 
LVITEM lvItem;
memset(&lvItem,0,sizeof(lvItem));
+
 
 +
memset(&lvItem, 0, sizeof(lvItem));
 
 
lvItem.mask =LVIF_IMAGE;//меняться будет картинка
+
lvItem.mask = LVIF_IMAGE; // меняться будет картинка
lvItem.iItem =...;// индекс элемента списка (Zero-based)
+
lvItem.iItem = ...; // индекс элемента списка (Zero-based)
lvItem.iSubItem =0;
+
lvItem.iSubItem = 0;
lvItem.iImage =...; //индекс иконки (из списка элемента)
+
lvItem.iImage = ...; //индекс иконки (из списка элемента)
 
 
 
pList->SetItem(&lvItem);
 
pList->SetItem(&lvItem);
Строка 28: Строка 36:
  
 
===Имеется класс Class1, содержащий член типа "указатель на Class2". В Class2 также имеется указатель на Class1. Компилятор выдаёт ошибку. Что надо делать?===
 
===Имеется класс Class1, содержащий член типа "указатель на Class2". В Class2 также имеется указатель на Class1. Компилятор выдаёт ошибку. Что надо делать?===
 +
 
Перекрёстное определение обходится следующим образом: код обоих классов разносится в пары файлов *.h и *.cpp, а перед каждым классом вписывается предопределение другого класса:
 
Перекрёстное определение обходится следующим образом: код обоих классов разносится в пары файлов *.h и *.cpp, а перед каждым классом вписывается предопределение другого класса:
  
 +
Файл "class1.h":
  
файл "class1.h"
 
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
class Class2;//предопределение Class2
+
class Class2; // предопределение Class2
  
Class1
+
class Class1
 
{
 
{
Class2* m_p2;//компилятор разрешит объявление указателя Class2*
+
Class2* m_p2; // компилятор разрешит объявление указателя Class2*
  
void F1(Class2* p);//компилятор разрешит объявление указателя Class2*
+
void F1(Class2* p); //компилятор разрешит объявление указателя Class2*
 
void F2(Class1* p);
 
void F2(Class1* p);
 
};
 
};
 
</syntaxhighlight>
 
</syntaxhighlight>
  
файл "class1.cpp"
+
Файл "class1.cpp":
 +
 
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
#include "class1.h"
 
#include "class1.h"
Строка 51: Строка 61:
 
void Class1::F1(Class2* p)
 
void Class1::F1(Class2* p)
 
{
 
{
...
+
// ...
 
}
 
}
  
 
void Class1::F2(Class1* p)
 
void Class1::F2(Class1* p)
 
{
 
{
...
+
// ...
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
Файл "class2.h":
  
файл "class2.h"
 
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
class Class1;//предопределение Class1
+
class Class1; // предопределение Class1
  
 
Class2
 
Class2
 
{
 
{
Class1* m_p1;//компилятор разрешит объявление указателя Class1*
+
Class1* m_p1; // компилятор разрешит объявление указателя Class1*
  
void F3(Class1* p);//компилятор разрешит объявление указателя Class1*
+
void F3(Class1* p); // компилятор разрешит объявление указателя Class1*
 
};
 
};
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
Файл "class2.cpp":
  
файл "class2.cpp"
 
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
#include "class2.h"
 
#include "class2.h"
Строка 81: Строка 91:
 
void Class2::F3(Class1* p)
 
void Class2::F3(Class1* p)
 
{
 
{
...
+
// ...
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 
  
 
После предопределения класса компилятор позволяет объявлять указатель на класс, так как переменная указателя на любой тип имеет всегда один и тот же размер.
 
После предопределения класса компилятор позволяет объявлять указатель на класс, так как переменная указателя на любой тип имеет всегда один и тот же размер.
  
===Как переключить раскладку в другом (то есть в активном) процессе?===
+
===Как переключить раскладку в другом (активном) процессе?===
Для этого можно использовать функции
+
  
* GetKeyboardLayout(...); // определить текущую раскладку
+
Для этого можно использовать функции:
* LoadKeyboardLayout(...); // загрузить новую раскладку
+
* GetKeyboardLayout - определить текущую раскладку
* VerLanguageName(...); // получить строку с описанием языка
+
* LoadKeyboardLayout - загрузить новую раскладку
 +
* VerLanguageName - получить строку с описанием языка
  
Подробности - в MSDN
+
Подробности - в MSDN.
  
 
===Как получить хендл элемента управления, зная его идентификатор?===
 
===Как получить хендл элемента управления, зная его идентификатор?===
Пример:
+
 
Пусть элемент Edit лежит на окне CMyWnd.
+
Пример: пусть элемент Edit лежит на окне CMyWnd.
 
Тогда:
 
Тогда:
 +
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
void CMyWnd::некая_процедура()
 
void CMyWnd::некая_процедура()
 
{
 
{
//для MFC
+
// для MFC
CEdit* ed=(CEdit* ) GetDlgItem(ID_EDIT1);
+
CEdit* ed = (CEdit* ) GetDlgItem(ID_EDIT1);
HWND hwnd=ed->GetSafeHwnd();
+
HWND hwnd = ed->GetSafeHwnd();
if(hwnd)
+
if (hwnd)
 
{
 
{
...
+
// ...
 
}
 
}
 
 
//для Win32 API
+
// для Win32 API
HWND hwnd=GetDlgItem(m_hWnd,ID_EDIT1);
+
HWND hwnd = GetDlgItem(m_hWnd, ID_EDIT1);
if(hwnd)
+
if (hwnd)
 
{
 
{
...
+
// ...
 
}
 
}
 
}
 
}
Строка 122: Строка 132:
  
 
===Как из дочернего окна закрыть приложение?===
 
===Как из дочернего окна закрыть приложение?===
Для этого нужно послать родительскому окну сообщение WM_CLOSE:
+
Для этого нужно послать родительскому окну сообщение WM_CLOSE.
 +
 
 +
Через указатель на родительское окно:
  
через указатель на родительское окно:
 
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
pParent->PostMessage(WM_CLOSE);
 
pParent->PostMessage(WM_CLOSE);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
при помощи хендла родительского окна:
+
При помощи хендла родительского окна:
 +
 
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
::PostMessage(pParent->m_hWnd,WM_CLOSE,(WPARAM)0,(LPARAM)0);
+
::PostMessage(pParent->m_hWnd, WM_CLOSE, (WPARAM)0, (LPARAM)0);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
===Как корректно перевести тип BSTR в CString и наоборот?===
 
===Как корректно перевести тип BSTR в CString и наоборот?===
  
# для конвертирования BSTR в CString нужно просто присвоить переменной типа CString переменную типа BSTR.
+
# Для конвертирования BSTR в CString нужно просто присвоить переменной типа CString переменную типа BSTR. Оператор "=" класса CString сам выполнит всю работу.
Оператор "=" класса CString сам выполнит всю работу.
+
# Для конвертирования BSTR в CString нужно выполнить код:
 
+
# для конвертирования BSTR в CString нужно выполнить код:
+
  
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
//указатель на будущий буфер с BSTR.
+
// указатель на будущий буфер с BSTR.
BSTR bstrHE=0;
+
// По сути, BSTR определён как typedef WCHAR* BSTR;
// (По сути, BSTR определён как  
+
// то есть - указатель на 16-битный символ юникод.
// typedef WCHAR* BSTR;
+
BSTR bstrHE = 0;
// то есть указатель на 16-битный символ юникод)
+
  
//строка для конвертации
+
// строка для конвертации
CString Str="мой текст";
+
CString Str = "мой текст";
  
//Выделяем память и загружаем адрес блока в bstrHE
+
// Выделяем память и загружаем адрес блока в bstrHE
bstrHE=Str.AllocSysString();
+
bstrHE = Str.AllocSysString();
  
//...
+
// ...
//тут работаем с bstrHE[]
+
// тут работаем с bstrHE[]
//...
+
// ...
  
//освобождаем память
+
// освобождаем память
 
SysFreeString(bstrHE);
 
SysFreeString(bstrHE);
 
</syntaxhighlight>
 
</syntaxhighlight>
Строка 164: Строка 173:
 
===Как получить доступ к графическим ресурсам элементов текущей темы оформления Windows?===
 
===Как получить доступ к графическим ресурсам элементов текущей темы оформления Windows?===
  
Для этого нужно использовать функции
+
Для этого нужно использовать функции:
 +
* OpenThemeData
 +
* DrawThemeBackground
 +
* DrawFrameControl
 +
* CloseThemeData
  
* OpenThemeData(...);
+
Подробности - в MSDN.
* DrawThemeBackground(...);
+
* DrawFrameControl(...);
+
* CloseThemeData(...);
+
 
+
(подробности - в MSDN)
+
  
 
===Имеется класс, производный от CDialog. Когда диалог в фокусе, нажатие на Enter или Esc приводит к закрытию диалога. Как это запретить?===
 
===Имеется класс, производный от CDialog. Когда диалог в фокусе, нажатие на Enter или Esc приводит к закрытию диалога. Как это запретить?===
При нажатии Enter происходит выполнение команды IDOK,при нажатии Esc - IDCANCEL.
 
  
Нужно переопределить в классе виртуальные функции OnOk() и OnCancel(), которые соответственно вызываются для этих команд. При помощи визарда эти функции добавить можно так:
+
При нажатии Enter происходит выполнение команды IDOK, при нажатии Esc - IDCANCEL.
 +
Нужно переопределить в классе виртуальные функции OnOk() и OnCancel(), которые соответственно вызываются для этих команд. При помощи визарда эти функции добавить можно следующим образом.
  
Положить на диалог две кнопки с идентификаторами IDOK и IDCANCEL (при создании нового диалога они там есть сразу), затем двойной щелчок по кнопке добавит соответствующий обработчик. В обработчиках надо удалить вызовы СDialog::OnOK() и CDialog::OnCancel(), тогда диалог закрываться не будет.
+
Поместить на диалог две кнопки с идентификаторами IDOK и IDCANCEL (при создании нового диалога они там есть сразу), двойной щелчок по кнопке добавит соответствующий обработчик. В обработчиках надо удалить вызовы СDialog::OnOK() и CDialog::OnCancel(), тогда диалог закрываться не будет.
  
 
Однако тогда диалог станет невозможно закрыть кнопкой с крестиком. Это обходится так: добавляем обработчик сообщения WM_CLOSE - OnClose(), и в нём делаем вызов OnOk() или OnCancel():
 
Однако тогда диалог станет невозможно закрыть кнопкой с крестиком. Это обходится так: добавляем обработчик сообщения WM_CLOSE - OnClose(), и в нём делаем вызов OnOk() или OnCancel():
 +
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
void CPlayersPropsDialog::OnClose()  
 
void CPlayersPropsDialog::OnClose()  
 
{
 
{
 
CDialog::OnClose();
 
CDialog::OnClose();
CDialog::OnCancel();//добавлено
+
CDialog::OnCancel(); // добавлено
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===Я написал в VC++ простейший макрос, где невозможно ошибиться, а компилятор всё же выдаёт ошибку. Не пойму, в чём дело?===
+
===Я написал в VC++ простейший макрос, где невозможно ошибиться, а компилятор всё же выдаёт ошибку.===
  
 
Скорее всего после одного из символов соединения строк "\" имеется пробел или табуляция. Их надо удалить. Можно найти их "на ощупь", а можно включить показ непечатных символов в студии. Найти эту команду можно так:
 
Скорее всего после одного из символов соединения строк "\" имеется пробел или табуляция. Их надо удалить. Можно найти их "на ощупь", а можно включить показ непечатных символов в студии. Найти эту команду можно так:
  
Tools->Customize...->вкладка Commands. В окошке Category выбрать "Edit", и среди кнопок справа найти кнопку, на которой написано "a.b"
+
Tools->Customize...->вкладка Commands. В окошке Category выбрать "Edit", и среди кнопок справа найти кнопку, на которой написано "a.b". Эту кнопку надо перенести на одну из панелей инструментов студии.
 
+
Эту кнопку надо перетащить на одну из панелей инструментов студии.
+
  
 
===Как получить список всех процессов, включая idle?===
 
===Как получить список всех процессов, включая idle?===
  
Использовать функции
+
Использовать функции:
* Process32First(...);
+
* Process32First
* Precess32Next(...);
+
* Precess32Next
  
(подробности - в MSDN)
+
Подробности - в MSDN.
  
 
===Как программно установить переменные окружения?===
 
===Как программно установить переменные окружения?===
 +
 
Чтобы добавить или изменить их программно, необходимо воспользоваться ключом реестра
 
Чтобы добавить или изменить их программно, необходимо воспользоваться ключом реестра
 +
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment
 
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Затем нужно отправить широковещательное сообщение WM_SETTINGCHANGE (это позволит приложениям узнать об изменениях):
+
Затем нужно отправить широковещательное сообщение WM_SETTINGCHANGE - это позволит приложениям узнать об изменениях:
 +
 
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
::SendMessage(HWND_BROADCAST,WM_SETTINGCHANGE,0,0);
+
::SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0);
 
</syntaxhighlight>
 
</syntaxhighlight>
 
  
 
===Как сделать, чтобы у окна был черный фон?===
 
===Как сделать, чтобы у окна был черный фон?===
 +
 
Нужно переопределить обработчик сообщения WM_CTLCOLOR - OnCtlColor():
 
Нужно переопределить обработчик сообщения WM_CTLCOLOR - OnCtlColor():
  
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
//глобальная переменная или член класса CMyDlg,
+
// глобальная переменная или член класса CMyDlg,
 
// инициализированный в OnInitDialog()
 
// инициализированный в OnInitDialog()
CBrush br(RGB(0,0,0));
+
CBrush br(RGB(0, 0, 0));
 
+
  
 
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)  
 
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)  
Строка 230: Строка 239:
 
HBRUSH hbr = CMyDlg::OnCtlColor(pDC, pWnd, nCtlColor);
 
HBRUSH hbr = CMyDlg::OnCtlColor(pDC, pWnd, nCtlColor);
 
 
//фон диалога (или View)
+
// фон диалога (или View)
if(nCtlColor==CTLCOLOR_DLG)
+
if (nCtlColor == CTLCOLOR_DLG)
 
{
 
{
 
return (HBRUSH)br;
 
return (HBRUSH)br;
 
}
 
}
 
 
//фон элементов SCtatic, лежащих на форме (если нужно)
+
// фон элементов SCtatic, лежащих на форме (если нужно)
if(nCtlColor==CTLCOLOR_STATIC)
+
if (nCtlColor == CTLCOLOR_STATIC)
 
{
 
{
//делаем фон текста статика прозрачным
+
// делаем фон текста статика прозрачным
 
pDC->SetBkMode(TRANSPARENT);
 
pDC->SetBkMode(TRANSPARENT);
 
return (HBRUSH)br;
 
return (HBRUSH)br;
Строка 248: Строка 257:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===Почему на моем компьютере экзешник, созданный в MFC запускается, а на других компьютерах - нет? Требует какую-то dll-ку.===
+
===Почему на моем компьютере экзешник, созданный в MFC запускается, а на других компьютерах - нет? Требует какую-то dll.===
Нужно выбирать режим Release:
+
  
Menu->Build->Configurations...->Release,
+
Нужно выбирать режим Release: Menu->Build->Configurations...->Release.
 
+
Экзешник, соответственно, брать из папки Release проекта.
и экзешник, соответственно, брать из папки Release проекта.
+
  
 
===Как в диалог добавить меню?===
 
===Как в диалог добавить меню?===
 +
 
Нужно создать в редакторе ресурсов новое меню, затем вставить его в диалог:
 
Нужно создать в редакторе ресурсов новое меню, затем вставить его в диалог:
 
+
# Открыть в редакторе диалог;
# открыть в редакторе диалог,
+
# В свойствах (во вкладке General, окошко Menu) указать идентификатор ресурса меню;
# в свойствах (во вкладке General, окошко Menu) указать идентификатор ресурса меню.
+
# При помощи визарда добавить для меню обработчики OnCommand() и OnUpdateСommand().
# при помощи визарда добавить для меню обработчики OnCommand() и OnUpdateСommand().
+
  
 
===Почему не вызывается OnUpdate для пунктов меню (не получается ни затенить, ни отметку поставить)?===
 
===Почему не вызывается OnUpdate для пунктов меню (не получается ни затенить, ни отметку поставить)?===
В диалоге (CDialog) у меню апдейт не происходит сам, в отличие от мейнфрейма (CFrameWnd). Для этого нужно сделать самим апдейт в обработчике сообщения WM_KICKIDLE.
+
 
 +
В диалоге (CDialog) у меню апдейт не происходит сам, в отличие от мейнфрейма (CFrameWnd). Для этого нужно сделать апдейт самим, в обработчике сообщения WM_KICKIDLE.
  
 
Визардом этот обработчик не добавляется, поэтому можно переопределить виртуальную DefWindowProc() и там обработать:
 
Визардом этот обработчик не добавляется, поэтому можно переопределить виртуальную DefWindowProc() и там обработать:
 +
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
#include <afxpriv.h> //этот файл надо включить, там определёна WM_KICKIDLE
+
#include <afxpriv.h> // этот файл надо включить, там определёна WM_KICKIDLE
  
 
LRESULT CMyDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)  
 
LRESULT CMyDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)  
 
{
 
{
if(message==WM_KICKIDLE)
+
if (message == WM_KICKIDLE)
 
{
 
{
//делаем апдейт для всех пунктов меню
+
// делаем апдейт для всех пунктов меню
CMenu* pMainMenu=GetMenu();
+
CMenu* pMainMenu = GetMenu();
if(pMainMenu)
+
if (pMainMenu)
 
{
 
{
 
CCmdUI cmdUI;
 
CCmdUI cmdUI;
for(UINT n=0; n < pMainMenu->GetMenuItemCount(); n++)
+
for (UINT n = 0; n < pMainMenu->GetMenuItemCount(); n++)
 
{
 
{
 
CMenu* pSubMenu = pMainMenu->GetSubMenu(n);
 
CMenu* pSubMenu = pMainMenu->GetSubMenu(n);
if(!pSubMenu)continue;
+
if (!pSubMenu)
 +
continue;
 
 
 
cmdUI.m_nIndexMax = pSubMenu->GetMenuItemCount();
 
cmdUI.m_nIndexMax = pSubMenu->GetMenuItemCount();
for(UINT i=0; i<cmdUI.m_nIndexMax; i++)
+
for (UINT i = 0; i < cmdUI.m_nIndexMax; i++)
 
{
 
{
 
cmdUI.m_nIndex = i;
 
cmdUI.m_nIndex = i;
Строка 299: Строка 309:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
===Как в главном окне отключить системное меню (в левом верхнем углу) и кнопки (в правом верхнем углу)?===
  
===Как в главном окне отключить системное меню (в левом верхнем углу) и кнопки(в правом верхнем углу)?===
+
При создании окна нужно убрать стиль WS_SYSMENU. Теперь пользователь корректно может закрыть окно только Alt+F4, ну, или если вы предоставите ему дополнительную возможность сделать это.
При создании окна нужно убрать стиль WS_SYSMENU (теперь пользователь корректно может закрыть окно только Alt+F4, ну или если вы предоставите ему дополнительную возможность сделать это)
+
  
 
Пример 1. (для SDI, MDI)
 
Пример 1. (для SDI, MDI)
 +
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
//этот обработчик уже добавлен визардом
+
// этот обработчик уже добавлен визардом
 
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
 
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
 
{
 
{
if( !CFrameWnd::PreCreateWindow(cs) )
+
if ( !CFrameWnd::PreCreateWindow(cs) )
 
return FALSE;
 
return FALSE;
 
// TODO: Modify the Window class or styles here by modifying
 
// TODO: Modify the Window class or styles here by modifying
Строка 314: Строка 325:
  
 
///////////////////////////////
 
///////////////////////////////
//добавленная часть
+
// добавленная часть
 
{
 
{
//убираем стиль
+
// убираем стиль
cs.style&=~WS_SYSMENU;
+
cs.style& =~ WS_SYSMENU;
 
}
 
}
 
///////////////////////////////
 
///////////////////////////////
Строка 326: Строка 337:
  
 
Пример 2. (для диалога)
 
Пример 2. (для диалога)
 
+
Если диалог описан в ресурсах, то в свойствах диалога убрать галочки:
Если диалог описан в ресурсах, то в свойствах диалога убрать галочки
+
 
+
 
* "System menu"
 
* "System menu"
 
* "Minimize box"
 
* "Minimize box"
Строка 334: Строка 343:
  
 
===Как запретить пользователю нажать на кнопку?===
 
===Как запретить пользователю нажать на кнопку?===
Нужно применить метод класса CWnd::EnableWindow(...) для кнопки. Значение параметра 0 делает кнопку неактивной, 1 - делает активной (кстати, не только для кнопки можно, а для любого класса, производного от класса CWnd).
 
  
 +
Нужно применить метод класса CWnd::EnableWindow(...) для кнопки. Значение 0 параметра делает кнопку неактивной, 1 - делает активной (кстати, не только для кнопки можно, а для любого класса, производного от класса CWnd).
 +
 +
Пусть имеется некий диалог, на нём лежит кнопка c ID == IDC_1. В любом месте кода диалога (кроме конструктора и деструктора, хотя, если проверить наличие валидного хендла диалога, как в примере, то ничего страшного не будет и там) выполняем код:
  
Пусть имеется некий диалог, на нём лежит кнопка c ID == IDC_1. В любом месте кода диалога (кроме конструктора и деструктора, хотя, если проверить наличие валидного хендла диалога, как в примере, то ничего страшного не будет и там) выполняем код
 
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
//делаем кнопку неактивной
+
// делаем кнопку неактивной
if(m_hWnd)
+
if (m_hWnd)
 
{
 
{
CWnd* pw=0;
+
CWnd* pw = 0;
pw=GetDlgItem(IDC_1);
+
pw = GetDlgItem(IDC_1);
if(pw)
+
if (pw)
 
{
 
{
 
pw->EnableWindow(0);
 
pw->EnableWindow(0);
Строка 351: Строка 361:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===Что означают сообщения, которые студия выводит при компиляции, вроде таких: Loaded 'C:\WINDOWS\SYSTEM\WSOCK32.DLL', no matching symbolic information found. ===
+
===Что означают сообщения, которые студия выводит при компиляции, вроде таких: Loaded 'C:\WINDOWS\SYSTEM\WSOCK32.DLL', no matching symbolic information found?===
Это строка говорит о том, что студия не смогла найти отладочные символы для WSOCK32.DLL. В этом нет ничего страшного, просто при наличии отладочных символов в процессе отладки можно получить доступ к именам функции из системных DLL. Например, вместо
+
<syntaxhighlight lang="cpp">
+
KERNEL32! 0x77E8B184()
+
</syntaxhighlight>
+
увидим
+
  
<syntaxhighlight lang="cpp">
+
Это строка говорит о том, что студия не смогла найти отладочные символы для WSOCK32.DLL. В этом нет ничего страшного. Просто, при наличии отладочных символов в процессе отладки, можно получить доступ к именам функции из системных DLL. Например, вместо ''KERNEL32! 0x77E8B184()'' увидим ''KERNEL32!CreateThread''.
KERNEL32!CreateThread.
+
 
</syntaxhighlight>
+
===Как обработать сообщения, которые приходят к элементу управления?===
 +
 
 +
Скажем, нужно обработать сообщения, приходящие к элементу класса CEdit. Нужно произвести от CEdit свой класс и в виртуальной процедуре класса WindowProc перехватить нужные сообщения.
  
===Как обработать сообщения, которое приходит к некому элементу управления?===
 
Скажем, нужно обработать сообщения, приходящие к элементу класса CEdit. Нужно произвести от CEdit свой класс, и в виртуальной процедуре класса WindowProc перехватить нужные сообщения.
 
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
virtual LRESULT WindowProc(
 
virtual LRESULT WindowProc(
Строка 372: Строка 377:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Пример. Полностью выключаем, скажем, обработку сообщения WM_CHAR
+
Пример. Полностью выключаем, скажем, обработку сообщения WM_CHAR.
 +
 
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)  
 
LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)  
 
{
 
{
switch(message)
+
switch (message)
 
{
 
{
 
case WM_CHAR:
 
case WM_CHAR:
Строка 390: Строка 396:
  
 
Чтобы связать экземпляр класса с элементом управления на форме, добавьте визардом для
 
Чтобы связать экземпляр класса с элементом управления на форме, добавьте визардом для
элемента управления переменную класса (выбрав не Value а Control).
+
элемента управления переменную класса (выбрав не Value, а Control).
  
 
===Как настроить количество пробелов в табуляции?===
 
===Как настроить количество пробелов в табуляции?===
Есть пара способов:
 
  
 +
Есть пара способов:
 
# Tools->Options->Tabs->Insert Spaces
 
# Tools->Options->Tabs->Insert Spaces
# правой кнопкой мыши щёлкнуть по тексту, в контекстном меню выбрать properties
+
# Правой кнопкой мыши щёлкнуть по тексту, в контекстном меню выбрать properties.
  
 
===Как автоматически расставить отступы?===
 
===Как автоматически расставить отступы?===
Нужно в студии выделить текст для форматирования, нажать Alt+F8.
+
 
 +
Нужно в студии выделить текст для форматирования и нажать Alt+F8.
  
 
Ещё есть программа Artistic Style ( http://sourceforge.net/projects/astyle/ ), которая занимается переформатированием кода.
 
Ещё есть программа Artistic Style ( http://sourceforge.net/projects/astyle/ ), которая занимается переформатированием кода.
  
===Поиск границ блока===
+
===Поиск границ блока.===
Сочетание клавиш CTRL+ "}" ищет парную фигурную скобку в тексте и переходит к ней.
+
 
 +
Сочетание клавиш CTRL+"}" ищет парную фигурную скобку в тексте и переходит к ней.
 +
 
 +
===Вертикальное выделение текста.===
  
===Вертикальное выделение текста===
 
 
Если удерживать клавишу Alt, а затем начать выделять текст мышкой, то область выделения принимает форму прямоугольника, что позволяет выделять вертикальные фрагменты текста.
 
Если удерживать клавишу Alt, а затем начать выделять текст мышкой, то область выделения принимает форму прямоугольника, что позволяет выделять вертикальные фрагменты текста.
  
 
===Как узнать количество установленных в CListCtrl столбцов?===
 
===Как узнать количество установленных в CListCtrl столбцов?===
Пример
+
 
 +
Пример:
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
//указатель на переменную-элемент управления
+
// указатель на переменную-элемент управления
CListCtrl* pL=...;
+
CListCtrl* pL = ...;
  
//получаем количество столбцов
+
// получаем количество столбцов
int count=pL->GetHeaderCtrl()->GetItemCount();
+
int count = pL->GetHeaderCtrl()->GetItemCount();
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
===Как получить иконку приложения?===
 
===Как получить иконку приложения?===
 +
 
Если приложение запущено, то нужно найти его главное окно и послать ему сообщение WM_GETICON.
 
Если приложение запущено, то нужно найти его главное окно и послать ему сообщение WM_GETICON.
 +
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
//функция возвращант хендл иконки  
+
// функция возвращант хендл иконки  
 
LRESULT SendMessage(hWnd, WM_GETICON, wParam, 0);
 
LRESULT SendMessage(hWnd, WM_GETICON, wParam, 0);
  
//hWnd == хендл окна приложения
+
// hWnd == хендл окна приложения
//wParam ==  
+
// wParam ==  
 
// 1)==ICON_BIG - получить большую иконку
 
// 1)==ICON_BIG - получить большую иконку
 
// 2)==ICON_SMALL - получить маленькую иконку
 
// 2)==ICON_SMALL - получить маленькую иконку
Строка 435: Строка 447:
  
 
===Как в CString можно найти или вырезать часть строки?===
 
===Как в CString можно найти или вырезать часть строки?===
 +
 
Это можно сделать при помощи методов класса CString:
 
Это можно сделать при помощи методов класса CString:
 +
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
//вырезает кусок строки
+
// вырезает кусок строки
 
CString Mid(int nFirst) const;
 
CString Mid(int nFirst) const;
CString Mid(int nFirst, int nCount) const;
+
CString Mid(int nFirst, int nCount) const;
  
//возвращает кусок строки (сначала или с конца)
+
// возвращает кусок строки (сначала или с конца)
CString Left(int nCount ) const;
+
CString Left(int nCount) const;
CString Right(int nCount ) const;
+
CString Right(int nCount) const;
  
//возвращает начальный кусок строки, в котором есть только
+
// возвращает начальный кусок строки, в котором есть только
//символы из набора, представленного в lpszCharSet
+
// символы из набора, представленного в lpszCharSet
CString SpanIncluding(LPCTSTR lpszCharSet ) const;
+
CString SpanIncluding(LPCTSTR lpszCharSet) const;
  
//возвращает начальный кусок строки, в котором нет
+
// возвращает начальный кусок строки, в котором нет
//символов из набора, представленного в lpszCharSet
+
// символов из набора, представленного в lpszCharSet
CString SpanExcluding(LPCTSTR lpszCharSet ) const;  
+
CString SpanExcluding(LPCTSTR lpszCharSet) const;  
  
//убирает "пробелоподобные" символы из самого начала строки
+
// убирает "пробелоподобные" символы из самого начала строки.
//(то есть - пробел, табуляцию (\t), возврат каретки, перевод строки (/r/n))
+
// то есть - пробел, табуляцию (\t), возврат каретки, перевод строки (/r/n)
 
void TrimLeft();
 
void TrimLeft();
//убирает все повторы символа из самого начала строки
 
void TrimLeft(TCHAR chTarget );
 
//убирает из самого начала строки все символа из набора lpszTargets
 
void TrimLeft(LPCTSTR lpszTargets );
 
  
 +
// убирает все повторы символа из самого начала строки
 +
void TrimLeft(TCHAR chTarget);
 +
 +
// убирает из самого начала строки все символа из набора lpszTargets
 +
void TrimLeft(LPCTSTR lpszTargets);
 
void TrimRight();
 
void TrimRight();
void TrimRight(TCHAR chTarget );
+
void TrimRight(TCHAR chTarget);
void TrimRight(LPCTSTR lpszTargets );
+
void TrimRight(LPCTSTR lpszTargets);
  
//поиск в строке
+
// поиск в строке
int Find( TCHAR ch ) const;
+
int Find(TCHAR ch) const;
int Find( LPCTSTR lpszSub ) const;
+
int Find(LPCTSTR lpszSub) const;
int Find( TCHAR ch, int nStart ) const;
+
int Find(TCHAR ch, int nStart) const;
int Find( LPCTSTR pstr, int nStart ) const;
+
int Find(LPCTSTR pstr, int nStart) const;
  
//поиск, начиная с конца
+
// поиск, начиная с конца
int ReverseFind( TCHAR ch ) const;
+
int ReverseFind(TCHAR ch) const;
  
//поиск позиции первого символа, одного из набора,
+
// поиск позиции первого символа, одного из набора,
 
// представленного в lpszCharSet
 
// представленного в lpszCharSet
int FindOneOf( LPCTSTR lpszCharSet ) const;
+
int FindOneOf(LPCTSTR lpszCharSet) const;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
===Как отобразить на элементах управления промежуточные результаты длительных вычислений?===
 
===Как отобразить на элементах управления промежуточные результаты длительных вычислений?===
В общем случае это делается принудительной перерисовкой нужного окна путём объявления этого окна невалидным
+
 
 +
В общем случае это делается принудительной перерисовкой нужного окна путём объявления этого окна невалидным.
 +
 
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
pWnd->Invalidate(0);
 
pWnd->Invalidate(0);
 
</syntaxhighlight>
 
</syntaxhighlight>
а затем непосредственной отсылки в оконную процедуру сообщения WM_PAINT
+
 
 +
Затем непосредственной отсылки в оконную процедуру сообщения WM_PAINT.
 +
 
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
pWnd->UpdateWindow();
 
pWnd->UpdateWindow();
Строка 491: Строка 510:
 
Пример:
 
Пример:
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
CWnd* pWnd=...;//окно, которое надо перерисовывать
+
CWnd* pWnd = ...; // окно, которое надо перерисовывать
  
for(int i=0; i<10000; i++)
+
for (int i = 0; i < 10000; i++)
 
{
 
{
//меняется содержимое окна
+
// меняется содержимое окна
//...
+
// ...
  
//немедленная перерисовка
+
// немедленная перерисовка
 
pWnd->Invalidate(0);
 
pWnd->Invalidate(0);
 
pWnd->UpdateWindow();
 
pWnd->UpdateWindow();
Строка 506: Строка 525:
 
Также можно также просто вызвать метод RedrawWindow() с параметрами по умолчанию.
 
Также можно также просто вызвать метод RedrawWindow() с параметрами по умолчанию.
  
===Я написал DLL, которую используют несколько приложений. Всё вроде работает, но когда происходит очередной вызов функции из DLL, почему то данные в функции обнуляются. С чем это связано?===
+
===Я написал DLL, которую используют несколько приложений. Всё работает, но когда происходит очередной вызов функции из DLL, почему то, данные в функции обнуляются. С чем это связано?===
 +
 
 
Переменные и массивы в DLL, содержимое которых должно использоваться несколькими процессами, должны объявляться статическими. Статическая переменная или массив инициализируются только один раз в момент загрузки DLL.
 
Переменные и массивы в DLL, содержимое которых должно использоваться несколькими процессами, должны объявляться статическими. Статическая переменная или массив инициализируются только один раз в момент загрузки DLL.
 +
 
Пример:
 
Пример:
 +
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
DWORD calltest()
 
DWORD calltest()
 
{
 
{
//будет выполнено только при первом вызове
+
// будет выполнено только при первом вызове
static DWORD callcount=0;
+
static DWORD callcount = 0;
static DWORD str[1000]={0};  
+
static DWORD str[1000] = {0};  
  
//будет выполняться каждый раз
+
// будет выполняться каждый раз
 
callcount++;
 
callcount++;
 
return callcount;
 
return callcount;
Строка 525: Строка 547:
  
 
Создание проекции:
 
Создание проекции:
 +
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
HANDLE CreateFileMapping(
 
HANDLE CreateFileMapping(
HANDLE hFile, //хендл уже открытого файла
+
HANDLE hFile, // хендл уже открытого файла
 
LPSECURITY_ATTRIBUTES lpAttributes,
 
LPSECURITY_ATTRIBUTES lpAttributes,
DWORD flProtect, //способ открытия проекции
+
DWORD flProtect, // способ открытия проекции
DWORD dwMaximumSizeHigh, //размер файла (старшие 4 байта, обычно==0)
+
DWORD dwMaximumSizeHigh, // размер файла (старшие 4 байта, обычно - 0)
DWORD dwMaximumSizeLow, //размер файла (младшие 4 байта)
+
DWORD dwMaximumSizeLow, // размер файла (младшие 4 байта)
 
LPCTSTR lpName
 
LPCTSTR lpName
 
);
 
);
Строка 537: Строка 560:
  
 
Доступ к созданной проекции производится процедурой:
 
Доступ к созданной проекции производится процедурой:
 +
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
LPVOID MapViewOfFile(
 
LPVOID MapViewOfFile(
HANDLE hFileMappingObject, //хендл проекции
+
HANDLE hFileMappingObject, // хендл проекции
DWORD dwDesiredAccess, //способ работы с проекцией
+
DWORD dwDesiredAccess, // способ работы с проекцией
 
DWORD dwFileOffsetHigh,
 
DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow, //смещение от начала файла (младшие 4 байта)
+
DWORD dwFileOffsetLow, // смещение от начала файла (младшие 4 байта)
SIZE_T dwNumberOfBytesToMap //длина в байтах (если ==0 - то весь файл)
+
SIZE_T dwNumberOfBytesToMap // длина в байтах (если 0 - то весь файл)
 
);
 
);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
далее с файлом можно работать как с обычным массивом в памяти.
+
Далее с файлом можно работать как с обычным массивом в памяти.
 +
 
 +
После работы с проекцией, её надо освободить.
  
После работы с проекцией, её надо освободить процедурой
 
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
BOOL UnmapViewOfFile(
 
BOOL UnmapViewOfFile(
LPCVOID lpBaseAddress //адрес, который вернула процедура MapViewOfFile
+
LPCVOID lpBaseAddress // адрес, который вернула процедура MapViewOfFile
 
);
 
);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
Пример:
 
Пример:
<syntaxhighlight lang="cpp">
 
HANDLE hFile=...;//хендл уже открытого файла
 
DWORD dwdFileLen=...;//размер открытого файла
 
  
HANDLE hMapFile=0;//хендл для проекции
+
<syntaxhighlight lang="cpp">
 +
HANDLE hFile = ...; // хендл уже открытого файла
 +
DWORD dwdFileLen = ...; // размер открытого файла
 +
HANDLE hMapFile = 0; // хендл для проекции
  
//создаём проекцию "только для чтения"
+
// создаём проекцию "только для чтения"
hMapFile=::CreateFileMapping(hFile,0,PAGE_READONLY,0,dwdFileLen,0);
+
hMapFile = ::CreateFileMapping(hFile, 0, PAGE_READONLY, 0, dwdFileLen, 0);
  
//хендл hFile можно закрыть уже здесь, в принципе,
+
// хендл hFile можно закрыть уже здесь, в принципе,
//но мы сделаем это позже
+
// но мы сделаем это позже
  
//получаем доступ к проекции (тоже только для чтения)
+
// получаем доступ к проекции (тоже только для чтения)
BYTE* pbyFile=(BYTE*)::MapViewOfFile(hMapFile,FILE_MAP_READ,0,0,0);
+
BYTE* pbyFile = (BYTE*)::MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
  
 
///////////////////
 
///////////////////
//тут работаем с массивом pbyFile[dwdFileLen] как с обычным,
+
// тут работаем с массивом pbyFile[dwdFileLen] как с обычным,
//только не забываем, что он открыт только для чтения
+
// только не забываем, что он открыт только для чтения
//...
+
// ...
//...
+
// ...
//...
+
// ...
 
///////////////////
 
///////////////////
  
//отключаем файл данных от адресного пространства
+
// отключаем файл данных от адресного пространства
 
UnmapViewOfFile(pbyFile);
 
UnmapViewOfFile(pbyFile);
  
//освобождаем хендл проекции
+
// освобождаем хендл проекции
 
CloseHandle(hMapFile)
 
CloseHandle(hMapFile)
  
//освобождаем хендл открытого файла
+
// освобождаем хендл открытого файла
 
CloseHandle(hFile);
 
CloseHandle(hFile);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
===Как в MFC Grid control отобразить картинку в ячейке?===
 
===Как в MFC Grid control отобразить картинку в ячейке?===
 +
 
Нужно создать список изображений (CImageList), затем передать указатель на список в таблицу. Поскольку элемент управления лишь копирует указатель, список должен создаваться динамически, либо быть членом класса, экземпляр которого существует всё время работы таблицы.
 
Нужно создать список изображений (CImageList), затем передать указатель на список в таблицу. Поскольку элемент управления лишь копирует указатель, список должен создаваться динамически, либо быть членом класса, экземпляр которого существует всё время работы таблицы.
 +
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
CImageList m_ImageList;
 
CImageList m_ImageList;
 
CGridCtrL m_Grid1;
 
CGridCtrL m_Grid1;
...
+
 
...
+
// ...
//неким образом создаётся список
+
 
 +
// неким образом создаётся список
 
m_ImageList.Create(...);
 
m_ImageList.Create(...);
//...
+
 
 +
// ...
  
 
//вставляем в элемент управления
 
//вставляем в элемент управления
 
m_Grid1.SetImageList(&m_ImageList);
 
m_Grid1.SetImageList(&m_ImageList);
 
//
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
===Как при помощи IPicture отобразить картинку из файла? ===
 
===Как при помощи IPicture отобразить картинку из файла? ===
Пример - несложная функция, отображающая картинку из файла. Поддерживаются форматы BMP, GIF, JPEG, PNG, TIFF, EMF
+
 
 +
Пример - несложная функция, отображающая картинку из файла. Поддерживаются форматы BMP, GIF, JPEG, PNG, TIFF, EMF.
 +
 
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
#include "atlconv.h"
 
#include "atlconv.h"
#define HandleIsValid(H) (H!=(HANDLE)-1 && H!=(HANDLE)0)
+
#define HandleIsValid(H) (H != (HANDLE) - 1 && H != (HANDLE)0)
  
//*pDestDC - CDC, на который предполагается вывод картинки
+
// *pDestDC - CDC, на который предполагается вывод картинки
//pchzFilePath - путь к файлу
+
// pchzFilePath - путь к файлу
//pWid - (возвращает) ширина картинки
+
// pWid - (возвращает) ширина картинки
//pHig - (возвращает) высота картинки
+
// pHig - (возвращает) высота картинки
bool DrawBitmapFromFile(CDC* pDestDC,const char* pchzFilePath,int *pWid=0,int *pHig=0)
+
bool DrawBitmapFromFile(CDC* pDestDC, const char* pchzFilePath, int *pWid = 0, int *pHig = 0)
 
{
 
{
bool result=false;
+
bool result = false;
 +
 
 +
if (pWid)
 +
*pWid = 0;
  
if(pWid)*pWid=0;
+
if (pHig)
if(pHig)*pHig=0;
+
*pHig = 0;
  
int Wid=0;
+
int Wid = 0;
int Hig=0;
+
int Hig = 0;
  
IPicture* pPic=0;
+
IPicture* pPic = 0;
 
try
 
try
 
{
 
{
IPicture* ptmpPic=0;
+
IPicture* ptmpPic = 0;
 
USES_CONVERSION;
 
USES_CONVERSION;
 
HRESULT hr;
 
HRESULT hr;
  
CString txt=pchzFilePath;
+
CString txt = pchzFilePath;
hr=::OleLoadPicturePath(
+
hr = ::OleLoadPicturePath(
 
const_cast<LPOLESTR>(T2COLE(txt)),
 
const_cast<LPOLESTR>(T2COLE(txt)),
0,0,0,IID_IPicture,
+
0, 0, 0, IID_IPicture,
 
reinterpret_cast<void **>(&ptmpPic)
 
reinterpret_cast<void **>(&ptmpPic)
 
);
 
);
  
if(hr==S_OK && ptmpPic)
+
if (hr == S_OK && ptmpPic)
 
{
 
{
pPic=ptmpPic;
+
pPic = ptmpPic;
 
}
 
}
 
else
 
else
Строка 653: Строка 685:
 
OLE_YPOS_HIMETRIC cySrc;
 
OLE_YPOS_HIMETRIC cySrc;
  
if(S_OK!=pPic->get_Width(&cxSrc))
+
if (S_OK != pPic->get_Width(&cxSrc))
 
{
 
{
 
throw 0;
 
throw 0;
 
}
 
}
  
if(S_OK!=pPic->get_Height(&cySrc))
+
if (S_OK != pPic->get_Height(&cySrc))
 
{
 
{
 
throw 0;
 
throw 0;
 
}
 
}
  
Wid=cxSrc/26;
+
Wid = cxSrc / 26;
Hig=cySrc/26;
+
Hig = cySrc / 26;
  
//рисуем
+
// рисуем
if(S_OK !=pPic->Render(pDestDC->GetSafeHdc(),
+
if (S_OK != pPic->Render(pDestDC->GetSafeHdc(),
0,Hig,Wid,-Hig,0,0,cxSrc,cySrc,0))
+
0, Hig, Wid, -Hig, 0, 0, cxSrc, cySrc, 0))
 
{
 
{
 
throw 0;
 
throw 0;
 
}
 
}
 
}
 
}
catch(...)
+
catch (...)
 
{
 
{
result=false;
+
result = false;
 
}
 
}
  
if(pPic)
+
if (pPic)
 
{
 
{
 
pPic->Release();
 
pPic->Release();
pPic=0;
+
pPic = 0;
 
}
 
}
  
 
+
if (pWid)
if(pWid)
+
 
{
 
{
*pWid=Wid;
+
*pWid = Wid;
 
}
 
}
  
if(pHig)
+
if (pHig)
 
{
 
{
*pHig=Hig;
+
*pHig = Hig;
 
}
 
}
  
Строка 700: Строка 731:
  
 
===Как позволить пользователю начать ввод новой строки в многострочном поле редактирования?===
 
===Как позволить пользователю начать ввод новой строки в многострочном поле редактирования?===
 +
 
Нужно в редакторе ресурсов поставить для свойств окошка CEdit галочку "WantReturn" или добавить стиль ES_WANTRETURN при создании CEdit элемента управления динамически. Тогда при нажатии Enter в поле редактирования будет вводиться новая строка.
 
Нужно в редакторе ресурсов поставить для свойств окошка CEdit галочку "WantReturn" или добавить стиль ES_WANTRETURN при создании CEdit элемента управления динамически. Тогда при нажатии Enter в поле редактирования будет вводиться новая строка.
  
===Как выводят картинку-логотип(splash screen) при запуске программы?===
+
===Как выводят картинку-логотип (splash screen) при запуске программы?===
 +
 
 
Для этого используется класс, производный от CDialog. Этот диалог после создания показывает себя на экран, выводя на себя рисунок. Также запускает таймер, по срабатывани которого диалог гасится. Создаётся диалог в процедуре InitInstance приложения.
 
Для этого используется класс, производный от CDialog. Этот диалог после создания показывает себя на экран, выводя на себя рисунок. Также запускает таймер, по срабатывани которого диалог гасится. Создаётся диалог в процедуре InitInstance приложения.
  
В VC6++ также есть уже готовый компонент
+
В VC6++ также есть уже готовый компонент: Project->Add To Project -> Components and Controls->(в папке "Visual C++ Components" есть SplashScreen.).
  
Project->Add To Project -> Components and Controls->(в папке "Visual C++ Components" есть SplashScreen.)
+
===Как сделать, чтобы при выпадении списка у ComboBox была не одна строка, а больше? Вроде все свойства покрутил, не помогает: вместо выпадающего списка - одна строка и скролл.===
  
===Как сделать, чтобы при выпадении списка у ComboBox была не одна строка, а больше, вроде все свойства покрутил, не помогает Вместо выпадающего списка одна строка и скролл...===
 
 
В редакторе ресурсов надо щелкнуть в комбобоксе на треугольнике - появляется рамка для растягивания вниз - размер выпадающего списка.
 
В редакторе ресурсов надо щелкнуть в комбобоксе на треугольнике - появляется рамка для растягивания вниз - размер выпадающего списка.
  
===В VC++.net, что делать после того, как на форму установил ActiveX ListView, как объявить класс и переменную для этого элемента?===
+
===VC++.NET. На форму установил ActiveX ListView. Как объявить класс и переменную для этого элемента?===
Щёлкнуть правой кнопкой мыши на элементе, в меню - add variable или add class
+
 
 +
Щёлкнуть правой кнопкой мыши на элементе, в меню - add variable или add class.
  
 
===Как работать с буфером обмена (Clipboard)?===
 
===Как работать с буфером обмена (Clipboard)?===

Версия 21:25, 2 ноября 2008

Содержание

Как узнать, что пользователь меняет текст в приложении на основе CRichEditView?

Нужно добавить обработчик сообщения EN_CHANGE. Сообщение генерируется CRichEditView каждый раз, когда пользователь изменяет текст в окне CRichEditView.

Чем отличается метод CArray::GetSize от метода CArray::GetCount?

Эти методы абсолютно идентичны. Скорее всего, в более старых версиях библиотек функции, одинаковые по смыслу, имели разные имена. Поэтому в целях совместимости разработчики оставили обе функции.

Как загрузить текстовую строку из ресурса?

Пример:

CString m_Temp;
 
m_Temp.LoadString(ID_MYSTRING);

Как поменять иконку у элемента item в CListCtrl?

Пример:

// заполняем структуру LVITEM
LVITEM lvItem;
 
memset(&lvItem, 0, sizeof(lvItem));
 
lvItem.mask = LVIF_IMAGE; // меняться будет картинка
lvItem.iItem = ...; // индекс элемента списка (Zero-based)
lvItem.iSubItem	= 0;
lvItem.iImage = ...; //индекс иконки (из списка элемента)
 
pList->SetItem(&lvItem);

Имеется класс Class1, содержащий член типа "указатель на Class2". В Class2 также имеется указатель на Class1. Компилятор выдаёт ошибку. Что надо делать?

Перекрёстное определение обходится следующим образом: код обоих классов разносится в пары файлов *.h и *.cpp, а перед каждым классом вписывается предопределение другого класса:

Файл "class1.h":

class Class2; // предопределение Class2
 
class Class1
{
	Class2* m_p2; // компилятор разрешит объявление указателя Class2*
 
	void F1(Class2* p); //компилятор разрешит объявление указателя Class2*
	void F2(Class1* p);
};

Файл "class1.cpp":

#include "class1.h"
#include "class2.h"
 
void Class1::F1(Class2* p)
{
	// ...
}
 
void Class1::F2(Class1* p)
{
	// ...
}

Файл "class2.h":

class Class1; // предопределение Class1
 
Class2
{
	Class1* m_p1; // компилятор разрешит объявление указателя Class1*
 
	void F3(Class1* p); // компилятор разрешит объявление указателя Class1*
};

Файл "class2.cpp":

#include "class2.h"
#include "class1.h"
 
void Class2::F3(Class1* p)
{
	// ...
}

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

Как переключить раскладку в другом (активном) процессе?

Для этого можно использовать функции:

  • GetKeyboardLayout - определить текущую раскладку
  • LoadKeyboardLayout - загрузить новую раскладку
  • VerLanguageName - получить строку с описанием языка

Подробности - в MSDN.

Как получить хендл элемента управления, зная его идентификатор?

Пример: пусть элемент Edit лежит на окне CMyWnd. Тогда:

void CMyWnd::некая_процедура()
{
	// для MFC
	CEdit* ed = (CEdit* ) GetDlgItem(ID_EDIT1);
	HWND hwnd = ed->GetSafeHwnd();
	if (hwnd)
	{
		// ...
	}
 
	// для Win32 API
	HWND hwnd = GetDlgItem(m_hWnd, ID_EDIT1);
	if (hwnd)
	{
		// ...
	}
}

Как из дочернего окна закрыть приложение?

Для этого нужно послать родительскому окну сообщение WM_CLOSE.

Через указатель на родительское окно:

pParent->PostMessage(WM_CLOSE);

При помощи хендла родительского окна:

::PostMessage(pParent->m_hWnd, WM_CLOSE, (WPARAM)0, (LPARAM)0);

Как корректно перевести тип BSTR в CString и наоборот?

  1. Для конвертирования BSTR в CString нужно просто присвоить переменной типа CString переменную типа BSTR. Оператор "=" класса CString сам выполнит всю работу.
  2. Для конвертирования BSTR в CString нужно выполнить код:
// указатель на будущий буфер с BSTR.
// По сути, BSTR определён как typedef WCHAR* BSTR;
// то есть - указатель на 16-битный символ юникод.
BSTR bstrHE = 0;
 
// строка для конвертации
CString Str = "мой текст";
 
// Выделяем память и загружаем адрес блока в bstrHE
bstrHE = Str.AllocSysString();
 
// ...	
// тут работаем с bstrHE[]
// ...
 
// освобождаем память
SysFreeString(bstrHE);

Как получить доступ к графическим ресурсам элементов текущей темы оформления Windows?

Для этого нужно использовать функции:

  • OpenThemeData
  • DrawThemeBackground
  • DrawFrameControl
  • CloseThemeData

Подробности - в MSDN.

Имеется класс, производный от CDialog. Когда диалог в фокусе, нажатие на Enter или Esc приводит к закрытию диалога. Как это запретить?

При нажатии Enter происходит выполнение команды IDOK, при нажатии Esc - IDCANCEL. Нужно переопределить в классе виртуальные функции OnOk() и OnCancel(), которые соответственно вызываются для этих команд. При помощи визарда эти функции добавить можно следующим образом.

Поместить на диалог две кнопки с идентификаторами IDOK и IDCANCEL (при создании нового диалога они там есть сразу), двойной щелчок по кнопке добавит соответствующий обработчик. В обработчиках надо удалить вызовы СDialog::OnOK() и CDialog::OnCancel(), тогда диалог закрываться не будет.

Однако тогда диалог станет невозможно закрыть кнопкой с крестиком. Это обходится так: добавляем обработчик сообщения WM_CLOSE - OnClose(), и в нём делаем вызов OnOk() или OnCancel():

void CPlayersPropsDialog::OnClose() 
{
	CDialog::OnClose();
	CDialog::OnCancel(); // добавлено
}

Я написал в VC++ простейший макрос, где невозможно ошибиться, а компилятор всё же выдаёт ошибку.

Скорее всего после одного из символов соединения строк "\" имеется пробел или табуляция. Их надо удалить. Можно найти их "на ощупь", а можно включить показ непечатных символов в студии. Найти эту команду можно так:

Tools->Customize...->вкладка Commands. В окошке Category выбрать "Edit", и среди кнопок справа найти кнопку, на которой написано "a.b". Эту кнопку надо перенести на одну из панелей инструментов студии.

Как получить список всех процессов, включая idle?

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

  • Process32First
  • Precess32Next

Подробности - в MSDN.

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

Чтобы добавить или изменить их программно, необходимо воспользоваться ключом реестра

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment

Затем нужно отправить широковещательное сообщение WM_SETTINGCHANGE - это позволит приложениям узнать об изменениях:

::SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0);

Как сделать, чтобы у окна был черный фон?

Нужно переопределить обработчик сообщения WM_CTLCOLOR - OnCtlColor():

// глобальная переменная или член класса CMyDlg,
// инициализированный в OnInitDialog()
CBrush br(RGB(0, 0, 0));
 
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
	HBRUSH hbr = CMyDlg::OnCtlColor(pDC, pWnd, nCtlColor);
 
	// фон диалога (или View)
	if (nCtlColor == CTLCOLOR_DLG)
	{
		return (HBRUSH)br;
	}
 
	// фон элементов SCtatic, лежащих на форме (если нужно)
	if (nCtlColor == CTLCOLOR_STATIC)
	{
		// делаем фон текста статика прозрачным
		pDC->SetBkMode(TRANSPARENT);
		return (HBRUSH)br;
	}
 
	return hbr;
}

Почему на моем компьютере экзешник, созданный в MFC запускается, а на других компьютерах - нет? Требует какую-то dll.

Нужно выбирать режим Release: Menu->Build->Configurations...->Release. Экзешник, соответственно, брать из папки Release проекта.

Как в диалог добавить меню?

Нужно создать в редакторе ресурсов новое меню, затем вставить его в диалог:

  1. Открыть в редакторе диалог;
  2. В свойствах (во вкладке General, окошко Menu) указать идентификатор ресурса меню;
  3. При помощи визарда добавить для меню обработчики OnCommand() и OnUpdateСommand().

Почему не вызывается OnUpdate для пунктов меню (не получается ни затенить, ни отметку поставить)?

В диалоге (CDialog) у меню апдейт не происходит сам, в отличие от мейнфрейма (CFrameWnd). Для этого нужно сделать апдейт самим, в обработчике сообщения WM_KICKIDLE.

Визардом этот обработчик не добавляется, поэтому можно переопределить виртуальную DefWindowProc() и там обработать:

#include <afxpriv.h> // этот файл надо включить, там определёна WM_KICKIDLE
 
LRESULT CMyDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
	if (message == WM_KICKIDLE)
	{
		// делаем апдейт для всех пунктов меню
		CMenu* pMainMenu = GetMenu();
		if (pMainMenu)
		{
			CCmdUI cmdUI;
			for (UINT n = 0; n < pMainMenu->GetMenuItemCount(); n++)
			{
				CMenu* pSubMenu = pMainMenu->GetSubMenu(n);
				if (!pSubMenu)
					continue;
 
				cmdUI.m_nIndexMax = pSubMenu->GetMenuItemCount();
				for (UINT i = 0; i < cmdUI.m_nIndexMax; i++)
				{
					cmdUI.m_nIndex = i;
					cmdUI.m_nID = pSubMenu->GetMenuItemID(i);
					cmdUI.m_pMenu = pSubMenu;
					cmdUI.DoUpdate(this, FALSE);
				}
			}
		}
	}
 
	return CDialog::DefWindowProc(message, wParam, lParam);
}

Как в главном окне отключить системное меню (в левом верхнем углу) и кнопки (в правом верхнем углу)?

При создании окна нужно убрать стиль WS_SYSMENU. Теперь пользователь корректно может закрыть окно только Alt+F4, ну, или если вы предоставите ему дополнительную возможность сделать это.

Пример 1. (для SDI, MDI)

// этот обработчик уже добавлен визардом
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	if ( !CFrameWnd::PreCreateWindow(cs) )
		return FALSE;
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs
 
	///////////////////////////////
	// добавленная часть
	{
		// убираем стиль
		cs.style& =~ WS_SYSMENU;
	}
	///////////////////////////////
 
	return TRUE;
}

Пример 2. (для диалога) Если диалог описан в ресурсах, то в свойствах диалога убрать галочки:

  • "System menu"
  • "Minimize box"
  • "Maximize box"

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

Нужно применить метод класса CWnd::EnableWindow(...) для кнопки. Значение 0 параметра делает кнопку неактивной, 1 - делает активной (кстати, не только для кнопки можно, а для любого класса, производного от класса CWnd).

Пусть имеется некий диалог, на нём лежит кнопка c ID == IDC_1. В любом месте кода диалога (кроме конструктора и деструктора, хотя, если проверить наличие валидного хендла диалога, как в примере, то ничего страшного не будет и там) выполняем код:

// делаем кнопку неактивной
if (m_hWnd)
{
	CWnd* pw = 0;
	pw = GetDlgItem(IDC_1);
	if (pw)
	{
		pw->EnableWindow(0);
	}
}

Что означают сообщения, которые студия выводит при компиляции, вроде таких: Loaded 'C:\WINDOWS\SYSTEM\WSOCK32.DLL', no matching symbolic information found?

Это строка говорит о том, что студия не смогла найти отладочные символы для WSOCK32.DLL. В этом нет ничего страшного. Просто, при наличии отладочных символов в процессе отладки, можно получить доступ к именам функции из системных DLL. Например, вместо KERNEL32! 0x77E8B184() увидим KERNEL32!CreateThread.

Как обработать сообщения, которые приходят к элементу управления?

Скажем, нужно обработать сообщения, приходящие к элементу класса CEdit. Нужно произвести от CEdit свой класс и в виртуальной процедуре класса WindowProc перехватить нужные сообщения.

virtual LRESULT WindowProc(
	UINT message,
	WPARAM wParam,
	LPARAM lParam 
);

Пример. Полностью выключаем, скажем, обработку сообщения WM_CHAR.

LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
	switch (message)
	{
		case WM_CHAR:
		{
			return 0;
		}
		break;
	}
 
	return CEdit::WindowProc(message, wParam, lParam);
}

Чтобы связать экземпляр класса с элементом управления на форме, добавьте визардом для элемента управления переменную класса (выбрав не Value, а Control).

Как настроить количество пробелов в табуляции?

Есть пара способов:

  1. Tools->Options->Tabs->Insert Spaces
  2. Правой кнопкой мыши щёлкнуть по тексту, в контекстном меню выбрать properties.

Как автоматически расставить отступы?

Нужно в студии выделить текст для форматирования и нажать Alt+F8.

Ещё есть программа Artistic Style ( http://sourceforge.net/projects/astyle/ ), которая занимается переформатированием кода.

Поиск границ блока.

Сочетание клавиш CTRL+"}" ищет парную фигурную скобку в тексте и переходит к ней.

Вертикальное выделение текста.

Если удерживать клавишу Alt, а затем начать выделять текст мышкой, то область выделения принимает форму прямоугольника, что позволяет выделять вертикальные фрагменты текста.

Как узнать количество установленных в CListCtrl столбцов?

Пример:

// указатель на переменную-элемент управления
CListCtrl* pL = ...;
 
// получаем количество столбцов
int count = pL->GetHeaderCtrl()->GetItemCount();

Как получить иконку приложения?

Если приложение запущено, то нужно найти его главное окно и послать ему сообщение WM_GETICON.

// функция возвращант хендл иконки 
LRESULT SendMessage(hWnd, WM_GETICON, wParam, 0);
 
// hWnd == хендл окна приложения
// wParam == 
//	1)==ICON_BIG - получить большую иконку
//	2)==ICON_SMALL - получить маленькую иконку
//	3)==ICON_SMALL2 - получить маленькую иконку, если она определена
//				в приложении. Если её нет, то маленькую иконку, 
//				сгенерированную системой из большой иконки

Как в CString можно найти или вырезать часть строки?

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

// вырезает кусок строки
CString Mid(int nFirst) const;
CString Mid(int nFirst, int nCount) const;
 
// возвращает кусок строки (сначала или с конца)
CString Left(int nCount) const;
CString Right(int nCount) const;
 
// возвращает начальный кусок строки, в котором есть только
// символы из набора, представленного в lpszCharSet
CString SpanIncluding(LPCTSTR lpszCharSet) const;
 
// возвращает начальный кусок строки, в котором нет
// символов из набора, представленного в lpszCharSet
CString SpanExcluding(LPCTSTR lpszCharSet) const; 
 
// убирает "пробелоподобные" символы из самого начала строки.
// то есть - пробел, табуляцию (\t), возврат каретки, перевод строки (/r/n)
void TrimLeft();
 
// убирает все повторы символа из самого начала строки
void TrimLeft(TCHAR chTarget);
 
// убирает из самого начала строки все символа из набора lpszTargets 
void TrimLeft(LPCTSTR lpszTargets);
void TrimRight();
void TrimRight(TCHAR chTarget);
void TrimRight(LPCTSTR lpszTargets);
 
// поиск в строке
int Find(TCHAR ch) const;
int Find(LPCTSTR lpszSub) const;
int Find(TCHAR ch, int nStart) const;
int Find(LPCTSTR pstr, int nStart) const;
 
// поиск, начиная с конца
int ReverseFind(TCHAR ch) const;
 
// поиск позиции первого символа, одного из набора,
// представленного в lpszCharSet
int FindOneOf(LPCTSTR lpszCharSet) const;

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

В общем случае это делается принудительной перерисовкой нужного окна путём объявления этого окна невалидным.

pWnd->Invalidate(0);

Затем непосредственной отсылки в оконную процедуру сообщения WM_PAINT.

pWnd->UpdateWindow();

Пример:

CWnd* pWnd = ...; // окно, которое надо перерисовывать
 
for (int i = 0; i < 10000; i++)
{
	// меняется содержимое окна
	// ...
 
	// немедленная перерисовка
	pWnd->Invalidate(0);
	pWnd->UpdateWindow();
}

Также можно также просто вызвать метод RedrawWindow() с параметрами по умолчанию.

Я написал DLL, которую используют несколько приложений. Всё работает, но когда происходит очередной вызов функции из DLL, почему то, данные в функции обнуляются. С чем это связано?

Переменные и массивы в DLL, содержимое которых должно использоваться несколькими процессами, должны объявляться статическими. Статическая переменная или массив инициализируются только один раз в момент загрузки DLL.

Пример:

DWORD calltest()
{
	// будет выполнено только при первом вызове
	static DWORD callcount = 0;
	static DWORD str[1000] = {0}; 
 
	// будет выполняться каждый раз
	callcount++;
	return callcount;
}

Как открыть проекцию файла в память и как с ней работать?

Создание проекции:

HANDLE CreateFileMapping(
	HANDLE hFile, // хендл уже открытого файла
	LPSECURITY_ATTRIBUTES lpAttributes,
	DWORD flProtect, // способ открытия проекции
	DWORD dwMaximumSizeHigh, // размер файла (старшие 4 байта, обычно - 0)
	DWORD dwMaximumSizeLow, // размер файла (младшие 4 байта)
	LPCTSTR lpName
);

Доступ к созданной проекции производится процедурой:

LPVOID MapViewOfFile(
	HANDLE hFileMappingObject, // хендл проекции
	DWORD dwDesiredAccess, // способ работы с проекцией
	DWORD dwFileOffsetHigh,
	DWORD dwFileOffsetLow, // смещение от начала файла (младшие 4 байта)
	SIZE_T dwNumberOfBytesToMap // длина в байтах (если 0 - то весь файл)
);

Далее с файлом можно работать как с обычным массивом в памяти.

После работы с проекцией, её надо освободить.

BOOL UnmapViewOfFile(
	LPCVOID lpBaseAddress // адрес, который вернула процедура MapViewOfFile
);

Пример:

HANDLE hFile = ...; // хендл уже открытого файла
DWORD dwdFileLen = ...; // размер открытого файла
HANDLE hMapFile = 0; // хендл для проекции
 
// создаём проекцию "только для чтения"
hMapFile = ::CreateFileMapping(hFile, 0, PAGE_READONLY, 0, dwdFileLen, 0);
 
// хендл hFile можно закрыть уже здесь, в принципе,
// но мы сделаем это позже
 
// получаем доступ к проекции (тоже только для чтения)
BYTE* pbyFile = (BYTE*)::MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
 
///////////////////
// тут работаем с массивом pbyFile[dwdFileLen] как с обычным,
// только не забываем, что он открыт только для чтения
// ...
// ...
// ...
///////////////////
 
// отключаем файл данных от адресного пространства
UnmapViewOfFile(pbyFile);
 
// освобождаем хендл проекции
CloseHandle(hMapFile)
 
// освобождаем хендл открытого файла
CloseHandle(hFile);

Как в MFC Grid control отобразить картинку в ячейке?

Нужно создать список изображений (CImageList), затем передать указатель на список в таблицу. Поскольку элемент управления лишь копирует указатель, список должен создаваться динамически, либо быть членом класса, экземпляр которого существует всё время работы таблицы.

CImageList m_ImageList;
CGridCtrL m_Grid1;
 
// ...
 
// неким образом создаётся список
m_ImageList.Create(...);
 
// ...
 
//вставляем в элемент управления
m_Grid1.SetImageList(&m_ImageList);

Как при помощи IPicture отобразить картинку из файла?

Пример - несложная функция, отображающая картинку из файла. Поддерживаются форматы BMP, GIF, JPEG, PNG, TIFF, EMF.

#include "atlconv.h"
#define HandleIsValid(H) (H != (HANDLE) - 1 && H != (HANDLE)0)
 
// *pDestDC - CDC, на который предполагается вывод картинки
// pchzFilePath - путь к файлу
// pWid - (возвращает) ширина картинки
// pHig - (возвращает) высота картинки
bool DrawBitmapFromFile(CDC* pDestDC, const char* pchzFilePath, int *pWid = 0, int *pHig = 0)
{
	bool result = false;
 
	if (pWid)
		*pWid = 0;
 
	if (pHig)
		*pHig = 0;
 
	int Wid = 0;
	int Hig = 0;
 
	IPicture* pPic = 0;
	try
	{
		IPicture* ptmpPic = 0;
		USES_CONVERSION;
		HRESULT hr;
 
		CString txt = pchzFilePath;
		hr = ::OleLoadPicturePath(
			const_cast<LPOLESTR>(T2COLE(txt)),
			0, 0, 0, IID_IPicture,
			reinterpret_cast<void **>(&ptmpPic)
			);
 
		if (hr == S_OK && ptmpPic)
		{
			pPic = ptmpPic;
		}
		else
		{
			throw 0;
		}
 
		OLE_XPOS_HIMETRIC cxSrc;
		OLE_YPOS_HIMETRIC cySrc;
 
		if (S_OK != pPic->get_Width(&cxSrc))
		{
			throw 0;
		}
 
		if (S_OK != pPic->get_Height(&cySrc))
		{
			throw 0;
		}
 
		Wid = cxSrc / 26;
		Hig = cySrc / 26;
 
		// рисуем
		if (S_OK != pPic->Render(pDestDC->GetSafeHdc(),
			0, Hig, Wid, -Hig, 0, 0, cxSrc, cySrc, 0))
		{
			throw 0;
		}
	}
	catch (...)
	{
		result = false;
	}
 
	if (pPic)
	{
		pPic->Release();
		pPic = 0;
	}
 
	if (pWid)
	{
		*pWid = Wid;
	}
 
	if (pHig)
	{
		*pHig = Hig;
	}
 
	return result;
}

Как позволить пользователю начать ввод новой строки в многострочном поле редактирования?

Нужно в редакторе ресурсов поставить для свойств окошка CEdit галочку "WantReturn" или добавить стиль ES_WANTRETURN при создании CEdit элемента управления динамически. Тогда при нажатии Enter в поле редактирования будет вводиться новая строка.

Как выводят картинку-логотип (splash screen) при запуске программы?

Для этого используется класс, производный от CDialog. Этот диалог после создания показывает себя на экран, выводя на себя рисунок. Также запускает таймер, по срабатывани которого диалог гасится. Создаётся диалог в процедуре InitInstance приложения.

В VC6++ также есть уже готовый компонент: Project->Add To Project -> Components and Controls->(в папке "Visual C++ Components" есть SplashScreen.).

Как сделать, чтобы при выпадении списка у ComboBox была не одна строка, а больше? Вроде все свойства покрутил, не помогает: вместо выпадающего списка - одна строка и скролл.

В редакторе ресурсов надо щелкнуть в комбобоксе на треугольнике - появляется рамка для растягивания вниз - размер выпадающего списка.

VC++.NET. На форму установил ActiveX ListView. Как объявить класс и переменную для этого элемента?

Щёлкнуть правой кнопкой мыши на элементе, в меню - add variable или add class.

Как работать с буфером обмена (Clipboard)?

КОПИРОВАНИЕ В БУФЕР ОБМЕНА

Алгоритм:

  1. Готовим данные
    • Выделяем память из кучи, вызывая GlobalAlloc()
    • Получаем указатель на выделенную память, вызывая GlobalLock()
    • Заполняем данные
    • Освобождаем указатель, вызывая GlobalUnlock();
  2. Открываем буфер обмена, вызывая OpenClipboard();
  3. Очищаем буфер, вызывая EmptyClipboard();
  4. Вызываем SetClipboardData() один раз для каждого формата вставляемых данных (имеется в виду - если одни и те же данные представлены в разных форматах, и приложение может эти форматы создать)
  5. Закрываем буфер, вызывая CloseClipboard();
  6. ВЫЗЫВАТЬ GlobalFree() НЕ НУЖНО, в этом случае это предоставлено системе

Скажем, хотим поместить в буфер обмена текст.

//готовим данные
//выделяем из кучи память для данных
HANDLE hglbCopy = GlobalAlloc(GMEM_MOVEABLE,10);
if(!hglbCopy)return;
 
//получаем указатель
void* lpStr = GlobalLock(hglbCopy);
if(!lpStr)return;
 
//заполняем данные
strcpy((char*)lpStr,"my text");
 
//освобождаем указатель
GlobalUnlock(hglbCopy);
lpStr=0;
 
//открываем буфер обмена
OpenClipboard();
//очищаем
EmptyClipboard();
 
//текстовый формат
SetClipboardData(CF_TEXT,hglbCopy);
 
//закрываем буфер
CloseClipboard();


ИЗВЛЕЧЕНИЕ ИЗ БУФЕРА ОБМЕНА

Алгоритм:

  1. Проверяем, что поддерживается нужный формат данных, вызывая IsClipboardFormatAvailable()
  2. Открываем буфер обмена, вызывая OpenClipboard();
  3. Достаём данные
    • Получаем из буфера хендл требуемого формата, вызывая GetClipboardData()
    • Получаем указатель на выделенную память, вызывая GlobalLock()
    • Работаем с данными
    • Освобождаем указатель, вызывая GlobalUnlock();
  4. Закрываем буфер, вызывая CloseClipboard();

Скажем, хотим извлечь из буфера обмена текст.

//Проверяем, что поддерживается нужный формат данных,
if(!IsClipboardFormatAvailable(CF_TEXT))return;
 
//открываем буфер обмена
OpenClipboard();
 
//достаём данные
 
//текстовый формат
HANDLE hglbCopy = GetClipboardData(CF_TEXT);
if(!hglbCopy)return;
 
//получаем указатель
void* lpStr = GlobalLock(hglbCopy);
if(!lpStr)return;
 
//читаем данные
char data[10];
memmove(data,lpStr,sizeof(data));
 
//освобождаем указатель
GlobalUnlock(hglbCopy);
lpStr=0;
 
//закрываем буфер
CloseClipboard();


Как получить полный путь к экзешнику из самой программы?

Можно прочитать параметры командной строки - в командную строку первым параметром система всегда передаёт заключённый в кавычки полный путь к файлу запущенной программы. Достаём путь следующим образом:

BOOL CMyApp::InitInstance()
{
	//добыча полного имени экзешника
	CString csFullExeName;
	{
		CString csAppName=GetCommandLine();
		csAppName.Delete(0,1);
		csAppName.Replace('\"','\0');
		csFullExeName=(const char*)csAppName;
	}
	//теперь csFullExeName содержит искомый путь
 
	//...
	//...
}

Каким способом exe файл может заменить самого себя?

К примеру, программа должна обновляется через Internet и хочет обновить свой exe-файл. Но так как он в данный момент запущен, это будет, естественно, невозможно сделать напрямую. Один из способов - сделать копию экзешника и из него обновиться

#define def_exeNAMEup	"c:\\myprog_toupdate.exe"		//путь к старому файлу
#define def_exeNAMEdnld	"c:\\myprog_downloaded.exe"		//путь к новому файлу (уже "скачали":) )
#define def_keyUdate	"/update"
 
void CTESTFAQApp::UpdateItself()
{
	//добыча полного имени экзешника
	CString csFullExeName;
	{
		CString csAppName=GetCommandLine();
		csAppName.Delete(0,1);
		csAppName.Replace('\"','\0');
		csFullExeName=(const char*)csAppName;
	}
	//теперь csFullExeName - содержит искомый путь
 
	//делаем копию экзешника с другим именем
	CopyFile(csFullExeName,def_exeNAMEup,0);
 
	//передаём в параметры нового процесса ключ и путь к текущему файлу
	CString csParams=def_keyUdate;
	csParams+=" ";
	csParams+=csFullExeName;
 
	//запускаем копию
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	ZeroMemory(&si,sizeof(si));
	si.cb = sizeof(si);
	ZeroMemory(&pi,sizeof(pi));
	if(CreateProcess(def_exeNAMEup,def_keyUdate,0,0,0,0,0,0,&si,&pi))
	{
		//завершаем текущий процесс
		ExitFromMyApp();
	}
}
 
void CTESTFAQApp::ExitFromMyApp()
{
	exit(0);
}
 
BOOL CTESTFAQApp::InitInstance()
{
	//смотрим, не запущено ли для апдейта?
	CString txt;
	txt=m_lpCmdLine;
	if(txt.Find(def_keyUdate)==0)
	{
		//делаем айдейт
		txt.Replace(def_keyUdate,"");
		txt.TrimLeft();
 
		CString csFullExeName=txt;
 
		//берём откуда то уже скачанный файл обновления
		//...
		CString csFull_Downloaded_ExeName=def_exeNAMEdnld;
 
		//копируем файл (обновляем старый то есть)
		CopyFile(csFull_Downloaded_ExeName,csFullExeName,0);
 
		//запускаем обновлённого мученника
		STARTUPINFO si;
		PROCESS_INFORMATION pi;
		ZeroMemory(&si,sizeof(si));
		si.cb = sizeof(si);
		ZeroMemory(&pi,sizeof(pi));
		if(CreateProcess(csFullExeName,0,0,0,0,0,0,0,&si,&pi))
 
		ExitFromMyApp();
 
	}
	//...
	//...
}

Как производится конвертация из кодировки UTF8 в 1251 и наоборот?

Можно перевести строку из UTF8 в Unicode, затем из Unicode в 1251

Ниже приведена структура, содержащая процедуры перекодирования, а также процедуру с примером использования

//описание структуры
struct coder
{
	//utf8->unicode
	static wchar_t* utf8_to_unicode__dontForgetDeleteArr(const char *utf8_string)
	{
		wchar_t* pRes=0;
		int res_len=0;
 
		//тест на возможность преобразования
		res_len=MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,0,0);
		if(!res_len)
		{
			return 0;
		}
 
		//выделяем память
		pRes = new wchar_t[res_len];
		if(!pRes)
		{
			return 0;
		}
 
		//преобразование
		if(!MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,pRes,res_len))
		{
			delete [] pRes;
			return 0;
		}
 
		return pRes;
	}
 
	//unicode->1251
	static char * unicode_to_1251__dontForgetDeleteArr(const wchar_t *unicode_string)
	{
		char* pRes=0;
		int res_len=0;
 
		//тест на возможность преобразования
		res_len = WideCharToMultiByte(1251,0,unicode_string,-1,0,0,0,0);
		if(!res_len)
		{
			return 0;
		}
 
		//выделяем память
		pRes=new char[res_len];
		if(!pRes)
		{
			return 0;
		}
 
		//преобразование
		if(!WideCharToMultiByte(1251,0,unicode_string,-1,pRes,res_len,0,0))
		{
			delete [] pRes;
			return 0;
		}
 
		return pRes;
	}
 
	//процедура с примером
	static void Example()
	{
		wchar_t* unicode_string=0;
		char* cp1251_string=0;
 
		//исходный текст
		char utf8_string[] = "UTF-8 + русский текст";
 
		for(;;)
		{
 
			unicode_string=utf8_to_unicode__dontForgetDeleteArr(utf8_string);
			if(!unicode_string)
			{
				AfxMessageBox("Не удалось конвертировать в unicode!");
				break;
			}
 
			cp1251_string = unicode_to_1251__dontForgetDeleteArr(unicode_string);
 
			if(!cp1251_string)
			{
				AfxMessageBox("Не удалось конвертировать из unicode!");
				break;
			}
 
			break;
		}
 
		//cp1251_string - результат
		AfxMessageBox(cp1251_string);
 
		//не забываем удалить массивы
		if(unicode_string)
		{
			delete [] unicode_string;
			unicode_string=0;
		}
 
		if(cp1251_string)
		{
			delete [] cp1251_string;
			cp1251_string=0;
		}
	}
};
 
//вызов примера
coder::Example();

Как работать с базой данных Access из программы на VC.net?

Проще всего подключить ADO компоненты и сделать все на них.

Компоненты ADO (ADODC,DATAGRID и т.п.) это ActiveX.

В редакторе ресурсов, во всплывающем меню, есть Insert ActiveX Control -> открывается список всех компонент, зарегистрированных на машине. Нужно найти компоненты (Это компоненты от MS и они помечены (OLEDB)) и вставить их в диалог. Для того что бы иметь возможность управлять ими, нужно импортировать обертки для них, это делается при помощи ClassWizard, там есть импорт->класс->указать файл с компонентой (OSX). Появляется список всех классов, объявленных внутри.

Расставляем нужные галочки, нажимаем ОК.