春暖花开
雪化了,花开了,春天来了
posts - 149,comments - 125,trackbacks - 0

为什么Microsoft code sample倾向使用ZeroMemory而不是{0}?

这是最近看的一片短文的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 阅读(686) | 评论 (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 阅读(2173) | 评论 (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 阅读(3834) | 评论 (1)编辑 收藏
今天在做东西的时候,用LoadString遇到了一些问题.可能大家日后也会用到,分享一下.

LoadString 从资源载入字符串,我们一般这么用。
举个例子:
TCHAR str[20];
LoadString(hInstance, IDS_STR, str, 20);

如果我们的字符串的长度不知道,或许它会变化的话,我们怎么来获得资源ID对应的字符串呢?这就要用到
LoadString的另一种用法,我们可以这样用
LPCTSTR lpcStr = (LPCTSTR)LoadString(hInstance, IDS_STR, NULL, 0);

感觉上没有什么问题啊?

但是实际应用中又出现问题了,读出的字符串没有截断处理,它包含了下一个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.htmlWM API : LoadString() 另一種使用方式),我才彻底明白过来。

我使用的是VS2005,在project->properties->Resource->Command Line中添加一个 “-n”,即可。

在运行程序,正常显示了。

大家如遇相同问题,可以试试这个方法。
posted @ 2008-12-17 20:07 Sandy 阅读(6587) | 评论 (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 阅读(561) | 评论 (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 阅读(13191) | 评论 (7)编辑 收藏
 

昨天,125,即农历十一月初八,我见证了别人订婚的温馨和浪漫,心里也暖暖的有一股温馨的冲动。

先简单介绍一下这两位吧,一位是即将成为成功男士的man,已经拿到了一家非常知名企业的offer,一位是小巧可爱的心理老师,两位也将在今年年末,步入婚姻的殿堂。令人流口水的羡慕。

一百朵玫瑰花,伴着香水百合,代表白头偕老,男生的“你愿意嫁给我么?”,女生激动的泪水洋溢着幸福。我们当时总共10人,除去这对,其他的是四对情侣,心里都有这么一点温馨的冲动。

幸福的时候是这么幸福,回忆过去的点滴,你会觉得男生也会这么细心,女生竟是这么体贴,幸福……

我们这一对,也走了很长的路,算算有五年多了,还在爱情长跑的路上,我们对爱很坚定,看着这么幸福的一对,我们也有所冲动。但是一切还没有完全定下来,目前还在上学。

只能将心中的冲动埋藏在心,待某一时刻,期待我们也能带给别人温馨的冲动吧。

祝福这幸福的一对,百年好合,甜甜美美,也希望我们手牵着手,走到幸福的终点。

幸福……真好!
posted @ 2008-12-06 10:11 Sandy 阅读(170) | 评论 (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 阅读(3846) | 评论 (0)编辑 收藏
     摘要: 今天在网上看到的.最近在弄浏览器,对其方法要熟悉一些.贴出来,以备查询. IWebBrowser2 Interface http://msdn.microsoft.com/en-us/library/aa752127(VS.85).aspx AddressBar ...  阅读全文
posted @ 2008-12-03 13:34 Sandy 阅读(2735) | 评论 (0)编辑 收藏
 

       向大家SHOW一下,我自己画的圆饼图。
                      

         呵呵,自我感觉不错。

         原理很简单,是通过画多边形,并填充不同的颜色来实现的。

         实际上,这个图是通过以下几个图拼成的。
                        

           这下大家清楚了很多了吧。

 

          这个图的关键在于弧上的各点的坐标如何得到?这个圆饼的最上面的那个图形其实是一个椭圆。我们可以利用一个椭圆上点的计算公式来求的弧上点的坐标。
                        

      长轴为a,短轴为b, 轴心为(x0, y0)那么椭圆上的某点坐标(x, y)

       x = x0 + a * cos(θ);

       y= y0 + b * sin(θ) ;

      通过这种方法计算弧上各点后,将弧平移,如下图:
                                   

       这样我们就可以计算出柱面下半部分的弧线坐标了。

 

       呵呵,这样就简单多了吧。

posted @ 2008-12-02 22:51 Sandy 阅读(2910) | 评论 (5)编辑 收藏
仅列出标题
共15页: First 7 8 9 10 11 12 13 14 15