|
摘要: Windbg(CDB) 新手指南 阅读全文
也许有人不知道CDB是什么,CDB是windbg的小兄弟,基于command line,对于我这个比较喜欢用command line的人,CDB比windbg更容易上手。
象GDB,CDB这些工具,命令都很多,但是我们只要熟记最常用的"三板斧"就可以工作了。
1.启动 1)直接调试: gdb program [core] cdb program or cdb -z DumpFile 2)attach方式 gdb attach pid cdb -pn ExeName or cdb -p pid
2.显示堆栈 GDB: bt CDB: k
3. 设置断点 GDB: b [file:]line CDB: bp 'file:line'
4. 运行/继续运行 GDB: run [arglist] c 继续运行 CDB: g
5. 单步 GDB : n (step over) s (step into) CDB : p
6. 打印变量的值 GDB : p expr CDB: ? expr
说老实话,CDB过于复杂,学起来比GDB难.
BTW:用CDB之前设置一下symbol的path set _NT_SYMBOL_PATH=srv*c:\symbols*http://msdl.microsoft.com/download/symbols
摘要: [STL] loop & erase 阅读全文
项目需要,写了一个帮助L10N的工程师计算utf8的小工具(html page)。如下 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> <TITLE> An utf8 count tool </TITLE> <meta http-equiv="Content-Type" content="text/html; charset=utf16"> <script> function utf16to8(str) { var out, i, len, c;
out = ""; len = str.length; for(i = 0; i < len; i++) { c = str.charCodeAt(i); if ((c >= 0x0001) && (c <= 0x007F)) { out += str.charAt(i); } else if (c > 0x07FF) { out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F)); out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F)); out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); } else { out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F)); out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); } } return out; } function count() { var temp = f1.value; temp=temp.replace(/\\r/g,"\r"); temp=temp.replace(/\\n/g,"\n"); result.innerHTML=utf16to8(temp).length; } </script> </HEAD>
<BODY> <TEXTAREA id="f1" NAME="f1" ROWS="10" COLS="50"></TEXTAREA> <br/> <INPUT TYPE="button" value="count length" onclick="count()"> <div id="result"></div> </BODY> </HTML>
摘要: snprintf的正确用法和错误用法 阅读全文
SendMessageTimeout并不是简单在SendMessage加上Timeout的功能。
MSDN上面有一段文字是这样说的
If the specified window was created by the calling thread, the window procedure is called immediately as a subroutine. If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code. The sending thread is blocked until the receiving thread processes the message. However, the sending thread will process incoming nonqueued messages while waiting for its message to be processed. To prevent this, use SendMessageTimeout with SMTO_BLOCK set. For more information on nonqueued messages, see Nonqueued Messages.
翻译一下:
SendMessage : 如果指定窗口由调用线程创建,那么窗口过程会被当成一个子程序立即调用。如果指定窗口由另外一个线程创建,那么系统会切换到那个线程,并且调用合适的窗口过程。在线程之间传递的消息仅仅当接收线程执行message retrieval code才会被处理。发送线程会被堵塞直到接收线程处理完消息。但是,发送线程在等待的同时会处理收到的nonqueued messages 。为了阻止这一点,使用带有SMTO_BLOCK参数 的SendMessageTimeout .
=================================华丽的分割线===========================
我曾经遇到这个问题,我调用SendMessage向另外一个线程窗口发message,本来以为他会一直block住,但是他却调用了另外一个消息的处理程序,导致了行为不正确。所以一定要小心使用SendMessage发给其他线程的窗口。
我修改了一下,把 pWnd->SendMessage(MSG_LOG_MESSAGE, nMsgType, (LPARAM)(LPCTSTR)m_cstrMessage); 改成了 HWND hWnd = pWnd->GetSafeHwnd(); ::SendMessageTimeout(hWnd,MSG_LOG_MESSAGE, nMsgType, (LPARAM)(LPCTSTR)m_cstrMessage,SMTO_BLOCK,15000,0); 解决了这个bug.
摘要: 介绍两个用于C/C++/Java格式化的工具 阅读全文
摘要: 使用标准库应该记住的一些东西(21条) 阅读全文
在linux/Unix平台上面做G11N的开发,大抵都会用到gettext库/工具集( ftp://ftp.gnu.org/gnu/gettext/ ) 和libiconv( http://www.gnu.org/software/libiconv/) ,前者是用于实现Resource bundle,而后者用于各种编码转化。 (注:这里没有考虑cross-platform) 1. 实现方法 a . 使用po文件作为资源文件 (建议编码是utf-8) 一方面因为UTF-8兼容ANSI,另外一方面考虑到G11N的程序大部分使用utf-8输出,比如输出到database,web UI, file等等。 b. 使用getext从resource file ( mo文件)读到相应的L10N resource文件 注意这里需要先setlocale来设置locale
#include <stdio.h> #include <locale.h> #include <libintl.h>
#define _(string) gettext (string)
int main(int argc, char **argv) { if (setlocale(LC_ALL, “”) == NULL) { fprintf(stderr, “setlocale() error.\n”); return -1; } if (bindtextdomain(package, “/usr/share/locale”) == NULL) { fprintf(stderr, “bindtextdomain() error.\n”); return –1; } if (textdomain(package) == NULL) { fprintf(stderr, “textdomain() error.\n”); return –1; } printf(“%s\n”, _(“Hello, world!”)); return 0; }
c.如果要输出到控制台(console),因为不是console都支持unicode output,所以推荐的方法是首先是把utf-8转化为本地编码,然后使用printf输出。不推荐使用wprintf进行输出,一方面是因为wchar_t的大小随编译器不同,不好控制。另外一方面,很多wprintf的实现也都是先把wchar_t[]转为本地编码,然后输出。转化编码使用libconv d.如果要输出到web pages,database,file,编码推荐使用utf-8. e.如果要输出本地化的日期和时间,使用API: strftime
#include <stdio.h> #include <time.h> int main(int argc, char **argv) { time_t t; struct tm *ptm; char buffer[100];
memset(buffer, 0, sizeof(buffer)); if (time(&t) < 0) { fprintf(stderr, “time() error: %m\n”); } if ((ptm = localtime(&t)) == NULL) { fprintf(stderr, “localtime() error: %m\n”); } strftime(buffer, sizeof(buffer), “%x %X”, ptm); printf(“%s\n”, buffer); return 0; }
f. 如果要输出本地化的数字和货币,使用API: strfmon
#include <stdio.h> #include <monetary.h>
int main(int argc, char **argv) { char buffer[100]; strfmon(buffer, sizeof(buffer), “%=*i", 12345.67); printf(“%s\n”, buffer); return 0; }
2.目录结构 /product /i18n /zh_TW your.mo /ja_JP your.mo
1. printf 只能提供ANSI/MB 的输出,不支持输出unicode stream. 例如: wchar_t test[]=L"测试1234"; printf("%s",test); 是不会正确输出的 2.wprintf 同样不会提供unicode output, 但是他会把wchar_t的string转为locale的SB/MB字符编码,然后输出 例如: wchar_t test[] = L"测试Test"; wprintf(L"%s",test); 会输出??1234之类的字符串,或者不输出任何结果 因为wprintf没有办法把L"测试Test"转为默认的ANSI,需要设置locale setlocale(LC_ALL,"chs"); wchar_t test[] = L"测试Test"; wprintf(L"%s",test); 会有正确的输出 等同于printf("%ls",test); 综上: CRT I/O functions do not provide Unicode output.
3. Window console自从NT4就是一个真正的unicode console 不过输出unicode string,只有使用Windows API, WriteConsoleW 例如:
wchar_t test[] = L"测试1234"; DWORD ws; WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),test,wcslen(test),&ws,NULL); 可以正确的输出而不需要设置locale,因为是真正的unicode的输出,跟codepage无关
4. 如何实现跨平台的console output 不要使用wchar_t和wprintf,因为这些都依赖于编译器. ICU是IBM的一个成熟的跨平台支持unicode的libary,推荐使用
以下是ICU的uprintf实现
void uprintf(const UnicodeString &str) { char *buf = 0; int32_t len = str.length(); int32_t bufLen = len + 16; int32_t actualLen; buf = new char[bufLen + 1]; actualLen = str.extract(0, len, buf/*, bufLen*/); // Default codepage conversion buf[actualLen] = 0; printf("%s", buf); delete buf; } 它也是先把Unicode string转化为本地的codepage,然后printf,虽然也不是unicode output,但是跨平台,大多数情况会工作得很好。
摘要: Globalization development 阅读全文
在windows的世界里面,很少有API没有返回值。但是到底返回什么代表成功,这个没有标准。我发现主要有三种模式 1 . 返回非0表示成功,返回0表示失败大多数Win32 Platform API都是这样,比如 int result =MoveFileEx(szTempName, "allcaps.txt", MOVEFILE_REPLACE_EXISTING);
if(!result) { printf("Could not move file. error:%d",GetLastError()); return 0; }
使用这种方法。你必须提供类似GetLastError的取错误的方法,而且你必须保证这个函数是thread-safe的,每个线程能维护自己的错误信息。 2. 返回大于等于0表示成功,返回-1表示失败
socket api大部分是这样设计的 while( bytesRecv != SOCKET_ERROR ) { bytesRecv = recv( ConnectSocket, recvbuf, 32, 0 ); if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET ) { printf( "Connection Closed.\n"); break; } printf( "Bytes Recv: %ld\n", bytesRecv ); }
这样的好处是返回值就可以用来表示成功和状态。比如这里的recv就可以返回收到的字节数。但是你还是要有一个查询错误的API,like WSAGetLastError(). 3.返回0表示成功
COM的接口大部分是这样设计的 if( FAILED(lpdd->QueryInterface(IID_IDirectDraw7, (LPVOID *) &lpdd))) { //error handle and return }
其他的一些考虑 1.如何定义错误值?
简单的一点使用宏连续定义,like #define E_NO_FILE 1 #define E_BAD_FILE 2 复杂的一点就像COM,严格的定义每一位的意义 这种情况下你可以提供一个宏来创建错误代码,like #define MAKE_HRESULT(sev,fac,code)\
( (HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) \
| ((unsigned long)(code))) )
2.可以提供一个宏或者函数来帮助判断是否成功
比如COM提供了FAILED宏来帮助你判断COM的返回值 #define FAILED(Status) ((HRESULT)(Status)<0)
3.如果只有错误和成功两个返回值,考虑使用bool来返回
这个适用于C++,优点是意义很清晰.返回 true就是成功,false就是失败. 4.要使用异常来表示错误的状态么?使用异常的好处就是返回值被省出来了,可以不返回或者返回其他信息,还有益于定义错误类型和简化程序流程。缺点就是C++对异常支持还不够好,没有finally,每一家编译器支持也不一样,实现可能大不同.
#include
<
stdio.h
>
int
main() {
int
a
=
10
,b
=
20
;
a
=
(a
+
b)
-
(b
=
a);
printf(
"
a=%d,b=%d\n
"
,a,b);
return
0
; }
很简单,交换a和b的值 在debug模式下,输出 a=20,b=10 在release模式下,输出 a=10,b=10 I think there is a bug in release version.
最近在使用金山词霸2005,由于金山词霸2005在启动的时候会发一个UDP包到局域网,然后检测是否有相同序列号的金山词霸,如果发现则要求退出。甚为无奈。windows 2000自带有防火墙的功能,但是只有Permit all 和 Permit only两种模式,居然没有Deny only,奇怪。 所以我就查了一下MSDN,发现有Routing and Remote Access Service一类的API可以用。 于是程序的流程就是这样 1.设置临时防火墙,以阻挡发到端口11113的UDP包 2.启动金山词霸 3.删除设置 代码: #include <stdlib.h> #include <Iphlpapi.h> #include <Fltdefs.h>
#pragma comment(lib, "Iphlpapi.lib")
const int XDICT_PORT = 11113;
unsigned long CharToIp(const char *sIp) { int octets[4]; int i; const char * auxCad = sIp; unsigned long lIp = 0; //we extract each octet of the ip address //atoi will get characters until it found a non numeric character(in our case '.') for(i = 0; i < 4; i++) { octets[i] = atoi(auxCad);
if(octets[i] < 0 || octets[i] > 255) return 0;
lIp |= (octets[i] << (i*8));
//update auxCad to point to the next octet auxCad = strchr(auxCad, '.');
if(auxCad == NULL && i!=3) return -1;
auxCad++; } return lIp; }
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { //first get adapter info PIP_ADAPTER_INFO pAdapterInfo = NULL,tmp; unsigned long len = 0; GetAdaptersInfo(pAdapterInfo,&len); pAdapterInfo = (PIP_ADAPTER_INFO) malloc (len); DWORD result = GetAdaptersInfo(pAdapterInfo, &len); if(result!=ERROR_SUCCESS) { MessageBox(NULL,"Fail to call GetAdaptersInfo","ERROR",MB_OK); return -1; }
//create filters interface INTERFACE_HANDLE hInterface = NULL; result = PfCreateInterface(0,PF_ACTION_FORWARD,PF_ACTION_FORWARD,FALSE,TRUE,&hInterface); if(result!=NO_ERROR) { MessageBox(NULL,"Fail to call PfCreateInterface","ERROR",MB_OK); return -1; }
//add the filter to adapter unsigned long dmp = 0; PF_FILTER_DESCRIPTOR ipFlt; ipFlt.dwFilterFlags = 0; ipFlt.dwRule = 0; ipFlt.pfatType = PF_IPV4; ipFlt.dwProtocol = FILTER_PROTO_UDP; ipFlt.fLateBound = 0; ipFlt.wSrcPort = 0; ipFlt.wSrcPortHighRange = 0; ipFlt.wDstPort = XDICT_PORT; ipFlt.wDstPortHighRange = XDICT_PORT; ipFlt.SrcAddr = (PBYTE)&dmp ; ipFlt.SrcMask = (PBYTE)&dmp; ipFlt.DstAddr = (PBYTE)&dmp; ipFlt.DstMask = (PBYTE)&dmp;
//bind IP_ADDR_STRING *localIp; for(tmp=pAdapterInfo;tmp != NULL;tmp=tmp->Next) { // each ip of a adapter for(localIp=&tmp->IpAddressList;localIp!=NULL;localIp=localIp->Next) { unsigned long ul = CharToIp(localIp->IpAddress.String); PBYTE lIp = (PBYTE)&ul; PfBindInterfaceToIPAddress(hInterface, PF_IPV4, lIp); } }
result = PfAddFiltersToInterface(hInterface,1,&ipFlt,1,&ipFlt,NULL); if(result!=NO_ERROR) { MessageBox(NULL,"Fail to call PfAddFiltersToInterface","ERROR",MB_OK); return -1; }
//start XDict STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); ::CreateProcess(NULL,"XDICT.exe", NULL, // Process handle not inheritable. NULL, // Thread handle not inheritable. FALSE, // Set handle inheritance to FALSE. 0, // No creation flags. NULL, // Use parent's environment block. NULL, // Use parent's starting directory. &si, // Pointer to STARTUPINFO structure. &pi ); // Pointer to PROCESS_INFORMATION structure.
// Wait until child process exits. WaitForSingleObject( pi.hProcess, INFINITE ); // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread );
//remove filter for(tmp=pAdapterInfo;tmp != NULL;tmp=tmp->Next) { result = PfRemoveFiltersFromInterface(hInterface,1,&ipFlt,1,&ipFlt); if(result!=NO_ERROR) { MessageBox(NULL,"Fail to call PfRemoveFiltersFromInterface","ERROR",MB_OK); return -1; } } PfUnBindInterface(hInterface); PfDeleteInterface(hInterface);
//free free(pAdapterInfo); return 0; }
使用的API有 GetAdapaterInfo --- 取得网卡的信息,如ip PfCreateInterface ----Create一个Filter Interface PfBindInterfaceToIPAddress ----绑定Filter Interface到IP PfAddFiltersToInterface ----增加Filter到Interface PfRemoveFiltersFromInterface ---Remove Filter PfUnBindInterface---取消绑定到ip PfDeleteInterface---删除Filter Interface 附上可执行文件: http://www.cppblog.com/Files/sandy/XDictWrapper.zip 使用的时候解压放在金山词霸同一个目录就可以了,然后通过这个程序来启动金山词霸。
|