在我几年前上大学那会,我就想开发一个小软件,里面集成更多的功能,方便更多的人使用,但因为各种原因,软件始终没做成。到了现在,我觉得我可以重新建立好这个软件。本着学习交流的目的,我将软件开源,开源协议GPL3.0,并将里面的工具类授权为MIT,方便需要找代码的朋友们直接使用。
分类: Win32
GDI/GDI+用法总结
GDI是Graphics Device Interface的缩写,含义是图形设备接口,它的主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形输出。GDI+是在GDI基础上提供的一层更高级的图像绘制抽象接口,语义更明确调用更方便。它们都支持向图片对象或者窗口上输出图形。在窗口上绘图时它们都使用窗口提供的HDC句柄实现绘制;在图片对象绘制图像时,GDI+支持直接传入图片对象实现对图片的绘制,GDI需要先创建一个与图片兼容的HDC,再将HDC与被绘制图片进行绑定,然后才能在图片上进行绘制。
它们在用法上相似,区别主要有以下几个方面:
- GDI不支持透明图片处理(AlphaBlend只能混合颜色,透明得由第三方库支持)
- GDI不支持反锯齿(对于图片绘制线条、图像或拉伸等处理时,可能出现白色锯齿形状图像,影响美观)
- GDI对于图片颜色处理具有很大优势。GDI+慢的一比
- GDI是以C的接口形式提供接口,GDI+是以C艹和托管类的方式提供接口
- 使用GDI+的程序在初始化后、程序关闭前需调用GDI+初始化、释放的代码
- 从层次结构上来说,GDI+更好用
C++:时间
时间在计算机中,通常以三种形式存储,三种方式各有各的特点。
1、Unix时间戳
这个东西算是时间表示的元老级结构了,因为出现的早,所以用的也最广泛。原理是,一个32位的数字,代表从1970年1月1日到现在的秒数。由于最高位代表符号位未被使用,所以可以表示的最长的时间点为2038年左右。目前所有Unix及类Unix操作系统都使用这种方式表示时间。著名的水果1970变砖BUG就是因为这种时间表示方式的固有特性所导致。这种时间表示方式还有一个非常大的问题就是,不能计算闰秒。闰秒的含义是,因为地球绕太阳自转的速度越来越慢,导致地球公转一圈的时间更久。现代的人们感受不出来,但如果时间线放长,并且不闰秒,那么可以预见,未来某一天的正午12点是晚上,凌晨12点是白天。所以,在某个时间点的闰秒尤为重要。闰秒通常在某个分钟的变化时,秒数记为57、58、59、60、0、1、2……,也就是说,多出来一个第60秒。闰秒虽好,统一地球公转,为太阳系历法做贡献,但每次闰秒通常会造成几千万美元的经济损失,原因为,使用了Unix时间戳这种计时方法的操作系统,并不能区分闰秒,导致操作系统时间与世界时间不同,然后在金融等领域,一秒钟多计算了什么什么,少计算了什么什么,导致结果不是实际想要的。这时候计算误差所导致的经济损失累积起来,就有这么严重了。另外,这种计时方式最多只能计算到2038年,之后就无能为力了。如果这些操作系统迟迟不更新原子计时方式,那么,等待它们的,只有,系统罢工了。因为以上两个问题太严重了,导致人们常常忽略了它的第三个问题:精度太差。最高精度就是秒了,但对于计算机来说,计算很多东西精度常常需要达到毫秒才够用,有的甚至需要微秒级精度,所以这些地方也用不了这种时间表示方式。
基于这种计时方式,出现了一个分支,使用64位进行计时,这就不存在年份限制这BUG了,不过这分支用的比较少。
继续阅读C++:时间
C++:字符串编码与字符串
1、编码
在讲字符串之前首先说说编码方式。字符串在程序用用数据类型进行存储,同时数据类型存储的也可以是不同编码方式的字符串。总的来说,常用编码方式有以下几种:
ASCII:最古老的编码方式,只使用后7位,可以存储英语大小写、数字及几乎所有常用半角符号。
ISO-8859-1:西欧地区使用的编码方式,兼容ASCII码,在最高位为1时用于描述西文符号。
GB2312/GBK/GB18030:这个是天朝用户专用编码方式,兼容ASCII码,对于英文字符使用1字节进行存储,对于中文使用2字节进行存储,同时两个字节的最高位均为1。值得注意的是,GB2312在Win32开发中常常被称作Ansi编码;其次,GBK为GB2312的扩充,GB18030为GBK的扩充。以前它们是不同的编码方式,但现在也没有严格的划分,通常三者代表同一种编码方式。
BIG-5:也是天朝用户专用编码方式,兼容ASCII码,与GB2312不同的是,它只能编码繁体字,不能编码简体字。
UTF-16/UCS-2:这两个名称所代表的是同一种编码方式,使用两个字节来存储一个中文字符或者一个字母,不兼容ASCII码。这种编码方式也划分为两种不同的子编码方式,分别为UCS-2 Big Endian与UCS2 Little Endian。常说的UTF-16或者UCS-2通常指的是UCS-2 Big Endian。这两种子编码方式的区别为,Big Endian高字节在前,低字节在后;Little Endian低字节在前,高字节在后。这种编码方式在Win32开发中常常被称作Unicode编码,但它属于一种误称;另外,这种编码方式有点浪费存储空间,并且也不能描述世界上所有的符号,相比其他编码,唯一优势是,字符串长度就等于字符个数。
UTF-8:使用最广泛的编码方式,没有之一!几乎所有的网页、XML描述文件、Json数据文件、大多数数据库以及Linux系统均使用的编码方式,相比而言GB2312、UTF-16只有在Windows平台用用而已,仗着Windows平台用的人多,所以也作为常用的编码方式,对于英文字符使用1字节进行存储,因此兼容ASCII编码;它同时也能编码世界上所有的文字,对于汉字而言这种编码方式使用3个字节进行存储,但理论上可以使用2、3、4、5或6字节来编码一个特定字符。
UTF-32/UCS-4:由于UTF-16不能编码所有的编码方式,但发明这编码的人不服,爱搞事,所以发明了4个字节来编码一个字符的编码方式,理论上可以描述世界上所有的字符,但由于一个字母都需要4个字节,过于浪费存储空间,所以这种编码方式几乎没有人使用。
以上是需要了解的编码方式,除了上面几个之外,不同地方也有他们自己的编码方式,以下为不完全统计:
西欧语系:ISO-8859-1
东欧语系:ISO-8859-2
土耳其语:ISO-8859-3
波罗的语:ISO-8859-4
斯拉夫语:ISO-8859-5
阿拉伯文:ISO-8859-6
希腊文:ISO-8859-7
希伯来文:ISO-8859-8
日文:Shift-JIS
韩文:EUC-KR
……
继续阅读C++:字符串编码与字符串
C++:调用协定
Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /www/wwwroot/fawdlstty.com/wp-content/plugins/wp-syntax/wp-syntax.php on line 383
调用协定这个东西涉及到C语言函数实现的原理,大家都知道,调用函数时,保存当前执行环境,跳转到目标函数指令地址执行函数代码,执行完成后恢复调用前的执行环境。但实现的方式这么多,甚至可能不同的语言提供的接口有不同的方式,如何实现与目标函数相同的方式来调用呢?调用协定因此诞生。
可能有人觉得,这东西我从没听说过,但我写的C艹代码一样没问题,有必要研究吗?说实话这东西还是有必要的,主要在不同框架、语言间使用。比如BCB主要用__fastcall实现函数调用,C语言自身默认使用__cdecl实现函数调用,Windows平台又以__stdcall作为主要函数调用方式,而.NET Framework托管平台又以__clrcall实现函数调用,它们之间如何互相调用就是个问题。
Win32平台上可用函数调用协定有以下几种,后面的为别名:
__cdecl : _cdecl 、 cdecl 、 CDECL 、 WINAPIV
__pascal : pascal 、 PASCAL
__stdcall : WINAPI 、 APIENTRY 、 CALLBACK 、 APIPRIVATE
__fastcall
__clrcall
可能因为操作系统版本不同,导致函数定义有些许差异,在Win8.1上,__pascal已经被定义成了__stdcall,但并不妨碍我们对调用协定的学习。上面的关键字看不懂?没关系,我们一一来验证它们的作用。
1、__cdecl调用协定
首先__cdecl,C语言默认调用协定。首先我们先定义一个这样的函数,然后对其进行调用。
1 2 3 4 5 | int __cdecl func_cdecl (int a, int b, int c) { return a + b + c; } //... func_cdecl (1, 2, 3); |
调用协定的定义方式为,将名称写在返回类型与函数名之间。写完之后,通过对齐进行Disassembly,显示如下结果:
继续阅读C++:调用协定
C++:如何制作高逼格二维码
在网上看到一个制作高逼格二维码的文章,来源http://www.chenxublog.com/2016/05/22/pic-qrcode-colorful.html
步骤那可是相当的复杂,一堆软件各种ps啊什么的,不过根据实现的效果一看,原理貌似很简单嘛,何必弄那么复杂,于是我用代码实现了一个,本文着重介绍原理。编译后的程序在最下面,不过建议使用前先看过去,否则可能你不会用2333
先来几张图你们感受下,支付宝:
C++:文件操作
Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /www/wwwroot/fawdlstty.com/wp-content/plugins/wp-syntax/wp-syntax.php on line 383
文件操作是个啥大家都懂了,下面我给出几个文件操作示例
1、C语言文件操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | //在windows平台下避免函数不安全报错而定义的一个宏 #define _CRT_SECURE_NO_WARNINGS #include <stdio .h> #include <stdlib .h> #include <string .h> int main () { //fopen第二个参数有以下几种取值模式 //首先是打开方式,从以下打开方式中任选一种或组合 // a(append) 以写方式打开文件并移动文件指针到文件尾部 // r(read) 以读方式打开文件,文件指针位置未知建议打开后重置文件指针 // w(write) 以写方式打开文件并清空文件内容 //然后是数据类型,默认为文本方式,如果加上b则为二进制方式,区别在于,在windows环境下,不加b(文本模式)会造成: // 以文本方式读文件时,换行符\r\n被读成\n // 以文本方式写文件时,换行符\n被写成\r\n //最后是扩展方式,如果带+号代表如果文件不存在则新建。但我实际测试结果为,带不带+号并没什么卵用 //示例:第二个参数为 rwb+ 代表以二进制读写方式打开文件,如果文件不存在则新建 FILE *f = fopen ("a.txt", "rw+"); if (f) { char *data = "hello"; //写文件,不多做解释 fwrite (data, strlen(data), 1, f); //移动文件指针到结束位置,第三个参数三种取值分别为 SEEK_SET(开始位置)、SEEK_CUR(当前位置)、SEEK_END(结束位置) fseek (f, 0, SEEK_END); //获取文件指针的偏移,这时候指针在末尾,含义就代表文件长度。 //值得注意的是如果以文本方式并且有回车并且读取文件时,文件长度与读取的字节数不一样,原因上面有说明 int len = ftell (f); //这行代码含义为移动文件指针到文件起始位置,等价于 fseek (f, 0, SEEK_SET); rewind (f); //其他文件操作函数不做说明,这儿给出常用列表 //fwrite 输出一块数据到文件 //fprintf 格式化输出到文件 //fputc 输出一个字节到文件 //fputs 输出一串字符串到文件 //fread 读取一块数据到文件 //fscanf 从文件格式化输入 //fgetc 从文件中读取一个字符,因为文件可能结束,所以返回类型为int。如果值为 EOF 代表文件已读到最后 //fgets 从文件中读取一串字符串 //feof 判断文件指针是否在文件末尾 //如果为多个程序同时访问文件的情况时建议加上这句。含义代表将文件缓冲区内容刷新到文件中 //不加可能出现文件更新不及时的现象,不管是否调用这句,关闭文件时始终会刷新的 fflush (f); //关闭文件 fclose (f); } else { printf ("打开文件失败!"); } system ("pause"); return 0; }</string></stdlib></stdio> |
Windows服务访问控制
Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /www/wwwroot/fawdlstty.com/wp-content/plugins/wp-syntax/wp-syntax.php on line 383
服务控制在win32用户层系统编程中比较重要,一般用于创建自启动项或加载驱动,这样的话启动服务就是载入驱动,停止服务就是卸载驱动,极大方便了驱动控制。下面贴一个服务控制代码,可用于方便的控制服务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | #pragma once #ifndef __HSERVER_HPP__ #define __HSERVER_HPP__ #include <Windows.h> class hService { SC_HANDLE h_scm = NULL, h_service = NULL; QUERY_SERVICE_CONFIG *h_qsc = NULL; SERVICE_STATUS h_status; public: hService (LPCTSTR serv_name) { h_qsc = (LPQUERY_SERVICE_CONFIG)new BYTE [8 * 1024]; if ((h_scm = ::OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS)) && serv_name && serv_name[0]) { h_service = ::OpenService (h_scm, serv_name, SERVICE_ALL_ACCESS); } } ~hService () { delete h_qsc; if (h_service) ::CloseServiceHandle (h_service); if (h_scm) ::CloseServiceHandle (h_scm); } //服务是否正在运行 BOOL is_running () { if (!h_service) return FALSE; if (::QueryServiceStatus (h_service, &h_status)) { if (h_status.dwCurrentState == SERVICE_RUNNING) return TRUE; } return FALSE; } //服务是否已停止 BOOL is_stopped () { if (!h_service) return FALSE; if (::QueryServiceStatus (h_service, &h_status)) { if (h_status.dwCurrentState == SERVICE_STOPPED) return TRUE; } return FALSE; } //服务是否已暂停 BOOL is_pause () { if (!h_service) return FALSE; if (::QueryServiceStatus (h_service, &h_status)) { if (h_status.dwCurrentState == SERVICE_PAUSED) return TRUE; } return FALSE; } //服务是否自动启动 BOOL is_auto_run () { DWORD d; if (!h_service) return FALSE; if (::QueryServiceConfig (h_service, h_qsc, 8 * 1024, &d)) { return h_qsc->dwStartType <= 2; } return FALSE; } //启动服务 BOOL start () { if (!h_service) return FALSE; if (is_running ()) return TRUE; return ::StartService (h_service, NULL, NULL); } //停止服务 BOOL stop () { if (!h_service) return FALSE; if (is_stopped ()) return TRUE; return ::ControlService (h_service, SERVICE_CONTROL_STOP, &h_status); } //暂停服务 BOOL pause () { if (!h_service) return FALSE; if (is_running ()) return ::ControlService (h_service, SERVICE_CONTROL_PAUSE, &h_status); return TRUE; } //恢复服务 BOOL resume () { if (!h_service) return FALSE; if (is_pause ()) return ::ControlService (h_service, SERVICE_CONTROL_CONTINUE, &h_status); return is_running (); } //设置自动启动服务 BOOL auto_start () { if (!h_service) return FALSE; if (is_auto_run ()) return TRUE; SC_LOCK sclLock = ::LockServiceDatabase (h_scm); BOOL bRet = ::ChangeServiceConfig (h_service, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (sclLock) ::UnlockServiceDatabase (sclLock); return bRet; } //设置手动启动服务 BOOL demand_start () { if (!h_service) return FALSE; if (!is_auto_run ()) return TRUE; SC_LOCK sclLock = ::LockServiceDatabase (h_scm); BOOL bRet = ::ChangeServiceConfig (h_service, SERVICE_NO_CHANGE, SERVICE_DEMAND_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (sclLock) ::UnlockServiceDatabase (sclLock); return bRet; } //创建服务 static hService *create_service (LPCTSTR serv_name, LPCTSTR display_name, DWORD service_type, LPCTSTR path) { hService *service = new hService (NULL); service->h_service = ::CreateService (service->h_scm, serv_name, display_name, SC_MANAGER_ALL_ACCESS, service_type, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, path, NULL, NULL, NULL, NULL, NULL); return service; } //删除服务 BOOL delete_service () { if (::DeleteService (h_service)) { h_service = NULL; return TRUE; } return FALSE; } }; #endif //__HSERVER_HPP__ |
创建头文件,引入以上代码之后,就可以方便进行服务控制了。调用方式在代码中已有注释。
Windows下编码转换
Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /www/wwwroot/fawdlstty.com/wp-content/plugins/wp-syntax/wp-syntax.php on line 383
对于网络程序来说经常需要用到编码转换,比如访问utf8编码网页下载之后,转为unicode进行显示。windows自带的编码API比较难用,所以对其进行简单的封装。分SDK和MFC两个版本代码,SDK版本如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #pragma once #ifndef __HCODEC_HPP__ #define __HCODEC_HPP__ #include <windows .h> #include <string> class hCodec { //不可实例化 hCodec () = delete; ~hCodec () = delete; static bool hCodec::_conv_Down (std::wstring& _old, std::string& _new, UINT ToType) { int lenOld = lstrlenW (_old.c_str ()); int lenNew = ::WideCharToMultiByte (ToType, 0, _old.c_str (), lenOld, NULL, 0, NULL, NULL); std::string s; s.resize (lenNew); bool bRet = ::WideCharToMultiByte (ToType, 0, _old.c_str (), lenOld, const_cast<char *>(s.c_str ()), lenNew, NULL, NULL); _new.clear (); _new = s.c_str (); return bRet; } static bool hCodec::_conv_Up (std::string& _old, std::wstring& _new, UINT ToType) { int lenOld = lstrlenA (_old.c_str ()); int lenNew = ::MultiByteToWideChar (ToType, 0, _old.c_str (), lenOld, NULL, 0); std::wstring s; s.resize (lenNew); bool bRet = ::MultiByteToWideChar (ToType, 0, _old.c_str (), lenOld, const_cast<wchar_t *>(s.c_str ()), lenNew); _new.clear (); _new = s.c_str (); return bRet; } public: static bool hCodec::AnsiToUnicode (std::string& _old, std::wstring& _new) { return hCodec::_conv_Up (_old, _new, CP_ACP); } static bool hCodec::UnicodeToAnsi (std::wstring& _old, std::string& _new) { return hCodec::_conv_Down (_old, _new, CP_ACP); } static bool hCodec::Utf8ToUnicode (std::string& _old, std::wstring& _new) { return hCodec::_conv_Up (_old, _new, CP_UTF8); } static bool hCodec::UnicodeToUtf8 (std::wstring& _old, std::string& _new) { return hCodec::_conv_Down (_old, _new, CP_UTF8); } static bool hCodec::AnsiToUtf8 (std::string& _old, std::string& _new) { std::wstring t; if (!hCodec::AnsiToUnicode (_old, t)) return false; return hCodec::UnicodeToUtf8 (t, _new); } static bool hCodec::Utf8ToAnsi (std::string& _old, std::string& _new) { std::wstring t; if (!hCodec::Utf8ToUnicode (_old, t)) return false; return hCodec::UnicodeToAnsi (t, _new); } }; #endif //__HCODEC_HPP__</wchar_t></char></string></windows> |
Windows注册表访问的封装
Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /www/wwwroot/fawdlstty.com/wp-content/plugins/wp-syntax/wp-syntax.php on line 383
注册表这东西用的越来越少了,但在特定场合还是不可替代的东西。比如开机启动项、环境变量和文件扩展名等各种系统信息都是放在注册表中。
由于注册表API访问稍微麻烦了点,于是我对其进行简单的封装。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | #pragma once #ifndef __HREG_HPP__ #define __HREG_HPP__ #include <Windows.h> // main_key 注册表根键可取值 // HKEY_CLASSES_ROOT // HKEY_CURRENT_CONFIG // HKEY_CURRENT_USER // HKEY_LOCAL_MACHINE // HKEY_USERS // type 键值类型可取值 // REG_BINARY 二进制数据 // REG_DWORD 双字 // REG_DWORD_LITTLE_ENDIAN 双字小头模式 // REG_DWORD_BIG_ENDIAN 双字大头模式 // REG_EXPAND_SZ 包含未展开的环境变量的引用的字串 // REG_LINK 一个用 RegCreateKeyEx 传 REG_OPTION_CREATE_LINK 创建的符号链接的字串 // REG_MULTI_SZ 多个字符串,用\0分隔,末尾为\0\0 // REG_NONE 没定义值类型 // REG_QWORD 四字 // REG_QWORD_LITTLE_ENDIAN 四字小头模式 // REG_SZ 普通字符串 class hReg { //不可实例化 hReg () = delete; ~hReg () = delete; hReg (hReg&) = delete; public: //创建注册表路径 //main_key: 注册表根键 //sub_key: 注册表路径 //type: 键值类型 //value: 值 //value_size: 值长度(字节) static BOOL set_path (HKEY main_key, LPCTSTR sub_key, DWORD type, LPBYTE value, DWORD value_size) { return ERROR_SUCCESS == ::RegSetValueEx (main_key, sub_key, 0, type, value, value_size); } //创建注册表键值 //main_key: 注册表根键 //sub_key: 注册表路径 //sub_key2: 键值名称 //type: 键值类型 //value: 值 //value_size: 值长度(字节) static BOOL set_key (HKEY main_key, LPCTSTR sub_key, LPCTSTR sub_key2, DWORD type, LPBYTE value, DWORD value_size) { HKEY hKey; if (ERROR_SUCCESS != ::RegOpenKeyEx (main_key, sub_key, 0, KEY_WRITE, &hKey)) return FALSE; BOOL bRet = ERROR_SUCCESS == ::RegSetValueEx (hKey, sub_key2, 0, type, value, value_size); ::RegCloseKey (hKey); return bRet; } //获取注册表路径键值 //main_key: 注册表根键 //sub_key: 注册表路径 //value: 值 //value_size: 值长度(字节) static BOOL get_path_value (HKEY main_key, LPCTSTR sub_key, LPBYTE value, DWORD &value_size) { return ERROR_SUCCESS == ::RegQueryValueEx (main_key, sub_key, NULL, NULL, value, &value_size); } //获取注册表路径键值 //main_key: 注册表根键 //sub_key: 注册表路径 //sub_key2: 键值名称 //value: 值 //value_size: 值长度(字节) static BOOL get_key_value (HKEY main_key, LPCTSTR sub_key, LPCTSTR sub_key2, LPBYTE value, DWORD &value_size) { HKEY hKey; if (ERROR_SUCCESS != ::RegOpenKeyEx (main_key, sub_key, 0, KEY_READ, &hKey)) return FALSE; BOOL bRet = ERROR_SUCCESS == ::RegQueryValueEx (hKey, sub_key2, NULL, NULL, value, &value_size); ::RegCloseKey (hKey); return bRet; } //删除注册表路径 //main_key: 注册表根键 //sub_key: 注册表路径 static BOOL delete_path (HKEY main_key, LPCTSTR sub_key) { return ERROR_SUCCESS == ::RegDeleteKey (main_key, sub_key); } //删除注册表键值 //main_key: 注册表根键 //sub_key: 注册表路径 //sub_key2: 注册表路径 static BOOL delete_key (HKEY main_key, LPCTSTR sub_key, LPCTSTR sub_key2) { HKEY hKey; if (ERROR_SUCCESS != ::RegOpenKeyEx (main_key, sub_key, 0, KEY_ALL_ACCESS, &hKey)) return FALSE; BOOL bRet = ERROR_SUCCESS == ::RegDeleteKey (hKey, sub_key2); ::RegCloseKey (hKey); return bRet; } }; #endif //__HREG_HPP__ |
全部为静态函数,注上了比较完整的注释,另外函数名也较之前清晰,统一返回BOOL表示执行成功或失败。
Win32打开文件/另存为/文件夹对话框实现
一个比较有年代的东西,适合收藏。效果如下:
调用稍微麻烦了点,已将其封装为库,首先引用hSelect.hpp,代码如下
继续阅读Win32打开文件/另存为/文件夹对话框实现
C++/SDK界面开发总结
这年代用C++/SDK开发界面的不多了,不是入门研究那绝壁是情怀,不过这东西还是有用,虽然麻烦了点,但可以使生成的exe文件非常小,对于一些对exe文件大小以及响应速度非常在乎的来说,这还是很好的选择
为避免误人子弟,这儿贴几个关键字,对于开发Windows窗体程序来说,这些都是不错的选择,1为个人最推荐使用的,2为其次,以此类推
- WinForm/WPF:这个就强大了,两种界面开发模式几乎可以满足在任何条件下的需要,并且C#程序可以在Linux下运行,在Windows下几乎无敌,只是响应比SDK界面稍微慢点,目测是几十毫秒的延迟
- wxWidgets:跨平台、强大的界面库,相对于Qt来说是优点是完全无限制,缺点是用的人并没Qt多,开发者社区人少
- UILib:强大的DuiLib的升级版,优点是小巧、免费,缺点是只支持Windows平台,另外由于DuiLib作者不参与维护后,建立的UiLib维护机制相当散乱,相当于一堆高手参与维护但基本是自己维护自己的
- MFC:对于新手入门来说,这就是麻烦C;对于用过几年MFC的来说,能用MFC就绝不用SDK;个人感觉,这库还是相当不错的,至少没SDK麻烦
- Qt:跨平台、强大的界面库,唯一瑕疵是使用LGPL开源协议,只可使用动态链接库,对于静态链接要收费
- WTL:从入门角度来说,WTL比MFC稍微简单点,效果比MFC炫酷,不过这个很久没更新咯,最新版本貌似是07年的
- CB++/Delphi:这个实际上就是C++ Builder自带的界面库VCL,开发环境一般为C++ Builder 6或者RAD Studio,对于新手来说开发界面相当轻松,不过有一个很大的问题,C++ Builder 6有时候会出BUG,RAD Studio与Visual Studio不兼容。另外Delphi 7开发界面还是很不错的,用的也是VCL界面库,但我不喜欢Pascal的语法,所以也没深入研究这个