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