我住包子山

this->blog.MoveTo("blog.baozishan.in")

#

ATL初学小记

 初学ATL...从头开始吧


<B>#include <shlobj.h>
#include <comdef.h></B>
 
class ATL_NO_VTABLE CDLLRegShlExt :
  public CComObjectRootEx<CComSingleThreadModel>,
  public CComCoClass<CDLLRegShlExt, &CLSID_DllRegShlExt>,
  <STRIKE>public IDllRegShlExt,</STRIKE>
  <B>public IShellExtInit</B>
{
  BEGIN_COM_MAP(CDLLRegShlExt)
    <STRIKE>COM_INTERFACE_ENTRY(IDllRegShlExt)</STRIKE>
    <B>COM_INTERFACE_ENTRY(IShellExtInit)</B>
  END_COM_MAP()


template<
class ThreadModel
>
class CComObjectRootEx : public CComObjectRootBase

这里CComObjectRootEx是一个ATL的类
我看来大概是管理Com对象的一个类,是搞计数的吧,一个实现COM的类必须要继承它的
它还是个模板类,模板参数是ThreadModel:
CComSingleThreadModel, CComMultiThreadModel, or CComMultiThreadModelNoCS. You can accept the server's default thread model by setting ThreadModel to CComObjectThreadModel or CComGlobalsThreadModel

A class that implements a COM server must inherit from CComObjectRootEx or CComObjectRoot.


template<
class T,
const CLSID* pclsid = &CLSID_NULL
>
class CComCoClass

CComCoClass的类应该之前

 


 继续加一些新的东西 看MSDN Magzine 关于COM的东西,提到一些对于rgs注册脚本的使用前提
Way back in the November and December 1999 issues of Microsoft Systems Journal (now known as MSDN®Magazine), I showed how to build a Band Object for Internet Explorer using the Active Template Library (ATL) IRegistrar interface. (Band Objects need to register a special category CATID_DeskBand.) IRegistrar is a really cool tool that lets you write a registration script (.RGS file) to add your registry entries, instead of calling registry functions like RegOpenKey, RegSetValue, and the rest. Figure 1 shows a typical script.

这一段讲IRegistrar接口的作用,hoho

 

posted @ 2007-05-16 23:03 Gohan 阅读(345) | 评论 (0)编辑 收藏

结束与Winpcap的学习,有机会可以学DX

MFC的问题就是在XP下占内存比较大,我不知道怎么优化,以后有空可以用win32 sdk完成一些事情.
最近在学关于FTP 协议的一些相关文档,准备在网络应用方面再学习一点.
http://cr.yp.to/ftp.html
一个ftp协议的介绍...个人觉得很全面

posted @ 2007-05-14 17:01 Gohan 阅读(164) | 评论 (0)编辑 收藏

winpcap学了点

东西这几天就能弄个大概了winpcap弄差不多,socket用mfc的就能弄好了。
mfc程序真的占用内存好多,做好这个以后决定用sdk /c 重写这个东西

posted @ 2007-05-05 01:19 Gohan 阅读(216) | 评论 (0)编辑 收藏

今天考试结束,学习了解一下winpcap。。

信号与系统考得很烂,准备了一晚上并不算理想,主要原因是高数计算基础烂+以及一些常用式没记住
有些东西很麻烦,很多东西有文档什么的记什么嘛

今天看了点winpcap的文档
做了和单纯用raw的对比
发现winpcap得到的包大小跟ipHeader的包头大小关系很奇怪,不是线形,所以可以解释为什么raw计算流量根本不准。。。不知道什么原因。。

来大学还是跟过去一般的懒+贪玩。。。想改掉

五一把计电算网速的东西弄出来吧。。

今晚开始不打游戏。。

posted @ 2007-04-27 22:13 Gohan 阅读(193) | 评论 (0)编辑 收藏

这个月开始只学CS了

开学到现在一直懒洋洋的,早上老睡到10点多12点,落了不少课。
假期到现在断续的学winsock,在做网速检测实现发现用原始套接字raw捕获消息报得到的数据(包的大小)很不准确,以前用CS写的那个调用别人的一个Develop Kit 的测速软件却还比较准,不知道是为什么??个人直觉判断是因为那个develop kit用了winpcap,要写的东西只有先放放了。

GPCT为了推广他们的技术办了个比赛,我和WF同学合作准备把它拿下,CS以前没怎么学,别的什么的也没会多少,还是搞搞突击吧。好好抓住这次锻炼机会吧

posted @ 2007-03-31 16:17 Gohan 阅读(203) | 评论 (0)编辑 收藏

VC++的Unicode编程


  

VC++的Unicode编程
来自 vckbase  我最近在使用VS2005做VC++/MFC方面的制作遇到了一些问题,这篇文章能够解决很多关于宽字符的周边。。呵呵,直接贴过来了,虽然很多贴图是VC6的
作者:韩耀旭

下载源代码

一、什么是Unicode

  先从ASCII说起,ASCII是用来表示英文字符的一种编码规范。每个ASCII字符占用1个字节,因此,ASCII编码可以表示的最大字符数是255(00H—FFH)。其实,英文字符并没有那么多,一般只用前128个(00H—7FH,最高位为0),其中包括了控制字符、数字、大小写字母和其它一些符号。而最高位为1的另128个字符(80H—FFH)被称为“扩展ASCII”,一般用来存放英文的制表符、部分音标字符等等的一些其它符号。
  这种字符编码规则显然用来处理英文没有什么问题。但是面对中文、阿拉伯文等复杂的文字,255个字符显然不够用。
于是,各个国家纷纷制定了自己的文字编码规范,其中中文的文字编码规范叫做“GB2312—80”,它是和ASCII兼容的一种编码规范,其实就是利用扩展ASCII没有真正标准化这一点,把一个中文字符用两个扩展ASCII字符来表示,以区分ASCII码部分。
  但是这个方法有问题,最大的问题就是中文的文字编码和扩展ASCII码有重叠。而很多软件利用扩展ASCII码的英文制表符来画表格,这样的软件用到中文系统中,这些表格就会被误认作中文字符,出现乱码。
  另外,由于各国和各地区都有自己的文字编码规则,它们互相冲突,这给各国和各地区交换信息带来了很大的麻烦。
要真正解决这个问题,不能从扩展ASCII的角度入手,而必须有一个全新的编码系统,这个系统要可以将中文、法文、德文……等等所有的文字统一起来考虑,为每一个文字都分配一个单独的编码。

于是,Unicode诞生了。

  Unicode也是一种字符编码方法,它占用两个字节(0000H—FFFFH),容纳65536个字符,这完全可以容纳全世界所有语言文字的编码。
在Unicode里,所有的字符被一视同仁,汉字不再使用“两个扩展ASCII”,而是使用“1个Unicode”,也就是说,所有的文字都按一个字符来处理,它们都有一个唯一的Unicode码。

二、使用Unicode编码的好处

  使用Unicode编码可以使您的工程同时支持多种语言,使您的工程国际化。
  另外,Windows NT是使用Unicode进行开发的,整个系统都是基于Unicode的。如果调用一个API函数并给它传递一个ANSI(ASCII字符集以及由此派生并兼容的字符集,如:GB2312,通常称为ANSI字符集)字符串,那么系统首先要将字符串转换成Unicode,然后将Unicode字符串传递给操作系统。如果希望函数返回ANSI字符串,系统就会首先将Unicode字符串转换成ANSI字符串,然后将结果返回给您的应用程序。进行这些字符串的转换需要占用系统的时间和内存。如果用Unicode来开发应用程序,就能够使您的应用程序更加有效地运行。

下面例举几个字符的编码以简单演示ANSI和Unicode的区别:

字符  A  N  和
ANSI码  41H  4eH  cdbaH
Unicode码  0041H  004eH  548cH

三、使用C++进行Unicode编程

  对宽字符的支持其实是ANSI C标准的一部分,用以支持多字节表示一个字符。宽字符和Unicode并不完全等同,Unicode只是宽字符的一种编码方式。

1、宽字符的定义

  在ANSI中,一个字符(char)的长度为一个字节(Byte)。使用Unicode时,一个字符占据一个字,C++在wchar.h头文件中定义了最基本的宽字符类型wchar_t:

typedef unsigned short wchar_t;

从这里我们可以清楚地看到,所谓的宽字符就是无符号短整数。

2、常量宽字符串

  对C++程序员而言,构造字符串常量是一项经常性的工作。那么,如何构造宽字符字符串常量呢?很简单,只要在字符串常量前加上一个大写的L就可以了,比如:

wchar_t *str1=L" Hello";

这个L非常重要,只有带上它,编译器才知道你要将字符串存成一个字符一个字。还要注意,在L和字符串之间不能有空格。

3、宽字符串库函数

为了操作宽字符串,C++专门定义了一套函数,比如求宽字符串长度的函数是

size_t __cdel wchlen(const wchar_t*);

  为什么要专门定义这些函数呢?最根本的原因是,ANSI下的字符串都是以’\0’来标识字符串尾的(Unicode字符串以“\0\0”结束),许多字符串函数的正确操作均是以此为基础进行。而我们知道,在宽字符的情况下,一个字符在内存中要占据一个字的空间,这就会使操作ANSI字符的字符串函数无法正确操作。以”Hello”字符串为例,在宽字符下,它的五个字符是:
0x0048 0x0065 0x006c 0x006c 0x006f
在内存中,实际的排列是:

48 00 65 00 6c 00 6c 00 6f 00

  于是,ANSI字符串函数,如strlen,在碰到第一个48后的00时,就会认为字符串到尾了,用strlen对宽字符串求长度的结果就永远会是1!

4、用宏实现对ANSI和Unicode通用的编程

  可见,C++有一整套的数据类型和函数实现Unicode编程,也就是说,您完全可以使用C++实现Unicode编程。
如果我们想要我们的程序有两个版本:ANSI版本和Unicode版本。当然,编写两套代码分别实现ANSI版本和Unicode版本完全是行得通的。但是,针对ANSI字符和Unicode字符维护两套代码是非常麻烦的事情。为了减轻编程的负担,C++定义了一系列的宏,帮助您实现对ANSI和Unicode的通用编程。
  C++宏实现ANSI和Unicode的通用编程的本质是根据”_UNICODE”(注意,有下划线)定义与否,这些宏展开为ANSI或Unicode字符(字符串)。

如下是tchar.h头文件中部分代码摘抄:

#ifdef  _UNICODE
typedef wchar_t     TCHAR;
#define __T(x)      L##x
#define _T(x)       __T(x)
#else
#define __T(x)      x
typedef char            TCHAR;
#endif 
  可见,这些宏根据”_UNICODE” 定义与否,分别展开为ANSI或Unicode字符。 tchar.h头文件中定义的宏可以分为两类:

A、实现字符和常量字符串定义的宏我们只列出两个最常用的宏:

未定义_UNICODE(ANSI字符) 定义了_UNICODE(Unicode字符)
TCHAR char wchar_t
_T(x) x L##x

注意:
  
“##”是ANSI C标准的预处理语法,它叫做“粘贴符号”,表示将前面的L添加到宏参数上。也就是说,如果我们写_T(“Hello”),展开后即为L“Hello”

B、实现字符串函数调用的宏

C++为字符串函数也定义了一系列宏,同样,我们只例举几个常用的宏:

未定义_UNICODE(ANSI字符) 定义了_UNICODE(Unicode字符)
_tcschr strchr wcschr
_tcscmp strcmp wcscmp
_tcslen strlen wcslen

四、使用Win32 API进行Unicode编程

Win32 API中定义了一些自己的字符数据类型。这些数据类型的定义在winnt.h头文件中。例如:

typedef char CHAR; 
typedef unsigned short WCHAR;    // wc,   16-bit UNICODE character 
typedef CONST CHAR *LPCSTR, *PCSTR; 
Win32 API在winnt.h头文件中定义了一些实现字符和常量字符串的宏进行ANSI/Unicode通用编程。同样,只例举几个最常用的:
#ifdef  UNICODE 
typedef WCHAR TCHAR, *PTCHAR;
typedef LPWSTR LPTCH, PTCH;
typedef LPWSTR PTSTR, LPTSTR;
typedef LPCWSTR LPCTSTR;
#define __TEXT(quote) L##quote      // r_winnt
#else   /* UNICODE */               // r_winnt
typedef char TCHAR, *PTCHAR;
typedef LPSTR LPTCH, PTCH;
typedef LPSTR PTSTR, LPTSTR;
typedef LPCSTR LPCTSTR;
#define __TEXT(quote) quote         // r_winnt
#endif /* UNICODE */                // r_winnt
  从以上头文件可以看出,winnt.h根据是否定义了UNICODE(没有下划线),进行条件编译。
   Win32 API也定义了一套字符串函数,它们根据是否定义了“UNICODE”分别展开为ANSI和Unicode字符串函数。如:lstrlen。API的字符串操作函数和C++的操作函数可以实现相同的功能,所以,如果需要的话,建议您尽可能使用C++的字符串函数,没必要去花太多精力再去学习API的这些东西。
  也许您从来没有注意到,Win32 API实际上有两个版本。一个版本接受MBCS字符串,另一个接受Unicode字符串。例如:其实根本没有SetWindowText()这个API函数,相反,有SetWindowTextA()和SetWindowTextW()。后缀A表明这是MBCS函数,后缀W表示这是Unicode版本的函数。这些API函数的头文件在winuser.h中声明,下面例举winuser.h中的SetWindowText()函数的声明部分:
#ifdef UNICODE
#define SetWindowText  SetWindowTextW
#else
#define SetWindowText  SetWindowTextA
#endif // !UNICODE
  可见,API函数根据定义UNICODE与否决定指向Unicode版本还是MBCS版本。
  细心的读者可能已经注意到了UNICODE和_UNICODE的区别,前者没有下划线,专门用于Windows头文件;后者有一个前缀下划线,专门用于C运行时头文件。换句话说,也就是在ANSI C++语言里面根据_UNICODE(有下划线)定义与否,各宏分别展开为Unicode或ANSI字符,在Windows里面根据UNICODE(无下划线)定义与否,各宏分别展开为Unicode或ANSI字符。
  在后面我们将会看到,实际使用中我们不加严格区分,同时定义_UNICODE和UNICODE,以实现UNICODE版本编程。

五、VC++6.0中编写Unicode编码的应用程序

  VC++ 6.0支持Unicode编程,但默认的是ANSI,所以开发人员只需要稍微改变一下编写代码的习惯便可以轻松编写支持UNICODE的应用程序。
  使用VC++ 6.0进行Unicode编程主要做以下几项工作:

1、为工程添加UNICODE和_UNICODE预处理选项。

  具体步骤:打开[工程]->[设置…]对话框,如图1所示,在C/C++标签对话框的“预处理程序定义”中去除_MBCS,加上_UNICODE,UNICODE。(注意中间用逗号隔开)改动后如图2:


图一


图二

  在没有定义UNICODE和_UNICODE时,所有函数和类型都默认使用ANSI的版本;在定义了UNICODE和_UNICODE之后,所有的MFC类和Windows API都变成了宽字节版本了。

2、设置程序入口点

  因为MFC应用程序有针对Unicode专用的程序入口点,我们要设置entry point。否则就会出现连接错误。
  设置entry point的方法是:打开[工程]->[设置…]对话框,在Link页的Output类别的Entry Point里填上wWinMainCRTStartup。


图三

3、使用ANSI/Unicode通用数据类型

  微软提供了一些ANSI和Unicode兼容的通用数据类型,我们最常用的数据类型有_T ,TCHAR,LPTSTR,LPCTSTR。
  顺便说一下,LPCTSTR和const TCHAR*是完全等同的。其中L表示long指针,这是为了兼容Windows 3.1等16位操作系统遗留下来的,在Win32 中以及其它的32位操作系统中,long指针和near指针及far修饰符都是为了兼容的作用,没有实际意义。P(pointer)表示这是一个指针;C(const)表示是一个常量;T(_T宏)表示兼容ANSI和Unicode,STR(string)表示这个变量是一个字符串。综上可以看出,LPCTSTR表示一个指向常固定地址的可以根据一些宏定义改变语义的字符串。比如:

TCHAR* szText=_T(“Hello!”);
TCHAR szText[]=_T(“I Love You”);
LPCTSTR lpszText=_T(“大家好!”);
使用函数中的参数最好也要有变化,比如:
MessageBox(_T(“你好”));

  其实,在上面的语句中,即使您不加_T宏,MessageBox函数也会自动把“你好”字符串进行强制转换。但我还是推荐您使用_T宏,以表示您有Unicode编码意识。

4、修改字符串运算问题

  一些字符串操作函数需要获取字符串的字符数(sizeof(szBuffer)/sizeof(TCHAR)),而另一些函数可能需要获取字符串的字节数sizeof(szBuffer)。您应该注意该问题并仔细分析字符串操作函数,以确定能够得到正确的结果。
ANSI操作函数以str开头,如strcpy(),strcat(),strlen();
Unicode操作函数以wcs开头,如wcscpy,wcscpy(),wcslen();
ANSI/Unicode操作函数以_tcs开头 _tcscpy(C运行期库);
ANSI/Unicode操作函数以lstr开头 lstrcpy(Windows函数);
考虑ANSI和Unicode的兼容,我们需要使用以_tcs开头或lstr开头的通用字符串操作函数。

六、举个Unicode编程的例子

第一步:
  打开VC++6.0,新建基于对话框的工程Unicode,主对话框IDD_UNICODE_DIALOG中加入一个按钮控件,双击该控件并添加该控件的响应函数:

void CUnicodeDlg::OnButton1() 
{
	TCHAR* str1=_T("ANSI和UNICODE编码试验");
	m_disp=str1;
	UpdateData(FALSE);
}
  添加静态文本框IDC_DISP,使用ClassWizard给该控件添加CString类型变量m_disp。使用默认ANSI编码环境编译该工程,生成Unicode.exe。

第二步:
  打开“控制面板”,单击“日期、时间、语言和区域设置”选项,在“日期、时间、语言和区域设置”窗口中继续单击“区域和语言选项”选项,弹出“区域和语言选项”对话框。在该对话框中,单击“高级”标签,将“非Unicode的程序的语言”选项改为“日语”,单击“应用”按钮,如图四:


图四

弹出的对话框单击“是”,重新启动计算机使设置生效。
运行Unicode.exe程序并单击“Button1”按钮,看,静态文本框出现了乱码。

第三步:
  改为Unicode编码环境编译该工程,生成Unicode.exe。再次运行Unicode.exe程序并单击“Button1”按钮。看到Unicode编码的优势了吧。

就说这些吧,祝您好运。




最新评论 [发表评论][文章投稿] 查看所有评论 推荐给好友 打印

还有那个转换函数没有说,记得有个参数是表示区域码的
  中文是936 日语932,记得要用,测的时候中日英下面都跑一下,不是单单改内码跑,最好是在各自语言版本的操作系统下面跑。 ( iv3ljf 发表于 2007-2-1 12:27:00)
 
楼主说的没多大用,关键的Unicode在98下的问题没有说
Dll和EXE在98下使用Unicode的问题没有说

等于没说 ( sheds 发表于 2007-1-4 20:18:00)
 
好文章,谢谢。最近正为这个苦恼呢 ( freewind2000 发表于 2007-1-3 22:14:00)
 
.......................................................
More...


版权所有 © 2006 VC知识库 

posted @ 2007-03-11 10:16 Gohan 阅读(813) | 评论 (0)编辑 收藏

[一篇VC小文章]VC++制作一个最小化最小托盘的8步骤(Minimize your app to systray in 8 easy steps)翻译完

Minimize your app to systray in 8 easy steps

By Yasar Arslan. From codeproject




这篇文章内容比较基础,最近看到觉得有用,顺便翻译一下
有空可以写一个自己的TrayIcon类,化简这些原始的操作。

Introduction

这篇文章解析了 Shell_NotifyIcon 这个函数用法--用来建立你自己的应用程序的系统托盘图标.
这篇文章给了基本的缩小到托盘的操作过程并让你从中了解.
这篇文章提供8个简单的步骤让你成功的实现在你的程序中建立系统托盘图标.
源代码提供了一个基于对话框的演示程序.

Tray Icons

为了用托盘图标你需要用一个shell函数 :)

