這是最近看的一片短文的title,當時就很好奇。
經常查閱MSDN的程序員都會有這個印象,微軟code sample中常見的是ZeroMemory,而不是語言提供的“{0}”清零功能(不過,我一直也沒有問個why)。c++語法中聲明對數組或純結構(struct),可以使用例如SPerson sTest = {0}; 來將所有成員置0.
那篇文章的解釋是,Microsoft使用ZeroMemory會更clear,因為“= {0}” 這樣的語法有些生僻,不是所有人都可以一下子明白。
實際上,兩者還是有一些區別。
其一,ZeroMemory會將結構所有字節置0,而={0}只會將成員置0,其中padding字節不變。
其二,但一個struct有構造函數或虛函數時,ZeroMemory可以,而={0}會編譯不過。顯然,后者起到了一些保護作用,因為對一個有虛函數的對象使用ZeroMemory時,會將其虛函數的指針置0,這是非常危險的,因為調用虛函數時,程序顯然會crash。參看如下代碼:
struct SPerson


{
//SPerson(){ }
char c;
float s;
};

class CTestVirtual


{
public:
CTestVirtual()

{
}

virtual int Draw()

{
return 10;
}

int a;
};

void Test()


{
char sztmp[20];
ZeroMemory(sztmp, sizeof(sztmp));


SPerson sTest =
{0};
int i = sizeof(SPerson);

//CTestVirtual otv = {0}; //Compire error
CTestVirtual tv;
ZeroMemory(&tv, sizeof(tv));
tv.Draw(); //As it is an object, don't use the virtual function pointer, so don't crash.
CTestVirtual *pTv = &tv;
pTv->Draw(); //Crash!!!
}
因此,在windows平臺下,對于數組或純結構使用ZeroMemory是安全的,對于class,則使用構造函數,不要調用ZeroMemory。如果有跨平臺要求,使用={0}則可以減少一些工作。
posted @
2008-12-20 15:04 Sandy 閱讀(699) |
評論 (1) |
編輯 收藏
原諒我無知,對LPTSTR不是很熟悉,盡管用了半年的WIN32,今天才想起思考LPTSTR這個變量.
例如:
LPTSTR lpStr = _T("Hello");
int len1 = wcslen(lpStr); // 值為5
int len2 = sizeof(lpStr); // 值為4
原來是這樣的啊,今天我終于弄明白了!
lpStr 是一個指針,它的用法應該與指針同.
犯了一個很低級的錯誤.記錄下來.
posted @
2008-12-19 21:10 Sandy 閱讀(2185) |
評論 (0) |
編輯 收藏
在LoadString的一些小用法中, 談到了對LoadString的一點用法,萬連文指出這個方法解決不夠徹底,聽取了他的意見,我參考了一下vc的CString的LoadString的寫法.
具體在VC98\MFC\SRC\WINSTR.CPP這個文件中,我也貼出來一部分:
#ifdef _UNICODE
#define CHAR_FUDGE 1 // one TCHAR unused is good enough
#else
#define CHAR_FUDGE 2 // two BYTES unused for case of DBC last char
#endif

BOOL CString::LoadString(UINT nID)


{
// try fixed buffer first (to avoid wasting space in the heap)
TCHAR szTemp[256];
int nLen = AfxLoadString(nID, szTemp, _countof(szTemp));
if (_countof(szTemp) - nLen > CHAR_FUDGE)

{
*this = szTemp;
return nLen > 0;
}

// try buffer size of 512, then larger size until entire string is retrieved
int nSize = 256;
do

{
nSize += 256;
nLen = AfxLoadString(nID, GetBuffer(nSize-1), nSize);
} while (nSize - nLen <= CHAR_FUDGE);
ReleaseBuffer();

return nLen > 0;
}

#ifndef _AFXDLL
int AFXAPI AfxLoadString(UINT nID, LPTSTR lpszBuf, UINT nMaxBuf)


