T: | 搞不懂,sizeof(struct x)不能正确返回字节数目,真Tmd怪 |
Q: | struct tagHDDFILEHEADER1 { char c1[2];// char c2[2];// char c3[2];// char c4[2];// char c5[2];// char c6[2];// char c7[2];// char c8[2];// char c9[2];// DWORD n;// char c;// }; long n=sizeof(tagHDDFILEHEADER1);//n会返回28,为什么,真Tmd怪 |
A: | 这不怪,就怪在缺省的对齐方式上 在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间;各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间 例如,下面的结构各成员空间分配情况 struct test { char x1; short x2; float x3; char x4; }; 结构的第一个成员x1,其偏移地址为0,占据了第1个字节。第二个成员x2为short类型,其起始地址必须2字节对界,因此,编译器在x2和x1之间填充了一个空字节。结构的第三个成员x3和第四个成员x4恰好落在其自然对界地址上,在它们前面不需要额外的填充字节。在test结构中,成员x3要求4字节对界,是该结构所有成员中要求的最大对界单元,因而test结构的自然对界条件为4字节,编译器在成员x4后面填充了3个空字节。整个结构所占据空间为12字节。 现在你知道怎么回事了吧? 更改C编译器的缺省分配策略 一般地,可以通过下面的两种方法改变缺省的对界条件: · 使用伪指令#pragma pack ([n]) · 在编译时使用命令行参数 #pragma pack ([n])伪指令允许你选择编译器为数据分配空间所采取的对界策略,见表2: 例如,在使用了#pragma pack (1)伪指令后,test结构各成员的空间分配情况就是按照一个字节对齐了 |
T: | 钩子函数和回调函数 |
Q: | 有谁能详细介绍一下钩子函数和回调函数吗,100分相送(一定送哦),有介绍电子书的也可以(最好附加能下载到的地址) |
A: | 一、引言 钩子的本质是一段用以处理系统消息的程序,通过系统调用,把它挂入系统。钩子的种类很多,每种钩子可以截获并处理相应的消息,每当特定的消息发出,在到达目的窗口之前,钩子程序先行截获该消息、得到对此消息的控制权。此时钩子函数可以对截获的消息进行加工处理,甚至可以强制结束消息的传递。这有点类似与MFC中的PreTranslateMessage函数,所不同的是该函数只能用于拦截本进程中的消息,而对系统消息则无能为力。 二、Win32系统钩子的实现 每种类型的钩子均由系统来维护一个钩子链,最近安装的钩子位于链的开始,拥有最高的优先级,而最先安装的钩子则处在链的末尾。要实现Win32的系统钩子,首先要调用SDK中的API函数SetWindowsHookEx来安装这个钩子函数,其原型是: HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId); 其中,第一个参数是钩子的类型,常用的有WH_MOUSE、WH_KEYBOARD、WH_GETMESSAGE等;第二个参数是钩子函数的地址,当钩子钩到任何消息后便调用这个函数;第三个参数是钩子函数所在模块的句柄;第四个参数是钩子相关函数的ID用以指定想让钩子去钩哪个线程,为0时则拦截整个系统的消息此时为全局钩子。如果指定确定的线程,即为线程专用钩子。 全局钩子函数必须包含在DLL(动态链接库)中,而线程专用钩子则可包含在可执行文件中。得到控制权的钩子函数在处理完消息后,可以调用另外一个SDK中的API函数CallNextHookEx来继续传递该消息。也可以通过直接返回TRUE来丢弃该消息,阻止该消息的传递。 使用全局钩子函数时需要以DLL为载体,VC6中有三种形式的MFC DLL可供选择,即Regular statically linked to MFC DLL(标准静态链接MFC DLL)、Regular using the shared MFC DLL(标准动态链接MFC DLL)以及Extension MFC DLL(扩展MFC DLL)。第一种DLL在编译时把使用的MFC代码链接到DLL中,执行程序时不需要其他MFC动态链接类库的支持,但体积较大;第二种DLL在运行时动态链接到MFC类库,因而体积较小,但却依赖于MFC动态链接类库的支持;这两种DLL均可被MFC程序和Win32程序使用。第三种DLL的也是动态连接,但做为MFC类库的扩展,只能被MFC程序使用。 三、Win32 DLL Win32 DLL的入口和出口函数都是DLLMain这同Win16 DLL是有区别的。只要有进程或线程载入和卸载DLL时,都会调用该函数,其原型是: BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason, LPVOID lpvReserved);其中,第一个参数表示DLL的实例句柄;第三个参数系统保留;第二个参数指明了当前调用该动态连接库的状态,它有四个可能的值:DLL_PROCESS_ATTACH(进程载入)、DLL_THREAD_ATTACH(线程载入)、DLL_THREAD_DETACH(线程卸载)、DLL_PROCESS_DETACH(进程卸载)。在DLLMain函数中可以通过对传递进来的这个参数的值进行判别,根据不同的参数值对DLL进行必要的初始化或清理工作。由于在Win32环境下,所有进程的空间都是相互独立的,这减少了应用程序间的相互影响,但大大增加了编程的难度。当进程在动态加载DLL时,系统自动把DLL地址映射到该进程的私有空间,而且也复制该DLL的全局数据的一份拷贝到该进程空间,每个进程所拥有的相同的DLL的全局数据其值却并不一定是相同的。当DLL内存被映射到进程空间中,每个进程都有自己的全局内存拷贝,加载DLL的每一个新的进程都重新初始化这一内存区域,也就是说进程不能再共享DLL。因此,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。一种方法便是把这些需要共享的数据单独分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享,建立一个内存共享的DLL。 四、全局共享数据的实现 可以用#pragma data_seg建立一个新的数据段并定义共享数据,其具体格式为: #pragma data_seg ("shareddata") HWND sharedwnd=NULL;//共享数据 #pragma data_seg() 所有在data_seg pragmas语句之间声明的变量都将在shareddata段中。仅定义一个数据段还不能达到共享数据的目的,还要告诉编译器该段的属性,有两种方法可以实现该目的(其效果是相同的),一种方法是在.DEF文件中加入如下语句: SETCTIONS shareddata READ WRITE SHARED 另一种方法是在项目设置链接选项中加入如下语句: /SECTION:shareddata,rws 五、鼠标钩子程序示例 本示例程序用到全局钩子函数,程序分两部分:可执行程序MouseDemo和动态连接库MouseHook。首先编制MFC扩展动态连接库MouseHook.dll: (一)选择MFC AppWizard(DLL)创建项目Mousehook; (二)选择MFC Extension DLL(MFC扩展DLL)类型; (三)通过Project菜单的AddToProject子菜单的"New…"添加头文件MouseHook.h。 (四)在头文件中建立钩子类: class AFX_EXT_CLASS CMouseHook:public CObject { public: CMouseHook(); //钩子类的构造函数 ~CMouseHook(); //钩子类的析构函数 BOOL StartHook(HWND hWnd); //安装钩子函数 BOOL StopHook(); //卸载钩子函数 }; (五)在MouseHook.cpp文件中加入#include"MouseHook.h"语句; (六)加入全局共享数据变量: #pragma data_seg("mydata") HWND glhPrevTarWnd=NULL; //上次鼠标所指的窗口句柄 HWND glhDisplayWnd=NULL; //显示目标窗口标题编辑框的句柄 HHOOK glhHook=NULL; //安装的鼠标勾子句柄 HINSTANCE glhInstance=NULL; //DLL实例句柄 #pragma data_seg() (七)在DEF文件中定义段属性: SECTIONS mydata READ WRITE SHARED (八)在主文件MouseHook.cpp的DllMain函数中加入保存DLL实例句柄的语句: extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { UNREFERENCED_PARAMETER(lpReserved); if (dwReason == DLL_PROCESS_ATTACH) { if (!AfxInitExtensionModule(MouseHookDLL, hInstance)) return 0; new CDynLinkLibrary(MouseHookDLL); glhInstance=hInstance; //插入保存DLL实例句柄 } else if (dwReason == DLL_PROCESS_DETACH) { AfxTermExtensionModule(MouseHookDLL); } return 1; // ok } 一、引言 钩子的本质是一段用以处理系统消息的程序,通过系统调用,把它挂入系统。钩子的种类很多,每种钩子可以截获并处理相应的消息,每当特定的消息发出,在到达目的窗口之前,钩子程序先行截获该消息、得到对此消息的控制权。此时钩子函数可以对截获的消息进行加工处理,甚至可以强制结束消息的传递。这有点类似与MFC中的PreTranslateMessage函数,所不同的是该函数只能用于拦截本进程中的消息,而对系统消息则无能为力。 二、Win32系统钩子的实现 每种类型的钩子均由系统来维护一个钩子链,最近安装的钩子位于链的开始,拥有最高的优先级,而最先安装的钩子则处在链的末尾。要实现Win32的系统钩子,首先要调用SDK中的API函数SetWindowsHookEx来安装这个钩子函数,其原型是: HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId); 其中,第一个参数是钩子的类型,常用的有WH_MOUSE、WH_KEYBOARD、WH_GETMESSAGE等;第二个参数是钩子函数的地址,当钩子钩到任何消息后便调用这个函数;第三个参数是钩子函数所在模块的句柄;第四个参数是钩子相关函数的ID用以指定想让钩子去钩哪个线程,为0时则拦截整个系统的消息此时为全局钩子。如果指定确定的线程,即为线程专用钩子。 全局钩子函数必须包含在DLL(动态链接库)中,而线程专用钩子则可包含在可执行文件中。得到控制权的钩子函数在处理完消息后,可以调用另外一个SDK中的API函数CallNextHookEx来继续传递该消息。也可以通过直接返回TRUE来丢弃该消息,阻止该消息的传递。 使用全局钩子函数时需要以DLL为载体,VC6中有三种形式的MFC DLL可供选择,即Regular statically linked to MFC DLL(标准静态链接MFC DLL)、Regular using the shared MFC DLL(标准动态链接MFC DLL)以及Extension MFC DLL(扩展MFC DLL)。第一种DLL在编译时把使用的MFC代码链接到DLL中,执行程序时不需要其他MFC动态链接类库的支持,但体积较大;第二种DLL在运行时动态链接到MFC类库,因而体积较小,但却依赖于MFC动态链接类库的支持;这两种DLL均可被MFC程序和Win32程序使用。第三种DLL的也是动态连接,但做为MFC类库的扩展,只能被MFC程序使用。 三、Win32 DLL Win32 DLL的入口和出口函数都是DLLMain这同Win16 DLL是有区别的。只要有进程或线程载入和卸载DLL时,都会调用该函数,其原型是: BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason, LPVOID lpvReserved);其中,第一个参数表示DLL的实例句柄;第三个参数系统保留;第二个参数指明了当前调用该动态连接库的状态,它有四个可能的值:DLL_PROCESS_ATTACH(进程载入)、DLL_THREAD_ATTACH(线程载入)、DLL_THREAD_DETACH(线程卸载)、DLL_PROCESS_DETACH(进程卸载)。在DLLMain函数中可以通过对传递进来的这个参数的值进行判别,根据不同的参数值对DLL进行必要的初始化或清理工作。由于在Win32环境下,所有进程的空间都是相互独立的,这减少了应用程序间的相互影响,但大大增加了编程的难度。当进程在动态加载DLL时,系统自动把DLL地址映射到该进程的私有空间,而且也复制该DLL的全局数据的一份拷贝到该进程空间,每个进程所拥有的相同的DLL的全局数据其值却并不一定是相同的。当DLL内存被映射到进程空间中,每个进程都有自己的全局内存拷贝,加载DLL的每一个新的进程都重新初始化这一内存区域,也就是说进程不能再共享DLL。因此,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。一种方法便是把这些需要共享的数据单独分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享,建立一个内存共享的DLL。 四、全局共享数据的实现 可以用#pragma data_seg建立一个新的数据段并定义共享数据,其具体格式为: #pragma data_seg ("shareddata") HWND sharedwnd=NULL;//共享数据 #pragma data_seg() 所有在data_seg pragmas语句之间声明的变量都将在shareddata段中。仅定义一个数据段还不能达到共享数据的目的,还要告诉编译器该段的属性,有两种方法可以实现该目的(其效果是相同的),一种方法是在.DEF文件中加入如下语句: SETCTIONS shareddata READ WRITE SHARED 另一种方法是在项目设置链接选项中加入如下语句: /SECTION:shareddata,rws 五、鼠标钩子程序示例 本示例程序用到全局钩子函数,程序分两部分:可执行程序MouseDemo和动态连接库MouseHook。首先编制MFC扩展动态连接库MouseHook.dll: (一)选择MFC AppWizard(DLL)创建项目Mousehook; (二)选择MFC Extension DLL(MFC扩展DLL)类型; (三)通过Project菜单的AddToProject子菜单的"New…"添加头文件MouseHook.h。 (四)在头文件中建立钩子类: class AFX_EXT_CLASS CMouseHook:public CObject { public: CMouseHook(); //钩子类的构造函数 ~CMouseHook(); //钩子类的析构函数 BOOL StartHook(HWND hWnd); //安装钩子函数 BOOL StopHook(); //卸载钩子函数 }; (五)在MouseHook.cpp文件中加入#include"MouseHook.h"语句; (六)加入全局共享数据变量: #pragma data_seg("mydata") HWND glhPrevTarWnd=NULL; //上次鼠标所指的窗口句柄 HWND glhDisplayWnd=NULL; //显示目标窗口标题编辑框的句柄 HHOOK glhHook=NULL; //安装的鼠标勾子句柄 HINSTANCE glhInstance=NULL; //DLL实例句柄 #pragma data_seg() (七)在DEF文件中定义段属性: SECTIONS mydata READ WRITE SHARED (八)在主文件MouseHook.cpp的DllMain函数中加入保存DLL实例句柄的语句: extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { UNREFERENCED_PARAMETER(lpReserved); if (dwReason == DLL_PROCESS_ATTACH) { if (!AfxInitExtensionModule(MouseHookDLL, hInstance)) return 0; new CDynLinkLibrary(MouseHookDLL); glhInstance=hInstance; //插入保存DLL实例句柄 } else if (dwReason == DLL_PROCESS_DETACH) { AfxTermExtensionModule(MouseHookDLL); } return 1; // ok } |
T: | 计算公式 |
Q: | 我要做一个计算公式的DLL给别人使用,处理+,—,*,/,(),取余,最好给出代码 |
A: | // Expression.cpp: implementation of the CExpression class. // // #include "stdafx.h" #include "Expression.h" #include "math.h" const int funTableLen = 17; //函数表长度 double sign(double x); static double ( * funTable[ ] )( double ) = { acos, asin, atan, ceil, cos, cosh, exp, fabs, floor, log, log10, sin, sinh, sqrt, tan, tanh, sign }; //单参数函数入口地址表 static char funNameTable[ ][6] = { "acos", "asin", "atan", "ceil", "cos", "cosh", "exp", "fabs", "floor", "log", "log10", "sin", "sinh", "sqrt", "tan", "tanh", "sign" }; //函数名表 // // CVar Class // // // Construction/Destruction // CVar::CVar() { InitVar(); } CVar::~CVar() { } void CVar::InitVar() { m_cFlag=1; m_strName=""; m_strSlave=""; m_dValue=0; } // // CVarList Class // // // Construction/Destruction // CVarList::CVarList() { } CVarList::~CVarList() { list<CVar*>::iterator iter; for(iter=m_VarList.begin();iter!=m_VarList.end();iter++) { delete (*iter); } m_VarList.clear(); } bool CVarList::AddVar(CVar *pVar) { m_VarList.insert(m_VarList.end(),pVar); return true; } // // Construction/Destruction // CExpression::CExpression() { m_iErrFlag=0; m_iFunFlag=0; m_iMatchFlag=0; m_dResult = 0; m_bDegUnit=true; m_strExp=NULL; strcpy(m_strToken,""); } CExpression::~CExpression() { } bool CExpression::CalExp() { bool ret; m_iErrFlag=0; m_iFunFlag=0; m_iMatchFlag=0; m_dResult = 0; if( strlen(m_strExp)==0) { m_iErrFlag = 1; Error(); return false; } UpdateSlaveVar(); //取表达式第一单元(利用m_strExp) if(GetToken() == true) { //进入高优先级运算 ret = Level1(&m_dResult); //若高级运算出现错误(m_iErrFlag被设置) if(ret == false) { //打印错误信息 Error(); return false; } else return true; } //从表达式中取符号错误 m_iErrFlag = 2; Error(); return false; } void CExpression::Error() { switch(m_iErrFlag) { case 1: Message( "表达式为空!" ); break; case 2: Message( "变量或函数非法或语法错误!/n表达式无法计算!" ); break; case 3: Message("括号不匹配!"); //"括号不匹配!" break; } } void CExpression::Message(const char *strMsg) { // printf("/n%s/n",strMsg); } bool CExpression::GetToken() { register char *temp; m_cTokenType = 0; //指针指向token的首地址 temp = m_strToken; //跳过空格及TAB符 while(IsWhite(*m_strExp) == true) m_strExp++; //首字符是为运算符 if(IsInStr(*m_strExp,"+-*/%^=(),") == true) { m_cTokenType = DELIMITER; *temp++ = *m_strExp++; *temp = 0; return true; } //首字符为ASSCI字符或汉字 else if( isalpha(*m_strExp) || (*m_strExp > 127) || (*m_strExp < 0) ) { //找到字符串结尾 while(IsDelim(*m_strExp) != true) *temp ++ = *m_strExp++; *temp = 0; //判断取得的符号是否为函数,孙永忠修改 if(IsFunc( m_strToken ) ) { m_cTokenType = FUNCTION; return true; } //搜索变量表,判断取得的符号是否为变量 string sToken = m_strToken; list<CVar*>::iterator iter; for(iter=m_VarList.m_VarList.begin();iter!=m_VarList.m_VarList.end();iter++) { if((*iter)->m_strName == sToken ) { m_cTokenType = VARIABLE; return true; } } return false; } //首字符为数字 else if(isdigit(*m_strExp) || *m_strExp == '.') { //.5按0.5处理 if(*m_strExp == '.') *temp++ = '0'; while(IsDelim(*m_strExp) != true) *temp ++ = *m_strExp++; *temp = 0; m_cTokenType = NUMBER; return true; } //首字符为NULL if(*m_strExp == 0) { strcpy(m_strToken,""); //到达结尾 return true; } return false; } //判断是否为空格或TAB bool CExpression::IsWhite(char c) { if(c == ' ' || c == 9) return true; return false; } //判断是否为分隔符 bool CExpression::IsDelim(char c) { if(IsInStr(c,"+-*/%^=() ,") == true || c == 9 || c == '/r' || c == 0) return true; return false; } //判断是否为函数 bool CExpression::IsFunc(const char *fname) { int i; for(i=0;i<funTableLen;i++) { if(strcmp(fname,funNameTable[i]) == 0) return true; } return false; } //判断C是否在串S中 bool CExpression::IsInStr(char ch,char *s) { while(*s) { if(*s++ == ch) return true; } return false; } double sign(double x) { if(x > 0) return x; else return 0; } //赋值运算 bool CExpression::Level1(double *result) { int index,ttok_type; char temp_token[80]; //变量单元,有可能是赋值的表达式运算 if(m_cTokenType == VARIABLE) { //保留该单元及单元类型 strcpy(temp_token,m_strToken); ttok_type = m_cTokenType; //若取不到变量在变量表中的索引值 if(GetVarIndex(m_strToken,&index) != true) { m_iErrFlag = 2; return false; } if(GetToken() != true) { m_iErrFlag = 2; //m_iErrFlag = 1; return false; } //若变量后紧跟'='号,则为赋值运算,否则为一般运算 if(*m_strToken != '=') { //将刚取得的单元回送到表达式中 PutBack(); //恢复当前单元变量及变量类型 strcpy(m_strToken,temp_token); m_cTokenType = ttok_type; } //若为赋值运算进入下面运算 else { //取'='号后面的单元 if(GetToken() != true) { m_iErrFlag = 2; //m_iErrFlag = 1; return false; } //进入高级的+-运算 if(Level2(result) == true) { list<CVar*>::iterator iter; int i=0; for(iter=m_VarList.m_VarList.begin();iter!=m_VarList.m_VarList.end();iter++) { if(i==index) { (*iter)->m_dValue=*result; return true; } i++; } } else return false; } } //第一单元不是变量,直接进入高优先级+-运算 if(Level2(result) == true) return true; else return false; } //加减运算 bool CExpression::Level2(double *result) { register char op; //运算符 double hold=0; //保留运算中间结果 //直接进入高优先级的*/%运算,没有高级运算才进入下面运算 if(Level3(result) != true) return false; //若下一单元为+-号 while((op = *m_strToken) == '+' || op == '-') { //取得+-号后的单元 if(GetToken() == true) { //运算+-号后面的表达式值,有可能又取得+-号 if(Level3(&hold) == true) { //数学运算,结果直接放在*result中 bool bRet = Arith(op,result,&hold); if( bRet == false ) return false; } else return false; } else { m_iErrFlag = 2; //m_iErrFlag = 1; return false; } } return true; } //乘除及求余数运算 bool CExpression::Level3(double *result) { register char op; //运算符 double hold=0; //保留中间运算结果 //直接进入高优先级运算,没有高级运算才进入下面运算 if(Level4(result) != true) return false; //若下一单元为*/% while((op=*m_strToken) == '*' || op == '/' || op == '%') { //取得运算符后的单元 if(GetToken() == true) { //运算*/%后的表达式值,有可能又获得*/% if(Level4(&hold) == true) { //数学运算,结果放在*result中 bool nRet = Arith(op,result,&hold); if( nRet == false ) return false; } else return false; } else { m_iErrFlag = 2; //m_iErrFlag = 1; return false; } } return true; } //乘方运算 bool CExpression::Level4(double *result) { register char op; //运算符 double hold=0; //保留中间运算结果 //直接进入高优先级运算,没有高级运算才进入下面运算 if(Level5(result) != true) return false; //若下一单元为^(乘方) while((op=*m_strToken) == '^') { if(GetToken() == true) { //取得运算符后的单元 if(Level5(&hold) == true) { //运算^后的表达式值,有可能又获得^ bool nRet = Arith(op,result,&hold); if( nRet == false ) return false; } else return false; } else { m_iErrFlag = 2; //m_iErrFlag = 1; return false; } } return true; } //单目求反运算 bool CExpression::Level5(double *result) { register char op = 0; if((m_cTokenType == DELIMITER) && *m_strToken == '+' || *m_strToken == '-' ) { //若表达式第一单元为+号或-号,记录该运算符 op = *m_strToken; //取得下一单元 if(GetToken() != true) { m_iErrFlag = 2; //m_iErrFlag = 1; return false; } } //进入高优先级运算 if(Level6(result) != true) return false; //进入高优先级运算 if(op) Unary(op,result); return true; } //函数处理 bool CExpression::Level6(double *result) { int num; char funcname[8]; char op = 0; int paranum=1; double para[6]; if( IsFunc( m_strToken ) ) // 如果是函数名 //if(expGetFunIndex(m_strToken,&num) == true) { op = 1; strcpy( funcname, m_strToken ); //取得下一单元 if(GetToken() != true) { m_iErrFlag = 2; //m_iErrFlag = 1; return false; } } if(op) { if((*m_strToken == '(') && (m_cTokenType == DELIMITER)) { //取得括号内第一单元 if(GetToken() == true) { //递归调用,完成括号内的表达式运算 if(Level2(result) != true) return false; while(m_cTokenType == DELIMITER && *m_strToken == ',') { paranum++; if(GetToken() != true) { m_iErrFlag = 2; //m_iErrFlag = 1; return false; } //递归调用,完成括号内的表达式运算 if(Level2(¶[paranum-1]) != true) return false; } para[0] = *result; //当前符号应为')' if(*m_strToken != ')') { //括号不匹配 m_iErrFlag = 3; return false; } if(GetToken() != true) { m_iErrFlag = 2; //m_iErrFlag = 1; return false; } } else { m_iErrFlag = 2; //m_iErrFlag = 1; return false; } } else { //括号不匹配 m_iErrFlag = 3; return false; } //单参数 if(paranum == 1) { *result = para[0]; //若函数为三角函数,进行角度到弧度的转换 if(stricmp(funcname,"sin") == 0 || stricmp(funcname,"cos") == 0 || stricmp(funcname,"tan") == 0 ) { if( stricmp( funcname, "tan" ) == 0 ) { if( fabs( *result - 90.0 ) < 0.0005 || fabs( *result - 270.0 ) < 0.0005 || fabs( *result + 90.0 ) < 0.0005 || fabs( *result + 270.0 ) < 0.0005 ) { Message( "正切函数值溢出!" );// return false; } } if( m_bDegUnit == true ) *result = *result /180 * PI; } else if( stricmp(funcname,"asin") == 0 || stricmp(funcname,"acos") == 0 ) { if( fabs( *result ) > 1.0 ) { // Message( "反正弦函数和反余弦函数的参数绝对值必须小于1!" ); return false; } } else if( stricmp( funcname, "sqrt" ) == 0 ) { if( *result < 0.0 ) { Message( "不能对负数开平方!" );// return false; } } else if( stricmp( funcname, "log" ) == 0 || stricmp( funcname, "log10" ) == 0 ) { if( *result <= 0.0 ) { Message( "负数和零没有对数!" );// return false; } } if( GetFunIndex( funcname, &num ) ) *result = ( *funTable[num])(*result); else { m_iErrFlag = 2; return false; } } else return false; if(paranum == 1) { //若为反三角函数,将弧度转化为度 if(stricmp(funcname,"asin") == 0 || stricmp(funcname,"acos") == 0 || stricmp(funcname,"atan") == 0 ) { if( m_bDegUnit == true ) *result = *result *180 / PI; } return true; } } if(Level7(result) != true) return false; return true; } //括号及函数处理 bool CExpression::Level7(double *result) { //若取得的单元为括号 if((*m_strToken == '(') && (m_cTokenType == DELIMITER)) { //跳过括号,取得括号内第一单元 if(GetToken() == true) { //递归调用,完成括号内的表达式运算 if(Level2(result) != true) return false; //当前符号应为')',否则出错 if(*m_strToken != ')') { m_iErrFlag = 3; return false; } //跳过符号')' if(GetToken() != true) { m_iErrFlag = 3; return false; } } else { m_iErrFlag = 2; //m_iErrFlag = 1; return false; } } //否则必为变量或常数 else { //取得变量数值或常数 if(Primitive(result) != true) { m_iErrFlag = 2; return false; } else return true; } return true; } bool CExpression::GetFunIndex(const char *name,int *index) { int i; for(i=0 ;i< funTableLen ;i++) { if(strcmp(funNameTable[i],name) == 0) { *index = i; return true; } } return false; } //回读表达式一token,在level1中调用. void CExpression::PutBack() { char *t; //将token回送到表达式 t = m_strToken; for( ; *t; t ++ ) m_strExp--; } //取反 void CExpression::Unary(char o,double *r) { if(o == '-') *r = -(*r); } bool CExpression::Arith(char o, double *r, double *h) { int t; double ex; switch(o) { case '-': *r=*r - *h; break; case '+': *r=*r + *h; break; case '*': *r=*r * *h; break; case '/': if(fabs(*h)<0.00000001) { Message("除数为零!" ); // return false; } *r=(*r) / (*h); break; case '%': t=(int)( (*r) / (*h) ); *r=*r- t*(*h); break; case '^': // 原有处理如果指数为小数则结果误差很大 ex=*r; if( fabs( *h ) < 1e-9 ) { *r=1.0; break; } // 以下修改:孙永忠 97/10/16 if( fabs( *h - floor( *h ) ) < 0.01 || fabs( *h - ceil( *h ) ) < 0.01 ) { for( t = (int)(*h) - 1; t > 0; t -- ) *r = (*r) * ex; } else *r = pow( *r, *h ); break; } return true; } //取变量或常数值 bool CExpression::Primitive(double *result) { if(strcmp(m_strToken,"") == 0) return true; //常数 if(m_cTokenType == NUMBER) { //串转化为实数 *result = atof(m_strToken); //取得下一单元 if(GetToken() != true) return false; return true; } //变量 else if(m_cTokenType == VARIABLE) { if(GetVarValue(m_strToken,result) != true) return false; //取得下一单元 if(GetToken() != true) return false; return true; } return false; } bool CExpression::GetVarValue( const char * n, double * result ) { list<CVar*>::iterator iter; for(iter=m_VarList.m_VarList.begin();iter!=m_VarList.m_VarList.end();iter++) { if((*iter)->m_strName==n) { *result=(*iter)->m_dValue; return true; } } return false; } //取得变量在变量表中的索引值 bool CExpression::GetVarIndex( const char * name, int * index ) { int i=0; list<CVar*>::iterator iter; for(iter=m_VarList.m_VarList.begin();iter!=m_VarList.m_VarList.end();iter++) { if((*iter)->m_strName==name) { *index=i; return true; } i++; } return false; } bool CExpression::UpdateSlaveVar() { bool bRet = true; list<CVar*>::iterator iter; for(iter=m_VarList.m_VarList.begin();iter!=m_VarList.m_VarList.end();iter++) { if((*iter)->m_strSlave!="") { double dResult=m_dResult; char* strExp=m_strExp; string str=(*iter)->m_strSlave; m_strExp=(char*)str.c_str(); (*iter)->m_strSlave=""; bRet=CalExp(); if(bRet==false) { string prompt=(*iter)->m_strName; prompt+="定义错误!"; Message(prompt.c_str()); return false; }else { (*iter)->m_dValue=m_dResult; } m_dResult=dResult; m_strExp=strExp; } } return true; } // Expression.h: interface for the CExpression class. // // #if !defined(AFX_EXPRESSION_H__2578E33F_FF86_4384_A7CE_A401BAC5A010__INCLUDED_) #define AFX_EXPRESSION_H__2578E33F_FF86_4384_A7CE_A401BAC5A010__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include <list> #include <string> using namespace std; #define DELIMITER 1 //分隔符 #define VARIABLE 2 //变量 #define NUMBER 3 //数值 #define FUNCTION 4 //函数 #define PI 3.1415926535898 class CVar //用来存放变量及变量值的表结构 { public: char m_cFlag; // 等于0为临时变量,否则等于1 string m_strName; //变量名 如变量a string m_strSlave; //约束表达式,如a=b+2 double m_dValue; //变量值 如10,表a=10 public: CVar(); virtual ~CVar(); void InitVar(); }; class CVarList { public: list<CVar*> m_VarList; CVarList(); virtual ~CVarList(); bool AddVar(CVar* pVar); }; class CExpression { public: double m_dResult; char* m_strExp; CVarList m_VarList; bool m_bDegUnit; // 缺省采用角度单位 protected: int m_iErrFlag; //标记表达式计算是否出错0:正常,1:表达式空2:非法变量或函数3:括号不匹配 int m_iFunFlag; //标记当前正在进行函数参数计算. int m_iMatchFlag; //标记括号是否匹配 char m_cTokenType; //标记符号的类型,如分格符,变量等 char m_strToken[80]; public: void Message(const char * strMsg); CExpression(); virtual ~CExpression(); bool CalExp(); bool UpdateSlaveVar(); protected: bool GetToken(); void Error(); bool IsDelim(char c); bool IsFunc(const char *fname); bool IsWhite(char c); bool IsInStr(char ch,char *s); bool Level1(double *result); bool Level2(double *result); bool Level3(double *result); bool Level4(double *result); bool Level5(double *result); bool Level6(double *result); bool Level7(double *result); bool GetFunIndex(const char *name,int *index); void PutBack(); void Unary(char o,double *r); bool Arith(char o, double *r, double *h); bool Primitive(double *result); bool GetVarValue( const char * n, double * result ); bool GetVarIndex( const char * name, int * index ); }; #endif // !defined(AFX_EXPRESSION_H__2578E33F_FF86_4384_A7CE_A401BAC5A010__INCLUDED_) |
T: | 如何用sendmessage和postmessage来对获取句柄的控件发送控件的函数 |
Q: | 比如 我获取到一个对话框的句柄,但是内部有个public的test()函数 此时如何用sendmessage或postmessage进行操作 |
A: | 要通过自定义消息来实现,搜索到以下两篇文章,你看一下 : mafangsan(mafangsan) ( ) 信誉:100 2003-7-8 10:41:29 得分:20 定义消息 向CmainFrame的头文件中添加消息的定义语句。 #define WM_SHELLMESSAGE WM_USER+100 添加消息处理函数 在CMainFrame的头文件的AFX_MSG块中添加消息处理函数声明: afx_msg void OnWmShellMessage(WPARAM wParam,LPARAM lParam); 消息映射 在CMainFrame类的CPP文件中用ON_MESSAGE宏指令将消息WM_MYSHELLMESSAGE映射到消息处理函数OnWmShellMessage。 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_MESSAGE(WM_SHELLMESSAGE,OnWmShellMessage) //}}AFX_MSG_MAP END_MESSAGE_MAP() : dzqsuper(丁轲) ( ) 信誉:100 2003-7-8 11:49:56 得分:10 内部进程间通讯和数据交换有多种方式:消息、共享内存、匿名(命名)管道、邮槽、Windows套接字等多种技术。其中利用消息机制实现IPC虽然同其他方法相比有交换的数据量小、携带的信息少等缺点,但由于其实现方便、应用灵活而广泛应用于无须大量、频繁数据交换的内部进程通讯系统之中,尤其是对于在上层主控软件与底层工作软件之间的命令与响应上更能充分显示其良好的性能。本文就通过编制一个主控软件和一个受其操作的底层工作软件来阐述如何用VC++6.0通过消息来实现内部进程通信。 一、Windows消息机制 Windows是一种面向对象的体系结构,Windows环境和应用程序都是通过消息来交互的。Windows应用程序开始执行后,Windows为该程序创建一个"消息队列(message queue)",用以存放邮寄给该程序可能创建的各种不同窗口的消息。消息队列中消息的结构(MSG)为: typedef struct tagMSG{ HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; }MSG; 其中第一个成员变量是用以标识接收消息的窗口的窗口句柄;第二个参数便是消息标识号,如WM_PAINT;第三个和第四个参数的具体意义同message值有关,均为消息参数。前四个参数是非常重要和经常用到的,至于后两个参数则分别表示邮寄消息的时间和光标位置(屏幕坐标)。把消息传送到应用程序有两种方法:一种是由系统将消息"邮寄(post)"到应用程序的"消息队列"这是"进队消息"Win32 API有对应的函数: PostMessage(),此函数不等待该消息处理完就返回;而另一种则是由系统在直接调用窗口函数时将消息"发送(send)"给应用程序的窗口函数,属于"不进队消息"对应的函数是SendMessage()其必须等待该消息处理完后方可返回。 二、主控程序的实现 (1)新建一工程文件:Sender,选取MFC AppWizard(exe)。 (2)第二步选取Single document(单文档)。 (3)其余几步均为确省值。 (4)添加三个菜单"命令一"、"命令二"、"命令三"及与之对应的函数: OnSendComm1() { CString str="Receiver"; CWnd *pWnd=CWnd::FindWindow(NULL,str); if(pWnd) pWnd->SendMessage(WM_COMM,0,0); } OnSendComm2() { CString str="Receiver"; CWnd *pWnd=CWnd::FindWindow(NULL,str); if(pWnd) pWnd->SendMessage(WM_COMM,0,1); } OnSendComm3() { CString str="Receiver"; CWnd *pWnd=CWnd::FindWindow(NULL,str); if(pWnd) pWnd->SendMessage(WM_COMM,1,0); } (5)在SenderView.h中添加自定义消息:#define WM_COMM WM_USER+100编译完成即可。 三、底层工作程序的实现 (1)新建工程Receiver、仍是单文档。 (2)在CReceiverApp类的InitInstance()函数末尾添加: m_pMainWnd->SetWindowText("Receiver"); 用以指定底层工作程序的窗口标题,以便主控程序能根据标题获取到此窗口的窗口句柄。 (3)在MainFrm.h中添加自定义消息:#define WM_COMM WM_USER+100。 (4)添加自定义消息WM_COMM的消息映射: BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) // NOTE - the ClassWizard will add and remove mapping macros here. // DO NOT EDIT what you see in these blocks of generated code ! ON_WM_CREATE() //}}AFX_MSG_MAP ON_MESSAGE(WM_COMM,OnSendMsg) END_MESSAGE_MAP() (5)完成消息响应函数OnSendMsg() void CMainFrame::OnSendMsg(WPARAM wParam, LPARAM lParam) { if(wParam==0 && lParam==0) AfxMessageBox("主控程序发送命令一!"); if(wParam==0 && lParam==1) AfxMessageBox("主控程序发送命令二!"); if(wParam==1 && lParam==0) AfxMessageBox("主控程序发送命令三!"); } 我们便可以通过辨别消息的两个消息参数来区分主控程序发送的是哪一个命令从而可以执行相应的操作。执行主控程序和底层工作程序由于本程序采用的是SendMessage()所以当主控程序发送消息给底层工作程序时,底层工作程序弹出响应的模式对话框,在没有关闭对话框前此消息未处理完,SendMessage()也就没有执行完,所以主控程序呈阻塞状态,如改用PoseMessage()则不会发生阻塞,具体选用哪个函数还应根据实际要求灵活掌握。 结论: 通过上面的实例可以看出利用消息进行进程间通信不失为一种便捷的方法,进程间的数据交换量不大却能完成相当的功能,上下层次有着明显的接口,上层和底层只通过这个接口进行通讯,因此只要对上下层程序制定好规范详尽的协议便可编制出协调性很好的软件控制系统。 |
T: | 求数据压缩算法 |
Q: | 要求是对数据(内存中的)进行压缩,而不是对文件进行压缩。 最好是源代码,也可以是lib |
A: | #include "compress.h" static unsigned _do_compress (byte *in, unsigned in_len, byte *out, unsigned *out_len) { static long wrkmem [16384L]; register byte *ip; byte *op; byte *in_end = in + in_len; byte *ip_end = in + in_len - 13; byte *ii; byte **dict = (byte **)wrkmem; op = out; ip = in; ii = ip; ip += 4; for(;;) { register byte *m_pos; unsigned m_off; unsigned m_len; unsigned dindex; dindex = ((0x21*(((((((unsigned)(ip[3])<<6)^ip[2])<<5)^ip[1])<<5)^ip[0]))>>5) & 0x3fff; m_pos = dict [dindex]; if(((unsigned)m_pos < (unsigned)in) || (m_off = (unsigned)((unsigned)ip-(unsigned)m_pos) ) <= 0 || m_off > 0xbfff) goto literal; if(m_off <= 0x0800 || m_pos[3] == ip[3]) goto try_match; dindex = (dindex & 0x7ff ) ^ 0x201f; m_pos = dict[dindex]; if((unsigned)(m_pos) < (unsigned)(in) || (m_off = (unsigned)( (int)((unsigned)ip-(unsigned)m_pos))) <= 0 || m_off > 0xbfff) goto literal; if (m_off <= 0x0800 || m_pos[3] == ip[3]) goto try_match; goto literal; try_match: if(*(unsigned short*)m_pos == *(unsigned short*)ip && m_pos[2]==ip[2]) goto match; literal: dict[dindex] = ip; ++ip; if (ip >= ip_end) break; continue; match: dict[dindex] = ip; if(ip - ii > 0) { register unsigned t = ip - ii; if (t <= 3) op[-2] |= (byte)t; else if(t <= 18) *op++ = (byte)(t - 3); else { register unsigned tt = t - 18; *op++ = 0; while(tt > 255) { tt -= 255; *op++ = 0; } *op++ = (byte)tt; } do *op++ = *ii++; while (--t > 0); } ip += 3; if(m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ || m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++ ) { --ip; m_len = ip - ii; if(m_off <= 0x0800 ) { --m_off; *op++ = (byte)(((m_len - 1) << 5) | ((m_off & 7) << 2)); *op++ = (byte)(m_off >> 3); } else if (m_off <= 0x4000 ) { -- m_off; *op++ = (byte)(32 | (m_len - 2)); goto m3_m4_offset; } else { m_off -= 0x4000; *op++ = (byte)(16 | ((m_off & 0x4000) >> 11) | (m_len - 2)); goto m3_m4_offset; } } else { { byte *end = in_end; byte *m = m_pos + 9; while (ip < end && *m == *ip) m++, ip++; m_len = (ip - ii); } if(m_off <= 0x4000) { --m_off; if (m_len <= 33) *op++ = (byte)(32 | (m_len - 2)); else { m_len -= 33; *op++=32; goto m3_m4_len; } } else { m_off -= 0x4000; if(m_len <= 9) *op++ = (byte)(16|((m_off & 0x4000) >> 11) | (m_len - 2)); else { m_len -= 9; *op++ = (byte)(16 | ((m_off & 0x4000) >> 11)); m3_m4_len: while (m_len > 255) { m_len -= 255; *op++ = 0; } *op++ = (byte)m_len; } } m3_m4_offset: *op++ = (byte)((m_off & 63) << 2); *op++ = (byte)(m_off >> 6); } ii = ip; if (ip >= ip_end) break; } *out_len = op - out; return (unsigned) (in_end - ii); } int _stdcall compress(void *in, unsigned in_len ,void *out) { byte *op = (unsigned char *)out; unsigned t , out_len; if (in_len <= 13) t = in_len; else { t = _do_compress ( (unsigned char *)in , in_len , op , &out_len ) ; op += out_len; } if (t > 0) { byte *ii = (byte*)in + in_len - t; if (op == (byte*)out && t <= 238) *op++ = (byte) ( 17 + t ); else if (t <= 3) op[-2] |= (byte)t ; else if (t <= 18) *op++ = (byte)(t-3); else { unsigned tt = t - 18; *op++ = 0; while (tt > 255) { tt -= 255; *op++ = 0; } *op++ = (byte)tt; } do *op++ = *ii++; while (--t > 0); } *op++ = 17; *op++ = 0; *op++ = 0; return (op - (byte*)out); } int _stdcall decompress ( void *in , unsigned in_len ,void *out) { register byte *op; register byte *ip; register unsigned t ; register byte *m_pos ; byte *ip_end = (byte*)in + in_len ; op = (unsigned char *)out ; ip = (unsigned char *)in ; if( *ip > 17 ) { t = *ip++ - 17; if (t < 4) { goto match_next; } do { *op++ = *ip++ ; }while (--t > 0) ; goto first_literal_run; } for(;;) { t = *ip++; if (t >= 16) goto match; if (t == 0) { while (*ip == 0) { t += 255; ip++; } t += 15 + *ip++; } *(unsigned *) op = * ( unsigned *) ip; op += 4 ; ip += 4 ; if( --t > 0 ) { if( t >= 4 ) { do { *(unsigned * ) op = *( unsigned * ) ip ; op += 4 ; ip += 4 ; t -= 4 ; } while (t >= 4 ) ; if (t > 0) { do { *op++ = *ip++; }while (--t > 0); } } else { do { *op++ = *ip++ ; }while (--t > 0); } } first_literal_run: t = *ip++; if (t >= 16) { goto match ; } m_pos = op - 0x0801 ; m_pos -= t >> 2 ; m_pos -= *ip++ << 2 ; *op++ = *m_pos++ ; *op++ = *m_pos++ ; *op++ = *m_pos ; goto match_done; for(;;) { match: if (t >= 64) { m_pos = op - 1; m_pos -= (t >> 2) & 7; m_pos -= *ip++ << 3; t = (t >> 5) - 1; goto copy_match; } else if (t >= 32) { t &= 31; if (t == 0) { while (*ip == 0) { t += 255; ip++; } t += 31 + *ip++; } m_pos = op - 1; m_pos -= (* ( unsigned short * ) ip) >> 2; ip += 2; } else if (t >= 16) { m_pos = op; m_pos -= (t & 8) << 11; t &= 7; if (t == 0) { while (*ip == 0) { t += 255; ip++; } t += 7 + *ip++; } m_pos -= (* ( unsigned short *) ip) >> 2; ip += 2; if (m_pos == op) { goto eof_found ; } m_pos -= 0x4000; } else { m_pos = op - 1; m_pos -= t >> 2; m_pos -= *ip++ << 2; *op++ = *m_pos++; *op++ = *m_pos ; goto match_done; } if (t >= 6 && (op - m_pos) >= 4) { * (unsigned *) op = * ( unsigned *) m_pos; op += 4; m_pos += 4; t -= 2; do { * (unsigned *) op = * ( unsigned *) m_pos; op += 4 ; m_pos += 4 ; t -= 4 ; }while (t >= 4); if (t > 0) { do { *op++ = *m_pos++ ; }while (--t > 0) ; } } else { copy_match: *op++ = *m_pos++; *op++ = *m_pos++; do { *op++ = *m_pos++; }while (--t > 0); } match_done: t = ip[-2] & 3 ; if (t == 0) break; match_next: do { *op++ = *ip++; }while (--t > 0) ; t = *ip++; } } eof_found: if( ip != ip_end ) { return -1 ; } return (op - (byte*)out) ; } |
链接1:文章,总结,代码等
最新推荐文章于 2024-08-12 08:17:55 发布