BOOL Shell_NotifyIcon( DWORD dwMessage, PNOTIFYICONDATA pnid );

The dwMessage 可选的参数包括 the NIM_ADD,NIM_DELETE and NIM_MODIFY功能分别是添加删除以及修改图标于系统图标.

PNOTIFYICONDATA 结构包括这些系统需要处理的任务图标状态区域消息等信息.
typedef  struct _NOTIFYICONDATA {
    DWORD cbSize;
    HWND hWnd;
    UINT uID;
    UINT uFlags;
    UINT uCallbackMessage;
    HICON hIcon;
    #if (_WIN32_IE < 0x0500)
        TCHAR szTip[64];
    #else
        TCHAR szTip[128];
    #endif    #if (_WIN32_IE >= 0x0500)
        DWORD dwState;
        DWORD dwStateMask;
        TCHAR szInfo[256];
        union {
            UINT  uTimeout;
            UINT  uVersion;
        } DUMMYUNIONNAME;
        TCHAR szInfoTitle[64];
        DWORD dwInfoFlags;
    #endif    #if (_WIN32_IE >= 0x600)
        GUID guidItem;
    #endif
} NOTIFYICONDATA, *PNOTIFYICONDATA;

*Note: 更完全的信息可以去参考MSDN

Creating the Application