{
ASSERT(AfxIsValidAddress(lpszBuf, nMaxBuf*sizeof(TCHAR)));
#ifdef _DEBUG
// LoadString without annoying warning from the Debug kernel if the
// segment containing the string is not present
if (::FindResource(AfxGetResourceHandle(),
MAKEINTRESOURCE((nID>>4)+1), RT_STRING) == NULL)

{
lpszBuf[0] = '\0';
return 0; // not found
}
#endif //_DEBUG
int nLen = ::LoadString(AfxGetResourceHandle(), nID, lpszBuf, nMaxBuf);
if (nLen == 0)
lpszBuf[0] = '\0';
return nLen;
}
#endif
這段代碼寫的挺精妙的.
posted @
2008-12-18 19:35 Sandy 閱讀(3877) |
評論 (1) |
編輯 收藏
今天在做東西的時候,用LoadString遇到了一些問題.可能大家日后也會用到,分享一下.
LoadString 從資源載入字符串,我們一般這么用。
舉個例子:
TCHAR str[20];
LoadString(hInstance, IDS_STR, str, 20);
如果我們的字符串的長度不知道,或許它會變化的話,我們怎么來獲得資源ID對應的字符串呢?這就要用到
LoadString的另一種用法,我們可以這樣用
LPCTSTR lpcStr = (LPCTSTR)LoadString(hInstance, IDS_STR, NULL, 0);
感覺上沒有什么問題?。?br>
但是實際應用中又出現問題了,讀出的字符串沒有截斷處理,它包含了下一個ID包含的字符串或者更多。
怎么辦?在MSDN中,LoadString已經清楚地指出
lpBuffer is set to NULL, the return value is a pointer to the requested string. The caller should cast the return value to an LPCTSTR. This pointer points directly to the resource, so the string is read-only. The length of the string, not including any terminating null character, can be found in the word preceding the string.
同時它也給出了解決辦法:
To use the lpBuffer pointer, the –n flag must be set with the resource compiler, RC.
Note String resources are not null-terminated by default. When lpBuffer is set to NULL, verify whether the string resource represented by the pointer returned by LoadString is null-terminated, and if necessary, append a terminating null character to the resource before using it in your application.
一開始我沒有太明白the –n flag must be set with the resource compiler, RC.的含義,很迷惑,不知道如何解決。但是在網上尋找方法的時候,發現這么一篇文章http://lak4cyut.blogspot.com/2008/08/wm-api-loadstring.html(WM API : LoadString() 另一種使用方式),我才徹底明白過來。
我使用的是VS2005,在project->properties->Resource->Command Line中添加一個 “-n”,即可。
在運行程序,正常顯示了。
大家如遇相同問題,可以試試這個方法。
posted @
2008-12-17 20:07 Sandy 閱讀(6643) |
評論 (8) |
編輯 收藏
最近做的很多事情都涉及快捷方式,所以整理一下。
快捷方式的格式
數字#路徑 參數
數字,我不太清楚這個是代表什么含義,也沒有看到確切的說法,有人說是#后的ACSII字符的數量,
路徑,有相對路徑,也有絕對路徑。如果路徑中包含空格的話,一定要用雙引號括起來,否則會產生錯誤, 把空格以后的內容當成參數了吧,這是我認為的。
參數,有多種吧,我還沒有查資料,等查到了再補充。
舉個例子:
39#"\Windows\Camera.exe"
這是手機的程序中相機的快捷方式。顯然39不是#后的字符的數量。
路徑有時會是一些縮寫,微軟自己的程序會這么寫,如手機中的圖片和視頻,其內容為22#:MSPIMG。
:MSPIMG是什么意思呢?路徑,又是指代什么呢?通過查閱資料,發現它對應注冊表HKEY_LOCAL_MACHINE下\\SOFTWARE\\Microsoft\\Shell\\Rai中的:MSPIMG,其中“1”對應的值為pimg.exe。
快捷方式的創建
快捷方式的創建可以通過SHCreateShortcut這個函數來創建,其原型如下:
DWORD WINAPI SHCreateShortcut(
LPTSTR szShortcut,
LPTSTR szTarget
);
例如:
SHCreateShortcut( _T("\\My Documents\\Windows Media Player.lnk"), _T("\\Windows\\Ceplayer.exe"));
快捷方式路徑的獲取
快捷方式的目標路徑獲取,可以通過SHGetShortcutTarget來獲取。其原型如下:
BOOL SHGetShortcutTarget(
LPTSTR szShortcut,
LPTSTR szTarget,
int cbMax
);
例如:
TCHAR str[MAX_PATH];
SHGetShortcutTarget(_T("\\My Documents\\Windows Media Player.lnk"), str, MAX_PATH);
posted @
2008-12-14 23:10 Sandy 閱讀(568) |
評論 (0) |
編輯 收藏
最近在看代碼,寫代碼的人很喜歡用回調函數和函數指針。一直覺得回調函數和函數指針挺神秘的,所以查了一些資料,來與大家一起來分享。
什么是回調函數
簡而言之,回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(地址)作為參數傳遞給另一個函數,當這個指針被用為調用它所指向的函數時,我們就說這是回調函數。
為什么要使用回調函數
因為使用回調函數可以把調用者和被調用者分開,調用者不關心誰是被調用者,所有它需知道的,只是存在一個具有某種特定原型、某些限制條件(如返回值為int)的被調用函數?;卣{函數就好像是一個中斷處理函數,系統在符合你設定的條件時自動調用。
如何使用回調函數
使用回調函數,我們需要做三件事:
- 聲明
- 定義
- 設置觸發條件:在你的函數種把你的回調函數名稱轉化為地址作為一個參數,以便于系統調用。
聲明和定義時應注意,回調函數由系統調用,所以可以認為它屬于windows系統,不要把它當作你的某個類的成員函數。
回調函數是一個程序員不能顯示調用的函數,通過將回調函數的地址傳給調用者從而實現調用?;卣{函數是十分必要的,在我們想通過一個統一接口實現不同的內容,這時回調函數非常合適。
函數指針的聲明
對回調函數有了一個初步的了解,下面我們來說一下函數指針。因為要實現回調,必須首先定義函數指針。
void (*) ()
左邊圓括弧中的星號是函數指針聲明的關鍵。另外兩個元素是函數的返回類型(void)和右邊圓括弧中的入口參數
為函數指針聲明類型定義:
Typedef void(* pfv)()
pfv 是一個函數指針,它指向的函數沒有輸入參數,返回類型為voie。使用這個類型定義名稱可以隱藏負責的函數指針語法。
void (*p)();
void func()
{
……
}
p = func;
p的賦值可以不同,但一定要是函數的指針,并且參數和返回類型相同。
例如:
現學現賣的一個小例子
#include <iostream>
using namespace std;

typedef void (*PF)();
void func()


{
cout << "func" << endl;
}

void caller( PF pf)


{
pf();
}

int main()


{
PF p = func;
caller(p);

system("pause");

return 0;
}

調用約定
在visual c++中,可以在函數類型前加_cdecl,_stdcall或者_pascal來表示調用規范(默認為_cdecl)。調用規范影響編譯器產生的給定函數名,參數傳遞的順序,堆棧清理責任以及參數傳遞機制。
不過,在win32的程序中,我見得比較多的是CALLBACK,這個宏定義在windef.h中,
#define CALLBACK __stdcall
它約定了函數在它們返回到調用者之前,都會從堆棧中移除掉參數。
摘自:
回調函數
http://hi.baidu.com/spidermanzy/blog/item/b25b00956469c6097bf48016.html
回調函數以及鉤子函數的概念
http://zq2007.blog.hexun.com/9068988_d.html
聲明函數指針并實現回調
http://www.vckbase.com/document/viewdoc/?id=195
posted @
2008-12-07 16:56 Sandy 閱讀(13215) |
評論 (7) |
編輯 收藏
昨天,12月5日,即農歷十一月初八,我見證了別人訂婚的溫馨和浪漫,心里也暖暖的有一股溫馨的沖動。
先簡單介紹一下這兩位吧,一位是即將成為成功男士的man,已經拿到了一家非常知名企業的offer,一位是小巧可愛的心理老師,兩位也將在今年年末,步入婚姻的殿堂。令人流口水的羨慕。
一百朵玫瑰花,伴著香水百合,代表白頭偕老,男生的“你愿意嫁給我么?”,女生激動的淚水洋溢著幸福。我們當時總共10人,除去這對,其他的是四對情侶,心里都有這么一點溫馨的沖動。
幸福的時候是這么幸福,回憶過去的點滴,你會覺得男生也會這么細心,女生竟是這么體貼,幸福……
我們這一對,也走了很長的路,算算有五年多了,還在愛情長跑的路上,我們對愛很堅定,看著這么幸福的一對,我們也有所沖動。但是一切還沒有完全定下來,目前還在上學。
只能將心中的沖動埋藏在心,待某一時刻,期待我們也能帶給別人溫馨的沖動吧。
祝福這幸福的一對,百年好合,甜甜美美,也希望我們手牽著手,走到幸福的終點。
幸福……真好!
posted @
2008-12-06 10:11 Sandy 閱讀(175) |
評論 (0) |
編輯 收藏
SHGetSpecialFolderPath
作用:
獲取特定文件夾路徑
原型:
BOOL SHGetSpecialFolderPath(
HWND hwndOwner,
LPTSTR lpszPath,
int nFolder,
BOOL fCreate
);
示例:
獲得自啟動文件夾的路徑
TCHAR filePath[MAX_PATH];
::SHGetSpecialFolderPath(NULL, filePath, CSIDL_STARTUP, FALSE);
以下是nFolder值的對應情況
獲取值的機器為多普達838
CSIDL_STARTMENU —— \Windows\“開始”菜單
CSIDL_STARTUP —— \Windows\StartUp
CSIDL_WINDOWS —— \Windows
CSIDL_RECENT ——
CSIDL_PROGRAMS —— \Windows\“開始”菜單\程序
CSIDL_PROGRAM_FILES —— \Program Files
CSIDL_PERSONAL —— \My Documents
CSIDL_MYVIDEO ——
CSIDL_MYPICTURES —— \My Documents\我的圖片
CSIDL_MYMUSIC —— \My Documents\我的音樂
CSIDL_FONTS —— \Windows\Fonts
CSIDL_FAVORITES —— \Windows\Favorites
CSIDL_DESKTOPDIRECTORY ——
CSIDL_DESKTOP —— \My Documents
CSIDL_APPDATA —— \Application Data
posted @
2008-12-05 16:35 Sandy 閱讀(3866) |
評論 (0) |
編輯 收藏
摘要: 今天在網上看到的.最近在弄瀏覽器,對其方法要熟悉一些.貼出來,以備查詢. IWebBrowser2 Interface http://msdn.microsoft.com/en-us/library/aa752127(VS.85).aspx
AddressBar
...
閱讀全文
posted @
2008-12-03 13:34 Sandy 閱讀(2751) |
評論 (0) |
編輯 收藏
向大家SHOW一下,我自己畫的圓餅圖。

呵呵,自我感覺不錯。
原理很簡單,是通過畫多邊形,并填充不同的顏色來實現的。
實際上,這個圖是通過以下幾個圖拼成的。

這下大家清楚了很多了吧。
這個圖的關鍵在于弧上的各點的坐標如何得到?這個圓餅的最上面的那個圖形其實是一個橢圓。我們可以利用一個橢圓上點的計算公式來求的弧上點的坐標。

長軸為a,短軸為b,, 軸心為(x0, y0)那么橢圓上的某點坐標(x, y)為
x = x0 + a * cos(θ);
y= y0 + b * sin(θ) ;
通過這種方法計算弧上各點后,將弧平移,如下圖:

這樣我們就可以計算出柱面下半部分的弧線坐標了。
呵呵,這樣就簡單多了吧。
posted @
2008-12-02 22:51 Sandy 閱讀(2918) |
評論 (5) |
編輯 收藏