m_pszAppName
|
向导中填写的工程名称,可以在CWndApp构造时传参指定。如果没有指定,会使用字符串资源“AFX_IDS_APP_TITLE”,如果还没设置这个串,将由可执行文件名代替。
|
属于CWndApp类
|
|
m_pszExeName
|
属于CWndApp类
|
||
m_pszProfileName
|
应用程序的INI配置文件名,在继承应用类中设置自己的配置文件 。
|
GetProfileString()等系列函数来配合。
|
属于CWndApp类(默认是执行程序.ini)
|
m_hInstance
|
模块在进程中的装入地址
|
属于CWndApp类
|
|
m_pMainWnd
|
在CSingleDocTemplate或CMultiDocTemplate构造时,就把资源文件绑定和主窗口框架类,文档类,视图类全都实例化,同时设置了此指针。基于对话框的也按其方式会设置此指针。注:没有命令行参数时,默认执行ID_FILE_NEW
|
文档,视图,都是MFC管理的,实例在堆上,不用手动回收。
当设置好,别忘记
ShowWindow(SW_SHOW);
UpdateWindow();
SetWindowText(“XXX程序”);
这样这个主窗口的消息循环,在Run时触发。
|
属于CWinThread。设置了此指针的UI窗口,在销毁时,都是安全的。
|
分类: c/C++
windows核心编程(第5版)读书笔记一
windows核心编程(第5版)读书笔记二
_tWinMain(WinMain)
|
wmainCRTStartup
|
_tmain(wMain)
|
_tmain(Main)
|
mainCRTStartup
|
wWinMainCRTStartup
|
WinMainCRTStartup
|
_tWinMain(wWinMain)
|
|
编码
|
ANSI |
UNICODE
|
UNICODE
|
ANSI
|
ANSI
|
UNICODE
|
ANSI
|
UNICODE
|
运行模式
|
GUI
|
CUI
|
CUI
|
CUI
|
CUI
|
GUI
|
GUI
|
GUI
|
运行环境
|
WIN16
|
WIN32
|
WIN16
|
WIN16
|
WIN32
|
WIN32
|
WIN32
|
WIN16
|
windows核心编程(第5版)读书笔记三
libCMt.lib
|
库的静态链接发行版本
|
|
libCMtD.lib
|
库的静态链接调试版本
|
|
MSVCRt.lib
|
导入库,用于动态链接MSVCR80.dll(默认库)
|
|
MSVCRtD.lib
|
导入库,用于动态链接MSVCR80D.dll
|
|
MSVCMRt.lib
|
导入库,.net的托管/本机代码混合
|
|
MSVCURt.lib
|
导入库,.net的MSIL代码
|
windows核心编程(第5版)读书笔记四
VC6的环境小结
tinyxml使用技巧
实在是好用呀,优点比如:
1,一次装载到内存,其它地方全用引用即可,一个小指针可以是一个元素,也可是一个节(内部很多子元素)。
2,不用管理元素的内存回收,我是没看源码,号称管理的很好。一个父元素删除,它包含的所有子都释放了。
3,api较少并且,一目了然。
遍历时基本就用三个算法:
1)同级的循环(没用遍历以防会误解包括子节点处理)
//pParent当然是父了
for (TiXmlNode *pSTATE = pParent->FirstChild( “STATE” ); pSTATE; pSTATE = pSTATE->NextSibling(“STATE” ))
{}
注意:要用TiXmlNode *结构,不要用TiXmlElement*
2)当同级的到了最后一个,NextSibling()会返回个空。这时你可以用跳了。
pParent->IterateChildren( pSTATE )
3)以上两个掌握了,就可以玩遍历了。不过,要注意,走到叶子节点时,要跳级。但如果你手工跳了,可能遍历会有重复情况。这时可以使用函数的静态变量喽。可以用静态变量记住父结点。可以用静态list来存放处理过的节点,跳过重复情况。示例代码如下:
void handleExportMap(TiXmlNode * pSrc)
{
if (!pSrc ) return;
static TiXmlNode *bodyItem;
if (“FRAME_BODY” == pSrc->ValueTStr())
{
bodyItem = pSrc ;
}
static TiXmlNode *curpItem;
int t = pSrc ->Type();
printf( “type %d \n” , t);
switch (t)
{
case TiXmlNode :: TINYXML_DOCUMENT:
printf( “Document” );
break ;
case TiXmlNode :: TINYXML_ELEMENT:
printf( “Element [%s]” , pSrc ->Value());
//
if (“CONTENT” == pSrc->ValueTStr())
{
curpItem = pSrc ;
}
if (“MAP” == pSrc->ValueTStr())
{
//跳过MAP的处理
pSrc = curpItem->IterateChildren(pSrc ->Parent());
if (!pSrc )
return ;
else
printf( “Element [%s]” , pSrc ->Value());
}
if (“STATE” == pSrc->ValueTStr() && pSrc == pSrc ->Parent()->LastChild())
{
//跳过STATE的处理
//map中的state
pSrc = curpItem->IterateChildren(pSrc ->Parent()->Parent());
if (!pSrc )
return ;
else
printf( “Element [%s]” , pSrc ->Value());
}
if (“ITEM” == pSrc->ValueTStr())
{
printf( “Element [%s]” , pSrc ->Value());
if (!pSrc ->NoChildren())
{
if (!bMoveItems(pSrc ))
return ;
}
} //end if (!pSrc->NoChildren())
if (“MESSAGE” == pSrc->ValueTStr())
{
curpItem = pSrc ;
if (!bMoveItems(pSrc ))
return ;
}
break ;
case TiXmlNode :: TINYXML_COMMENT:
printf( “Comment: [%s]” , pSrc ->Value());
break ;
case TiXmlNode :: TINYXML_UNKNOWN:
printf( “Unknown” );
break ;
case TiXmlNode :: TINYXML_TEXT:
printf( “Text: [%s]\n” , pSrc ->ToText()->Value());
break ;
case TiXmlNode :: TINYXML_DECLARATION:
printf( “Declaration” );
break ;
default :
break ;
}
if (pSrc ->NoChildren())
{
pSrc = pSrc ->NextSibling();
handleExportMap( pSrc );
}
else
{
//过滤,直到合法
while (pSrc = pSrc->FirstChild())
{
handleExportMap( pSrc );
}
}
}
在这个遍历的框架基础上,可以变化和设计出你的需求了,注意,要分化任务,只做遍历,和只做节点的处理,不要混在一起,不然,一个bug两三天呀。上面的bMoveItems就是当定位到了ITEM节点时,我调用其它的业务处理。因为,人只关注ITEM节点,所以它有一些子节点MAP或子子节点STATE,都在上面一一跳过了。
最后,附上“米”,好“下锅”,注意层次。
<?xml version=”1.0″ encoding=”UTF-8″ ?>
<!– edited with XMLSpy v2013 (http://www.altova.com) by () –>
<LINE ID=”11″ VERSION=”1″>
<FRAME_HEADER>
<ITEM ID=”system_id” LENGTH=”1″ CURPOS=”0″ />
<ITEM ID=”total_length” LENGTH=”2″ CURPOS=”1″ MAX_VALUE=”1025″ />
<ITEM ID=”multi_flag” LENGTH=”1″ CURPOS=”3″ DEFAULT=”0″ />
</FRAME_HEADER>
<FRAME_BODY>
<MESSAGE ID=”NETWORK_ALIVE_STATUS” TYPE=”1″ TRANS=”O2N”>
<ITEM ID=”message_length” LENGTH=”2″ CURPOS=”4″ DESC=”消息长度” MIN_VALUE=”13″ interal_index=”1″ />
<ITEM ID=”time” LENGTH=”4″ CURPOS=”6″ DESC=”时间” FORMAT=”HHMMSS” interal_index=”2″>
<MAP NID=”time” MODE=”1″ SAME=”Y” NINDEX=”2″ KEY=”time|6|4″ DESC=”时间” EX_CODE_KEY=”” />
</ITEM>
<ITEM ID=”version” LENGTH=”2″ CURPOS=”10″ DESC=”版本” DEFAULT=”01H” interal_index=”3″ />
<ITEM ID=”msg_id” LENGTH=”2″ CURPOS=”12″ DESC=”报文ID” interal_index=”4″ />
<CONTENT ID=”data0″ DEFAULT_LEN=”3″>
<ITEM ID=”line_id” LENGTH=”2″ CURPOS=”14″ DESC=”线路号” interal_index=”5″>
<MAP NID=”line_id” MODE=”1″ SAME=”Y” NINDEX=”5″ KEY=”line_id|14|2″ EX_CODE_KEY=”” />
</ITEM>
<ITEM ID=”status” LENGTH=”1″ CURPOS=”16″ DESC=”状态字节:1:代表与当前线路号的信息源(server)连接正常;0:代表断开。” interal_index=”6″>
<MAP NID=”xt_pkg” MODE=”1″ SAME=”N” NINDEX=”6″ KEY=”xt_pkg|16|1″ EX_CODE_KEY=””>
<STATE ID=”11_STATUS_CODE_1″ RAWVALUE=”0x00″ HINT=”通信中断” SAME=”Y”>0x80</STATE>
<STATE ID=”11_STATUS_CODE_2″ RAWVALUE=”0x01″ HINT=”通信正常” SAME=”Y”>0x02</STATE>
</MAP>
</ITEM>
</CONTENT>
</MESSAGE>
<MESSAGE ID=”LOAD_DEVICE_STATUS” TYPE=”1″ TRANS=”N2O”>
<ITEM ID=”message_length” LENGTH=”2″ CURPOS=”4″ DESC=”消息长度” MIN_VALUE=”12″ interal_index=”1″ />
<ITEM ID=”time” LENGTH=”4″ CURPOS=”6″ DESC=”时间” FORMAT=”HHMMSS” interal_index=”2″ />
<ITEM ID=”version” LENGTH=”2″ CURPOS=”10″ DESC=”版本” DEFAULT=”01H” interal_index=”3″ />
<ITEM ID=”msg_id” LENGTH=”2″ CURPOS=”12″ DESC=”报文ID” interal_index=”4″ />
<CONTENT ID=”data0″ DEFAULT_LEN=”2″>
<ITEM ID=”line_id” LENGTH=”2″ CURPOS=”14″ DESC=”线路号” interal_index=”5″ />
</CONTENT>
</MESSAGE>
</MESSAGE>
</FRAME_BODY>
</LINE>
保存和另存,一个TiXmlDocument的SaveFile()函数就搞定了。
生成新的XML时,会用一个api就成了。parent->LinkEndChild(TiXmlNode *);根据不用我解释了吧。加同级,用parent()找父指针嘛。
VS2013字符集小结
VS新版本打开旧项目,即当升级一个vcproject文件时,可能会涉及从“多字节字符集”(可能是utf-8)到unicode字符集的转换。
所以总结一下,代码端如何适应转换。
unicode字符集下,微软引入了一个宽字符集的概念(多讨厌)
所以,有些winapi就是以宽字符集来传参的。
第一类问题:messagebox()函数
所以字符串常量前,加一个L,即L“原来的字符串”;
L的意思是小端序。当为unicode时,长度要么1要么2(汉字),所以,再加上小端序,不会有歧义了。
第二类问题:strcpy()函数要求多字符集,事实此时的CSting已经入乡随俗了用了宽字符集,而直接强制转换就会出现让你头大的提示,
居然const char * 和 CString不等价了。
char SendBuf[512] = {0};
strcpy(SendBuf,strEdit); //CString参数strEdit,报错说不能转换CString到const char *
——————————–
办法一:用新的缓冲区放置,并且必须再转换一下。
char SendBuf[512] = {0};
strcpy(SendBuf,( const char *)strEdit.GetBuffer());
办法二:复杂,此时要做的是把“变质的”CString给救回来。
char SendBuf[512] = {0};
wchar_t temp[512];
MultiByteToWideChar(CP_ACP, NULL, (LPCCH)strEdit.GetBuffer(), 512, temp, 512);
strcpy(SendBuf,(const char *)temp);
m_Conn.Send(SendBuf,strlen(SendBuf));
第三类问题,atoi转int:
把atoi换成_ttoi即可,这是神器,在啥字符集下,都可编译。
第四类问题,CString->std::string 举例如下:
CString strMfc=“test“;
std::string strStl;
#ifdef _UNICODE
USES_CONVERSION
strStl=W2A(strMfc.LockBuffer());
strMfc.UnlockBuffer();
#else
strStl = strMfc.GetBuffer(0);
strMfc.ReleaseBuffer();
#endif
—————-
有时,CString可以做为桥梁,把乱码的UTF-8字符串转成string打印正确。思路是先用下面的函数转换乱码,再把返回的CString转string.
CString UTF8toUnicode(const char* utf8Str, UINT length)
{
CString unicodeStr;
unicodeStr = _T(“”);
if (!utf8Str)
return unicodeStr;
if (length == 0)
return unicodeStr;
//转换
WCHAR chr = 0;
for (UINT i = 0; i
BSTR bstrTest = ::SysAllocString(L”Test”);
_bstr_t bstr_t(bstrTest);
std::strStl = bstr_t;
SysFreeString(bstrTest );
std::string -> BSTR 举例如下
std::string name = “nisb”;
_bstr_t bstr_t(name.c_str());
BSTR ret_val = bstr_t.GetBSTR();
————————————————-
转来一篇原理编码的原理:
1:使用CString,要包含文件afx.h,比如在Win32 Console Application中Alt+F7选择Use MFC in a Static Liberary,然后再添加#include
2:WCHAR ch = L’中’;与CHAR ch = ’中’;的区别是第一种使用UNICODE编码,第二种方式一般不经常用到,比如:
WCHAR strA [ 2 ] = { L’中’ , 0 } ;//打开VC的Options菜单,选中Debug选项卡中的Display unicode strings后,可以看到strA的值。
WCHAR strB [ 2 ] = { ‘中’ , 0 } ;
CString strC ;
strC+ = ( ( char * ) strB ) [ 1 ] ;
strC+ = ( ( char * ) strB ) [ 0 ] ;//strC==”中”
3:CString的AllocSysString ( )成员函数;可以方便的把一个字符串转换成UNICODE形式。记得使用完该UNICODE字符串后要调用::SysFreeString()函数释放字符串。
4: CString::AllocSysString ( )或者::SysAllocString得到的字符串并不是普通的UNICODE字符串,它之前的四个字节会存放申请的字符串的长度:
CString strD = ”asdf”;
BSTR strD = strC.AllocSysString( ) ;
long i =* ( ( long * ) strD – 1 ) ; // i == 8;一个UNICDE字符的长度是2字节,所以strD的长度为8个字节。
4:UTF-8码转换为一般的字符串:
#include ” Windows.h ”
int main(void)
{
char str [ 256 ] = {( char )0xE4, ( char ) 0xBD, ( char ) 0xA0, ( char ) 0xE5 ,
( char)0xA5 ,(char)0xBD, (char)0x61, (char)0x62 ,(char)0x63,(char)0} ; //一段UTF-8编码
WCHAR* strA;
int i= MultiByteToWideChar ( CP_UTF8 , 0 ,(char*) str ,-1 ,NULL,0);
strA = new WCHAR[i];
MultiByteToWideChar ( CP_UTF8 , 0 ,( char * ) str, -1, strA , i );
i= WideCharToMultiByte(CP_ACP,0,strA,-1,NULL,0,NULL,NULL);
char *strB=new char[i];
WideCharToMultiByte (CP_ACP,0,strA,-1,strB,i,NULL,NULL);
//strB即为所求
delete []strA;
delete []strB;
return 0;
}
5:在转换方面_bstr_t是最最灵活的,他提供了UNICODE到一般字符串的直接转换:
#include
_bstr_t strA;
char *strB=”中国人”;
strA=strB;
WCHAR *strC=strA;
long i =* ( ( long * ) strC – 1 ) ;// i 亦是字符串的字节长度
char *strD=strA;
return 0;
宽窄字串转换!
两种方法:1、CString 2、_bstr_t
#include “comutil.h”
//注意在Project-》Setting-》Link中加入comsupp.lib,从而使_bstr_t可用
void CAaaDlg::OnButton1()
{
// TODO: Add extra cleanup here
_bstr_t a(L”sdfsafds”);
a+=”zzz”;
char * b = (char *)a;//获得内部BSTR的char*指针,勿做修改和释放
WCHAR *c=(WCHAR *)a;//获得内部BSTR的WCHARr*指针,勿做修改和释放
CString p = L”asdfsa”;
p+=”ppp”;
WCHAR *y =p.AllocSysString(); //获得WCHAR*指针,使用完请释放,否则有内存泄漏。
char *z = p.GetBuffer(p.GetLength()+1);//内部Buffer指针,z不要释放
::SysFreeString(y);
}
程序员的自我修养
四大神器,解决依赖:
ldd是用来查看执行文件或.a,.so的依赖关系利器(从链接的角度)。
nm———————查看静态符号表,观察依赖关系
-sD *.so
objdump -p t_sql.o | grep NEEDED
库命令:
file *.o—————看ELF信息
objdump -[看列表] *.o——看目标文件的结构和内容
基本信息(-h)
更多信息(-x)
依赖信息(-p)objdump -p t_sql.o | grep NEEDED
动态链接的可执行文件中包括got,有时有调用别模块时的共享对象也存在此段。
查看一个so是否PIC(地址无关性)编译的:
readelf -d .so | grep TEXTREL
如果有输出,用的是装载时重定位(虽多进程调用可以,但牺牲了效率),否则,证明编译时加了-fPIC,是地址无关。
readelf—————-看elf详细信息,包括(系统位,大小端,是否可执行)
文件头信息(-h)
详细的信息(-S)较权威的段表信息
从linker角度来查看链接器使用的dynamic段的信息(-d *.so)链接库的elf信息,同于ldd(宏观模块体现)。
-sD *.so查看动态符号表(从库提供服务或使用的角度),针对段.dynsym观察依赖关系
-l ../bin/devcomm | grep interpreter(链接器使用的段)查看生成它的链接器(可执行文件)
-r *.so查看重定向符号表
链接的秘密:
目标文件静态重定向—动态链接文件重定向——可执行动态链接文件重定向
rel.text——————rel.dyn———–针对数据引用,修正位于数据段中的got(全局变量的引用地址)
rel.data——————rel.plt————针对函数引用,修正got.plt
全局符号表
二元信号量:
信号量(多元):
互斥量:不同于二元信号量:哪线程存得,哪线程释放
相同二元信号量:都是约束线程排队的
临界区:在一点处与互斥量不同:其它进程不可见。(和内核对象名称不太相符)
条件变量:同时阻塞和唤醒多个线程