Create a new VC++ dialog based project and call it TrayMin.
创建一个名叫TrayMin的基于对话框的VC++工程

Step: 1

自定义消息于 TrayMinDlg.h 头文件.

				#define WM_TRAY_MESSAGE (WM_USER + 1)
		

The WM_USER 常量用来帮助用户定义自己的消息被用来建立个人的窗口类, 定义时通常用这种格式 WM_USER+X, 这里 X 是一个整形变量.

*更详细的看MSDN

Step: 2

现在在Now add the DECLARE_MESSAGE_MAP() 之前添加下面的用户函数吧( TrayMinDlg.h file)   afx_msg void OnTrayNotify(WPARAM wParam, LPARAM lParam);
 


当添加一个图标到托盘时这有一个图标的回调消息,注意到 NOTIFYICONDATA 结构中有uCallbackMessage成员是回调消息识别的关键,它会被传给NIM_ADD(我们之后将会见到更详细的)。当添加托盘图标这个事件发生时,系统发送一个回调函数到由hWnd成员对象指定的窗口过程(winproc),wParam 参数可以用来被识别究竟发生了什么操作。lParam参数存放发生事件相关的鼠标或者键盘消息。举个例子,当一个鼠标指针指向一个托盘图标,lParam将包括WM_MOUSEMOVE

