|
摘要: 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.shnenglu.com/Files/sandy/XDictWrapper.zip 使用的時候解壓放在金山詞霸同一個目錄就可以了,然后通過這個程序來啟動金山詞霸。
|