|
|
| (не показано 8 промежуточных версий этого же участника) |
| Строка 1: |
Строка 1: |
| − | === Как узнать, что пользователь меняет текст в приложении на основе CRichEditView?===
| + | #REDIRECT [[FAQ:WinAPI_VCPP]] |
| − | | + | |
| − | Нужно добавить обработчик сообщения EN_CHANGE. Сообщение генерируется CRichEditView каждый раз, когда пользователь изменяет текст в окне CRichEditView.
| + | |
| − | | + | |
| − | ===Чем отличается метод CArray::GetSize от метода CArray::GetCount?===
| + | |
| − | | + | |
| − | Эти методы абсолютно идентичны. Скорее всего, в более старых версиях библиотек функции, одинаковые по смыслу, имели разные имена. Поэтому в целях совместимости разработчики оставили обе функции.
| + | |
| − | | + | |
| − | ===Как загрузить текстовую строку из ресурса?===
| + | |
| − | | + | |
| − | Пример:
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | CString m_Temp;
| + | |
| − | | + | |
| − | m_Temp.LoadString(ID_MYSTRING);
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Как поменять иконку у элемента item в CListCtrl?===
| + | |
| − | | + | |
| − | Пример:
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | // заполняем структуру LVITEM
| + | |
| − | LVITEM lvItem;
| + | |
| − | | + | |
| − | memset(&lvItem, 0, sizeof(lvItem));
| + | |
| − |
| + | |
| − | lvItem.mask = LVIF_IMAGE; // меняться будет картинка
| + | |
| − | lvItem.iItem = ...; // индекс элемента списка (Zero-based)
| + | |
| − | lvItem.iSubItem = 0;
| + | |
| − | lvItem.iImage = ...; //индекс иконки (из списка элемента)
| + | |
| − |
| + | |
| − | pList->SetItem(&lvItem);
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Имеется класс Class1, содержащий член типа "Class2*". А в Class2 имеется член типа "Class1*". Компилятор выдаёт ошибку. Что надо делать?===
| + | |
| − | | + | |
| − | Перекрёстное определение обходится следующим образом: код обоих классов разносится в пары файлов *.h и *.cpp, а перед каждым классом прописывается предопределение другого класса:
| + | |
| − | | + | |
| − | Файл "class1.h":
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | class Class2; // предопределение Class2
| + | |
| − | | + | |
| − | class Class1
| + | |
| − | {
| + | |
| − | Class2* m_p2; // компилятор разрешит объявление указателя Class2*
| + | |
| − | | + | |
| − | void F1(Class2* p); //компилятор разрешит объявление указателя Class2*
| + | |
| − | void F2(Class1* p);
| + | |
| − | };
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Файл "class1.cpp":
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | #include "class1.h" | + | |
| − | #include "class2.h"
| + | |
| − | | + | |
| − | void Class1::F1(Class2* p)
| + | |
| − | {
| + | |
| − | // ...
| + | |
| − | }
| + | |
| − | | + | |
| − | void Class1::F2(Class1* p)
| + | |
| − | {
| + | |
| − | // ...
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Файл "class2.h":
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | class Class1; // предопределение Class1
| + | |
| − | | + | |
| − | Class2
| + | |
| − | {
| + | |
| − | Class1* m_p1; // компилятор разрешит объявление указателя Class1*
| + | |
| − | | + | |
| − | void F3(Class1* p); // компилятор разрешит объявление указателя Class1*
| + | |
| − | };
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Файл "class2.cpp":
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | #include "class2.h"
| + | |
| − | #include "class1.h"
| + | |
| − | | + | |
| − | void Class2::F3(Class1* p)
| + | |
| − | {
| + | |
| − | // ...
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | После предопределения класса компилятор позволяет объявлять указатель на класс, так как переменная указателя на любой тип имеет всегда один и тот же размер (4 байта).
| + | |
| − | | + | |
| − | ===Как переключить раскладку клавиатуры в другом (активном) процессе?===
| + | |
| − | | + | |
| − | Для этого можно использовать функции:
| + | |
| − | * GetKeyboardLayout - определить текущую раскладку
| + | |
| − | * LoadKeyboardLayout - загрузить новую раскладку
| + | |
| − | * VerLanguageName - получить строку с описанием языка
| + | |
| − | | + | |
| − | Подробности - в MSDN.
| + | |
| − | | + | |
| − | ===Как получить хендл элемента управления, зная его идентификатор?===
| + | |
| − | | + | |
| − | Пример: пусть элемент Edit лежит на окне CMyWnd.
| + | |
| − | Тогда:
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | 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)
| + | |
| − | {
| + | |
| − | // ...
| + | |
| − | }
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Как из дочернего окна закрыть приложение?===
| + | |
| − | | + | |
| − | Для этого нужно послать родительскому окну сообщение WM_CLOSE.
| + | |
| − | | + | |
| − | Через указатель на родительское окно:
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | pParent->PostMessage(WM_CLOSE);
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | При помощи хендла родительского окна:
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | ::PostMessage(pParent->m_hWnd, WM_CLOSE, (WPARAM)0, (LPARAM)0);
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Примечание: WM_CLOSE аналогично нажатию на крестик окна. То есть, это "мягкое" закрытие окна, так как это сообщение приложение может обработать по своему.
| + | |
| − | Если же точно так же отправить сообщение WM_QUIT (при этом в wParam указывается значение, возвращаемое процессом после жавершения), то оконная процедура, получив это сообщение, просто прекращает работу и приложение закрывается сразу.
| + | |
| − | | + | |
| − | ===Как корректно перевести тип BSTR в CString и наоборот?===
| + | |
| − | | + | |
| − | # Для конвертирования BSTR в CString нужно просто присвоить переменной типа CString переменную типа BSTR. Оператор "=" класса CString сам выполнит всю работу.
| + | |
| − | # Для конвертирования BSTR в CString нужно выполнить код:
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | // указатель на будущий буфер с BSTR.
| + | |
| − | // По сути, BSTR определён как typedef WCHAR* BSTR;
| + | |
| − | // то есть - указатель на 16-битный символ юникод.
| + | |
| − | BSTR bstrHE = 0;
| + | |
| − | | + | |
| − | // строка для конвертации
| + | |
| − | CString Str = "мой текст";
| + | |
| − | | + | |
| − | // Выделяем память и загружаем адрес блока в bstrHE
| + | |
| − | bstrHE = Str.AllocSysString();
| + | |
| − | | + | |
| − | // ...
| + | |
| − | // тут работаем с bstrHE[]
| + | |
| − | // ...
| + | |
| − | | + | |
| − | // освобождаем память
| + | |
| − | SysFreeString(bstrHE);
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Как получить доступ к графическим ресурсам элементов текущей темы оформления 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():
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | void CPlayersPropsDialog::OnClose()
| + | |
| − | {
| + | |
| − | CDialog::OnClose();
| + | |
| − | CDialog::OnCancel(); // добавлено
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Я написал в VC++ простейший макрос, где невозможно ошибиться, а компилятор всё же выдаёт ошибку.===
| + | |
| − | | + | |
| − | Скорее всего после одного из символов соединения строк "\" имеется пробел или табуляция. Их надо удалить. Можно найти их "на ощупь", а можно включить показ непечатных символов в студии. Найти эту команду можно так:
| + | |
| − | | + | |
| − | Tools->Customize...->вкладка Commands. В окошке Category выбрать "Edit", и среди кнопок справа найти кнопку, на которой написано "a.b". Эту кнопку надо перенести на одну из панелей инструментов студии.
| + | |
| − | | + | |
| − | ===Как получить список всех процессов, включая idle?===
| + | |
| − | | + | |
| − | Использовать функции:
| + | |
| − | * Process32First
| + | |
| − | * Precess32Next
| + | |
| − | | + | |
| − | Подробности - в MSDN.
| + | |
| − | | + | |
| − | ===Как программно установить переменные окружения?===
| + | |
| − | | + | |
| − | Чтобы добавить или изменить их программно, необходимо воспользоваться ключом реестра
| + | |
| − | | + | |
| − | HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment
| + | |
| − | | + | |
| − | Затем нужно отправить широковещательное сообщение WM_SETTINGCHANGE - это позволит приложениям узнать об изменениях:
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | ::SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0);
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Как сделать, чтобы у окна был черный фон?===
| + | |
| − | | + | |
| − | Нужно переопределить обработчик сообщения WM_CTLCOLOR - OnCtlColor():
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | // глобальная переменная или член класса 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;
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Почему на моем компьютере экзешник, созданный в MFC запускается, а на других компьютерах - нет? Требует какую-то dll.===
| + | |
| − | | + | |
| − | Нужно выбирать режим Release: Menu->Build->Configurations...->Release.
| + | |
| − | Экзешник, соответственно, брать из папки Release проекта.
| + | |
| − | | + | |
| − | ===Как в диалог добавить меню?===
| + | |
| − | | + | |
| − | Нужно создать в редакторе ресурсов новое меню, затем вставить его в диалог:
| + | |
| − | # Открыть в редакторе диалог;
| + | |
| − | # В свойствах (во вкладке General, окошко Menu) указать идентификатор ресурса меню;
| + | |
| − | # При помощи визарда добавить для меню обработчики OnCommand() и OnUpdateСommand().
| + | |
| − | | + | |
| − | ===Почему не вызывается OnUpdate для пунктов меню (не получается ни затенить, ни отметку поставить)?===
| + | |
| − | | + | |
| − | В диалоге (CDialog) у меню апдейт не происходит сам, в отличие от мейнфрейма (CFrameWnd). Для этого нужно сделать апдейт самим, в обработчике сообщения WM_KICKIDLE.
| + | |
| − | | + | |
| − | Визардом этот обработчик не добавляется, поэтому можно переопределить виртуальную DefWindowProc() и там обработать:
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | // этот файл надо включить, там определёна WM_KICKIDLE
| + | |
| − | #include <afxpriv.h>
| + | |
| − | | + | |
| − | 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);
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Как в главном окне отключить системное меню (в левом верхнем углу) и кнопки (в правом верхнем углу)?===
| + | |
| − | | + | |
| − | При создании окна нужно убрать стиль WS_SYSMENU. Теперь пользователь корректно может закрыть окно только Alt+F4, ну, или если вы предоставите ему дополнительную возможность сделать это.
| + | |
| − | | + | |
| − | Пример 1. (для SDI, MDI)
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | // этот обработчик уже добавлен визардом
| + | |
| − | 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;
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Пример 2. (для диалога)
| + | |
| − | Если диалог описан в ресурсах, то в свойствах диалога убрать галочки:
| + | |
| − | * "System menu"
| + | |
| − | * "Minimize box"
| + | |
| − | * "Maximize box"
| + | |
| − | | + | |
| − | ===Как запретить пользователю нажать на кнопку?===
| + | |
| − | | + | |
| − | Нужно применить метод класса CWnd::EnableWindow(...) для кнопки. Значение 0 параметра делает кнопку неактивной, 1 - делает активной (кстати, не только для кнопки можно, а для любого класса, производного от класса CWnd).
| + | |
| − | | + | |
| − | Пусть имеется некий диалог, на нём лежит кнопка c ID == IDC_1. В любом месте кода диалога (кроме конструктора и деструктора, хотя, если проверить наличие валидного хендла диалога, как в примере, то ничего страшного не будет и там) выполняем код:
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | // делаем кнопку неактивной
| + | |
| − | if (m_hWnd)
| + | |
| − | {
| + | |
| − | CWnd* pw = 0;
| + | |
| − | pw = GetDlgItem(IDC_1);
| + | |
| − | if (pw)
| + | |
| − | {
| + | |
| − | pw->EnableWindow(0);
| + | |
| − | }
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Что означают сообщения, которые студия выводит при компиляции, вроде таких: Loaded 'C:\WINDOWS\SYSTEM\WSOCK32.DLL', no matching symbolic information found?===
| + | |
| − | | + | |
| − | Это строка говорит о том, что студия не смогла найти отладочные символы для WSOCK32.DLL. В этом нет ничего страшного. Просто, при наличии отладочных символов в процессе отладки, можно получить доступ к именам функции из системных DLL. Например, вместо ''KERNEL32! 0x77E8B184()'' увидим ''KERNEL32!CreateThread''.
| + | |
| − | | + | |
| − | ===Как обработать сообщения, которые приходят к элементу управления?===
| + | |
| − | | + | |
| − | Скажем, нужно обработать сообщения, приходящие к элементу класса CEdit. Нужно произвести от CEdit свой класс и в виртуальной процедуре класса WindowProc перехватить нужные сообщения.
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | virtual LRESULT WindowProc(
| + | |
| − | UINT message,
| + | |
| − | WPARAM wParam,
| + | |
| − | LPARAM lParam
| + | |
| − | );
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Пример. Полностью выключаем, скажем, обработку сообщения WM_CHAR.
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
| + | |
| − | {
| + | |
| − | switch (message)
| + | |
| − | {
| + | |
| − | case WM_CHAR:
| + | |
| − | {
| + | |
| − | return 0;
| + | |
| − | }
| + | |
| − | break;
| + | |
| − | }
| + | |
| − |
| + | |
| − | return CEdit::WindowProc(message, wParam, lParam);
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Чтобы связать экземпляр класса с элементом управления на форме, добавьте визардом для
| + | |
| − | элемента управления переменную класса (выбрав не Value, а Control).
| + | |
| − | | + | |
| − | ===Как настроить количество пробелов в табуляции?===
| + | |
| − | | + | |
| − | Есть пара способов:
| + | |
| − | # Tools->Options->Tabs->Insert Spaces
| + | |
| − | # Правой кнопкой мыши щёлкнуть по тексту, в контекстном меню выбрать properties.
| + | |
| − | | + | |
| − | ===Как автоматически расставить отступы?===
| + | |
| − | | + | |
| − | Нужно в студии выделить текст для форматирования и нажать Alt+F8.
| + | |
| − | | + | |
| − | Ещё есть программа Artistic Style ( http://sourceforge.net/projects/astyle/ ), которая занимается переформатированием кода.
| + | |
| − | | + | |
| − | ===Поиск границ блока.===
| + | |
| − | | + | |
| − | Сочетание клавиш CTRL+"}" ищет парную фигурную скобку в тексте и переходит к ней.
| + | |
| − | | + | |
| − | ===Вертикальное выделение текста.===
| + | |
| − | | + | |
| − | Если удерживать клавишу Alt, а затем начать выделять текст мышкой, то область выделения принимает форму прямоугольника, что позволяет выделять вертикальные фрагменты текста.
| + | |
| − | | + | |
| − | ===Как узнать количество установленных в CListCtrl столбцов?===
| + | |
| − | | + | |
| − | Пример:
| + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | // указатель на переменную-элемент управления
| + | |
| − | CListCtrl* pL = ...;
| + | |
| − | | + | |
| − | // получаем количество столбцов
| + | |
| − | int count = pL->GetHeaderCtrl()->GetItemCount();
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Как получить иконку приложения?===
| + | |
| − | | + | |
| − | Если приложение запущено, то нужно найти его главное окно и послать ему сообщение WM_GETICON.
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | // функция возвращант хендл иконки
| + | |
| − | LRESULT SendMessage(hWnd, WM_GETICON, wParam, 0);
| + | |
| − | | + | |
| − | // hWnd == хендл окна приложения
| + | |
| − | // wParam ==
| + | |
| − | // 1)==ICON_BIG - получить большую иконку
| + | |
| − | // 2)==ICON_SMALL - получить маленькую иконку
| + | |
| − | // 3)==ICON_SMALL2 - получить маленькую иконку, если она определена
| + | |
| − | // в приложении. Если её нет, то маленькую иконку,
| + | |
| − | // сгенерированную системой из большой иконки
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Как в CString можно найти или вырезать часть строки?===
| + | |
| − | | + | |
| − | Это можно сделать при помощи методов класса CString:
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | // вырезает кусок строки
| + | |
| − | 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;
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Как отобразить на элементах управления промежуточные результаты длительных вычислений?===
| + | |
| − | | + | |
| − | В общем случае это делается принудительной перерисовкой нужного окна путём объявления этого окна невалидным.
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | pWnd->Invalidate(0);
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Затем непосредственной отсылки в оконную процедуру сообщения WM_PAINT.
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | pWnd->UpdateWindow();
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Пример:
| + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | CWnd* pWnd = ...; // окно, которое надо перерисовывать
| + | |
| − | | + | |
| − | for (int i = 0; i < 10000; i++)
| + | |
| − | {
| + | |
| − | // меняется содержимое окна
| + | |
| − | // ...
| + | |
| − | | + | |
| − | // немедленная перерисовка
| + | |
| − | pWnd->Invalidate(0);
| + | |
| − | pWnd->UpdateWindow();
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Также можно также просто вызвать метод RedrawWindow() с параметрами по умолчанию.
| + | |
| − | | + | |
| − | ===Я написал DLL, которую используют несколько приложений. Всё работает, но когда происходит очередной вызов функции из DLL, почему то, данные в функции обнуляются. С чем это связано?===
| + | |
| − | | + | |
| − | Переменные и массивы в DLL, содержимое которых должно использоваться несколькими процессами, должны объявляться статическими. Статическая переменная или массив инициализируются только один раз в момент загрузки DLL.
| + | |
| − | | + | |
| − | Пример:
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | DWORD calltest()
| + | |
| − | {
| + | |
| − | // будет выполнено только при первом вызове
| + | |
| − | static DWORD callcount = 0;
| + | |
| − | static DWORD str[1000] = {0};
| + | |
| − | | + | |
| − | // будет выполняться каждый раз
| + | |
| − | callcount++;
| + | |
| − | return callcount;
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Как открыть проекцию файла в память и как с ней работать?===
| + | |
| − | | + | |
| − | Создание проекции:
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | HANDLE CreateFileMapping(
| + | |
| − | HANDLE hFile, // хендл уже открытого файла
| + | |
| − | LPSECURITY_ATTRIBUTES lpAttributes,
| + | |
| − | DWORD flProtect, // способ открытия проекции
| + | |
| − | DWORD dwMaximumSizeHigh, // размер файла (старшие 4 байта, обычно - 0)
| + | |
| − | DWORD dwMaximumSizeLow, // размер файла (младшие 4 байта)
| + | |
| − | LPCTSTR lpName
| + | |
| − | );
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Доступ к созданной проекции производится процедурой:
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | LPVOID MapViewOfFile(
| + | |
| − | HANDLE hFileMappingObject, // хендл проекции
| + | |
| − | DWORD dwDesiredAccess, // способ работы с проекцией
| + | |
| − | DWORD dwFileOffsetHigh,
| + | |
| − | DWORD dwFileOffsetLow, // смещение от начала файла (младшие 4 байта)
| + | |
| − | SIZE_T dwNumberOfBytesToMap // длина в байтах (если 0 - то весь файл)
| + | |
| − | );
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Далее с файлом можно работать как с обычным массивом в памяти.
| + | |
| − | | + | |
| − | После работы с проекцией, её надо освободить.
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | BOOL UnmapViewOfFile(
| + | |
| − | LPCVOID lpBaseAddress // адрес, который вернула процедура MapViewOfFile
| + | |
| − | );
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Пример:
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | 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);
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Как в MFC Grid control отобразить картинку в ячейке?===
| + | |
| − | | + | |
| − | Нужно создать список изображений (CImageList), затем передать указатель на список в таблицу. Поскольку элемент управления лишь копирует указатель, список должен создаваться динамически, либо быть членом класса, экземпляр которого существует всё время работы таблицы.
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | CImageList m_ImageList;
| + | |
| − | CGridCtrL m_Grid1;
| + | |
| − | | + | |
| − | // ...
| + | |
| − | | + | |
| − | // неким образом создаётся список
| + | |
| − | m_ImageList.Create(...);
| + | |
| − | | + | |
| − | // ...
| + | |
| − | | + | |
| − | //вставляем в элемент управления
| + | |
| − | m_Grid1.SetImageList(&m_ImageList);
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Как при помощи IPicture отобразить картинку из файла? ===
| + | |
| − | | + | |
| − | Пример - несложная функция, отображающая картинку из файла. Поддерживаются форматы BMP, GIF, JPEG, PNG, TIFF, EMF.
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | #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;
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Как позволить пользователю начать ввод новой строки в многострочном поле редактирования?===
| + | |
| − | | + | |
| − | Нужно в редакторе ресурсов поставить для свойств окошка 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)?===
| + | |
| − | | + | |
| − | ====КОПИРОВАНИЕ В БУФЕР ОБМЕНА====
| + | |
| − | | + | |
| − | Алгоритм:
| + | |
| − | # Готовим данные
| + | |
| − | #* Выделяем память из кучи, вызывая GlobalAlloc()
| + | |
| − | #* Получаем указатель на выделенную память, вызывая GlobalLock()
| + | |
| − | #* Заполняем данные
| + | |
| − | #* Освобождаем указатель, вызывая GlobalUnlock();
| + | |
| − | # Открываем буфер обмена, вызывая OpenClipboard();
| + | |
| − | # Очищаем буфер, вызывая EmptyClipboard();
| + | |
| − | # Вызываем SetClipboardData() один раз для каждого формата вставляемых данных (имеется в виду - если одни и те же данные представлены в разных форматах, и приложение может эти форматы создать)
| + | |
| − | # Закрываем буфер, вызывая CloseClipboard();
| + | |
| − | # ВЫЗЫВАТЬ GlobalFree() НЕ НУЖНО, в этом случае это предоставлено системе
| + | |
| − | | + | |
| − | Скажем, хотим поместить в буфер обмена текст.
| + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | //готовим данные
| + | |
| − | //выделяем из кучи память для данных
| + | |
| − | 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();
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | | + | |
| − | | + | |
| − | ====ИЗВЛЕЧЕНИЕ ИЗ БУФЕРА ОБМЕНА====
| + | |
| − | | + | |
| − | Алгоритм:
| + | |
| − | # Проверяем, что поддерживается нужный формат данных, вызывая IsClipboardFormatAvailable()
| + | |
| − | # Открываем буфер обмена, вызывая OpenClipboard();
| + | |
| − | # Достаём данные
| + | |
| − | #* Получаем из буфера хендл требуемого формата, вызывая GetClipboardData()
| + | |
| − | #* Получаем указатель на выделенную память, вызывая GlobalLock()
| + | |
| − | #* Работаем с данными
| + | |
| − | #* Освобождаем указатель, вызывая GlobalUnlock();
| + | |
| − | # Закрываем буфер, вызывая CloseClipboard();
| + | |
| − | | + | |
| − | Скажем, хотим извлечь из буфера обмена текст.
| + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | //Проверяем, что поддерживается нужный формат данных,
| + | |
| − | 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();
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | | + | |
| − | ===Как получить полный путь к экзешнику из самой программы?===
| + | |
| − | Можно прочитать параметры командной строки - в командную строку первым параметром система всегда передаёт заключённый в кавычки полный путь к файлу запущенной программы. Достаём путь следующим образом:
| + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | BOOL CMyApp::InitInstance()
| + | |
| − | {
| + | |
| − | //добыча полного имени экзешника
| + | |
| − | CString csFullExeName;
| + | |
| − | {
| + | |
| − | CString csAppName=GetCommandLine();
| + | |
| − | csAppName.Delete(0,1);
| + | |
| − | csAppName.Replace('\"','\0');
| + | |
| − | csFullExeName=(const char*)csAppName;
| + | |
| − | }
| + | |
| − | //теперь csFullExeName содержит искомый путь
| + | |
| − | | + | |
| − | //...
| + | |
| − | //...
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Каким способом exe файл может заменить самого себя? ===
| + | |
| − | | + | |
| − | К примеру, программа должна обновляется через Internet и хочет обновить свой exe-файл. Но так как он в данный момент запущен, это будет, естественно, невозможно сделать напрямую.
| + | |
| − | Один из способов - сделать копию экзешника и из него обновиться
| + | |
| − | | + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | #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();
| + | |
| − | }
| + | |
| − | //...
| + | |
| − | //...
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | === Как производится конвертация из кодировки UTF8 в 1251 и наоборот?===
| + | |
| − | | + | |
| − | Можно перевести строку из UTF8 в Unicode, затем из Unicode в 1251
| + | |
| − | | + | |
| − | Ниже приведена структура, содержащая процедуры перекодирования,
| + | |
| − | а также процедуру с примером использования
| + | |
| − | <syntaxhighlight lang="cpp">
| + | |
| − | //описание структуры
| + | |
| − | 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();
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | ===Как работать с базой данных Access из программы на VC.net?===
| + | |
| − | Проще всего подключить ADO компоненты и сделать все на них.
| + | |
| − | | + | |
| − | Компоненты ADO (ADODC,DATAGRID и т.п.) это ActiveX.
| + | |
| − | | + | |
| − | В редакторе ресурсов, во всплывающем меню, есть Insert ActiveX Control -> открывается список всех компонент, зарегистрированных на машине. Нужно найти компоненты (Это компоненты от MS и они помечены (OLEDB)) и вставить их в диалог. Для того что бы иметь возможность управлять ими, нужно импортировать обертки для них, это делается при помощи ClassWizard, там есть импорт->класс->указать файл с компонентой (OSX). Появляется список всех классов, объявленных внутри.
| + | |
| − | | + | |
| − | Расставляем нужные галочки, нажимаем ОК.
| + | |
| − | | + | |
| − | [[Category:FAQ]]
| + | |