Step: 3


现在添加下面的这行在消息宏中(MessageMap)在TrayMinDlg.cpp

ON_MESSAGE(WM_TRAY_MESSAGE,OnTrayNotify)
 

现在应该是这样的.

    BEGIN_MESSAGE_MAP(CTrayMinDlg, CDialog)
      //{{AFX_MSG_MAP(CTrayMinDlg)
      ON_WM_SYSCOMMAND()
      ON_WM_PAINT()
      ON_WM_QUERYDRAGICON()
      ON_MESSAGE(WM_TRAY_MESSAGE ,OnTrayNotify)
      //}}AFX_MSG_MAP
    END_MESSAGE_MAP()

  

Step: 4

现在在TrayMinDlg.cpp 定义OnTrayNotify函数,不要忘记在函数头部添加afx_msg。

  afx_msg void CTrayMinDlg::OnTrayNotify(WPARAM wParam, LPARAM lParam)
  {
    UINT uID; 
    UINT uMsg; 
 
    uID = (UINT) wParam;
    uMsg = (UINT) lParam; 
 
  
    if (uID != 1)
      return;
  
    CPoint pt;  
  
  
    switch (uMsg ) 
    { 

    case WM_LBUTTONDOWN:
      GetCursorPos(&pt);
      ClientToScreen(&pt);
      OnTrayLButtonDown(pt);
      break;
  
    case WM_RBUTTONDOWN:
    case WM_CONTEXTMENU:
      GetCursorPos(&pt);
      OnTrayRButtonDown(pt);
      break;

    } 
    return; 
  }
  

