| 茂隆's profileHorsehead NabulaBlogListsNetwork | Help |
|
|
Horsehead Nabula这里是我的工作和学习空间,欢迎光临!-__- January 22 UNICODE编程资料 (Unicode使Windows程序跑得更快,扩展性更强,但我常常看到Unicode就心虚,自己写则更不知从何写起,读下文受益匪浅,特转过来。不过这东西最重要还是实践,呵呵) -------------------------------------------------------------------------------- 一. UNICODE FAQ(转贴) 1. 如何取得一个既包含单字节字符又包含双字节字符的字符串的字符个数? 2. 如何对DBCS(双字节字符集)字符串进行操作? 3. 为什么要使用Unicode? 4. 如何编写Unicode源代码? 5. Windows定义的Unicode数据类型有哪些? 6. 如何对Unicode进行操作? 7. 如何表示Unicode字符串常量? 8. 为什么应当尽量使用操作系统函数? 9. 如何编写符合ANSI和Unicode的应用程序? 10. 如何对字符串进行有选择的比较? 11. 如何判断一个文本文件是ANSI还是Unicode? 12. 如何判断一段字符串是ANSI还是Unicode? 13. 如何在Unicode与ANSI之间转换字符串? -------------------------------------------------------------------------------- Visual C++ 概念:添加功能 定义 _UNICODE。 指定入口点。 使用“可移植的”运行时函数和类型。 使用支持 Unicode 中描述的 _TCHAR 和相关的可移植数据类型。 正确地处理字符串。 L"this is a literal string"指出这是 Unicode 字符的字符串。可以对文字字符使用相同的前缀。一般使用 _T 宏对字符串进行编码,因此在 Unicode 下字符串编译为 Unicode 字符串,不使用 Unicode 时字符串编译为 ANSI 字符串(包括 MBCS)。例如,不使用: pWnd->SetWindowText( "Hello" );而使用: pWnd->SetWindowText( _T("Hello") );使用已定义的 _UNICODE,_T 将字符串翻译为以 L 为前缀的格式;否则 _T 将字符串翻译为不带 L 前缀的格式。 提示 _T 宏与 _TEXT 宏相同。 archive.Write( str, str.GetLength( ) ); // invalid在 Unicode 应用程序中,由于每个字符都是双字节宽,因此长度会给出字符数但不给出正确的字节数。所以必须使用: archive.Write( str, str.GetLength( ) * sizeof( _TCHAR ) ); // valid它指定要写入的正确字节数。 但是,MFC 成员函数是面向字符而非面向字节的,因此无需此额外的编码: pDC->TextOut( str, str.GetLength( ) );CDC::TextOut 采用字符数而非字节数。 总之,MFC 和运行时库对 Windows 2000 下的 Unicode 编程提供下列支持: 除数据库类成员函数外,所有 MFC(包括 CString)函数都支持 Unicode。CString 还提供 Unicode/ANSI 转换函数。
在windows下编程还是支持unicode吧,大势所趋啊,window 2k以后的系统底层都是基于Unicode的,就算你调用ANSI的API(以A结尾比如SetWidowsTextA),系统也会在你的进程默认堆上动态分配一块内存,存放转换后的Unicode字符串,然后把转换后的字符串传递给API,如果调用了返回值为ANSI字符串的API,Windows会在后台进行相反的转换,多浪费时间啊!!就算不考虑效率问题,难道你不想让你的软件国际化吗?你还想面临半个汉字等尴尬的问题吗? 其实VC中进行Unicode编程也不麻烦,大概如下: 2.Include <TCHAR.h>(一般在stdafx.h中)然后把所有使用char*定义变量的地方换为LPTSTR/TCHAR*或LPCTSTR/const TCHAR*(对应于const char*). 3.把所有的字符串常量用_T()宏包起来,比如 TCHAR* szText = _T("我的Text"); 4.所有的C库字符串操作函数也做相应的替换,比如 5.API调用一般不用做特殊处理,当定义了UNICODE和_UNICODE后,所有的API都会被宏指向W结尾的版本(不定义则指向A结尾的版本). 其实,上面所说的并非强制你使用UNICODE,如果你还想回去使用ANSI,没有问题,把第一步定义的两个宏拿掉就OK了,继续我们的ANSI编程!! January 15 成为符合ANSI和Unicode的应用程序即使你不打算立即使用Unicode,最好也应该着手将你的应用程序转换成符合Unicode的应 用程序。下面是应该遵循的一些基本原则: • 将文本串视为字符数组,而不是chars数组或字节数组。 • 将通用数据类型(如TCHAR和PTSTR)用于文本字符和字符串。 • 将显式数据类型(如BYTE和PBYTE)用于字节、字节指针和数据缓存。 • 将TEXT宏用于原义字符和字符串。 • 执行全局性替换(例如用PTSTR替换PSTR)。 • 修改字符串运算问题。例如函数通常希望你在字符中传递一个缓存的大小,而不是字节。这意味着你不应该传递sizeof(szBuffer),而应该传递(sizeof(szBuffer)/sizeof(TCHAR)。另外,如果需要为字符串分配一个内存块,并且拥有该字符串中的字符数目,那么请记住要按字节来分配内存。这就是说,应该调用malloc(nCharacters *sizeof(TCHAR)), 而不是调用malloc(nCharacters)。在上面所说的所有原则中,这是最难记住的一条原则,如果操作错误,编译器将不发出任何警告。 --摘自《Windows核心编程》 December 26 Flash与VC的通信方法基于做智能家居演示程序的需要,必须开发出较好的动画介面。主程序由VC开发通过串口与无线模块通信。动画界面用VC来做是不可取的,于是决定用Flash实现。做成控件的形式嵌入VC,然后通过Flash按钮触发VC的程序,实现相应的功能。
这里只说明Flash是如何给VC发消息,和VC是如何捕获消息的。方法比我们想像中简单。
1)首先是Flash
把Flash动画都做好后,选择要触发的事件,如按钮或时间轴上的某个关键帧,然后在Action选项卡上代码区加入一个函数:fscommand(const char *str1,const char *str2);
参数str1和str2是函数的两个参数均为字符串指针,有点像API消息函数里的WPARAM和LPARAM。调用如下:
fscommand('1','2');
这样,事件一但发生(按钮按下或运行到该关键帧),fscommand就会运行,就会向VC发送一个参数为'1'和'2'的消息。剩下的工作就是在VC里捕获此消息。
运行Ctrl+Enter生成swf文件。
2)VC端
在VC工程文件里选Project -> Add to project -> Conponents and Controls,然后选 Registered ActiveX Controls -> Shockwave Flash Object ,然后Insert即可。然后你会发觉工程里多了一个类CShockwaveFlash。这个类可用来播放Flash文件,但这不是我的重点。这里要做的是捕捉由Flash发送出来的消息:fscommand('1','2');
在VC工程打开一个对话框资源,在控件栏里加入刚才添加的ShockwaveFlash控件。然后Ctrl+W打开Classwizard。在Class name里选择你要响应Flash消息的类。如CMyView或CMyDlg等。在Object ID里选择IDC_SHOCKWAVEFLASH1,在Message里双击FSCommand,然后Edit Code,添加如下代码:
void CFlashToVCDlg::OnFSCommandShockwaveflash1(LPCTSTR command, LPCTSTR args)
{ // TODO: Add your control notification handler code here
UCHAR com,arg; com = *command; arg = *args; switch(com) { case '1': switch(arg) { case '1': break;
case '2': MessageBox(_T("12")); break; default: break; } break; case '2': break; default: break; } }
运行结果输出12的MessageBox。具体怎样跑的应该看得出来。
功能就这样,是Flash向VC通信的。基于VC向Flash通信,网上说可以在Flash设置一变量,用定时器不断检测变量值。用VC来改变这个值即可。至于具体怎么做有空可以试试。呵呵。
还有一点奇怪的是fscommand中参数是字符串,但我用fscommand(1,2)调用也行,但换成字母就不行了。一般用一个字符即可。多个字符好像只识别第一个。不过其实一个字符都足够我们实现足够多的功能了。
终于写了一篇原创,高兴,呵呵。 December 05 驱动程序与应用程序之间的通信总的来说驱动程序与应用程序之间的通信可概括为以下两点
1)应用程序通过API和WDM设备进行通信,进行读写和控制的请求;
2)驱动程序通过事件句柄(应用程序调用API时传送给驱动程序的事件句柄,由应用程序建立)设置事件,触发应用程序。应用程序通过一个辅助线程等待事件的发生,或用WaitForSingleObject等函数等待。
具体说明如下:
在Windows程序中,应用程序是通过与驱动程序的通讯对硬件进行操控的。而驱动程序对于用户接口软件来说应该是透明的,即应该使用户能感觉到似乎直接在对硬件进行操作。应用程序实现与WDM驱动程序的通讯过程是:应用程序通过调用Win32函数CreateFile打开和创建到设备的连接,然后调用DeviceIoControl发出特许的请求和WDM进行通讯,可以发送数据给驱动程序也可以从驱动程序中读取数据,还可以通过调用ReadFile函数从WDM中读取数据或是调用WriteFile函数将数据发送到WDM程序中去。当一个进程完成时,Win32应用程序保证所有的句柄都被关闭,并取消任何在等待的I/O请求,CloseHandle就是在完成设备文件使用时关闭文件句柄。例如在应用程序中:
m_hDevice = CreateFile("\\\\.\\Pci", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); //用异步方式打开设备驱动程序句柄 当驱动程序捕捉到特定的事件(如中断)发生时,应通知应用程序。一般,WDM可以使用WIN32事件与应用程序通信,应用程序创建一个事件后,直接将该事件句柄传递给驱动程序,然后等待驱动程序发送事件消息。当驱动程序获得这个事件的一个对象指针后,可以在IRQL≤DISPATCH_LEVEL级别的例程中设置事件信号状态来触发应用程序。因此在应用程序中用一个辅助线程来等待驱动程序发送的事件消息: m_hSealTBEvent = CreateEvent(NULL, FALSE, FALSE,NULL); //创建事件 CardSourceInfo.Ring3Application = m_hSealTBEvent; //将事件句柄封装以传递给驱动 DeviceIoControl(Ring0_DrvHandel, IOCtrl_Set_SourceInfo, &CardSourceInfo, sizeof(CardSourceInfo), NULL, 0, &nBytesRead, NULL) //将事件句柄传递给驱动程序 WaitForSingleObject(m_hSealTBEvent, INFINITE); //当事件被驱动设置为信号态时,此线程才向下执行。 在驱动程序中m_pEventToSignal->Set(); //设置事件为信号态,以通知应用程序。 最后一句还不明白是为什么是m_pEventToSignal,不知道哪里来的变量。
内容网址: http://bbs.gd-emb.org/?display=topic&id=6958
延时过程调用的应用延时调用可用在Windows驱动程序的中断处理中。由于中断处理的中断级别较高--在DIRQL级别,所以应该使其执行时间尽可能短。于是一般的情况是在中断处理程序里判断中断发生,然后调用延时过程调用例程实现中断程序的功能。说明如下:
当硬件设备产生中断请求时,驱动程序则需要注册一个处理程序,在中断到达时进行正确的处理。在DriverWorks中通过KInterrupt类实现硬件中断处理,该类封装了IoConnectInterrupt函数来初始化中断及将一个中断服务例程连接到一个中断上。中断服务例程是运行在DIRQL级别上,因此处理时间应该尽可能的短,并且在该级别上还有很多内核函数不能调用。所以一般在中断服务例程中只判断该中断是否由自己的设备产生,若是则调用一个在DISPATCH_LEVEL级别上运行的延迟过程调用。在延迟过程调用例程中可完成大部分的中断处理工作。
例如,在中断服务程序中通过判断是不是该设备产生的中断,以响应中断(以下程序都只给出关键代码): status = m_IoPortRange0.ind(INTCSR); //获取设备的中断状态 if ((status & 0x800000) != 0x800000) { return FALSE; } //判断是不是由该设备产生的中断,如果不是则返回 m_IoPortRange0.outd(INTCSR, status & 0xff02ffff); //屏蔽中断 if (!m_DpcFor_Irq.Request(NULL, NULL)) ; //调用延时过程调用例程,处理中断事件 文档网址
December 04 笑脸C程序程序如下:
#include "stdio.h"
typedef struct {
char *c; }C; #define PRINT_ME &(((C *)2)->c) int main(int argc, char* argv[])
{ printf("%c\n",PRINT_ME); return 0; } 这段程序,猜猜输出了什么,呵呵。……
程序首先把2强制转换为指向C类型的指针,即2已经不是常量,是一个地址,2这个地址存放的是一个C类型的数据;C类只有一个成员c,所以取c的地址,实际上就是C的地址,(即结构体C中成员指针c的地址)值为2; 打印出ASCII码为2的字符……一个笑脸吧…… 绕了半天,其实和下面的结果是一样的…… #include <stdio.h>
void main() { printf("%c\n", 2); } 呵呵,C语言真能玩花样,如果是考试题,见了那不郁闷才怪。
December 03 #pragma 预处理指令详解在别的网页考过来的,关于#pragma预处理指令详解如下:
在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。其格式一般为: #Pragma Para
其中Para 为参数,下面来看一些常用的参数。 (1)message 参数。 Message 参数是我最喜欢的一个参数,它能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为: #Pragma message(“消息文本”) 当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。 当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏可以用下面的方法 #ifdef _X86 #Pragma message(“_X86 macro activated!”) #endif 当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示“_X86 macro activated!”。我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了。 (2)另一个使用得比较多的pragma参数是code_seg。格式如: #pragma code_seg( ["section-name"[,"section-class"] ] ) 它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。 (3)#pragma once (比较常用) 只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。 (4)#pragma hdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。BCB可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。 有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。你可以用#pragma startup指定编译优先级,如果使用了#pragma package(smart_init) ,BCB就会根据优先级的大小先后编译。 (5)#pragma resource "*.dfm"表示把*.dfm文件中的资源加入工程。*.dfm中包括窗体 外观的定义。 (6)#pragma warning( disable : 4507 34; once : 4385; error : 164 ) 等价于: #pragma warning(disable:4507 34) // 不显示4507和34号警告信息 #pragma warning(once:4385) // 4385号警告信息仅报告一次 #pragma warning(error:164) // 把164号警告信息作为一个错误。 同时这个pragma warning 也支持如下格式: #pragma warning( push [ ,n ] ) #pragma warning( pop ) 这里n代表一个警告等级(1---4)。 #pragma warning( push )保存所有警告信息的现有的警告状态。 #pragma warning( push, n)保存所有警告信息的现有的警告状态,并且把全局警告 等级设定为n。 #pragma warning( pop )向栈中弹出最后一个警告信息,在入栈和出栈之间所作的 一切改动取消。例如: #pragma warning( push ) #pragma warning( disable : 4705 ) #pragma warning( disable : 4706 ) #pragma warning( disable : 4707 ) //....... #pragma warning( pop ) 在这段代码的最后,重新保存所有的警告信息(包括4705,4706和4707)。 (7)pragma comment(...) 该指令将一个注释记录放入一个对象文件或可执行文件中。 常用的lib关键字,可以帮我们连入一个库文件。 每个编译程序可以用#pragma指令激活或终止该编译程序支持的一些编译功能。例如,对循环优化功能: #pragma loop_opt(on) // 激活 #pragma loop_opt(off) // 终止 有时,程序中会有些函数会使编译器发出你熟知而想忽略的警告,如“Parameter xxx is never used in function xxx”,可以这样: #pragma warn —100 // Turn off the warning message for warning #100 int insert_record(REC *r) { /* function body */ } #pragma warn +100 // Turn the warning message for warning #100 back on 函数会产生一条有唯一特征码100的警告信息,如此可暂时终止该警告。 每个编译器对#pragma的实现不同,在一个编译器中有效在别的编译器中几乎无效。可从编译器的文档中查看。 |
||||
|
|