|
|
(не показана одна промежуточная версия этого же участника) |
Строка 1: |
Строка 1: |
− | ===Что означают сообщения, которые студия выводит при компиляции, вроде таких: Loaded 'C:\WINDOWS\SYSTEM\WSOCK32.DLL', no matching symbolic information found?===
| + | #REDIRECT [[FAQ:WinAPI_VCPP]] |
− | | + | |
− | Это строка говорит о том, что студия не смогла найти отладочные символы для 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]]
| + | |