Step: 5

现在在TrayMinDlg类添加两个成员函数来相应鼠标事件。

实现鼠标左键单击的相应

  • 函数类型:void  
  • 函数声明: OnTrayLButtonDown(CPoint pt)

实现鼠标右键单击的相应

  • 函数类型: void
  • 函数声明: OnTrayRButtonDown(CPoint pt)

OnTrayLButtonDown(CPoint pt)的定义如下.

				void CTrayMinDlg::OnTrayLButtonDown(CPoint pt)
    {  
      MessageBox("You have clicked Left mouse Button ");
    }
  

The Declaration of OnTrayRButtonDown(CPoint pt) is as following.

				void CTrayMinDlg::OnTrayRButtonDown(CPoint pt)
    {  
      //m_menu is the member of CTrayMinDlg as CMenu m_menu;
      m_menu.GetSubMenu(0)->TrackPopupMenu(TPM_BOTTOMALIGN|
       TPM_LEFTBUTTON|TPM_RIGHTBUTTON,pt.x,pt.y,this);      
    }
  

Step: 6

Add two member variable to the CTrayMinDlg.
为CTrayMinDlg添加两个成员变量

  • Variable Type: NOTIFYICONDATA
  • Variable Name: m_TrayData;
  • Variable Type: CMenu
  • Variable Name: m_menu;


