花了两天多的时间做了一个“信使服务”程序,呵呵,以前在网上见到过,居然要花钱注册的。其实就是用了那个NetMessageBufferSend函数,再用一个NetMessageNameAdd函数把随便一个名字加进去,就可以把自己的身份隐藏了。以前在学校的时候由于用的是固定IP,经常收到的很多广告就是用这种方式发送的。有时候在课堂上老师正在讲课,突然就冒出这么一个窗口来,十分气人,所以我们一般都把Messenger服务给屏蔽掉,嘿嘿,现在我居然做起这个东西来。
通过命令行方式用net send命令就可以发这种消息,不过会暴露你的计算机名,因为它没有选择名字的参数,而使用NetMessageBufferSend则可以使用你计算机上的任意一个“名字”,那个名字又叫“消息别名”,似乎跟计算机名不一样,但是默认的“消息别名”就是计算机名。开始的时候以为可以随便给NetMessageBufferSend的from参数赋值,网上很多人也这样说,但我试了总是出错。后来才发现那个名字必须是计算机上已经有的“消息别名”之一。那我怎么才能随便用一个名字呢?于是就必须用到NetMessageNameAdd函数,这个函数可以增加一个随便起的消息别名,接着就可以把这个名字传给NetMessageBufferSend来发送了。
NetMessageBufferSend的原型是:
NET_API_STATUS NetMessageBufferSend(
LPCWSTR servername,
LPCWSTR msgname,
LPCWSTR fromname,
LPBYTE buf,
DWORD buflen
);
开始的时候以为第一个参数servername就是目标的名字,后来才知道原来是要运行这个函数的服务器的名字,因为这个函数一般用于局域网管理,有时候需要控制某台服务器来运行程序。如果在本机上运行,把这个参数设成NULL就可以了。以Net开头的很多函数都有这个参数。
第二个参数msgname,在网上看到很多人说这个就是指向要发的消息字符串的指针,跟第4个参数buf是一样的。我试了很错次都是失败的。后来在某个地方看到一个牛人的解释才知道这个msgname的意思根本就不是“消息字符串的名字”,而是目标机器的“消息别名”!一般就是目标的计算机名了,如果那台计算机还有其他消息别名的话,这个也可以是其中一个,不过发消息的那台机器也要知道该别名指的是那台计算机才行。
第三个参数最折腾人了,总以为随便起一个名字就可以了,后来跟踪了错误信息,说没有找到这个名字,想起以前用net send玩的时候还用过一个net name,通过net name xxx /add就可以增加一个名字xxx,然后用net send 就可以给xxx发消息了。既然说没找到这个名字,是不是那个名字还没通过net name来加进去呢?于是我就用了最古老的一种方法,通过system()函数执行net name命令,把随意输入的名字加进去,再用那个名字发消息,哈哈,成功了。不过要弹出那个黑黑的cmd 窗口比较难看。再到MSDN看看,有个NetNameAdd函数,正好可以干这种事情,呵呵,搞定。
LPCWSTR与LPBYTE也比较难受。LPCWSTR的意思是“常量宽字符串”,因为Net系列函数使用的都是UNICODE。那怎么把CString转换成这个东西呢?CString本身可以被看作LPCTSTR,即“常量T字符串”,呵呵,T字符就是那种“骑墙”字符,你定义了_UNICODE,它就表示W,宽字符,没有定义_UNICODE,它就表示一般的8比特字符,为了同时兼容ASCII版本和UNICODE版本,定义字符串的时候最好都用T字符。那怎么把CString转换成宽字符串呢?在网上看到有人说用一些宏就可以了。那些宏是在atlconv.h里面定义的,包括:
ATL String Conversion Macros
A2BSTR | OLE2A | T2A | W2A |
A2COLE | OLE2BSTR | T2BSTR | W2BSTR |
A2CT | OLE2CA | T2CA | W2CA |
A2CW | OLE2CT | T2COLE | W2COLE |
A2OLE | OLE2CW | T2CW | W2CT |
A2T | OLE2T | T2OLE | W2OLE |
A2W | OLE2W | T2W | W2T |
每次使用前,都要在前面加上一句:
USES_CONVERSION;
然后就可以很方便地在这些类型之间转换了。例如要把CString str转换成LPCWSTR lpw,只要:
#include <atlconv.h>
...
USES_CONVERSION;
LPCWSTR lpw=T2W(str);
这样,前三个参数就可以搞定了。
第四个参数是LPBYTE,这又是一种奇怪的类型,从字面上看是指向BYTE类型的指针。在C里面是没有BYTE类型的,跟它最象的就是unsigned char类型了,实际上就是它。那怎么把CString转换成这个呢?首先,要把CString转换成LPCWSTR,因为Net用的都是UNICODE,里面的字符串编码必须是UNICODE;接着,由于LPCWSTR的每个字符是16bit,不符合LPBYTE的要求,所以还必须强制转换成LPBYTE。这样,可以写成:
LPBYTE=(LPBYTE)T2W(CString);
不过还是分步转换好一点:
LPCWSTR=T2W(CString);
LPBYTE=(LPBYTE)LPCWSTR;
因为后面一个参数buflen要用到LPCWSTR的长度。buflen是以字节来计算的buf的长度,通过wcslen(LPCWSTR)可以得到LPCWSTR的字符个数,然后每个字符的长度是sizeof(wchar_t)字节,那么LPCWSTR的长度就是wcslen(LPCWSTR)*sizeof(wchar_t)字节。
我想用CString的GetLength()函数来做,但是总是失败,不知道为什么。CString.GetLength()*sizeof(TCHAR)总是长度不够,后面有一个或几个字符截断了。
到这里,输入的东西就搞定了,搞定了这个,后面的群发、局域网计算机列表就问题不大了。下次再把心得写出来