??xml version="1.0" encoding="utf-8" standalone="yes"?>
要消除窗口对?必须清楚H口对象的构?在一个通常的程序中Q先创徏c++H口对象,然后由Windows创徏实际的窗口结?q返回句柄与c++对象q接.也就是说,H口对象包含c++H口对象和W(xu)indowsH口对象,两者通过句柄HWND联系.
现在,让我们看?正规"的窗口对象清除流E?所谓对象的清除是指释放对象所占的资源,H口对象中WindowsH口对象占有的是pȝ资源,c++对象占有的是内存资源.释放pȝ资源相对要简单一?调用虚函数DestroyWindow删除WindowsH口对象.如果DestroyWindow删除的是父窗?Windows?x)自动?f)子窗口调用DestroyWindow.一般来?E序不必调用DestroyWindow.因ؓ(f)当用户关闭窗口时,Windows便发送WM_CLOSE消息,WM_CLOSE的缺省消息处理函数CWnd::OnClose调用DestroyWindow.
到这?清除工作已经完成?jin)一?屏幕上的H口已经不见?但是别忘?在内存中q有一个c++H口对象.让我们再看看c++对象清除的过E?当窗口被取消?H口最后发送的一个消息是WM_NCDESTROY.它缺省的消息处理函数CWnd::OnNcDestroy把c++H口对象与句柄HWND分离,q调用一个很重要的虚函数PostNcDestroy.q个函数是搞清窗口对象清除的关键.Cwnd中的PostNcDestroy什么都不做.有些MFCH口cM(x)重蝲?q加入delete this代码删除c++对象.q些H口cd常是以new操作W徏立在堆中?׃重蝲?jin)PostNcDestroy,使窗口有自动清除功能.因此,我们不用兛_(j)清除问题?另外的一些MFCH口cM般是以变量Ş式创建的,MFC没有Z没必要ؓ(f)它们重蝲PostNcDestroy函数.
不具备自动清除功能的H口c?一般在堆栈中创建或嵌入于其它c++对象?
所有标准的Windows控gc?如CStatic, CEdit, CListBox{等)
由CWndcȝ接派生出来的子窗口对?如用户定制的控g)
拆分H口c?CSplitterWnd)
~省的控制条c?CControlBar的派生类)
对话框类(CDialog)在堆栈上创徏的模态对话框c?/p>
所有的Windows通用对话?除CFindReplaceDialog)
由ClassWizard创徏的对话框
h自动清除功能的窗口类,一般在堆中创徏:
L架窗口类(直接或间接从CFrameWndcL?
视图c?直接或间接从CViewcL?
从某U程度上来说,MFC?服务到家"使初学者有些找不着?不过,不得不承?MFCq的很漂?
谈到q里,我们应该明白c++里一条重要的准则:用DestroyWindow清除H口对象,不要?delete".
对于不具备自动清除功能的H口cM?delete"?"delete"先调用析构函数里的DestroyWindow,׃在析构函C,虚机制不起作?q里只能调用本地版本(Cwndc?DestroyWindow函数,昄q不是我们想要的.对于有自动清除功能的H口c?好象问题更严重一?前面提到?jin)重载的PostNcDestroy已经含有?delete this",q样c++对象p释放?jin)两?
很多?vc++同vb一?是一个完全可视化的?不用在看c++的书?通过上面对窗口对象的清除的介l?可以发现,WindowsE序是与Windows紧密l合?而且牉|到很多c++的知?如虚函数、析构函数、new操作W等).要对vc++有进一步理?必须理解Windows机制,深入学习(fn)c++.
一、与加速键表有关的几个API函数和结构?/p>
操作加速键表用的几个API函数Q关于这几个函数的详l说明请参考有关书c)(j)Q?br> HACCEL LoadAccelerators(HINSTANCE hInstance, LPCTSTR lpTableNAme);
LoadAccelerators函数从程序的资源中加载一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表,加蝲成功后返回一个加速健表的句柄。其中:(x)
hInstance 应用E序的实例句柄?br> lpTableName 指向加速键表名U字W串的指针?/p>
HACCEL CreateAcceleratorTable(LPACCEL lpaccl, int cEntries);
CreateAcceleratorTable函数Ҏ(gu)一个ACCELl构数组创徏一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表。该函数与LoadAccelerators不同的是QLoadAccelerators函数加蝲?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表在E序l束后系l会(x)自动该加速键表从内存中清除,但CreateAcceleratorTable函数创徏?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表需要用函数DestoryAceleratorTable函数q行清除?br> lpaccl 一个指向ACCELl构数组的指针?br> cEntries 数组中元素的个数?/p>
BOOL DestoryAcceleratorTable(HACCEL hAccel);
DestoryAcceleratorTable函数清除由CreateAcceleratorTable函数创徏?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表,成功则返回TRUE。其中:(x)
hAccel 需要清除的加速键表句柄?/p>
int TranslateAccelerator(HWND hWd, HACCEL hAccTable, LPMSG lpMsg);
TranslateAccelerator函数负责译加速键。其中:(x)
hWnd H口句柄Q翻译后的消息将被发往该窗?br> hAccTable 加速键表句柄?br> lpMsg 指向MSGl构的指针?/p>
ACCELl构的定义:(x)
typedef struct tagACCEL{
BYTE fVirt;
WORD key;
WORD cmd;
}ACCEL,*LPACCEL;
其中Q?br> fVirt 加速键的标记?br> key 键的代码。如fVirt成员包含FVIRTKEY标志Q则key指一个虚键码Q否则是一个ASCII码?br> cmd 命o(h)IDP该参数将被放入WMQCOMMAND或WMQSYSCOMMAND消息的wParam参数的低位字发至H口?/p>
二、在windows下如何?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表?/p>
在window下?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表一般有两种Ҏ(gu)Q?Q创Z?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键资源Q在E序中用API函数LoadAccelerators来将加速键表加载入内存。ƈ在消息@环中使用API函数TranslateAccelerator来翻译该加速键表?、在E序中填充一个ACCEL数组。然后调用API函数CreateAcceleratorTable来创建加速表Q翻?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键同上Q但不要忘记在退出程序前使用API函数DestoryAcceleratorTable来清除它。下面分别给Z个例子:(x)
/*?:使用LoadAccelerators?br> 假设你已l徏立了(jin)一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键资源QID为IDRQACCEL?br> 假设你已l定义了(jin)初始化函数InitApplication(HINSTANCE hInstance,int nCmdShow),
该函数执行注册窗口类和创建窗口操作?br>*/
#include <windows.h>
#include "rc/resource.h"
BOOL InitApplication(HINSTANCE hInstance,int nCmdShow);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HANDLE hAccelTable;
// 初始化应用程序,q生成主H口.
if (!InitApplication(hInstance, nCmdShow))
{
return FALSE; // 初始化失?br> }
//使用函数LoadAccelerators从程序资源中加蝲加速键?br> hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCEL));
// 取得q分发消息直到接收到 WM_QUIT 消息.
while (GetMessage(&msg, NULL, 0, 0))
{
//在分发消息前首先试着?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表进行翻译,如果是一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键则由
//TranslateAccelerator函数q行译Q不再l处理该消息?br> if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam; // Returns the value from PostQuitMessage
}
/*?:使用CreateAcceleratorTable?br> 假设你已l定义了(jin)初始化函数InitApplication(HINSTANCE hInstance,int nCmdShow),
该函数执行注册窗口类和创建窗口操作?br>*/
#include <windows.h>
#include "rc/resource.h"
Qdefine ID_CMD_A 0x00000230
Qdefine ID_CMD_B 0x00000231
Qdefine ID_CMD_C 0x00000232
Qdefine ID_CMD_D 0x00000233
Qdefine ID_CMD_E 0x00000234
Qdefine ID_CMD_F 0x00000235
Qdefine ID_CMD_G 0x00000236
//定义?jin)七?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键,请在消息回调函数中处理这七个命o(h)ID?br>static ACCEL accel[]={
{FVIRTKEY|FCONTROL,VK_F5,ID_CMD_A},
{FVIRTKEY|FCONTROL,VK_F6,ID_CMD_B},
{FVIRTKEY|FCONTROL,VK_HOME,ID_CMD_C},
{FVIRTKEY|FCONTROL,VK_END,ID_CMD_D},
{FVIRTKEY|FCONTROL,"G",ID_CMD_E},
{FVIRTKEY|FCONTROL,VK_SPACE,ID_CMD_F},
{FVIRTKEY|FCONTROL,"K",ID_CMD_G},
};
BOOL InitApplication(HINSTANCE hInstance,int nCmdShow);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HANDLE hAccelTable;
// 初始化应用程序,q生成主H口.
if (!InitApplication(hInstance, nCmdShow))
{
return FALSE; // 初始化失?br> }
//使用函数CreateAcceleratorTable从数laccel中加?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键?br> hAccelTable = CreateAcceleratorTable(accel, sizeof(accel)/sizeof(ACCEL));
// 取得q分发消息直到接收到 WM_QUIT 消息.
while (GetMessage(&msg, NULL, 0, 0))
{
//在分发消息前首先试着?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表进行翻译,如果是一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键则由
//TranslateAccelerator函数q行译Q不再l处理该消息?br> if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//删除加速键?br> DestoryAcceleratorTable(hAccelTable);
return msg.wParam; // Returns the value from PostQuitMessage
}
在MFCE序设计中,有关?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表的操作已经被CFrameWndc进行了(jin)装。通常Q我们的E序的主框架cCMainFrame从CFrameWndcL生(SDI界面E序Q,或者从CMDIFrameWndcL生(MDI界面E序Q,而CMDIFrameWndcM是从CFrameWndcL生的。所以,我们q不用去兛_(j)那个资源号ؓ(f)IDR_MAINFRAME?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表是如何加蝲的,如果你只是需要一个这L(fng)?rn)态的加速键表的话?br> 那么我们能不能用自q加速键表呢Q答案是Q可以的?br> 创徏加速键表的Ҏ(gu)同前。由于在MFC中,W(xu)inMain函数被隐藏,我们不能直接修改WinMain函数Q所以,加速键表的创徏在CMainFrame的OnCreate函数中创建?br> 1、在CMainFramecMd一个HACCELcd保护成员变量Qm_hMyAccel。在构造函C初始化ؓ(f)NULL?br> 2、在CMainFrame::OnCreate函数?“return 0;”句前增加创徏加速键表的代码。返回的加速键表句柄保存在m_hMyAccel中:(x)
Ҏ(gu)1Q?IDRQMYACCELZ定义?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表资源号)
m_hMyAccel=LoadAccelerators(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_MYACCEL));
Ҏ(gu)2Q?accel同前面的例子一样在本文件的开头部分进行定?
m_hMyAccel=CreateAcceleratorTable(accel,sizeof(accel)/sizeof(ACCEL));
3、如果是使用CreateAccelTable函数创徏的,则重载虚拟函数DestoryWindow()。在该函数的“return CMDIFrameWnd::DestroyWindow();”前增加如下代?
if(m_hMyAccel!=NULL){
DestroyAcceleratorTable(m_hMyAccel);
m_hMyAccel=NULL;
}
通过前面的三步,加速键表已l能正确地被创徏和删除了(jin)Q但是它q没有工作。下面就是要让我们刚才所创徏?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表工作v来?br> 在APIE序设计中大家已l知道了(jin)加速键是如何工作的。也是在消息还没有分发出去之前先检查是不是一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键。我们通过API函数TranslateAccelerator来实现。在MFC中,消息机制已经被封装了(jin)Q我们不能去修改消息循环。但是,框架在分发消息前?x)调用虚拟函数PerTranslateMessageQƈ且如果该函数q回TRUEQ则不再处理该消息。这正是我们所需要的?br> 让我们再回到CMainFramec,生成PerTranslateMessage函数的覆盖版本。修改函C如下Q?/p>
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
if(m_hMyAccel&&TranslateAccelerator(m_hWnd, m_hMyAccel, pMsg))
return TRUE;
return CMDIFrameWnd::PreTranslateMessage(pMsg);
}
好了(jin)Q现在我们的加速键已经能正常地工作?jin)。以上方法用在其它窗口同h效(如对话框中,你不妨在对话框中试试Q?/p>
三、可在运行时~辑?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表?/p>
通过上面的叙qͼ你可能已l对可编辑的加速键表有?jin)一定的轮廓。其实其实现思想很简单:(x)只要对一个ACCEL数组q行修改Q然后重新生?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表就行了(jin)?br> Z(jin)区分命o(h)Q我们ؓ(f)每个命o(h)取一个名字。在CMainFramecd义的前面加上下面的一个结构定义:(x)
typedef struct{
char cCmd[32];
ACCEL accel;
}ACCELITEM,*LPACCELITEM;
我们用该l构来保?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表的数据。在CMainFramecMd两个保护成员变量Q?/p>
LPACCELITEM m_lpAccel;
DWORD m_dwAccelCount;
在构造函Cm_lpAccel初始化ؓ(f)NULLQm_dwAccelCount初始化ؓ(f)0。在数组accel的定义下面增加一个字W串数组的静(rn)态变量的定义Q用来指定命令的名称,请仿照下面自己定义,个数多少不限Q字W串长度不要过31个字W)(j)Q?/p>
static char strCmd[][32]={
"Command One",
"Command Two",
"Command Three",
"Command Four",
"Command Five"
};
在CMainFramecMd一个保护成员函数LoadAccel(),该函数用来将加速键表装入,定义如下Q?/p>
BOOL CMainFrame::LoadAccel()
{
ASSERT(m_hActAccel==NULL);
ASSERT(m_lpAccel==NULL);
m_dwAccelCount=sizeof(accel)/sizeof(ACCEL);
m_lpAccel=new ACCELITEM[m_dwAccelCount];
memset(m_lpAccel,0,sizeof(ACCELITEM)*m_dwAccelCount);
DWORD dwCmdStr=sizeof(strCmd)/sizeof(char[32]);
for(DWORD dw=0;dw<m_dwAccelCount;dw++){
m_lpAccel[dw].accel=accel[dw];
strcpy(m_lpAccel[dw].cCmd,dw<dwCmdStr?strCmd[dw]:"Command Unknow");
}
m_hActAccel=CreateAcceleratorTable(accel,m_dwAccelCount);
return TRUE;
}
删除OnCreate函数中原来创?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表的代码Q改成对LoadAccel()的调用:(x)
LoadAccel();
在CMainFrame的析构函C增加以下内容Q?/p>
if(m_lpAccel)
delete[] m_lpAccel;
Z(jin)能够?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键数据q行~辑Q我们在工程中添加一个对话框资源QID?#8220;IDD_ACCELEDIT”Q在对话框上攄三个成组框(Group BoxQ,左边一个标题ؓ(f)“命o(h)”Q中间一个标题ؓ(f)“l合?#8221;Q右边一个标题ؓ(f)“虚键?#8221;。在左边成组框中攄一个列表框QList BoxQ,ID?#8220;IDC_LST_CMD”。在中间成组框中攄三个栔R框QCheck BoxQ,上下排列。上面的栔R框的ID?#8220;IDC_CHK_ALT”Q标题ؓ(f)“Alt”QƈN?#8220;Group”属性;中间的核选框的ID?#8220;IDC_CHK_SHIFT”Q标题ؓ(f)“Shift”Q取?#8220;Group”属性;下面的核选框的ID?#8220;IDC_CHK_CTRL”Q标题ؓ(f)“Ctrl”Q取?#8220;Group”属性。在双的成l框中放|一个列表框QID?#8220;IDC_LST_KEY”。调整各个控件的寸?qing)位|至合适。设|控件的TAB跌{序Q从左至叟뀁从上到下。依ơؓ(f)Q左成组框、IDC_LST_CMD列表框、中成组框、IDC_CHK_ALT栔R框、IDC_CHK_SHIFT栔R框、IDC_CHK_CTRL栔R框、右成组框、IDC_LST_KEY列表框、OK按钮、CANCEL按钮?br> 打开cd|为对话框新徏一个类Q类名ؓ(f)“CDlgEditAccel”。ؓ(f)两个列表框和三个栔R框映射变量Q如下:(x)
控gID:ID_LST_CMDQ类?Control/CListBoxQ名U?m_LstCmdQ?br> 控gID:ID_LST_KEYQ类?Control/CListBoxQ名U?m_LstKeyQ?br> 控gID:ID_CHK_ALTQ类?Control/CButtonQ名U?m_ChkAltQ?br> 控gID:ID_CHK_SHIFTQ类?Control/CButtonQ名U?m_ChkShiftQ?br> 控gID:ID_CHK_CTRLQ类?Control/CButtonQ名U?m_ChkCtrlQ?/p>
在类CDlgEditAccel的定义前加入下面的定义:(x)
typedef struct tag_KeyName{
CString m_strName;
WORD m_wID;
tag_KeyName(CString str,WORD id){m_strName=str,m_wID=id;}
}KEYNAME,*LPKEYNAME;
typedef struct tag_ActAccel{
CString m_strCmd;
ACCEL m_Accel;
}ACTACCEL,*LPACTACCEL;
class CActAccelList
{
public:
CActAccelList();
~CActAccelList();
protected:
LPACTACCEL m_lpActAccel;
int m_iCount;
public:
ACTACCEL& operator[](int index);
BOOL SetSize(int iSize);
int GetSize();
};
在文件DlgEditAccel.cpp文g中定义类CActAccelList的成员函敎ͼ代码如下Q?br>CActAccelList::CActAccelList()
{
m_lpActAccel=NULL;
m_iCount=0;
}
CActAccelList::~CActAccelList()
{
if(m_iCount>0&&m_lpActAccel)
delete[] m_lpActAccel;
}
int CActAccelList::GetSize()
{
return m_iCount;
}
ACTACCEL& CActAccelList::operator []( int index)
{
if(!(index>=0&&index<m_iCount))
AfxThrowMemoryException();
return m_lpActAccel[index];
}
BOOL CActAccelList::SetSize(int iSize)
{
if(iSize<0)
return FALSE;
if(m_iCount>0&&m_lpActAccel)
delete[] m_lpActAccel;
m_iCount=0;
m_lpActAccel=new ACTACCEL[iSize];
if(m_lpActAccel==NULL)
return FALSE;
m_iCount=iSize;
return TRUE;
}
在DlgAccelEdit.cpp文g头部定义全局变量Q-数组keyQ?br>static KEYNAME key[]={
KEYNAME("Left mouse button",VK_LBUTTON),
KEYNAME("Right mouse button",VK_RBUTTON),
KEYNAME("Control-break processing",VK_CANCEL),
KEYNAME("Middle mouse button",VK_MBUTTON),
KEYNAME("Back Space",VK_BACK),
KEYNAME("Tab",VK_TAB),
KEYNAME("Clear",VK_CLEAR),
KEYNAME("Enter",VK_RETURN),
KEYNAME("Shift",VK_SHIFT),
KEYNAME("Ctrl",VK_CONTROL),
KEYNAME("Alt",VK_MENU),
KEYNAME("Pause",VK_PAUSE),
KEYNAME("Caps Lock",VK_CAPITAL),
KEYNAME("Esc",VK_ESCAPE),
KEYNAME("Space",VK_SPACE),
KEYNAME("Page Up",VK_PRIOR),
KEYNAME("Page Down",VK_NEXT),
KEYNAME("End",VK_END),
KEYNAME("Home",VK_HOME),
KEYNAME("Left",VK_LEFT),
KEYNAME("Up",VK_UP),
KEYNAME("Right",VK_RIGHT),
KEYNAME("Down",VK_DOWN),
KEYNAME("Select",VK_SELECT),
KEYNAME("Excute",VK_EXECUTE),
KEYNAME("Print Screen",VK_SNAPSHOT),
KEYNAME("Insert",VK_INSERT),
KEYNAME("Delete",VK_DELETE),
KEYNAME("Help",VK_HELP),
KEYNAME("0",'0'),
KEYNAME("1",'1'),
KEYNAME("2",'2'),
KEYNAME("3",'3'),
KEYNAME("4",'4'),
KEYNAME("5",'5'),
KEYNAME("6",'6'),
KEYNAME("7",'7'),
KEYNAME("8",'8'),
KEYNAME("9",'9'),
KEYNAME("A",'A'),
KEYNAME("B",'B'),
KEYNAME("C",'C'),
KEYNAME("D",'D'),
KEYNAME("E",'E'),
KEYNAME("F",'F'),
KEYNAME("G",'G'),
KEYNAME("H",'H'),
KEYNAME("I",'I'),
KEYNAME("J",'J'),
KEYNAME("K",'K'),
KEYNAME("L",'L'),
KEYNAME("M",'M'),
KEYNAME("N",'N'),
KEYNAME("O",'O'),
KEYNAME("P",'P'),
KEYNAME("Q",'Q'),
KEYNAME("R",'R'),
KEYNAME("S",'S'),
KEYNAME("T",'T'),
KEYNAME("U",'U'),
KEYNAME("V",'V'),
KEYNAME("W",'W'),
KEYNAME("X",'X'),
KEYNAME("Y",'Y'),
KEYNAME("Z",'Z'),
KEYNAME("Left windows",VK_LWIN),
KEYNAME("Right windows",VK_RWIN),
KEYNAME("Applications",VK_APPS),
KEYNAME("Numeric keypad 0", VK_NUMPAD0),
KEYNAME("Numeric keypad 1", VK_NUMPAD1),
KEYNAME("Numeric keypad 2", VK_NUMPAD2),
KEYNAME("Numeric keypad 3", VK_NUMPAD3),
KEYNAME("Numeric keypad 4", VK_NUMPAD4),
KEYNAME("Numeric keypad 5", VK_NUMPAD5),
KEYNAME("Numeric keypad 6", VK_NUMPAD6),
KEYNAME("Numeric keypad 7", VK_NUMPAD7),
KEYNAME("Numeric keypad 8", VK_NUMPAD8),
KEYNAME("Numeric keypad 9", VK_NUMPAD9),
KEYNAME("Multiply",VK_MULTIPLY),
KEYNAME("Add",VK_ADD),
KEYNAME("Separator",VK_SEPARATOR),
KEYNAME("Subtract",VK_SUBTRACT),
KEYNAME("Decimal Point",VK_DECIMAL),
KEYNAME("Divide",VK_DIVIDE),
KEYNAME("F1",VK_F1),
KEYNAME("F2",VK_F2),
KEYNAME("F3",VK_F3),
KEYNAME("F4",VK_F4),
KEYNAME("F5",VK_F5),
KEYNAME("F6",VK_F6),
KEYNAME("F7",VK_F7),
KEYNAME("F8",VK_F8),
KEYNAME("F9",VK_F9),
KEYNAME("F10",VK_F10),
KEYNAME("F11",VK_F11),
KEYNAME("F12",VK_F12),
KEYNAME("F13",VK_F13),
KEYNAME("F14",VK_F14),
KEYNAME("F15",VK_F15),
KEYNAME("F16",VK_F16),
KEYNAME("F17",VK_F17),
KEYNAME("F18",VK_F18),
KEYNAME("F19",VK_F19),
KEYNAME("F20",VK_F20),
KEYNAME("F21",VK_F21),
KEYNAME("F22",VK_F22),
KEYNAME("F23",VK_F23),
KEYNAME("F24",VK_F24),
KEYNAME("Attn",VK_ATTN),
KEYNAME("CrSel",VK_CRSEL),
KEYNAME("ExSel",VK_EXSEL),
KEYNAME("Erase",VK_EREOF),
KEYNAME("Play",VK_PLAY),
KEYNAME("Zoom",VK_ZOOM),
KEYNAME("Reserved for future use",VK_NONAME ),
KEYNAME("PA1",VK_PA1),
KEYNAME("Clear(OEM)",VK_OEM_CLEAR ),
KEYNAME("file://",'//'),
KEYNAME("-",'-'),
KEYNAME("=",'='),
KEYNAME("[",'['),
KEYNAME("]",']'),
KEYNAME(";",';'),
KEYNAME("\'",'\''),
KEYNAME(",",','),
KEYNAME(".",'.'),
KEYNAME("/",'/'),
KEYNAME("`",'`')
};
在类CDlgAccelEdit中响应Windows消息QWM_INITDIALODQ代码如下:(x)
BOOL CDlgEditAccel::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
SetWindowText("Edit Accelerator Table");
int iCount=m_AccelList.GetSize();
int i;
for(i=0;i<iCount;i++){
m_LstCmd.AddString(m_AccelList[i].m_strCmd);
}
for(i=0;i<sizeof(key)/sizeof(KEYNAME);i++)
{
m_LstKey.AddString(key[i].m_strName);
}
m_LstCmd.SetCurSel(0);
OnSelchangeLstCmd();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
为类CDglAccelEdit增加一个保护成员函敎ͼ(x)
void SaveChange(int index=-1);
在文件DlgAccelEdit中定义该函数Q代码如下:(x)
void CDlgEditAccel::SaveChange(int index)
{
if(index>=0||(index=m_LstCmd.GetCurSel())>=0)
{
if(m_LstKey.GetCurSel()<0){
AfxMessageBox("你必需选择一个键?");
return;
}
BYTE btCmp=((m_ChkAlt.GetCheck()==1)?FALT:NULL)|
((m_ChkCtrl.GetCheck()==1)?FCONTROL:NULL)|
((m_ChkShift.GetCheck()==1)?FSHIFT:NULL)|FVIRTKEY;
WORD wKey=key[m_LstKey.GetCurSel()].m_wID;
m_AccelList[index].m_Accel.fVirt=btCmp;
m_AccelList[index].m_Accel.key=wKey;
return;
}
}
响应列表框ID_LST_CMD的通知消息“LBN_SELCHANGE”Q函C码如下:(x)
void CDlgEditAccel::OnSelchangeLstCmd()
{
// TODO: Add your control notification handler code here
int iCmd=m_LstCmd.GetCurSel();
WORD wKey=m_AccelList[iCmd].m_Accel.key;
BYTE btCmp=m_AccelList[iCmd].m_Accel.fVirt;
m_ChkAlt.SetCheck(btCmp&FALT);
m_ChkCtrl.SetCheck(btCmp&FCONTROL);
m_ChkShift.SetCheck(btCmp&FSHIFT);
int iCount=sizeof(key)/sizeof(KEYNAME);
int id=-1;
for(int i=0;i<iCount;i++)
{
if(key[i].m_wID==wKey){
id=i;
break;
}
}
m_LstKey.SetCurSel(id);
}
响应列表框ID_LST_KEY的通知消息“LBN_SELCHANGE”Q函C码如下:(x)
void CDlgEditAccel::OnSelchangeLstKey()
{
SaveChange();
}
响应栔R框ID_CHK_ALT的通知消息“BN_CLICKED”Q函C码如下:(x)
void CDlgEditAccel::OnChkAlt()
{
SaveChange();
}
响应栔R框ID_CHK_SHIFT的通知消息“BN_CLICKED”Q函C码如下:(x)
void CDlgEditAccel::OnChkShift()
{
SaveChange();
}
响应栔R框ID_CHK_CTRL的通知消息“BN_CLICKED”Q函C码如下:(x)
void CDlgEditAccel::OnChkCtrl()
{
SaveChange();
}
xQ用于编?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键的对话框已经完成。我们现在要做的是在程序中打开对话框来~辑?jin)。让我们回到CMainFramecM。我们将在该cM响应一个命令来打开~辑对话框,?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表进行编辑。完成后Ҏ(gu)OK回到ȝ序中Q然后更?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表。这样后Q我们刚刚编辑好?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表就开始v作用?jin)?br> 首先Q打开菜单。在“查看”后增加一?#8220;工具(&T)”下拉菜单Q在下拉菜单中增加一个了(jin)菜单Q?#8220;~辑加速键?&A)...”QID?#8220;ID_TOOL_ACCELEDIT”。打开cd|选择CMainFramec,响应“ID_TOOL_ACCELEDIT”命o(h)。编辑响应函数如下:(x)
void CMainFrame::OnToolAcceledit()
{
// TODO: Add your command handler code here
CDlgEditAccel dlg;
DWORD i;
dlg.m_AccelList.SetSize(m_dwAccelCount);
for(i=0;i<m_dwAccelCount;i++){
dlg.m_AccelList[i].m_strCmd=m_lpAccel[i].cCmd;
dlg.m_AccelList[i].m_Accel=m_lpAccel[i].accel;
}
if(IDOK==dlg.DoModal()){
ACCEL* pAccel=new ACCEL[m_dwAccelCount];
for(DWORD dw=0;dw<m_dwAccelCount;dw++){
m_lpAccel[dw].accel=pAccel[dw]=dlg.m_AccelList[dw].m_Accel;
}
if(m_hActAccel!=NULL)
DestroyAcceleratorTable(m_hActAccel);
m_hActAccel=CreateAcceleratorTable(pAccel,m_dwAccelCount);
}
}
在该文g的头部包含类CDlgEditAccel的头文gQ?/p>
#include "DlgEditAccel.h"
xQ可~辑?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表已l完成了(jin)。不妨试试看?/p>
三、将加速键表保存至文gQƈ在程序运行时自动从文件中加蝲?/p>
上面我们实现?jin)可~辑?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表。但是,当程序退出后Q我们编辑过?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键数据消׃(jin)Q下ơ运行程序时q是和以前一样了(jin)。将加速键表保存v来以备下ơ用,q是我们所希望的。下面讨论的Ҏ(gu)是用文件来保存我们?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表?br> 首先Q在MainFrm.cpp文g的头部定义一个全局字符Ԍ也就是用于保?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键的文件名Q?/p>
static char strAccelFileName[]="Accel.cus";
定义一个DWORDg为文件头Q我们通过该DWORD值来判断是否是一个有效格式的文gQ?/p>
#define ACCEL_FILE_HEAD 0x00434341
其次Qؓ(f)CMainFramecL加一个保护的成员函数Q?#8220;BOOL SaveAccel()”Q编辑其代码如下Q?br>BOOL CMainFrame::SaveAccel()
{
char lpAppName[256];
char lpAppPath[256];
char* lpFilePart=NULL;
GetModuleFileName(AfxGetInstanceHandle(),lpAppName,255);
GetFullPathName(lpAppName,255,lpAppPath,&lpFilePart);
TRACE1("Application File Name:%s.\n",lpAppName);
strcpy(lpFilePart,strAccelFileName);
TRACE1("Accelerator File Name:%s.\n",lpAppPath);
try
{
DWORD dwHead=ACCEL_FILE_HEAD;
DWORD dwCount=m_dwAccelCount;
CFile fAccel(lpAppPath,CFile::modeCreate|CFile::modeWrite);
fAccel.SeekToBegin();
fAccel.Write(&dwHead,sizeof(DWORD));
fAccel.Write(&dwCount,sizeof(DWORD));
for(DWORD dw=0;dw<dwCount;dw++)
{
fAccel.Write(m_lpAccel+dw,sizeof(ACCELITEM));
}
return TRUE;
}
catch(CFileException* e)
{
char buf[256];
char buf2[512];
int iError;
iError=e->m_cause;
e->GetErrorMessage(buf,256);
sprintf(buf2,"?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表保存到文g \"%s\" 中时发生错误!\n"
"???%d\n"
"错误描述:%s\n"
"\0",
strAccelFileName,iError,buf);
AfxMessageBox(buf2,MB_OK|MB_ICONSTOP|MB_DEFBUTTON1);
return FALSE;
}
}
再次Q修改LoadAccel()函数如下Q?/p>
BOOL CMainFrame::LoadAccel()
{
char lpAppName[256];
char lpAppPath[256];
char* lpFilePart=NULL;
GetModuleFileName(AfxGetInstanceHandle(),lpAppName,255);
GetFullPathName(lpAppName,255,lpAppPath,&lpFilePart);
TRACE1("Application File Name:%s.\n",lpAppName);
strcpy(lpFilePart,strAccelFileName);
TRACE1("Accelerator File Name:%s.\n",lpAppPath);
try
{
DWORD dwHead;
DWORD dwCount;
CFile fAccel(lpAppPath,CFile::modeRead);
fAccel.SeekToBegin();
if(fAccel.Read(&dwHead,sizeof(DWORD))!=sizeof(DWORD))
AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);
if(dwHead!=ACCEL_FILE_HEAD)
AfxThrowFileException(CFileException::invalidFile,13,lpAppPath);
if(fAccel.Read(&dwCount,sizeof(DWORD))!=sizeof(DWORD))
AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);
ASSERT(m_lpAccel==NULL);
m_lpAccel=new ACCELITEM[dwCount];
memset(m_lpAccel,0,sizeof(ACCELITEM)*dwCount);
m_dwAccelCount=dwCount;
for(DWORD dw=0;dw<dwCount;dw++)
{
if(fAccel.Read(m_lpAccel+dw,sizeof(ACCELITEM))!=sizeof(ACCELITEM))
AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);
}
ACCEL* pAccel=new ACCEL[dwCount];
for(dw=0;dw<dwCount;dw++){
pAccel[dw]=m_lpAccel[dw].accel;
}
m_hActAccel=CreateAcceleratorTable(pAccel,dwCount);
return TRUE;
}
catch(CFileException* e)
{
char buf[256];
char buf2[512];
int iError;
iError=e->m_cause;
e->GetErrorMessage(buf,256);
sprintf(buf2,"从文?\"%s\" 中加?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表时发生错误!\n"
"???%d\n"
"错误描述:%s\n"
"是否生成默认?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键?\n\0",
strAccelFileName,iError,buf);
if(IDYES==AfxMessageBox(buf2,MB_YESNO|MB_SYSTEMMODAL|MB_ICONSTOP|MB_DEFBUTTON1))
{
ASSERT(m_hActAccel==NULL);
ASSERT(m_lpAccel==NULL);
m_dwAccelCount=sizeof(accel)/sizeof(ACCEL);
m_lpAccel=new ACCELITEM[m_dwAccelCount];
memset(m_lpAccel,0,sizeof(ACCELITEM)*m_dwAccelCount);
DWORD dwCmdStr=sizeof(strCmd)/sizeof(char[30]);
for(DWORD dw=0;dw<m_dwAccelCount;dw++){
m_lpAccel[dw].accel=accel[dw];
strcpy(m_lpAccel[dw].cCmd,dw<dwCmdStr?strCmd[dw]:"Command Unknow");
}
m_hActAccel=CreateAcceleratorTable(accel,m_dwAccelCount);
SaveAccel();
return TRUE;
}
return FALSE;
}
}
最后,在DestroyWindow()函数头部增加对SaveAccel()函数的调用:(x)
SaveAccel();
...
好了(jin)Q你自己?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键数据已经能保存在文g中了(jin)Qƈ能从中正加载。如果文件不存在或程序读取时发现错误则提醒你是否建立~省?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键表,如你认的话则生成缺省的加速键表ƈ立刻保存x件中?br> ׃水^有限Q其中难免有误,Ƣ迎批评指正、发表你的意见。本Z胜感Ȁ?br>
一ơ偶然的情况下我发现以下代码竟然无法被编译通过Q如果你的编译器Q比如VC6或VC2003Q允许它~译通过Q我想你首先应该换个~译器,比如GCC或VC2005Q:(x)
void foo( const char* [] ) { }
int main( void )
{
char* s[2];
foo( s );
}
化成更一般的形式是:(x)
char** p1 = 0;
const char** p2 = p1;
错误是:(x)invalid conversion from `char**' to `const char**'.
lostpencil更加仔细Q用C~译器给出的是一个警告:(x)
initialization from incompatible pointer type.
随后hphol出?jin)合理的解释Q同?a target=_blank>comp.lang.c++.moderated上的Ulrich Eckhardt也用代码q行?jin)说明?/p>
用代码来说明最直观?jin)?x)
const char* s = "abc";
int main( void )
{
char* p0 = 0;
char** p1 = &p0;
const char** p2 = p1; // 先假设这一句是合法?( 试Ӟ可以先强制类?strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">?/strong>化一?)
*p2 = s;
*p0 = 'A'; // 通过p0在修改不应该被修改的sQ这昄?strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const相违背,其运行结果不可知?br>}
看了(jin) **?惛_?br>tekyDec 29, 2005 - Show original item
看完?明白**讲的Z?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char** 不能自动?/strong>化ؓ(f) const char**,(原文)但对我媄(jing)响最q是下面的?
==================================================================
char *p="abc" 能不能编译通过要看你用的~译器。鉴于大量遗留代码的存在Q大部分~译器允许其通过Q或者给个警告。当?dng)E序员自己必M证绝不去修改其倹{?
E序员不应该在代码中出现*p='A'q样的语句。这是当初约定好?jin)的Q编译器允许char *p="abc"通过Q而程序员保证不去修改它?
b. *p='A'~译时应该允?dng)R过Q因为单p条语句而言Q它完全合法?
c. q行?p='A'能不能通过要看实际的运行环境,包括你用的操作pȝ、编译器、编译器选项 {等Q一句话Q其q行l果׃得你Q且不应该由你去兛_(j)Q因U行为本w已l违反约定了(jin)?
==================================================================
工作关系?用CString 和string用的太多?很少q样定义字符?char *p=“abcde“?br>匝一?q不适应,:(,渐渐的回x惌v一些来(?q是太生?赶快写下?以后别忘?
q样定义的字W串char *p=“abcde“ ; char *p1=“123445667“;
正如上面提到的是不能?*p='A',q行的时候会(x)出错,同样,strcpy(p,p1)也会(x)出错?
"abcde"字符串可以看做是个常量字W串?是不能被修改?
但如?char p[]=“abcde“ q样定义,没有问?你可以修?p='A',只要不越界就ok.
q且发现q样两种定义
char *p=“abcde“
char p[]=“abcde“
在运行的时?p指向的地址也不是一L(fng),可见char *p=“abcde“q是有特D的处理 :),具体怎么处理׃知道?高手h?)
随着试,又发C问题,可能是个老问题了(jin)?
int main(int argc, char* argv[])
{
int t[10];
char p1[7]="123456";
const char *p2="1234567890123213123";
int len(0);
//*p1='C'; err
len=strlen(p1);
printf("%d\n",len);
strcpy(p1,p2); ///??????????
printf("%s\n",p1);
len=strlen(p1);
printf("%d\n",len);
return 0;
}
我定义的?个字W数l? 但用strcpy把p2拷到p1?p1是放不下?但程序却正常执行,warning ,err都没?q行也正?
输出
6
1234567890123213123
19
应该是用内存越界了(jin)??怎么?x)正常运行?
N对于内存界的?q气好才崩溃表现出来,q气不好正常运??
posted on 2006-02-22 13:04 Vincent.Chen 阅读(232) 评论(0) ~辑 收藏 所属分c? ?/font>
q是来说说原理把(本h也是菜鸟?!
q程注入是在目标进E中用VirtualAllocEx甌一D内?
然后用WriteProcessMemory函数自己dll的完整\径复制到q程q程?
然后在Kernel32中计LoadLibraryA的地址,再调用LoadLibraryA函数加蝲q程dll,
q在CreateRemoteThread创徏q程q程!
Code Language : C
#include \"stdafx.h\"
#include \"windows.h\"
#include \"tlhelp32.h\"
#include \"stdio.h\"
#pragma comment(lib,\"ws2_32\")
int EnableDebugPriv(const char * name)//提提权函?br>{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
//打开q程令牌?br> if(!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
&hToken))
{
MessageBox(NULL,\"OpenProcessToken Error!\",\"Error!\",MB_OK);
return 1;
}
//获得q程本地唯一ID
if(!LookupPrivilegeValue(NULL,name,&luid))
{
MessageBox(NULL,\"LookupPrivivlegeValue Error!\",\"Error\",MB_OK);
}
tp.PrivilegeCount=1;
tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
tp.Privileges[0].Luid=luid;
//调整权限
if(!AdjustTokenPrivileges(hToken,0,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL))
{
MessageBox(NULL,\"AdjustTokenPrivileges Error!\",\"Error\",MB_OK);
return 1;
}
return 0;
}
BOOL injectit(const char *DllPath,const DWORD dwRemoteProcessld)//注入d?br>{
HANDLE hrp;
if(EnableDebugPriv(SE_DEBUG_NAME))
{
MessageBox(NULL,\"Add Privilege Error!\",\"Error\",MB_OK);
return FALSE;
}
if((hrp=OpenProcess(PROCESS_CREATE_THREAD|//允许q程创徏U程
PROCESS_VM_OPERATION|//允许q程VM操作
PROCESS_VM_WRITE,//允许q程VM?br> FALSE,dwRemoteProcessld))==NULL)
{
MessageBox(NULL,\"OpenProcess Error!\",\"Error\",MB_OK);
return FALSE;
}
char *psLibFileRemote;
//使用VirtualAllocEx函数在远E进E的内存地址I间分配DLL文g名缓?br> psLibFileRemote=(char *)VirtualAllocEx(hrp,NULL,lstrlen(DllPath)+1,
MEM_COMMIT,PAGE_READWRITE);
if(psLibFileRemote==NULL)
{
MessageBox(NULL,\"VirtualAllocEx Error!\",\"Error\",MB_OK);
return FALSE;
}
//使用WriteProcessMemory函数DLL的\径名复制到远E的内存I间
if(WriteProcessMemory(hrp,psLibFileRemote,(void *)DllPath,lstrlen(DllPath)+1,NULL)==0)
{
MessageBox(NULL,\"WriteProcessMemory Error!\",\"Error\",MB_OK);
return FALSE;
}
//计算LoadLibraryA的入口地址
PTHREAD_START_ROUTINE pfnStartAddr=(PTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(TEXT(\"Kernel32\")),\"LoadLibraryA\");
if(pfnStartAddr==NULL)
{
MessageBox(NULL,\"GetProcAddress Error!\",\"Error\",MB_OK);
return FALSE;
}
//pfnStartAddr地址是LoadLibraryA的入口地址
HANDLE hrt;
if((hrt=CreateRemoteThread(hrp,
NULL,
0,
pfnStartAddr,
psLibFileRemote,
0,
NULL))==NULL)
{
MessageBox(NULL,\"CreateRemote Error!\",\"Error\",MB_OK);
return FALSE;
}
return TRUE;
}
unsigned long getpid(char *pn)//得到q程pid
{
BOOL b;
HANDLE hnd;
PROCESSENTRY32 pe;
//得到q程快照
hnd=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
pe.dwSize=sizeof(pe);
b=Process32First(hnd,&pe);
while(b)
{
if(strcmp(pn,pe.szExeFile)==0)
return pe.th32ProcessID;
b=Process32Next(hnd,&pe);
}
}
int main(int argc, char* argv[])
{
if(argc<2)
{
printf(\"++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\");
printf(\"injectpro V1.0!\nAuthor:text QQ:52674548\nusage:\n injectpro.exe targetprocess youdll\n\");
printf(\" eg:injectpro.exe iexplorer.exe c:\\youdll.dll\n\");
printf(\"++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\");
return 0;
}
EnableDebugPriv(SE_DEBUG_NAME);//自n提权
DWORD pid=getpid(argv[1]);
//printf(\"%d\",pid);
if(pid==0)
return 1;
if(injectit(argv[2],pid))
{
printf(\"inject success!\");
}
else
{
printf(\"inject error!\");
}
return 0;
}
本篇文章来源?黑反在线-信息安全W一?原文链接Q?a >http://www.hf110.com/hack/hackprg/200809/203556.html
2. 调用CRT函数wcstombs()
3. 使用CString构造器或赋值操?/p>
4. 使用ATL串{换宏
那么什么是BSTR、LPSTR以及(qing)LPWSTR呢?
BSTR(Basic STRingQBasic字符?是一个OLECHAR*cd的Unicode字符丌Ӏ它被描q成一个与自动化相兼容的类型。由于操作系l提供相应的API函数(如SysAllocString)来管理它以及(qing)一些默认的调度代码Q因此BSTR实际上就是一个COM字符Ԍ但它却在自动化技术以外的多种场合下得到广泛用。图1描述?jin)BSTR的结构,其中DWORD值是字符串中实际所占用的字节数Q且它的值是字符串中Unicode字符的两倍?/p>
LPSTR和LPWSTR是Win32和VC++所使用的一U字W串数据cd。LPSTR被定义成是一个指向以NULL(‘\0’)l尾?位ANSI字符数组指针Q而LPWSTR是一个指向以NULLl尾?6位双字节字符数组指针。在VC++中,q有cM的字W串cdQ如LPTSTR、LPCTSTR{,它们的含义如?所C?/p>
例如QLPCTSTR是指“long pointer to a constant generic string”Q表C?#8220;一个指向一般字W串帔R的长指针cd”Q与C/C++的const char*相映,而LPTSTR映射?char*?/p>
一般地Q还有下列类型定义:(x)
#ifdef UNICODE
typedef LPWSTR LPTSTR;
typedef LPCWSTR LPCTSTR;
#else
typedef LPSTR LPTSTR;
typedef LPCSTR LPCTSTR;
#endif
二、CString、CStringA ?CStringW
Visual C++.NET中将CStringT作ؓ(f)ATL和MFC的共享的“一?#8221;字符串类Q它有CString、CStringA和CStringW三种形式Q分别操作不同字W类型的字符丌Ӏ这些字W类型是TCHAR、char和wchar_t。TCHAR在Unicodeq_中等同于WCHAR(16位Unicode字符)Q在ANSI中等价于char。wchar_t通常定义为unsigned short。由于CString在MFC应用E序中经常用刎ͼq里不再重复?/p>
三、VARIANT、COleVariant 和_variant_t
在OLE、ActiveX和COM中,VARIANT数据cd提供?jin)一U非常有效的机制Q由于它既包含了(jin)数据本nQ也包含?jin)数据的cdQ因而它可以实现各种不同的自动化数据的传输。下面让我们来看看OAIDL.H文g中VARIANT定义的一个简化版Q?/p>
struct tagVARIANT {
VARTYPE vt;
union {
short iVal; // VT_I2.
long lVal; // VT_I4.
float fltVal; // VT_R4.
double dblVal; // VT_R8.
DATE date; // VT_DATE.
BSTR bstrVal; // VT_BSTR.
…
short * piVal; // VT_BYREF|VT_I2.
long * plVal; // VT_BYREF|VT_I4.
float * pfltVal; // VT_BYREF|VT_R4.
double * pdblVal; // VT_BYREF|VT_R8.
DATE * pdate; // VT_BYREF|VT_DATE.
BSTR * pbstrVal; // VT_BYREF|VT_BSTR.
};
};
昄QVARIANTcd是一个Cl构Q它包含?jin)一个类型成员vt、一些保留字节以?qing)一个大的unioncd。例如,如果vt为VT_I2Q那么我们可以从iVal中读出VARIANT的倹{同P当给一个VARIANT变量赋值时Q也要先指明其类型。例如:(x)
VARIANT va;
:: VariantInit(&va); // 初始?br>int a = 2002;
va.vt = VT_I4; // 指明long数据cd
va.lVal = a; // 赋?/p>
Z(jin)方便处理VARIANTcd的变量,W(xu)indowsq提供了(jin)q样一些非常有用的函数Q?/p>
VariantInit —?变量初始化为VT_EMPTYQ?/p>
VariantClear —?消除q初始化VARIANTQ?/p>
VariantChangeType —?改变VARIANT的类型;
VariantCopy —?释放与目标VARIANT相连的内存ƈ复制源VARIANT?/p>
COleVariantcL对VARIANTl构的封装。它的构造函数具有极为强大大的功能,当对象构造时首先调用VariantInitq行初始化,然后Ҏ(gu)参数中的标准cd调用相应的构造函敎ͼq用VariantCopyq行转换赋值操作,当VARIANT对象不在有效范围Ӟ它的析构函数׃(x)被自动调用,׃析构函数调用?jin)VariantClearQ因而相应的内存׃(x)被自动清除。除此之外,COleVariant的赋值操作符在与VARIANTcd转换中ؓ(f)我们提供极大的方ѝ例如下面的代码Q?/p>
COleVariant v1("This is a test"); // 直接构?br>COleVariant v2 = "This is a test";
// l果是VT_BSTRcdQgؓ(f)"This is a test"
COleVariant v3((long)2002);
COleVariant v4 = (long)2002;
// l果是VT_I4cdQgؓ(f)2002
_variant_t是一个用于COM的VARIANTc,它的功能与COleVariant怼。不q在Visual C++.NET的MFC应用E序中用时需要在代码文g前面d下列两句Q?/p>
#include "comutil.h"
#pragma comment( lib, "comsupp.lib" )
四、CComBSTR和_bstr_t
CComBSTR是对BSTR数据cd装的一个ATLc,它的操作比较方便。例如:(x)
CComBSTR bstr1;
bstr1 = "Bye"; // 直接赋?br>OLECHAR* str = OLESTR("ta ta"); // 长度?的宽字符
CComBSTR bstr2(wcslen(str)); // 定义长度?
wcscpy(bstr2.m_str, str); // 宽字符串复制到BSTR?br>CComBSTR bstr3(5, OLESTR("Hello World"));
CComBSTR bstr4(5, "Hello World");
CComBSTR bstr5(OLESTR("Hey there"));
CComBSTR bstr6("Hey there");
CComBSTR bstr7(bstr6);
// 构造时复制Q内容ؓ(f)"Hey there"
_bstr_t是是C++对BSTR的封装,它的构造和析构函数分别调用SysAllocString和SysFreeString函数Q其他操作是借用BSTR API函数。与_variant_t怼Q用时也要dcomutil.h和comsupp.lib?/p>
五、BSTR、char*和CString转换
(1) char*转换成CString
若将char*转换成CStringQ除?jin)直接赋值外Q还可用CString::Formatq行。例如:(x)
char chArray[] = "This is a test";
char * p = "This is a test";
?/p>
LPSTR p = "This is a test";
或在已定义Unicode应的用程序中
TCHAR * p = _T("This is a test");
?/p>
LPTSTR p = _T("This is a test");
CString theString = chArray;
theString.Format(_T("%s"), chArray);
theString = p;
(2) CString转换成char*
若将CStringc{换成char*(LPSTR)cdQ常怋用下列三U方法:(x)
Ҏ(gu)一Q用强制{换。例如:(x)
CString theString( "This is a test" );
LPTSTR lpsz =(LPTSTR)(LPCTSTR)theString;
Ҏ(gu)二,使用strcpy。例如:(x)
CString theString( "This is a test" );
LPTSTR lpsz = new TCHAR[theString.GetLength()+1];
_tcscpy(lpsz, theString);
需要说明的是,strcpy(或可UdUnicode/MBCS的_tcscpy)的第二个参数?const wchar_t* (Unicode)或const char* (ANSI)Q系l编译器会(x)自动对其q行转换?/p>
Ҏ(gu)三,使用CString::GetBuffer。例如:(x)
CString s(_T("This is a test "));
LPTSTR p = s.GetBuffer();
// 在这里添加用p的代?br>if(p != NULL) *p = _T('\0');
s.ReleaseBuffer();
// 使用完后?qing)时释放Q以便能使用其它的CString成员函数
(3) BSTR转换成char*
Ҏ(gu)一Q用ConvertBSTRToString。例如:(x)
#include "comutil.h"
#pragma comment(lib, "comsupp.lib")
int _tmain(int argc, _TCHAR* argv[]){
BSTR bstrText = ::SysAllocString(L"Test");
char* lpszText2 = _com_util::ConvertBSTRToString(bstrText);
SysFreeString(bstrText); // 用完释放
delete[] lpszText2;
return 0;
}
** 此方法不好,?x)造成内存泄露QSysFreeString也没有效果?/font>
Ҏ(gu)二,使用_bstr_t的赋D符重蝲。例如:(x)
_bstr_t b = bstrText;
char* lpszText2 = b;
* 不会(x)有内存泄Ԍ推荐Ҏ(gu)
(4) char*转换成BSTR
Ҏ(gu)一Q用SysAllocString{API函数。例如:(x)
BSTR bstrText = ::SysAllocString(L"Test");
BSTR bstrText = ::SysAllocStringLen(L"Test",4);
BSTR bstrText = ::SysAllocStringByteLen("Test",4);
Ҏ(gu)二,使用COleVariant或_variant_t。例如:(x)
//COleVariant strVar("This is a test");
_variant_t strVar("This is a test");
BSTR bstrText = strVar.bstrVal;
Ҏ(gu)三,使用_bstr_tQ这是一U最单的Ҏ(gu)。例如:(x)
BSTR bstrText = _bstr_t("This is a test");
Ҏ(gu)四,使用CComBSTR。例如:(x)
BSTR bstrText = CComBSTR("This is a test");
?/p>
CComBSTR bstr("This is a test");
BSTR bstrText = bstr.m_str;
Ҏ(gu)五,使用ConvertStringToBSTR。例如:(x)
char* lpszText = "Test";
BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText);
(5) CString转换成BSTR
通常是通过使用CStringT::AllocSysString来实现。例如:(x)
CString str("This is a test");
BSTR bstrText = str.AllocSysString();
…
SysFreeString(bstrText); // 用完释放
(6) BSTR转换成CString
一般可按下列方法进行:(x)
BSTR bstrText = ::SysAllocString(L"Test");
CStringA str;
str.Empty();
str = bstrText;
?/p>
CStringA str(bstrText);
(7) ANSI、Unicode和宽字符之间的{?/p>
Ҏ(gu)一Q用MultiByteToWideCharANSI字符转换成Unicode字符Q用WideCharToMultiByteUnicode字符转换成ANSI字符?/p>
Ҏ(gu)二,使用“_T”ANSI转换?#8220;一?#8221;cd字符Ԍ使用“L”ANSI转换成UnicodeQ而在托管C++环境中还可用SANSI字符串{换成String*对象。例如:(x)
TCHAR tstr[] = _T("this is a test");
wchar_t wszStr[] = L"This is a test";
String* str = S”This is a test”;
Ҏ(gu)三,使用ATL 7.0的{换宏和类。ATL7.0在原?.0基础上完善和增加?jin)许多字W串转换宏以?qing)提供相应的c,它具有如?所C的l一形式Q?/p>
其中Q第一个C表示“c?#8221;Q以便于ATL 3.0宏相区别Q第二个C表示帔RQ?表示“to”QEX表示要开辟一定大的~冲。SourceType和DestinationType可以是A、T、W和OLEQ其含义分别是ANSI、Unicode?#8220;一?#8221;cd和OLE字符丌Ӏ例如,CA2CT是ANSI转换成一般类型的字符串常量。下面是一些示例代码:(x)
LPTSTR tstr= CA2TEX<16>("this is a test");
LPCTSTR tcstr= CA2CT("this is a test");
wchar_t wszStr[] = L"This is a test";
char* chstr = CW2A(wszStr);