现在添加菜单资源

Step: 7

现在画一个最小化的按钮在对话框设计中
并且添加这个按钮的执行函数
void CShellDlg::OnMinimize() 
  {
    m_TrayData.cbSize = sizeof(NOTIFYICONDATA);
    //Size of this structure, in bytes. 
    
    
    m_TrayData.hWnd  = this->m_hWnd;
    //Handle to the window that receives notification //messages associated with an icon in the taskbar //status area. The Shell uses hWnd and uID to //identify which icon to operate on when //Shell_NotifyIcon is invoked. 
  
    m_TrayData.uID = 1;
    //Application-defined identifier of the taskbar icon.//The Shell uses hWnd and uID to identify which icon //to operate on when Shell_NotifyIcon is invoked. You// can have multiple icons associated with a single //hWnd by assigning each a different uID. 

    m_TrayData.uCallbackMessage  = WM_TRAY_MESSAGE;
    //Application-defined message identifier. The system //uses this identifier to send notifications to the //window identified in hWnd. These notifications are //sent when a mouse event occurs in the bounding //rectangle of the icon, or when the icon is selected //or activated with the keyboard. The wParam parameter //of the message contains the identifier of the taskbar //icon in which the event occurred. The lParam parameter //holds the mouse or keyboard message associated with the// event. For example, when the pointer moves over a //taskbar icon, lParam is set to WM_MOUSEMOVE. 
    


    m_TrayData.hIcon = this->m_hIcon;
    //Handle to the icon to be added, modified, or deleted
    
    strcpy(m_TrayData.szTip,"My Icon");
    //Pointer to a null-terminated string with the text //for a standard ToolTip. It can have a maximum of 64 //characters including the terminating NULL. 
    
    
    m_TrayData.uFlags = NIF_ICON|NIF_MESSAGE;
    //Flags that indicate which of the other members contain 
    valid data.  
  

    BOOL bSuccess = FALSE;
    BOOL BSus = FALSE;

    BSus = m_menu.LoadMenu(IDR_MENU1);
    if(!(BSus))
      MessageBox("Unabled to Loa menu");

    bSuccess = Shell_NotifyIcon(NIM_ADD,&m_TrayData);

    if(!(bSuccess))
      MessageBox("Unable to Set Tary Icon");
    else
    {
      this->ShowWindow(SW_MINIMIZE);
      this->ShowWindow(SW_HIDE);

    }
  }
  
  

Step: 8


在退出菜单的执行函数写下如下

Shell_NotifyIcon(NIM_DELETE,&m_TrayData);
  DestroyWindow();


现在可以运行程序,并且尝试最小化按钮的使用(他会最小化导系统托盘)。
现在尽情发挥,完善这些步骤,完成自己的系统托盘图标吧!

Yasar Arslan

posted @ 2007-03-06 19:06 Gohan 阅读(1811) | 评论 (0)编辑 收藏

翻译一篇文章Introduction to Multi-threaded Code 多线程编程的一些代码 已经全译好了

Someone recently asked me what I recommend for synchronizing worker threads and I suggested setting an event. This person's response was that you could not do that since worker threads do not support a message pump (UI threads are required to support messages). The confusion here is that events and messages are different animals under windows.

我忘记了我从哪里copy的这些例子代码,他们可是非常简单而有趣的。如果有人知道这些代码的作者,我一定要好好感谢你和这位作者。

注意这里有很多对于没有提及的MFC的支持。像_beginthread(一个C运行时库调用)的API可以在MFC应用程序中替换成AfxBeginThread

无同步(No Synchronization)

