Алекс Jenter - Программирование на Visual C++. Архив рассылки
- Название:Программирование на Visual C++. Архив рассылки
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Алекс Jenter - Программирование на Visual C++. Архив рассылки краткое содержание
РАССЫЛКА ЯВЛЯЕТСЯ ЧАСТЬЮ ПРОЕКТА RSDN, НА САЙТЕ КОТОРОГО ВСЕГДА МОЖНО НАЙТИ ВСЮ НЕОБХОДИМУЮ РАЗРАБОТЧИКУ ИНФОРМАЦИЮ, СТАТЬИ, ФОРУМЫ, РЕСУРСЫ, ПОЛНЫЙ АРХИВ ПРЕДЫДУЩИХ ВЫПУСКОВ РАССЫЛКИ И МНОГОЕ ДРУГОЕ.
Программирование на Visual C++. Архив рассылки - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
void ShowContextMenu (CWnd *pWnd, LPCTSTR pszPath, CPoint point) {
// Строим полное имя.
TCHAR tchPath[MAX_PATH];
GetFullPathName(pszPath, sizeof(tchPath)/sizeof(TCHAR), tchPath, NULL);
// Если нужно, перекодируем ANSI в UNICODE.
WCHAR wchPath[MAX_PATH];
if(IsTextUnicode (tchPath, lstrlen (tchPath), NULL)) lstrcpy ((char *)wchPath, tchPath);
else MultiByteToWideChar(CP_ACP, 0, pszPath, -1, wchPath, sizeof(wchPath)/sizeof(WCHAR));
// Получаем интерфейс IShellFolder рабочего стола
IShellFolder *pDesktopFolder;
SHGetDesktopFolder(&pDesktopFolder);
// Преобразуем путь в LPITEMIDLIST
LPITEMIDLIST pidl;
pDesktopFolder->ParseDisplayName(pWnd->m_hWnd, NULL, wchPath, NULL, &pidl, NULL);
// Получаем интерфейс IShellFolder для заданного файла (папки)
IShellFolder *pFolder;
pDesktopFolder->BindToObject(pidl, NULL, IID_IShellFolder, (void**)&pFolder);
// Получаем интерфейс IContextMenu для заданного файла (папки)
IContextMenu *pContextMenu;
pFolder->GetUIObjectOf(pWnd->m_hWnd, 1, (LPCITEMIDLIST*)&pidl, IID_IContextMenu, NULL, (void**)&pContextMenu);
// Создаём меню
CMenu PopupMenu;
PopupMenu.CreatePopupMenu();
// Заполняем меню
pContextMenu->QueryContextMenu(PopupMenu.m_hMenu, 0, 1, 0x7FFF,CMF_EXPLORE);
// Отображаем меню
UINT nCmd = PopupMenu.TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON|TPM_RETURNCMD, point.x, point.y, pWnd);
// Выполняем команду (если она была выбрана)
if(nCmd) {
CMINVOKECOMMANDINFO ici;
ZeroMemory(&ici, sizeof(CMINVOKECOMMANDINFO));
ici.cbSize = sizeof(CMINVOKECOMMANDINFO);
ici.hwnd = pWnd->m_hWnd;
ici.lpVerb = MAKEINTRESOURCE(nCmd-1);
ici.nShow = SW_SHOWNORMAL;
ContextMenu->InvokeCommand(&ici);
}
// Получаем интерфейс IMalloc.
IMalloc *pMalloc;
SHGetMalloc(&pMalloc);
// Используем его для освобождения памяти, выделенной на ITEMIDLIST
pMalloc->Free(pidl);
// Освобождаем все полученные интерфейсы
pDesktopFolder->Release();
pFolder->Release();
pContextMenu->Release();
pMalloc->Release();
return;
}
Эту функцию можно вызывать, например, из обработчика OnContextMenu. Делается это так:
void CMyView::OnContextMenu(CWnd* pWnd, CPoint point) {
ShowContextMenu(pWnd, "C:\\command.com", point);
}
За дополнительной информацией следует обратиться к следующим статьям в MSDN:
– Periodicals 1997, Microsoft Systems Journal, April, Wicked Code
– Knowledge Base, статья ID: Q198288
– Описание IShellFolder и IContextMenu
Что касается второго вопроса (о создании собственных пунктов меню), мы имеем полный контроль над процессом создания меню, а значит можем делать с ним всё, что угодно. Нужно только иметь в виду 2 момента.
Во-первых, поскольку функция TrackPopupMenu вызывается с флагом TPM_RETURNCMD, она на будет отправлять окну сообщение WM_COMMAND. Поэтому нужно анализировать значение nCmd, возвращённое функцией TrackPopupMenu и вызывать нужный обработчик вручную. Например:
UINT nCmd = PopupMenu.TrackPopupMenu(…);
if (nCmd) {
if (nCmd == 0x8000) {
AfxMessageBox("It works!!!");
} else {
// Используем IContextMenu::InvokeCommand
}
}
Во-вторых, функция IContextMenu::QueryContextMenu получает параметры idCmdFirst, idCmdLast (в примере выше они равны 1 и 0x7FFF соответственно). Идентификаторы для стандартных пунктов меню выбираются именно в диапазоне от idCmdFirst до idCmdLast. Поэтому нужно проследить, чтобы идентификаторы пользовательских пунктов меню в этот диапазон не попали.
Alexander SharginКогда начал читать вашу статью на тему мерцания, подумал было, что вы обязательно упомянете тот метод, который использовал я в своей программе. На мой взгляд, он достаточно известен, и, кажется, является самым самым лучшим.
Нужно просто создать обработчик события WM_ERASEBKGND с одной-единственной строчкой:
BOOL CSomeClass::OnEraseBkgnd(CDC* pDC) {
return FALSE;
}
Т.е., по-русски говоря, программа фон не очистила, рисуйтесь полностью.
VladНа ответ A 1из прошлого выпуска:
Теперь практика. Пусть имеется готовое SDI приложение (с технологией Документ/Представление). Создаем дополнительное Представление. Это делается в функции CFrameWnd::OnCreateClient примерно так:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) {
// class CNewView – это наше новое представление
pContext->m_pNewViewClass = RUNTIME_CLASS(CNewView);
// обратите внимание на идентификатор нового Представления
// переменная m_pNewView описанна в CMainFrame как
CNewView* m_pNewView;
m_pNewView = STATIC_DOWNCAST(CNewView, CreateView(pContext, AFX_IDW_PANE_FIRST+1));
m_pNewView->ShowWindow(SW_HIDE); // для сброса флага WS_VISIBLE
return CFrameWnd::OnCreateClient(lpcs, pContext);
}
Этот код работает неправильно, причём это видно даже невооружённым взглядом. В последней строчке функции CMainFrame::OnCreateClient вызывается функция базового класса. Но ведь поле pContext->pNewViewClass уже изменилось! В результате вместо двух разных видов будет создано два одинаковых. Ошибка лечится переносом вызова функции из базового класса в начало переопределённой функции:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) {
int nResult = CFrameWnd::OnCreateClient(lpcs, pContext);
…
return nResult;
}
Кроме того, неясно, как использовать функцию SwitchView. Указатель на созданный нами вид хранится в m_pNewView, но для получения указателя на вид, созданный самой MFC, не видно удобного способа. Вероятно, лучший вариант – также сохранить его в члене класса CMainFrame.
Alexander SharginQ. У меня dialog-base приложение, живет в systray. Необходимо, чтобы приложение при повторном запуске находило уже запущеный экземпляр программы и активизировало его. Я пытался сделать это через FindWindow(), в которую передается имя зарегистрированного класса окна, и заголовок окна, которое разыскивается. По заголовку я искать не могу, так как он все время у меня меняется. Следовательно, нужно искать по зарегистрированному имени класса окна. Вот тут то и начинается проблема. Я его не знаю. MFC сама их раздает dialog-based приложениям. А переопределить это имя можно было бы в PreCreateWindow(), но этот метод CDialog не наследует из CWnd. Во всех остальных методах, имя класса уже зарегистрированно, т.е. менять его поздно. Как быть?
el-fЭто все на сегодня. До новых встреч!
Алекс Jenter jenter@mail.ru Красноярск, 2000.Программирование на Visual C++
Выпуск №26 от 3 декабря 2000 г.
Здравствуйте!
Итак, вот уж и зима на дворе… Время, когда отходить от компьютера не хочется даже ненадолго ;) Правда, это если у вас в комнате достаточно тепло. В другом случае не хочется вылезать из-под трех одеял;)
В прошлом выпуске мы с вами говорили о профилировании программ. Некоторые читатели просили также рассказать обо всех богатых возможностях отладки, которые предлагает Visual C++. Александр Шаргин, наш постоянный автор, любезно предложил написать в рассылку статью на эту тему. Думаю, что даже умеющие пользоваться отладчиком программисты найдут в ней для себя много интересного.
В этой статье я очень кратко расскажу о возможностях встроенного отладчика Visual C++.
Читать дальшеИнтервал:
Закладка: