(уже готовое, часть2)
(1/1)
Алексей++:
Q:
Как на Visual C++ 6.0 в Главном окне отключить системное меню
(в левом верхнем углу) и кнопки(в правом верхнем углу) ?
A:
При создании окна нужно убрать стиль WS_SYSMENU
(теперь пользователь корректно может закрыть окно только Alt+F4 ,
ну или если вы предоставите ему дополнительную возможность сделать это )
Пример 1. (для SDI, MDI)
Код:
//этот обработчик уже добавлен визардом
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
///////////////////////////////
//добавленная часть
{
//убираем стиль
cs.style&=~WS_SYSMENU;
}
///////////////////////////////
return TRUE;
}
Пример 2. (для диалога)
Если диалог описан в ресурсах, то в свойствах диалога убрать галочки
"System menu"
"Minimize box"
"Maximize box"
Q:Хочу сделать так, чтобы пользователь не мог нажать на кнопку,
пока программа не разрешит.
A:Нужно применить метод класса CWnd::EnableWindow(...) для кнопки.
Значение параметра 0 делает кнопку неактивной, 1 - делает активной.
(кстати, не только для кнопки можно, а для любого класса, производного
от класса CWnd)
Пример 1. Пусть имеется некий диалог, на нём лежит кнопка c ID == IDC_1.
в любом месте кода диалога (кроме конструктора и деструктора , хотя, если
проверить наличие валидного хендла диалога, как в примере, то ничего
страшного не будет и там)
Код:
//делаем кнопку неактивной
if(m_hWnd)
{
CWnd* pw=0;
pw=GetDlgItem(IDC_1);
if(pw)pw->EnableWindow(0);
}
Q:Что означают сообщения, которые студия выводит при компиляции,
вроде таких :
Loaded 'C:\WINDOWS\SYSTEM\WSOCK32.DLL', no matching symbolic information found.
A:Это строка говорит о том, что студия не смогла найти отладочные
символы для WSOCK32.DLL. В этом нет ничего страшного, просто при наличии
отладочных символов в процессе отладки можно получить доступ к именам
функции из системных DLL. Например, вместо
KERNEL32! 0x77E8B184() -
увидим
KERNEL32!CreateThread.
Q:Как обработать сообщения , которое приходит к некому
контролу (скажем CEdit) ?
A:
Нужно произвести от CEdit свой класс, и в виртуальной процедуре
класса WindowProc перехватить нужные сообщения.
Код:
virtual LRESULT WindowProc(
UINT message,
WPARAM wParam,
LPARAM lParam
);
Пример. Полностью выключаем, скажем, обработку сообщения WM_CHAR
Код:
LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_CHAR:
{
return 0;
}
break;
}
return CEdit::WindowProc(message, wParam, lParam);
}
Чтобы связать экземпляр класса с контролом на форме, добавьте визардом для
контрола переменную класса (выбрав не Value а Control).
Q:Как настроить количество пробелов в табуляции?
A:
Tools->Options->Tabs->Insert Spaces
(или правой кнопкой мыши по тексту-> properties)
Q:Как автоматически расставить отступы?
A: Выделить текст для форматирования, нажать Alt+F8
Есть ещё программа Artistic Style, которая занимается
переформатированием кода
http://sourceforge.net/projects/astyle/
Q:Поиск границ блока
A:
"CTRL+ }" ищет парную фигурную скобку в тексте и переходит на неё
Q:Вертикальное выделение текста
A:
"Alt + выделение мышкой" - позволяет выделять вертикальные фрагменты текста
Q:Как узнать количество установленных в CListCtrl столбцов ?
A:
Код:
CListCtrl* pL=...; //указатель на переменную-контрол
int count=pL->GetHeaderCtrl()->GetItemCount();
Q:Как получить иконку приложения?
A:
Если приложение запущено, то нужно найти его главное окно и
послать ему сообщение WM_GETICON.
Код:
//функция возвращант хендл иконки
LRESULT SendMessage(hWnd, WM_GETICON, wParam, 0);
//hWnd == хендл окна приложения
//wParam ==
// 1)==ICON_BIG - получить большую иконку
// 2)==ICON_SMALL - получить маленькую иконку
// 3)==ICON_SMALL2 - получить маленькую иконку, если она определена
// в приложении. Если её нет, то маленькую иконку,
// сгенерированную системой из большой иконки
Q:Как в CString можно найти или вырезать часть строки?
A:
есть такие методы в CString :
Код:
//вырезает кусок строки
CString Mid(int nFirst) const;
CString Mid(int nFirst, int nCount) const;
//возвращает кусок строки (сначала или с конца)
CString Left(int nCount ) const;
CString Right(int nCount ) const;
//возвращает начальный кусок строки, в котором есть только
//символы из набора,представленного в lpszCharSet
CString SpanIncluding(LPCTSTR lpszCharSet ) const;
//возвращает начальный кусок строки, в котором нет
//символов из набора,представленного в lpszCharSet
CString SpanExcluding(LPCTSTR lpszCharSet ) const;
//убирает "пробелоподобные" символы из самого начала строки
//(то есть - пробел, табуляцию (\t) , возврат каретки, перевод строки (/r/n))
void TrimLeft();
//убирает все повторы символа из самого начала строки
void TrimLeft(TCHAR chTarget );
//убирает из самого начала строки все символа из набора lpszTargets
void TrimLeft(LPCTSTR lpszTargets );
void TrimRight();
void TrimRight(TCHAR chTarget );
void TrimRight(LPCTSTR lpszTargets );
//поиск в строке
int Find( TCHAR ch ) const;
int Find( LPCTSTR lpszSub ) const;
int Find( TCHAR ch, int nStart ) const;
int Find( LPCTSTR pstr, int nStart ) const;
//поиск, начиная с конца
int ReverseFind( TCHAR ch ) const;
//поиск позиции первого символа, одного из набора,
// представленного в lpszCharSet
int FindOneOf( LPCTSTR lpszCharSet ) const;
Q:
Есть у меня CListBox и я в ходе выполнения программы добавляю
в него строки. Но я не могу посмотреть что именно добавляется.
Вывод результатов происходит в конце выполнения процедуры...
A:
Если нужно делать принудительную перерисовку окна во время
длительных вычислений, то нужно вызывать для окна, которое
надо перерисовать метод
RedrawWindow()
с параметрами по умолчанию, или пару
Invalidate(0);
UpdateWindow();
Это приводит к пометке всего окна к перерисовке и отправлению
сообщения WM_PAINT в оконную процедуру в обход очереди
сообщений, вызывая немедленную перерисовку окна.
Код:
CWnd* pw=...;//окно , которое надо перерисовывать
for(int i=0;i<10000)
{
//меняется содержимое окна
//...
//немедленная перерисовка
pw->Invalidate(0);
pw->UpdateWindow();
}
Q:Я написал DLL , которую используют несколько приложений.
Всё вроде работает, но когда происходит очередной вызов функции
из DLL , почему то данные в функции обнуляются.
С чем это связано ?
A:
Переменные и массивы в DLL, содержимое которых должно использоваться
несколькими процессами, должны объявляться статическими.
Статическая переменная или массив инициализируются только
один раз в момент загрузки DLL.
Пример:
Код:
DWORD calltest()
{
//будет выполнено только при первом вызове
static DWORD callcount=0;
static DWORD str[1000]={0};
//будет выполняться каждый раз
return ++callcount;
}
Q: Как открыть проекцию файла в память и как с ней работать?
A:
Проекция файла в память (маппирование) создаётся процедурой API
Код:
HANDLE CreateFileMapping(
HANDLE hFile, //хендл уже открытого файла
LPSECURITY_ATTRIBUTES lpAttributes,
DWORD flProtect, //способ открытия проекции
DWORD dwMaximumSizeHigh, //размер файла (старшие 4 байта , обычно==0)
DWORD dwMaximumSizeLow, //размер файла (младшие 4 байта)
LPCTSTR lpName
);
Доступ к созданной проекции производится процедурой
Код:
LPVOID MapViewOfFile(
HANDLE hFileMappingObject, //хендл проекции
DWORD dwDesiredAccess, //способ работы с проекцией
DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow, //смещение от начала файла (младшие 4 байта)
SIZE_T dwNumberOfBytesToMap //длина в байтах (если ==0 - то весь файл)
);
далее с файлом можно работать как с обычным массивом в памяти.
После работы с проекцией , её надо освободить процедурой
Код:
BOOL UnmapViewOfFile(
LPCVOID lpBaseAddress //адрес, который вернула процедура MapViewOfFile
);
Пример.
Код:
HANDLE 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);
Алексей++:
Q:Использую MFC Grid control 2.25 , не получается отобразить
картинку в ячейке. Как это делается ?
A:
Нужно создать список изображений (CImageList) , затем передать
указатель на список в контрол. Поскольку контрол лишь копирует
указатель , список должен создаваться динамически, либо быть
членом класса, экземпляр которого существует всё время работы
контрола.
Код:
m_GridMarket
CImageList m_ImageList;
CGridCtrL m_Grid1
...
...
//неким образом создаётся список
m_ImageList.Create(...);
//...
//вставляем в контрол
m_Grid1.SetImageList(&m_ImageList);
//
Q:Как при помощи IPicture отобразить картинку из файла?
A:
Пример - несложная функция, отображающая картинку из файла
поддерживаются форматы
BMP, GIF, JPEG, PNG, TIFF, EMF
Код:
#include "atlconv.h"
#define HandleIsValid(H) (H!=(HANDLE)-1 && H!=(HANDLE)0)
//*pDestDC - CDC, на который предполагается вывод картинки
//pchzFilePath - путь к файлу
//pWid - (возвращает) ширина картинки
//pHig - (возвращает) высота картинки
bool DrawBitmapFromFile(CDC* pDestDC,const char* pchzFilePath,int *pWid=0,int *pHig=0)
{
bool result=false;
if(pWid)*pWid=0;
if(pHig)*pHig=0;
int Wid=0;
int Hig=0;
IPicture* pPic=0;
try
{
IPicture* ptmpPic=0;
USES_CONVERSION;
HRESULT hr;
CString txt=pchzFilePath;
hr= ::OleLoadPicturePath(
const_cast<LPOLESTR>(T2COLE(txt)),
0,0,0,IID_IPicture,
reinterpret_cast<void **>(&ptmpPic)
);
if(hr==S_OK && ptmpPic)
{
pPic=ptmpPic;
}
else
{
throw 0;
}
OLE_XPOS_HIMETRIC cxSrc;
OLE_YPOS_HIMETRIC cySrc;
if(S_OK!=pPic->get_Width(&cxSrc))throw 0;
if(S_OK!=pPic->get_Height(&cySrc))throw 0;
Wid=cxSrc/26;
Hig=cySrc/26;
//рисуем
if(S_OK !=pPic->Render(pDestDC->GetSafeHdc(),
0,Hig,Wid,-Hig,0,0,cxSrc,cySrc,0))throw 0;
}
catch(...)
{
result=false;
}
if(pPic)
{
pPic->Release();
pPic=0;
}
if(pWid)*pWid=Wid;
if(pHig)*pHig=Hig;
return result;
}
Q:У меня модальное диалоговое окно, в нем поле редактирования
мультилайновое, т.е. чтобы перейти на новую строку надо нажать
ентер, но вызывается стандартный обработчик диалогового окна.
Подскажите, что делать?
A:
Нужно в редакторе ресурсов поставить для CEdit окошка галочку
свойства WantReturn,
или добавить ES_WANTRETURN при создании CEdit контрола динамически.
Q:Как выводят картинку-логотип(splash screen) при запуске
программы? То есть, когда загружается программа на экран выводится
картинка, потом она исчезает(загрузка программы закончена) и
пользователь может приступать к работе
A:
Для этого используется класс, производный от CDialog.
Этот диалог после создания показывает себя на экран,
выводя на себя рисунок. Также запускает таймет, по срабатывани
которого диалог гасится. Создаётся диалог InitInstance приложения.
В VC6++ также есть уже готовый компонент
Project->Add To Project -> Components and Controls->(в папке
"Visual C++ Components" есть SplashScreen.)
Q:Как сделать, чтобы при выпадении списка у ComboBox была не одна
строка, а больше, вроде все свойства покрутил, не помогает
Вместо выпадающего списка одна строка и скролл...
A:
В редакторе ресурсов надо щелкнуть в комбобоксе на треугольнике -
появляется рамка для растягивания вниз - размер выпадающего списка.
Алексей++:
Q:В VC++.net , что делать после того, как на форму
установил ActiiveX ListView, как объявить класс и
переменную для этого элемента?
A:
Щёлкнуть правой кнопкой мыши на элементе , в меню -
add variable или add class
Q:Как вставить данные в буфер обмена (Clipboard) ?
Как их оттуда вытащить ?
A:
1) копирование в буфер обмена:
1.Готовим данные
а.Выделяем память из кучи, вызывая GlobalAlloc()
б.Получаем указатель на выделенную память, вызывая GlobalLock()
в.Заполняем данные
г.Освобождаем указатель , вызывая GlobalUnlock();
2.Открываем буфер обмена , вызывая OpenClipboard();
3.Очищаем буфер, вызывая EmptyClipboard();
4.Вызываем SetClipboardData() один раз для каждого формата
вставляемых данных (имеется в виду - если одни и те же
данные представлены в разных форматах, и приложение
может эти форматы создать)
5.Закрываем буфер, вызывая CloseClipboard();
6.ВЫЗЫВАТЬ GlobalFree() НЕ НУЖНО , в этом случае это
предоставлено системе
Скажем, хотим поместить в буфер обмена туда текст.
Код:
//готовим данные
//выделяем из кучи память для данных
HANDLE hglbCopy = GlobalAlloc(GMEM_MOVEABLE,10);
if(!hglbCopy)return;
//получаем указатель
void* lpStr = GlobalLock(hglbCopy);
if(!lpStr)return;
//заполняем данные
strcpy((char*)lpStr,"my text");
//освобождаем указатель
GlobalUnlock(hglbCopy);
lpStr=0;
//открываем буфер обмена
OpenClipboard();
//очищаем
EmptyClipboard();
//текстовый формат
SetClipboardData(CF_TEXT,hglbCopy);
//закрываем буфер
CloseClipboard();
2) извлечение из буфера обмена
1.Проверяем, что поддерживается нужный формат данных,
вызывая IsClipboardFormatAvailable()
2.Открываем буфер обмена , вызывая OpenClipboard();
3.Достаём данные
а.Получаем из буфера хендл требуемого формата,
вызывая GetClipboardData()
б.Получаем указатель на выделенную память, вызывая GlobalLock()
в.Работаем с данными
г.Освобождаем указатель , вызывая GlobalUnlock();
4.Закрываем буфер, вызывая CloseClipboard();
Код:
//Проверяем, что поддерживается нужный формат данных,
if(!IsClipboardFormatAvailable(CF_TEXT))return;
//открываем буфер обмена
OpenClipboard();
//достаём данные
//текстовый формат
HANDLE hglbCopy = GetClipboardData(CF_TEXT);
if(!hglbCopy)return;
//получаем указатель
void* lpStr = GlobalLock(hglbCopy);
if(!lpStr)return;
//читаем данные
char data[10];
memmove(data,lpStr,sizeof(data));
//освобождаем указатель
GlobalUnlock(hglbCopy);
lpStr=0;
//закрываем буфер
CloseClipboard();
Алексей++:
Q:Как получить полный путь к экзешнику из самой программы ?
A:
В командную строку первым параметром система всегда передаёт
заключённый в кавычки полный путь к файлу запущенной программы
Достаём путь таким образом :
Код:
BOOL CMyApp::InitInstance()
{
//добыча полного имени экзешника
CString csFullExeName;
{
CString csAppName=GetCommandLine();
csAppName.Delete(0,1);
csAppName.Replace('\"','\0');
csFullExeName=(const char*)csAppName;
}
//теперь csFullExeName - содержит искомый путь
//...
//...
}
Q:Каким способом можно exe файл может заменить самого себя?
То есть, моя программа обновляется, например, через Internet,
и хочет обновить свой exe-файл. Но так как он в данный момент
запущен - это будет, естественно, запрещено.
Как это можно проще всего сделать?
A:
Один из способов - сделать копию экзешника и из него обновиться
Код:
#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();
}
//...
//...
}
Q:Есть строка символов (страничка из Инета) в кодировке
utf-8 (строка char*). Как мне ее получить в формате CString
или в char* в кодировке ANSI (cp 1251) ?
A:
Можно перевести строку из UTF8 в Unicode, затем из Unicode в 1251
Ниже приведена структура, содержащая процедуры перекодирования,
а также процедуру с примером использования
Код:
//описание структуры
struct coder
{
//utf8->unicode
static wchar_t* utf8_to_unicode__dontForgetDeleteArr(const char *utf8_string)
{
wchar_t* pRes=0;
int res_len=0;
//тест на возможность преобразования
res_len=MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,0,0);
if(!res_len)return 0;
//выделяем память
pRes = new wchar_t[res_len];
if(!pRes)return 0;
//преобразование
if(!MultiByteToWideChar(CP_UTF8,0,utf8_string,-1,pRes,res_len))
{
delete [] pRes;
return 0;
}
return pRes;
}
//unicode->1251
static char * unicode_to_1251__dontForgetDeleteArr(const wchar_t *unicode_string)
{
char* pRes=0;
int res_len=0;
//тест на возможность преобразования
res_len = WideCharToMultiByte(1251,0,unicode_string,-1,0,0,0,0);
if(!res_len)return 0;
//выделяем память
pRes=new char[res_len];
if(!pRes)return 0;
//преобразование
if(!WideCharToMultiByte(1251,0,unicode_string,-1,pRes,res_len,0,0))
{
delete [] pRes;
return 0;
}
return pRes;
}
//процедура с примером
static void Example()
{
wchar_t* unicode_string=0;
char* cp1251_string=0;
//исходный текст
char utf8_string[] = "UTF-8 + русский текст";
for(;;)
{
unicode_string=utf8_to_unicode__dontForgetDeleteArr(utf8_string);
if(!unicode_string)
{
AfxMessageBox("Не удалось конвертировать в unicode!");
break;
}
cp1251_string = unicode_to_1251__dontForgetDeleteArr(unicode_string);
if(!cp1251_string)
{
AfxMessageBox("Не удалось конвертировать из unicode!");
break;
}
break;
}
//cp1251_string - результат
AfxMessageBox(cp1251_string);
//не забываем удалить массивы
if(unicode_string)
{
delete [] unicode_string;
unicode_string=0;
}
if(cp1251_string)
{
delete [] cp1251_string;
cp1251_string=0;
}
}
};
//вызов примера
coder::Example();
Q:Как организовать взаимодействие программы на
VC.net с Access-овской базой данных?
A:
Проще всего подключить ADO компоненты и сделать все на них.
Компоненты ADO (ADODC,DATAGRID и т.п.) это ActiveX.
В редакторе ресурсов, во всплывающем меню, есть
Insert ActiveX Control -> открывается список всех компоент,
зарегистрированых на машине. Нужно найти компоненты (Это
компоненты от MS и они помечены (OLEDB)) и вставить их в
диалог. Для того что бы иметь возможность управлять ими,
нужно импортировать обертки для них, это делается при помощи
ClassWisard, там есть
импорт->класс->указать файл с компоентой (OSX).
Появляется список всех классов, объявленых внутри.
Проставляем галочки, нажимаем ОК.
Навигация