这第一个例子描述了两个互不同步的线程。进程中的首要线程--主函数循环,输出全局整形数组的内容。还有一个线程“Thread”不停的给数组每个元素+1。
 The thread called "Thread" continuously populates the global array of integers.

				  #include <process.h>
				  #include <stdio.h>
				int a[ 5 ];
  
  void Thread( void* pParams )
  { int i, num = 0;
  
    while ( 1 )
    { 
       for ( i = 0; i < 5; i++ ) a[ i ] = num;
       num++;
    }
  }
  
  int main( void )
  { 
     _beginthread( Thread, 0, NULL );
  
     while( 1 )
        printf("%d %d %d %d %d\n", 
               a[ 0 ], a[ 1 ], a[ 2 ],
               a[ 3 ], a[ 4 ] );
  
   return0;
  }

注意这个例子的输出,红色的数处在一个主线程抢先于Thread工作过程中执行的打印动作

81751652 81751652 81751651 81751651 81751651
81751652 81751652 81751651 81751651 81751651
83348630 83348630 83348630 83348629 83348629
83348630 83348630 83348630 83348629 83348629
83348630 83348630 83348630 83348629 83348629

 

关键区域/临界区域 对象(Critical Section Objects)

如果你想让主线程等待Thread线程处理好全局数组再做打印,一种解决方法是使用关键区域对象。
关键区域对象提供同步于使用互斥器(Mutex)对象很相似, 除了关键区域对象之能在一个进程内发挥效用。Event, mutex, 以及 semaphore 对象也可以用在单进程的应用程序中, 但是关键区域对象提供一个相对快捷更加高效的同步机制. 就像互斥器一样, 一个关键区域对象只能同时被一个线程拥有, 这个关键区域能够在同时发生的数据存取时保护共享资源. 获取关键区域的先后顺序不定,可是不用太担心,系统对于每一个线程都是平等的。

     
  CRITICAL_SECTION cs;
  int a[ 5 ];
  
  void Thread( void* pParams )
  {
    int i, num = 0;
  
    while ( TRUE )
    {
       EnterCriticalSection( &cs );
       for ( i = 0; i < 5; i++ ) a[ i ] = num;
       LeaveCriticalSection( &cs );
       num++;
    }
  }
  
  int main( void )
{ InitializeCriticalSection( &cs ); _beginthread( Thread, 0, NULL ); while( TRUE ) { EnterCriticalSection( &cs ); printf( "%d %d %d %d %d\n", a[ 0 ], a[ 1 ], a[ 2 ], a[ 3 ], a[ 4 ] ); LeaveCriticalSection( &cs ); } return 0; }

If you are running Windows 9x/NT/2000, you can run this program by clicking here.

互斥器(Mutex Objects)

一个互斥器是一个信号状态的同步对象,当它不属于任何一个线程时就用信号来体现,当被拥有时他的信号状态就为None. 同一时刻只有一个线程可以拥有互斥器, 互斥器这个名字来自于他们对于并列的线程存取共享资源时表现出的行为。举个例子,避免两个线程同时写入一个共享内存,每一个线程当需要执行存取共享资源的代码时首先等待直到自己获得拥有权. 在存取共享资源之后,线程释放对互斥器的拥有权。

两个或以上的进程可以调用CreateMutex 来建立同样名字的互斥器. 实际上第一个进程建立的这个互斥器, 随后的进程只是得到了那个存在的互斥器的句柄. 这能使多进程共用一个互斥器, 当然用户应该有确保建立互斥器的进程首先启动的责任. 使用这种技术,你应该将这个 bInitialOwner标记设置成FALSE; 否则, 它可以因不同的进程最初拥有它而带来困难.

多进程可以有同一个mutex对象的句柄, 让mutex对象能够用于多进程间同步. 下面的对象共享机制是适用的:

  • 一个子进程通过CreateProcess 函数被建立,当CreateMutex的lpMutexAttributes 参数给予相应的mutex对象指针它可以继承到一个mutex对象的句柄.
  • 一个进程可以在DuplicateHandle 函数中指定一个mutex对象句柄来建立一个句柄的拷贝由其他进程使用.
  • 一个继承可以指定一个mutex的名字通过 CreateMutex 函数得到这个mutex对象的句柄.

总的来说, 如果你想要进行线程同步,临界区域更高效些.

				#include <windows.h>
				#include <process.h>
				#include <stdio.h>
  
  HANDLE hMutex;
  int a[ 5 ];
  
  void Thread( void* pParams )
  { 
     int i, num = 0;
  
     while ( TRUE )
     { 
        WaitForSingleObject( hMutex, INFINITE );
        for ( i = 0; i < 5; i++ ) a[ i ] = num;
        ReleaseMutex( hMutex );
        num++;
     }
  }
  
  int main( void )
  {
     hMutex = CreateMutex( NULL, FALSE, NULL );
     _beginthread( Thread, 0, NULL );
  
     while( TRUE )
{ WaitForSingleObject( hMutex, INFINITE ); printf( "%d %d %d %d %d\n", a[ 0 ], a[ 1 ], a[ 2 ], a[ 3 ], a[ 4 ] ); ReleaseMutex( hMutex ); } return0; }

If you are running Windows 9x/NT/2000, you can run this program by clicking here.

Event Objects事件对象

若我们想要强制第二线程在主线程完成全局数组的内容输出时执行该如何?这样的话每行的输出就只是递增1。

一个事件对象也是一个可以通过SetEvent or PulseEvent 函数设置像信号般的状态的同步对象. 下面是两种类型的事件对象.

Object Description
Manual-reset event
手动激发对象
只有使用ResetEvent 函数才可以将其设置为无激发状态. 当它在激发状态时, 它会激发所有正在等待的线程, 执行对相同 event对象的线程会立即从wait函数返回.
Auto-reset event
自动激发对象
一个只相应一个线程的wait函数的事件对象(当这个对象是激发状态),wait函数返回同时事件对象自动变成无激发状态 ,当没有线程执行wait事件对象仍然是激发状态.

event object的用处就在于它可以在它发生时向等待着的线程发出信号标志从而使其wait结束. 举个例子, 在overlapped I/O 操作时, 当异步操作完成时系统设置了那个由程序员指定(specified)的事件对象为信号状态. A 一个单一线程可以指定许多不同的事件对象在许多同时发生的overlapped 操作运作, 调用一个多对象的wait函数可以当任意一个event object激发时结束等待.

在一个线程中可使用 CreateEvent 函数建立一个event object. 在这个线程中指定这个event object 的特性是manual-reset 或者 auto-reset . 在这个线程中也可以命名一个event object. 其他进程中的线程也可以使用 OpenEvent 通过event object的名字打开一个现存event object . 另外关于mutex, event, semaphore, 以及 timer objects的其他信息, 就参考《Interprocess Synchronization》的文章.

一个线程能够用 PulseEvent 函数设置一个event object 为信号状态而后激发当前适当数量的wait线程,之后切换为无信号状态 . 对于一个manual-reset event object, 所有的等待线程被返回(release). 对于一个auto-reset event object, 这个函数只能释放一个等待的线程, 即使有更多线程在等待. 如果没有线程在函数调用时等待, PulseEvent 只是简单的将事件状态设为无信号并且返回(个人注释,这应该是跟setevent最不相同的地方!).

Collapse
				  #include <windows.h>
				  #include <process.h>
				  #include <stdio.h>
  
  HANDLE hEvent1, hEvent2;
  int a[ 5 ];
  
  void Thread( void* pParams )
  {
     int i, num = 0;

     while ( TRUE )
     {
        WaitForSingleObject( hEvent2, INFINITE );
        for ( i = 0; i < 5; i++ ) a[ i ] = num;
        SetEvent( hEvent1 );
        num++;
     }
  }
  
  int main( void )
  {
     hEvent1 = CreateEvent( NULL, FALSE, TRUE, NULL );
     hEvent2 = CreateEvent( NULL, FALSE, FALSE, NULL );
  
     _beginthread( Thread, 0, NULL );
  
     while( TRUE )
     { 
        WaitForSingleObject( hEvent1, INFINITE );
        printf( "%d %d %d %d %d\n", 
                a[ 0 ], a[ 1 ], a[ 2 ],
                a[ 3 ], a[ 4 ] );
        SetEvent( hEvent2 );
     }
     return0;
  }

If you are running Windows 9x/NT/2000, you can run this program by clicking here.

Summary of Synchronization Objects

The MSDN News for July/August 1998 has a front page article on Synchronization Objects. The following table is from that article:

Name Relative speed Cross process Resource counting Supported platforms
Critical Section Fast No No (exclusive access) 9x/NT/CE
Mutex Slow Yes No (exclusive access) 9x/NT/CE
Semaphore Slow Yes Automatic 9x/NT
Event Slow Yes Yes 9x/NT/CE
Metered Section Fast Yes Automatic 9x/NT/CE

by William T. Block


from codeproject

谢谢回复的补充 ~~,上面拼错了个词,改过。。译完了

posted @ 2007-02-16 14:06 Gohan 阅读(956) | 评论 (1)编辑 收藏

These days work..

玩太阁立志传比较堕落。。。
这两天学做了几个Win Socket几个demo,有点心得,在win32做网络编程基本了解,现在想知道怎么能做一个支持断点续传的下载软件。
那几个计划还在酝酿。
电子制作还是一无所知。。

hostent *hp;
sockaddr_in server;

下面这句话还是太生猛
server.sin_addr.s_addr=*((ULONG *)hp->h_addr);

容我再学深入一点再说

posted @ 2007-02-06 21:56 Gohan 阅读(199) | 评论 (1)编辑 收藏

继续在这写些随笔吧

之前很长一段时间没来,各方面的原因,最主要是因为登陆密码重置后我没有及时得到。
这个学期完成了,好几门科目过的很险。。。
很多东西还没学成。。
放弃netbios的学习,那本书太让我失望,直接开学WinSock。。
让一切继续

posted @ 2007-02-02 17:07 Gohan 阅读(226) | 评论 (0)编辑 收藏

仅列出标题
共16页: First 8 9 10 11 12 13 14 15 16