jiangsheng

http://www.csdn.net/develop/author/netauthor/jiangsheng/
随笔 - 142, 评论 - 629, 引用 - 27

导航

关于

 
这下要维护3个BLOG了,faint 其他的地址:

所有的文章版权归原文作者所有,任何人需要转载文章,必须征得原文作者授权。
我的MVP配置

标签

每月存档

最新留言

广告

BUG,规范,断言和调试

好长时间没更新BLOG了,向大家拜个晚年先。最近没怎么写代码,转几篇在网易虚拟社区发的文章过来充数。

对于BUG的自信

Donald E. Knuth(高德纳)在TeX: The Program的前言中说:
"我相信,在1985年11月27日,TeX代码里面的最后一个BUG已经被发现和解决了。但是,如果代码中仍旧有BUG,我很高兴付给任何第一个发现BUG的人20.48美元(这是前一个金额的两倍,而且我计划在一年内把它翻倍。你看,我很自信!)" 

想知道后来发生了什么吗?

http://truetex.com/knuthchk.htm可以看到他写出去的支票的金额是从2.56美元开始翻倍的。微基百科中关于这种支票的文章(http://en.wikipedia.org/wiki/Knuth_reward_check)说,截至2001年10月为止,他写出去了超过两千张这样的支票,但是他的BUG支票是如此有名,以至于很多人把他的支票收藏起来而不是拿出去兑现(http://www.tug.org/whatis.html)。

有多少程序员在发布产品的时候可以这样自信地声明产品没有问题?

遗憾的是,现在的程序员经常把发现BUG的责任推给测试人员——“不用担心,测试人员会发现所有BUG的,这是他们的工作”。实际上,测试人员并没有开发人员的条件,他们不可能进行源代码级别的调试,很大程度上只能靠运气——没错,是靠运气,如果一个BUG很容易被发现,程序员不太可能自己没有发现它——来发现BUG。

还有一些人干脆就认为BUG是不可避免的,或者认为不值得这么精益求精(参见网易虚拟社区http://p5.club.163.com/viewArticleByWWW.m?boardId=clanguage&articleId=clanguage_108eacc622169e7&boardOffset=0的讨论),但是实际上防止BUG出现的最好的时机,就是在编写代码的时候。在编写代码一段时间之后,即使是编写者本人也可能需要一段时间来理解代码(如果不习惯写注释的话,这段时间会更长),更别说定位问题所在了。在编写代码时,如果具有良好的习惯,可以免去很多在之后消灭BUG的困难。

规范不是语法

太多人把不要使用goto奉为圣旨,从来不想去打破。他们会争论,goto会造成难以维护的难读的代码,以及使编译器无法进行优化。这两点在很大程度上是真的,但是也有使用goto可以增加程序可读性和效率时候。在这种情况下,遵循“不使用goto语句”规范会产生更糟糕的代码。

一些人喜欢在成员函数后面加const,但是另外一些人没有养成这个习惯。一个直接的结果就是,一些看起来对对象完全没有影响的函数不能在const函数里面使用。这时候应该怎么办?看看Paul DiLascia建议的,把this指针强行转化为一个非const指针(http://www.microsoft.com/msj/archive/S126E.aspx)。如果函数实际上会对对象成员造成影响(例如CToolBar::GetItemRect),这也会带来潜在危险。

为了和ANSI标准之前编写的代码兼容,ANSI C中的memchr函数的声明为

void *memchr( const void *buf, int c, size_t count );


这里c是一个字符。很明显,标准为了兼容性放弃了明确性和更强的类型检查。如果放弃兼容性,这个函数应该声明为如下形式

void *memchr( const void *buf, unsigned char c, size_t count );



微软的很多代码使用一种叫做匈牙利表示法的命名规范。这使得标识符的含义和类型更加明确——但是这是从广义的角度来说的。考虑如下函数声明

char *strcpy( char *strDestination, const char *strSource );



如果严格遵循原始的匈牙利表示法,那么两个参数的声明应该是pch开头。但是以str开头给这两个参数更多含义:它们指向以\0为结束符的字符串。
   
规范是用来在大部分时间里遵循,以及在可以得到更好的结果时打破的。

编译警告的意义

智能化的编译器开始将语法正确的语句列为警告:

while(size-->0);//注意这里有个分号 *pTo++=*pFrom++;


编译器会报告空循环问题。
但是对于以0结尾的字符串复制

while(*pTo++=*pFrom++);


,这样的警告是多余的。
更加常见的警告是在条件判断语句中

if(ch='\0') EndOfString();


为了绕过这个警告,需要添加额外的运算或者语句,或者更正错误的赋值。

while((*pTo++=*pFrom++)!='\0'){} if(ch=='\0')


一些程序员甚至将比较语句修改成

if('\0'==ch)


这样作的原因显而易见:为了减少潜在的BUG。如果你的编译器没有这样的警告,那么你可以使用一些工具来检查那些语法正确但是有潜在BUG的代码。LintProject (http://www.codeproject.com/tools/lintproject.asp)就是其中一个。但是,良好的编程习惯还是减少BUG出现的最好的方法。

在觉得警告消息太烦人的时候,不妨想想编译器的开发人员为什么要编写这么多警告消息,而不是仅仅寻求关闭警告的方法。

P.S. Visual C++的默认警告等级是3级。发布软件之前应该改成4级,之后检查所有的编译警告。

无处不在的断言

使用编译器来捕获BUG的主意很好,Visual Studio 2005甚至会报告定义的变量不符合命名规范(Warning 1 CA1709 : Microsoft.Naming : Correct the casing of type name 'welcome'.);但是我敢打赌你检查BUG列表的时候,你会发现只有一小部分BUG会被编译器抓到。很多BUG在程序运行过程中很少会出现,例如内存分配失败的问题

char* strBuffer=new char [length]; MyZeroMemory(strBuffer,length);



这段代码在绝大多数情况下会成功,但是在虚拟内存不足的时候,Windows会报告“您的系统虚拟内存太低,WINDOWS会增加虚拟内存页面文件的大小。在这个过程中,一些应用程序的内存请求会被拒绝”然后开始增加虚拟内存,在这个过程中,new这样的内存分配可能会因为内存不足而失败,而MyZeroMemory则可能会造成访问越界。如果你足够幸运,你会在产品发布之前发现这个BUG,否则,你的用户会代替你发现这个BUG。要是用户刚好没有备份的习惯,丢失了几十分钟甚至是几小时的工作进度,用户会很生气,后果很严重。

编译器不能捕获这种运行时才会出现的错误(顺便说一下,我在CSDN上居然还看到有人抱怨编译器不会报告除0错误);也不能捕获算法中的BUG和检验参数中的数据。但要是你知道怎么做的话,这类问题很容易被发现。你可以用SetProcessWorkingSetSize函数或者msconfig工具减少虚拟内存大小,或者使用Virtual PC之类的虚拟机或者磁盘配额策略来模拟内存和磁盘空间不足的情况。

你有可能想在这种极限情况下调试你的代码,但是大多数时间内,内存分配不会失败,而设置条件断点又太麻烦了。这时候可以在代码里面加上一段用来在内存分配失败时触发调试器的断言代码

void MyZeroMemory(char* strBuffer, int length) { assert(strBuffer!=NULL); }



如果使用的是MFC或者ATL,建议使用对应的宏ASSERT和ATLASSERT。现在你可以编写健壮的代码使得程序在strBuffer这块内存分配失败时也能够正常运行。

现在的问题是,加入的这些代码增加了应用程序的大小,减慢了运行速度。在解决了内存分配失败造成的程序崩溃的问题之后,有必要在发布的版本中去掉这些断言代码。一个简单的办法是使用预处理标识符:

void MyZeroMemory(char* strBuffer, int length) { #ifdef DEBUG assert(strBuffer!=NULL); #endif }



这样你可以只维护同一份代码。当然,这也意味着调试的代码在发行版中会被去除,所以为了避免不可预料的行为,为了调试而加入的代码应该尽可能少地影响应用程序的行为。

你有可能需要重新定义assert来实现扩展的行为——例如在assert断言失败中断程序时打开源文件并且跳到assert那一行——这时候你可以编写自己的断言函数,然后重定义assert为这个断言函数。

#ifdef DEBUG /*display a dialog and if the user selected break , jump to the assert line*/ void _assert(char*,unsigned int); #define assert(f)\ if(f)\ {}\ else _assert(__FILE__,__LINE__) #else #define assert(f) #endif


空的if语句块可能看起来有点奇怪,但是这可以避免和宏外的if-else产生冲突。同样,最后一行语句没有结束的分号,因为在使用的时候再加上会更加自然。

assert最有用的地方就是用来检验函数的参数——但是也可以在其他地方起作用。在程序中的断言语句越多,异常的情况就越容易被侦测到。

既然assert是代码,它不可避免的需要注释。即使是自己写的代码,过了六个月之后再来审视也可能需要一点时间来重新理解这部分代码。一个简单的注释可以把这部分时间减少:

void MyZeroMemory(char* strBuffer, int length) { /*should not be called when buffer allocation failed*/ #ifdef DEBUG assert(strBuffer!=NULL); #endif }


在编写完函数之后,应该审视函数中的代码,之后在函数的开头验证函数正常运行所需的条件。如果你在写一个库函数,那么应该在函数的文档中加入函数正常运行所需的条件——否则就会增加使用者发现BUG的难度。举例来说,Windows API的文档不可谓不详尽,但是我在用汇编调用Windows API的时候,也花了很长时间才发现调用Windows API之前栈顶要设置成4的倍数。

注意不要把一些条件当成默认成立的了。assert(sizeof(int)==4);这样的语句在一些人看来很荒谬,但是在Windows开发中通常是32位的long在一些64位平台上已经是64位的了,而在目前还不知道sizeof(int)在什么时候会升位。如果你的代码依赖于int的大小,那么写上这行可以在未来升位之后更快发现问题。

一些保守的程序员在参数错误时会让函数继续运行——返回一个错误码——但是不报告错误。在编写核心模块时这可能很有必要,但是这也经常会把BUG藏起来——在多层函数返回之后时候,错误码经常会丢失或者被替代。尽量不要使用保守编程来替代断言,如果你认为保守编程会造成定位问题的困难,那么就加上断言代码。

在一些时候,校验参数数据似乎是不可能的事情——想象一下那些被设计来搞糊涂解密者的加密算法的中间数据——但是校验这种复杂算法的方法也不是没有。为了确认手算和心算的正确性,我们会使用电子计算器的结果来进行比较,反过来,我们也可以编写另外一个的算法来断言计算结果的正确性。这种方法也可以被用来断言一个函数的汇编版本和C版本的一致性——为了获取最大性能,函数的汇编版本的算法可能和C版本的有很大差异。当然,不是每个函数都有必要用这种方式来验证,实际上,只有极其重要的算法和对性能极其敏感的代码才会需要这种双保险来验证。同样,为了调试而加入的算法也应该尽可能少地影响应用程序的行为。

最后,你不应该在发布程序时从代码中去掉断言语句,而是把它们留在那里以供你升级或者查找BUG时使用。帖来自于网易社区:http://p5.club.163.com/viewArticleByWWW.m?boardId=clanguage&articleId=clanguage_10938d0575c4afe

消灭不可预料的行为

断言并不能抓住所有BUG——它们都是人写出来的,而是人就会犯错误。一些常见的错误包括:

  • 使用状态不确定的资源
  • 在释放资源之后继续访问资源
  • 在资源重新定位之后继续引用旧的资源
  • 申请资源之后丢失对资源的引用
  • 访问时未注意是否越界
  • 忽略错误信息

这些并不是杞人忧天的问题——实际上,这些问题属于日常开发中最常见的问题。这些问题的特点是,它们并不是时常造成程序行为的异常,并且症状不可重复。以内存为例,释放内存之后编译器和操作系统通常不会自动去擦除内存中的内容,所以继续访问内存不太可能造成程序行为的异常——直到内存被重新分配出去,而另一块代码开始重写这块数据。申请资源之后丢失对资源的引用可能只是造成长时间运行之后系统资源不足而已。另外,这些问题都是算法的问题,而编译器并不会替你校验你的算法,你自己也不太可能会怀疑你自己的算法。

不要认为职业的程序员就不会犯这类错误。举几个例子来说明这些问题。

  • 在IE4.0中,MSHTML的HTMLDocument对象的IPersistStreamInit::Load假定传入的IStream流的访问指针已经定位到开头——而在IE5.0中,IPersistStreamInit::Load会自行调用IStream::Seek
  • 在Visual C++ 6.0中,CHTMLView类有字符串资源未释放问题(http://support.microsoft.com/kb/241750)
  • 在Visual C++.Net中,CHTMLView类有两个BUG:
    • 参数传递错误:
      HRESULT CHtmlView::ExecFormsCommand(DWORD dwCommandID, VARIANT* pVarIn, VARIANT* pVarOut) { HRESULT hr = E_FAIL; CComPtr spDoc = (IHTMLDocument2*) GetHtmlDocument(); if (spDoc != NULL) { CComQIPtr spCmdTarget = spDoc; if (spCmdTarget != NULL) hr = spCmdTarget->Exec(&CMDSETID_Forms3, dwCommandID, OLECMDEXECOPT_DONTPROMPTUSER, pVarOut, pVarIn); } return hr; }
      COM指针未释放错误:
      void CHtmlView::OnFilePrint() { // get the HTMLDocument if (m_pBrowserApp != NULL) { CComPtr spDisp = GetHtmlDocument(); if (spDisp != NULL) { // the control will handle all printing UI CComQIPtr spTarget = spDisp; if (spTarget != NULL) spTarget->Exec(NULL, OLECMDID_PRINT, 0, NULL, NULL); } } }

这些不确定的行为是很大一部分不可重复(因此也很难跟踪)的BUG的根源。举例来说,释放一块内存之后,在操作系统切换到另外一个线程之前,重新分配同一块内存,并且写入数据这个事件发生的可能性十分之小。为了解决这些问题,Visual C++编译器采取了一种保护性的措施,在调试模式下再分配和释放内存时将内存用一般不会用到的值填充,例如0xccccccc,0xdddddddd和0xfefefefe(参见编译器文档中的/RTC参数的说明)。这样你可以减少不可预料的程序行为,强迫BUG重现。如果你的编译器没有这么做,你可以自己编写一个调试模式下专用的内存管理程序进行这样的工作。为什么选择这样的值?在Intel系统中,0xcc的含义是int 3中断(参见http://blogs.msdn.com/oldnewthing/archive/2004/11/11/255800.aspx)——如果不小心执行了这块数据,那么程序会马上中断并且提示用户,其他的值则是典型的非法数据。如果你在为其他环境编写程序。你可能需要查阅一些资料来决定使用什么值来在调试模式下填充内存。

MFC的另一个保护措施是内存泄漏监测器——这也是在每个文件开头要加上#define new DEBUG_NEW的原因——但是这也变更了应用程序的行为。举例来说,为了检查内存泄漏,MFC总是分配比所需要多的内存,然后加入调试信息。如果你的程序有访问越界的代码,那么有可能擦除一部分额外分配的内存,可能的结果就是在调试模式下运行正常,而在发布模式下程序崩溃。当然,这是必须的。如果你的发布版本的程序依赖于这些额外字节,那么你就有麻烦了。

在发布模式下程序的崩溃有助于你发现问题,但是也造成定位问题的困难。你可以在发布模式下加入调试信息(没错,在工程的C++和连接选项中选中Program Database和Generate Debug Info)来生成一个中间版本;MSDN文章Generating and Deploying Debug Symbols with Microsoft Visual C++ 6.0(http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp)甚至教你怎么怎么发布这样的版本,但是也要注意这样的版本和最终发布版本还是可能有区别的——特别是在程序中有BUG的情况下。另一个办法是在调试时将EIP寄存器修改成崩溃信息中的值,这样可以很容易在源代码中定位造成崩溃的代码的位置(参见http://www.codeproject.com/debug/XCrashReportPt1.asp)。

MFC开发中另一个比较有用的定位内存访问越界方法是,将数据封装成对象成员变量,尽量可能让所有类都从CObject派生,并且在代码中大量加上ASSERT_VALID。如果成员变量被越界的访问重写了,那么CObject指向AssertValid的虚函数表会被改写,而ASSERT_VALID会报告这个错误。

不要发布调试版本,这对用户来说并无意义。虽然这么说可能是多此一举,但是我在玩游戏的时候还真看见过断言对话框。调试信息是被设计用来发现问题的,不是用来隐藏问题的。如果你确实需要这么做(微软就定期发布核心模块的调试信息以供软件开发人员定位问题),那么你需要让用户认识到调试版本和最终发布版本的性能差异,例如在程序开始时显示一个消息。

广告时间:

最新Windows SDK不支持Visual C++ 6.0

可能大部分人已经知道了,但是CSDN论坛上仍旧不断出现关于这个兼容性的提问。最新的支持Visual C++ 6.0的版本是2003年2月版,下载地址是http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm

取消对Visual C++ 6.0的支持的原因是为了支持新的/GS参数。XP SP2和Windows Server 2003 SP 1都增加了很多安全特性,以致于新的Windows SDK中包含的编译器和库文件不再和Visual C++ 6.0兼容。

参见

posted on 2006-02-05 17:48:00 by jiangsheng  评论(7) 阅读(13927)

网络钓鱼?Nomination of Microsoft Award for Customer Excellence

这两个月连续有两人经过我的安全教育之后仍旧把自己的银行帐户信息、社会保险号什么的给骗子了,一次是电话诈骗,声明是受害者的银行的合作伙伴,已经有了银行帐户号码等信息,但是为了发送礼品,需要支票上的流水号,但是电话误导受害者读出来的位置实际上是需要保密的数据。另一次是伪造paypal网站,用email欺骗用户登录。一直以来我的邮箱里面也不断出现我的ebay、paypal帐户即将被关闭,要打开网页输入我的个人信息验证——尽管我在这些站点并没有帐户。对于这些明显是网络诈骗(Phishing,也被称为网路钓鱼)的邮件,我都是直接拖到垃圾箱。但是,大约一个月之前,我收到这样一封怀疑是网络诈骗的email:

Dear Sheng Jiang,
Thank you for being a great contributor to Microsoft Visual Studio 2005.
You have been nominated to receive the Award for Customer Excellence. This award recognizes your extraordinary contribution to the Visual Studio 2005 product and will be shipped to you without charge.  Please click the following link to arrange shipment of your award:
www.microsoft-ace.com
Should you have any questions about this award, please contact (email omitted).
All the best,
S. Somasegar
Corporate Vice President,
Microsoft Developer Division
看起来很像一封真实的信件。但是,这封email十分可疑,因为它来自www.microsoft-ace.com而不是Microsoft.com,而且这个站点的SSL证书已经过期。一个whois查询显示www.microsoft-ace.com的注册人是

Saltmine Inc.
710 Second Avenue
Suite 1100
Seattle, WA 98104
US
Domain Name: MICROSOFT-ACE.COM

随后,我在Somasegar的BLOG上留言询问http://blogs.msdn.com/somasegar/archive/2005/11/19/494871.aspx ,一个叫Kunal Sikka的人回复说这封email的内容是真的:

The Award for Customer Excellence program is very much a Microsoft program and offer is a genuine offer. The fulfillment of the award is handled by an external vendor. Very much like ancillary processes of other Microsoft programs are handled by vendors - eg: the survey of the MVP program.
Re: the SSL certificate. The vendor involved informed us rather late that their SSL certificate has expired. We have asked the vendor to update their SSL security certificate ASAP and we are expecting that to happen any day.

但是既然任何一个人都可以像我一样在上面留言,我也无从验证Kunal Sikka的评论的真伪。OK,我自己来看看710 Second Avenue, Suite 1100到底是什么公司。Google搜索给出的第一个页面http://mspublisher.saltmine.com/privacy.aspx看起来是微软的Publisher2003站点——Google搜索出问题了?第二个站点看起来才是公司的网站:http://saltmine.com/Aboutus/ContactUs.aspx,和前面的结果在同一个主域名下。且慢,第一个站点到底是什么?打开根目录看看:http://mspublisher.saltmine.com/看起来十分地像一个Microsoft Publisher 2003站点——但是Microsoft Publisher 2003站点为什么不在http://office.microsoft.com下面?这肯定又是一个网络钓鱼站点!

且慢,网站可能是网络钓鱼站点,但是也可能是真的微软合作伙伴。搜索一下Publisher Service Provider Program找到了关于这个项目的介绍http://office.microsoft.com/en-us/assistance/HA010772371033.aspx,点上面的Click to register for PSPP链接,发现了什么?打开了http://mspublisher.saltmine.com/!这个是微软的合作伙伴!

看起来判断是否是网络钓鱼站点的标准不仅仅要判断站点域名,而且要上官方网站搜索合作公司信息?还是且慢。微软的网站上可没有提到这个Award for Customer Excellence。http://www.microsoft-ace.com/ 现在也上不去了,所以我现在无从验证这个网站到底是否是钓鱼站点——但是这更增加了我的怀疑:这个网站是因为网络钓鱼还是别的什么原因所关闭的吗?

参见

Update:Got it

posted on 2005-12-25 16:41:00 by jiangsheng  评论(6) 阅读(7213)

使用WinDbg调试VC程序

使用WinDbg调试VC程序

虽然在VC6.0中可以通过安装Visual C++ Toolkit(网站:http://msdn.microsoft.com/visualc/vctoolkit2003/)来编写基于最新版本的平台SDK、DirectX SDK的程序以及托管代码,但是VC6附带的调试器并不支持新版本的调试信息,所以实际上是不能用VC6来调试新版本编译器生成的程序的。一个替代的解决方案是使用新版本的Windows调试工具Windbg(网站:http://www.microsoft.com/whdc/DevTools/Debugging/default.mspx)。Windbg的调试功能基本和Visual C++中的相同,但是需要手动设定源文件和调试符号文件的搜索路径(可以参考VC6.0中的对应设置)。一些代码,例如MFC的代码比较难于定位,这时可以双击调用堆栈中的函数名称来打开文件并定位到函数所在位置。Windbg可以进行有限的托管代码调试,但是调试过程比较麻烦。在没有安装Visual Studio的计算机上调试,例如进行远程调试的时候可能还需要部署调试符号(Generating and Deploying Debug Symbols With Visual C++ 6.0)。

调试Visual Studio .Net 的程序需要用户是管理员或者"Debug User"用户组成员。如果登录用户不是该组成员,那么也可以用WinDbg来调试程序。

posted on 2005-06-08 23:53:00 by jiangsheng  评论(2) 阅读(13458)

在线地址本服务

 我收到的来自在线地址本服务的邀请现在越来越频繁了。今天我又收到了一封这样的邮件:
Add yourself to xxx's address book!
Open your invitation

This invitation was sent to my email address on behalf of xxxxxx (xxxxxx@hotmail.com)

If you do not wish to receive invitations from this Ringo member, click here. To stop receiving invitations from all Ringo members, click here.

在我的上一篇BLOG(Please don't show your password to 3rd party.)中,我提到了一些站点的服务存在风险,因为它们要求用户提供邮箱的密码,而这样可能导致身份冒用——实际上,他们已经用我朋友——其中一些名字我比较陌生,因为我不熟悉一些网友的真实姓名——的名义给我发送了数十封这样的电子邮件,而且看起来我将会持续收到这样的邮件,即使是在我注册之后。尽管一些网站声称我可以通过提供我的电子邮件地址来停止接收他们给我发送的邀请,但是这样的方法显然没有生效——和垃圾邮件中的停止接收链接一样,这仅仅证明这个电子邮箱正在被使用,并且准备好接收更多的垃圾邮件。记得蠕虫病毒么?这种收集邮件地址的方法更加简单,而且可以绕过任何防火墙。我建议收到这样的邮件的人在注册之前看看这篇文章:http://www.anu.edu.au/people/Roger.Clarke/DV/ContactPITs.html ,以了解可能付出的代价。

OK,在继续讨论之前,让我们来看看这些网站到底是什么。有多少人在注册之前看过他们的服务条款?要使用他们的服务,你必须同意他们的服务和隐私条款并且提供你的个人信息,例如生日、性别诸如此类。第一眼看上去这些服务条块似乎是完全无害的,除了:
http://www.bebo.com/Privacy.jsp

You agree that we may use personal information about you to improve our marketing and promotional efforts, to analyze site usage, improve our content and product offerings, and customize the Site's content, layout, and services. These uses improve the Site and better tailor it to meet your needs, so as to provide you with a smooth, efficient, safe and customized experience while using the Site.

We use your personal information to: troubleshoot problems; measure consumer interest in our services, inform you about offers, products, services, and updates; customize your experience; detect and protect us against error, fraud and other criminal activity; enforce our Terms of Use; and as otherwise described to you at the time of collection.

You agree that we may use your personal information to contact you and deliver information to you that, in some cases, are targeted to your interests, such as targeted banner advertisements, administrative notices, product offerings, and communications relevant to your use of the Site. By accepting the Terms of Use and Privacy Policy, you expressly agree to receive this information. You may make changes to your email notification preferences at any time.

It is possible that as we continue to develop our website and our business, Bebo's service and/or related assets might be acquired. Notwithstanding any provision in this policy to the contrary, in event of a merger or acquisition, your personal information may be transferred to the acquiring entity, and become subject to the acquirer's data practices.

http://www.bebo.com/TermsOfUse.jsp

Bebo reserves the right at all times to monitor, review, retain, and/or disclose in good faith any information it believes in good faith that such action or disclosure is necessary to conform to legal and government requirements, or to protect and defend the rights or property of Bebo or enforce the TOU.

Bebo reserves the right to collect and distribute non-personal demographic information to third parties. As such this information would not contain any information that would allow your identity to be deduced.

不够危险?来看看这个:(http://ringo.com/about/terms.html)

Modifications to Service

These Terms & Conditions were last modified on January 25, 2005. At any time and without prior notice, Ringo shall have the right, in its sole discretion, to modify, add or remove terms of these Terms & Conditions, without notifying our customers of such modifications, additions or removals, and all such changes shall be effective immediately. Your continued participation and use of this website and/or the Ringo services following our posting of any such change on our site will constitute binding acceptance of such change. You agree that Ringo shall not be liable to you or to any third party for any modification, suspension or discontinuance of the service.

OK,看过上面的文字,我也同意Ringo不liable,所以我不会去注册。因为这个网站的拥有者是Monster.com,我所知道的世界上最大的求职网站,所以从现在开始我不会理会任何类似的邀请,不管这样的邀请来自哪里。

我更加忧虑的是那些要求电子邮箱密码的服务,例如http://www.sms.ac, http://www.bebo.comhttp://www.hi5.com 之类。一些电子邮件服务和其他服务共享密码,例如MSN Money和Yahoo Messenger,而这样的电子邮件的密码被泄漏可能造成的损失不仅仅是发送垃圾邮件而已。很多人——包括我在内——在很多站点(甚至可能是银行的网站)使用同样的用户名和密码。但是,有多少人阅读过并且对法律条文有足够认识来理解它们的服务条款?有多少人知道很多这样的密码要求页面(在我发表这篇文章的时候,我没找到一个反例)完全没有加密措施?通过任何一个路由器——如果有人愿意的话,可以是在网站服务器所在网络上的那个——都可以获得这样的用户名和密码而不违反任何任何服务条款。更不用说这样的安全防护措施是否可以阻止黑客获取服务器上的数据了。

大多数人知道垃圾邮件和连锁信息(把这个信息发送给XX个人你就可以XXXX之类)是不受欢迎的。但是我还是不断收到一些这样的无用电子邮件、MSN和QQ消息——如果我还在使用手机的话,可能还有需要付费的文字消息——这大约占我的日常通讯量的2/3。再次提醒并不会阻止那些不听劝告的人发送这样的信息,但是我希望能够让一些没有被提醒过的人认识到,免费的蛋糕并不是看起来那么美味可口。我也建议你在阅读之后,做一些你自己的搜索和研究来做出你自己的判断。

posted on 2005-05-13 12:20:00 by jiangsheng  评论(5) 阅读(3365)

Please don't show your password to 3rd party.

请勿向第三方公开你的个人密码
Please don't show your password to 3rd party.

一直以来我都持续收到一些加入在线手机社区http://www.sms.ac的邀请,因为我没有手机(要找我的人注意:我醒着的话一般都挂在MSN上),所以总是看过就算。但是今天收到了来自一个不是很熟的朋友的加入这个社区和另外一个社区http://www.bebo.com的邀请,所以上网搜索了一下一些个人BLOG对这两个网站的引用。搜索的结果触目惊心。
这些网站显然都要求用户输入邮箱和邮箱的密码,同时使用邮箱中保存的联系人信息来邀请用户的联系人加入。但是,向第三方公开你的密码意味着公开你的全部邮件、联系人的家庭地址、电话等信息。这可能不是你的朋友愿意看到的情形。

密码是私有的,并且从不应该向第三方公开。任何在注册时要求现存密码的服务都是可疑的,特别在询问你的邮箱密码而没有警告用户这样可能造成的危险的情况下。如果某个网站询问你的hotmail账户和密码,那么几乎可以肯定这是个没有和微软合作的网站,因为真正和微软合作的商业网站应该会使用.Net Passport来和微软共享用户注册信息,例如http://www.match.com

如果你收到了注册某个网站的邀请,首先搜索因特网上对这个网站的引用以确定是否值得向这个网站公开你的个人信息。如果有必要,你可以新建一个电子邮件和密码组合来参与在线社区。


参考
http://hownow.brownpau.com/archives/2005/02/spam_from_smsac
http://www.jaffacake.net/BensBlog.nsf/dx/bebo.com---update

顺便说一下,微软发布了Windows XP和Windows 2003的64位版本(Microsoft Windows XP Professional x64 Edition )Windows Server 2003 x64 Editions。

posted on 2005-04-25 18:22:00 by jiangsheng  评论(5) 阅读(3582)

在浏览器控件中显示信息栏

Windows XP SP2 中的Internet Explorer 6 引入了一个新的安全用户界面元素,称为信息栏。在特定操作被阻止的时候,信息栏给用户显示一个用户界面元素。特别的,它会在以下操作被阻止的时候显示。

  • 弹出窗口初始化
  • 文件下载
  • 安装ActiveX 控件
  • ActiveX控件安全提示的原因是用户安全设置或者是控件未标记为脚本安全的。
  • 文件的扩展名和多用途因特网邮件扩展类型(MIME)不符的
  • 网络协议锁死的内容

SP2WebBrowserControl 

信息栏是Windows XP SP2 中的Internet Explorer 6引入的安全特性之一。和其他安全特性控制一样,可以通过一个注册表键来控制:FEATURE_SECURITYBAND。 默认情况下IE(iexplorer.exe) 和Windows 资源管理器(explorer.exe) 在这个安全特性控制下。下面显示注册表键和启用过程:

HKEY_LOCAL_MACHINE (or HKEY_CURRENT_USER)
SOFTWARE
Microsoft
Internet Explorer
Main
FeatureControl
FEATURE_SECURITYBAND
iexplorer.exe= 0x00000001
explorer.exe= 0x00000001
TTraveler.exe= 0x00000001
process name.exe=0x00000001

 

这个FEATURE_SECURITYBAND 安全特性控制影响IE是否显示信息栏,信息栏在一个操作被阻止的时候提示用户。它不控制操作的阻止过程。

一个集成浏览器控件的程序可以通过将其进程添加到这个注册表键来启用信息栏,也可以通过调用CoInternetSetFeatureEnabled函数来在运行时执行。如果一个应用程序并未在这个安全特性控制下,那么浏览器控件的行为和Internet Explorer 6 SP1b中的一样.

没有方法通过脚本来访问这个特性。

在FEATURE_SECURITYBAND及相关安全特性控制下的应用程序可以使用信息栏应用程序编程接口(API)来在一个URL 操作被禁止时自定义显示的用户界面。为信息栏引入了很多新的OLECMDID命令。头三个是属于CGID_DocHostCommandHandler组。宿主应用程序应该在它们的IDocHostUIHandler实现的同一个对象中实现IOleCommandTarget ,以接受来自浏览器控件IOleCommandTarget::Exec调用。

  • OLECMDID_PAGEACTIONBLOCKED
  • OLECMDID_PAGEACTIONUIQUERY
  • OLECMDID_FOCUSVIEWCONTROLS

宿主应用程序可以使用下面两个新的OLECMDID 命令来执行浏览器控件IOleCommandTarget::Exec调用。

  • OLECMDID_FOCUSVIEWCONTROLSQUERY
  • OLECMDID_SHOWPAGEACTIONMENU
这个示例使用IWebBrowser2::ExecWB 来执行OLECMDID_SHOWPAGEACTIONMENU 命令。
   POINT pt = { 0 };
   GetCursorPos(&pt);

   CComVariant varHwnd((LONG)hwnd);
   CComVariant varX(pt.x);
   CComVariant varY(pt.y);

   SAFEARRAY* psa = SafeArrayCreateVector(VT_VARIANT, 0, 3);

   LONG lIndex = 0;
   SafeArrayPutElement(psa, &lIndex, &varHwnd);
   lIndex++;
   SafeArrayPutElement(psa, &lIndex, &varX);
   lIndex++;
   SafeArrayPutElement(psa, &lIndex, &varY);

   CComVariant varArgIn;
   V_VT(&varArgIn) = VT_ARRAY | VT_I4;
   V_ARRAY(&varArgIn) = psa;

   pBrowser->ExecWB(OLECMDID_SHOWPAGEACTIONMENU, (OLECMDEXECOPT)dwPageActionFlags, &varArgIn, NULL);

另外,应用程序可以实现IInternetSecurityManager来重载默认的安全区域设置,参见创建一个自定义URL安全管理器以获得更多信息。

要在Visual C++中使用CoInternetSetFeatureEnabled函数等XPSP2新增的API的话,必须安装了Windows XP SP2 Platform SDK。这个SDK可以在http://www.microsoft.com/msdownload/platformsdk/sdkupdate/下载。

Windows XP SP2 Platform SDK不支持Visual C++6.0附带的编译器。Visual C++6.0用户建议升级到Visual C++.Net,或者安装Microsoft Visual C++ Toolkit 2003

Microsoft Visual C++ Toolkit 2003 可以在http://msdn.microsoft.com/visualc/vctoolkit2003/下载到,但是在Visual C++6.0中使用Microsoft Visual C++ Toolkit 2003的代价之一就是不能使用内建的调试器。VC的选项中可执行文件、头文件和库文件的目录搜索顺序应该依次是:

  1. Microsoft Visual C++ Toolkit 2003
  2. Windows XP SP2 Platform SDK
  3. Windows SDK (Windows Server 2003)
  4. VC98 (Visual C++ 6.0)

posted on 2004-11-12 14:57:00 by jiangsheng  评论(8) 阅读(10163)

动态屏蔽Control+Alt+Delete(Update)

CSDN上那个BLOG灌多了,有点疏忽这里了。今天转几篇BLOG过来

我曾经总结过一篇关于动态屏蔽Control+Alt+Delete的文章(http://blog.csdn.net/jiangsheng/archive/2003/11/09/3789.aspx)。数月之后我把文章的英文修订版发在了CodeProject(http://www.codeproject.com/useritems/preventclose.asp)。但是当时我并未发现代码在调试模式下崩溃的原因。在很长时间之后,我看到Antonio Feijao在他最近发表的一篇文章之中用C重写了这个代码,并且在代码添加了一些注释说明了各种编译器设置可能出现的问题。我认为这篇文章对我的文章的读者也是很有用的,所以在我的文章中添加了他的文章的链接。

文章介绍:

Antonio Feijao在限制用户访问桌面和应用程序上研究了很长时间。尽管他最终并没有使用文中描述的技术,但是他还是决定把研究过程中搜集到的代码公布出来,以供可能的使用者参考。他并未声明是代码的作者,并且他声明会尽可能的联系代码的作者。

文章地址

http://codeproject.com/w2k/AntonioWinLock.asp

 

原文发表在[http://community.csdn.net/expert/Topicview2.asp?id=3072485]

带子窗口的ActiveX控件问题,如何获取回车键?

问题:

新建一个MFC ActiveX工程,添加一对话框资源,上面有一些标准控件,如按钮、编辑框等,并生成一个类CCtrlPanel。
在CXXXXCtrl类中:
int CXXXXCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 if (COleControl::OnCreate(lpCreateStruct) == -1)
  return -1;

 m_CtrlPanel.Create(IDD_CTRLPANEL,this);
 //m_CtrlPanel在.h文件中申明为:CCtrlPanel m_CtrlPanel;
 OnActivateInPlace(TRUE,NULL);
 return 0;
}

这样一来,的确做了个带界面的ActiveX控件,可是用于网页中的时候,控件的子窗口,就是CCtrlPanel类收不到tab键、回车键和方向键,这样控件显得很不专业(如:用户在一EDIT框中输入完了内容,回车想表示按那个默认按钮,却不能实现),后来我发现这些按键被CXXXXCtrl类截获了!于是我理所当然的加了如下代码:
BOOL CSluiceCtrl::PreTranslateMessage(MSG* pMsg)
{
 if(pMsg->message==WM_KEYDOWN)
 {
  if(pMsg->wParam==VK_TAB ||pMsg->wParam==VK_RETURN ||
   pMsg->wParam==VK_LEFT || pMsg->wParam==VK_RIGHT)
  {
   m_CtrlPanel.SendMessage(pMsg->message,pMsg->wParam, pMsg->lParam);
   return TRUE;
  }
 }
 return COleControl::PreTranslateMessage(pMsg);
}
但结果证明我想得太天真,但我始终不明白这样做为什么不行?还请高手指教!
另外想请教高手,这个问题到底应该如何解决?我甚至最极端的方法也试过了,如下:
BOOL CSluiceCtrl::PreTranslateMessage(MSG* pMsg)
{
 m_CtrlPanel.SendMessage(pMsg->message,pMsg->wParam, pMsg->lParam);
 return TRUE;
}
答:

PretranslateMessage依赖于MFC的消息循环。如果容器的消息循环不是MFC的,那么PretranslateMessage不会被调用。
int CWinApp::Run()
 {
 ?
 ?
 ?
    for (;;) {
       while (!::PeekMessage(&m_msgCur,...)) {
          if (!OnIdle(...))    // do some idle work
             break;
       }
       // I have a message, or else no idle work to do: // pump it
       if (!PumpMessage())
          break;
    }
    return ExitInstance();
 }


BOOL CWinApp::PumpMessage()
 {
 ?
 ?
 ?
    if (!::GetMessage(&m_msgCur,...)) {
       return FALSE;
    }
    if (!PreTranslateMessage(&m_msgCur)) {
       ::TranslateMessage(&m_msgCur);
       ::DispatchMessage(&m_msgCur);
    }
    return TRUE;
 }
BOOL CWinApp::PreTranslateMessage(MSG* pMsg)
 {
    for (pWnd = /* window that sent msg */; pWnd; pWnd=pWnd->getParent())
       if (pWnd->PreTranslateMessage(pMsg))
          return TRUE;
    if (pMainWnd = /* main frame and it's not one of the parents */)
       if (pMainWnd->PreTranslateMessage(pMsg))
          return TRUE;

    return FALSE;  // not handled
 }


MFC对话框相应的键盘处理依赖于MFC的消息循环。

 BOOL CDialog::PreTranslateMessage(MSG* pMsg)
 {
  if (pMsg->message >= WM_KEYFIRST && // for performance
      pMsg->message <= WM_KEYLAST)

    // maybe translate dialog key
    return ::IsDialogMessage(m_hWnd, pMsg);

  return FALSE;
 }


如果容器的消息循环没有调用IsDialogMessage,那么相应的键盘处理不会被调用。

解决的方法是用Hook来获得需要的键盘输入,然后转发到对话框。参见PRB: Modeless Dialog Box in a DLL Does Not Process TAB Key (233263)
参考文档
PRB: Modeless Dialog Box in a DLL Does Not Process TAB Key (233263)
http://support.microsoft.com/default.aspx?kbid=233263

FAQ: WebBrowser Keystroke Problems
http://www.microsoft.com/mind/0499/faq/faq0499.asp

Meandering Through the Maze of MFC Message and Command Routing
http://www.microsoft.com/msj/0795/dilascia/dilascia.aspx

C++ Q&A: Enabling Menus in MFC Apps, Changing the Behavior of Enter with DLGKEYS Sample App -- MSDN Magazine, July 2000
http://msdn.microsoft.com/msdnmag/issues/0700/c/default.aspx

 

在应用程序中集成浏览器控件

概述

什么是浏览器控件

浏览器控件是一个提供浏览器绝大部分功能的ActiveX控件,随Microsoft? Internet Explorer 4.0(IE)或者更高版本发行。实际上,IE可以认为是一个集成浏览器控件的程序。

为什么要使用浏览器控件

怎么给用户提供丰富的内容一直是程序员们努力的目标。尽管各种各样的界面库可能使你眼花缭乱,但是这些也是美工和程序员的恶梦——要自定义界面上的每个元素的外观并不是一件容易的事情,而且有时候需要比较复杂的技术,例如自定义程序中出现的滚动条的颜色。

浏览器控件的出现使这一切变得简单。一个简单的应用是使用浏览器控件显示丰富的内容,就像Microsoft Outlook的预览窗格。你可以让美工为你做出华丽的效果,例如界面上面的渐变效果、动画GIF或者Flash动画,而顶多只需要编写少量的HTML代码;进阶的应用包括使用浏览器控件显示整个或者部分用户界面,例如Norton Antivirus和Real Player都使用HTML来显示界面,使用层叠样式表统一界面风格;使用DHTML对象模型进行无界面网页分析,或者编写浏览器辅助对象(BHO)来自定义浏览器的行为。

我也必须在这里说一下集成浏览器可能的问题,以供使用者斟酌

浏览器控件是进程内组件。也就是说,如果浏览器或者相关模块崩溃,那么整个程序会崩溃。虽然这不太可能会发生,但是由于浏览器加载的组件/插件太多太多,万无一失是肯定做不到的。这可能也是默认情况下,浏览器控件不会加载BHO的原因。

浏览器占用的资源很多。这包括CPU资源和内存。同时,网页可能需要额外的资源,例如客户端XML解析(CSDN……),动态的图片,ActiveX控件(大部分是Flash控件)。实际上,如果不限制用户浏览的网址,那么网站上常见的广告(通常是动态的图片或者Flash控件)会大大增加浏览器占用的资源,特别是CPU资源。

浏览器控件中加载的脚本可能造成程序不稳定。微软推荐禁用脚本,但是这会大大降低浏览器控件的实用性,同时使得某些高级的自定义特性,例如扩展DOM,变得毫无意义。

浏览器不太适合自动化的浏览操作。尽管微软把浏览器作为操作系统的核心,但是我们还是看到,在浏览器控件不断浏览网页的过程中,它的内存占用不断上升。因为这种现象,浏览器控件推荐的用途还是作为静态或者人控的显示。

入门

在使用浏览器控件之前,你需要创建它。这可以通过在对话框编辑器中插入微软浏览器控件,或者使用类标识CLSID_WebBrowser创建一个控件来完成。如果你仅仅把控件用于显示,那么第一种方法就足够了,如果你需要一些比较高级的功能,例如自定义一些特性,那么你需要用代码来控制控件的创建过程。某些类库,(例如MFC),内建了对浏览器控件的支持(CHTMLxxxx和CDHTMLDialog类),但是它们在提供你访问浏览器控件的便利的同时,也使得你自定义浏览器的过程更加复杂。在我看来,它们最好的用途是用作访问浏览器控件的示例和自定义的基础。

浏览器控件提供的一个最主要的COM接口是IWebBrowser2。它提供一个浏览器的基本操作接口,以及这个接口的一些方法,例如比较常用的方法是Navigate/Navigate2,它使得浏览器控件打开一个你指定的目标,例如一个文件夹,一个网页,或者一个活动文档。你可能需要要有效地理解IWebBrowser2接口提供给你的应用程序的特性,你首先需要对Internet ExplorerDHTML两者的对象模型有一个基本的了解。当然,完全解释这些模型可能会占据大量篇幅,因为DHTML文件中每种独立的元素类型(<B> <HTML> <BODY>等等)都具有代表自己的COM对象类或者接口。获得对这些对象模型的彻底的理解的最好方法是看一些书和获得一个工具。Inside Dynamic HTML 微软出版社 1997)是DHTML对象模型的最好的参考书之一。关于对象模型的更多技术信息可以通过研究Internet Client SDKDHTML相关头文件(特别是mshtml.h expdispid.h mshtmhst.hmshtmdid.h)。这些文件指定各种类或者对象支持的接口。不幸的是,可用的Internet Client SDK中的帮助文档只有中等程度的辅助,他们解释了如何使用IWebBrowser2接口的细节,但是没有提供太多对象和接口之间的关系的信息。微软的相关文档很少,所以探索DHTML对象到底支持那些接口是一个有趣的事情。在微软知识库中,你经常会看到一些DHTML对象支撑标准的IConnectionPointContainer、IOleCommandTarget或者IOleContainer接口。

如何...

使用MFC集成浏览器控件

MFC6开始内建了对浏览器控件的支持,但是高级的接口,例如IDocHostUIHandler,到7.0版本才支持。使用MFC编写浏览器控件应用程序比较简洁,用户可能只需要少量代码就可以创建出一个具有大部分浏览器功能的程序。使用MFC的缺点是MFC6的这些类的BUG很多,而且要自定义一些功能的话,需要了解了MFC的控件创建过程。MFC有一个MFCIE示例演示了一个使用CHTMLView创建的简单的浏览器程序。Paul DiLascia 在MSDN杂志中他的C++Q&A专栏中演示了在对话框中集成CHtmlView,以及禁用浏览器控件的右键菜单的方法。

自定义浏览器的行为

如果在应用程序中集成浏览器控件,可以参考MSDN中WebBrowser Customization这篇文章。一个基于MFC的示例可以在http://www.beginthread.com/Article/Ehsan/Advanced%20CHtmlView%20Hosting找到。

如果编写BHO,那么MSDN文章Browser Helper Objects: The Browser the Way You Want It(Dino Esposito著)这篇文章可以用来入门。

在MFC中重载默认的控件站点

为了实现一些高级浏览器宿主特性,需要在控件站点的同一个对象上实现某些接口。例如用于查询宿主提供的服务接口的IServiceProvider(常用的服务有用于HTML编辑器的IHTMLEditHost或者IHTMLEditServices和用于自定义IE的安全选项的IInternetHostSecurityManager )和 用于自定义浏览器的行为和界面的IDocHostUIHandler、IDocHostUIHandler2以及IDocHostShowUI接口。

虽然在MFC7中,可以重载CWnd::CreateControlSite来覆盖控件站点的创建,但是在MFC6中,这个工作要复杂得多。微软知识库文章HOWTO: Disable the Default Pop-up Menu for CHtmlView介绍了其中一种方法,但是这种方法看起来不那么优雅,要在启动时就覆盖掉默认的OLE容器创建者,而且窗口无法创建其他类型的控件站点。实际上,这不是必要的。分析一下下面的MFC6代码
void AFX_CDECL AfxEnableControlContainer(COccManager* pOccManager)
{
    if (pOccManager == NULL)
        afxOccManager = _afxOccManager.GetData();
    else
        afxOccManager = pOccManager;
}
你可以看到只需要在创建前调用AfxEnableControlContainer,传递你自己的容器创建者作为参数,创建站点之后再调用一次传递NULL作为参数就可以达到覆盖掉默认的OLE容器创建者的目的。这是在你覆盖的CHtmlView::Create中调用的.你必须覆盖这个过程,因为CHtmlView::Create会调用AfxEnableControlContainer(NULL)。
BOOL CHtmlView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
UINT nID, CCreateContext* pContext)
{
……
//假定控件容器已经启用
AfxEnableControlContainer();
……

常见问题

MFC6的CHtmlView的BUG

在我编写我的一种基于网页的游戏的外挂的第二个版本的时候,我试图把我的经验编写成文章(这篇文章已经发表在我的专栏)。作为我的第一个非测试用途的(其他的浏览器基本上都过于简单,而且有这样那样的不便或者缺陷,以至于不能方便和稳定地使用)MDI浏览器,我碰见的第一个问题就是修复MFC的BUG(暂且不谈IE本身的BUG)。尽管我查到和发现的BUG不算太多,但是用于解决这些BUG的代码量也很可观。我到目前为止发现的大部分BUG的都在这篇文章中的示例代码里解决了,尽管文章中关于这些问题的篇幅很少。

在CDHtmlDialog派生的对话框中按Ctrl+N会弹出IE

CDHtmlDialog捕获了DWebBrowserEvets事件,并将其转发到虚函数,而没有捕获DWebBrowserEvents2;所以在按Ctrl+N触发DWebBrowserEvents2事件的时候,执行默认操作——打开新的IE窗口。这可能不是你预料之中的行为。解决的方法是自己写一个EventSink,你可以不必将其转发到虚函数。参见微软知识库文章Q181845 HOWTO: Create a Sink Interface in MFC-Based COM Client


ActiveX控件中访问文档对象模型

知识库文章Q172763 INFO: Accessing the Object Model from Within an ActiveX Control 描述了这个问题的解决方案。可以看到,可以同样使用IOleClientSite来和IE这个控件容器交互。可以使用IOleClientSite::GetContainer得到网页所在HTML文档对象的IOleContainer接口,然后再查询其他接口,例如IHTMLDocument2来进行对DHTML对象模型的访问。

创建并且操纵IE浏览器

可以使用CoCreateInstance来创建一个浏览器对象,使用的CLSID是CLSID_InternetExplorer。创建成功之后,可以查询浏览器对象的其他接口,例如IWebBrowser2,IOleObject等等。

分析网页和自动提交网页表单

经常被提出的问题,但是网页千奇百怪,要写个通用的不容易。一般的应用都是首先把可以参考MSDN中文站上的文章拆取Web页

如何调用网页中Script中的函数?

IHTMLDocument2::scripts属性表示HTML文档中所有脚本对象。使用脚本对象的IDispatch接口的::GetIDsOfNames方法可以"发现其中的函数和对象成员,使用IDispatch::Invoke可以访问这些成员。

参考

  • Inside OLE, 第二版, Kraig Brockschmidt著 (微软出版社)
  • Understanding ActiveX and OLE, David Chappell著 (微软出版社)
  • Inside COM, by Dale Rogerson著 (微软出版社)

posted on 2004-07-20 11:59:00 by jiangsheng  评论(3) 阅读(9939)

重新启动服务

最近常去的论坛挂了,看起来是IIS进程系统资源占用太多了;服务器管理员又度周末去了,不能重启IIS,郁闷。CSDN服务器的IIS可能重启过于频繁了,分论坛页面经常来不及更新,自己发的帖子出现在列表里面的时候已经沉了,还是郁闷。

微软知识库文章Q194916?Restarting?Web?Services?and?Scheduled?Tasks?with?a?Batch?File(http://support.microsoft.com/?kbid=194916?)中描述了定时用命令行重新启动IIS的方法,有想偷懒的网管可以试试。

如果用程序来重新启动IIS的话,可以使用Shell对象的IShellDispatch2接口的ServiceStop 和ServiceStart方法。要使用Shell对象,可以调用CoCreateInstance,传递Shell对象的CLSID CLSID_SHELL来创建对象,然后查询其IShellDispatch/IShellDispatch2等接口。

另外,WMI类Win32_ApplicationService?也提供了控制服务的方法StartService和StopService。cideguru上面有一个示例Using WMI to Extract Management Information(http://www.codeguru.com/Cpp/W-P/system/misc/article.php/c5675/)。


当然,使用Windows服务API也是可以的——尽管需要OpenService之后再ControlService和StartService,看起来不是很简洁。平台SDK中的示例Sending Control Requests to a Service(http://msdn.microsoft.com/library/en-us/dllproc/base/sending_control_requests_to_a_service.asp)描述了这一点。

这些方法都可以应用于其它服务。要查询服务的短名称的话,可以参考微软知识库文章Q271362?How?to?Find?the?Short?Names?of?Services?(http://support.microsoft.com/?kbid=271362
参考文档
Browse?for?a?Folder?the?COM?Way(Visual?C++?Developer,?Aug. 1999)

More Windows 2000 UI Goodies: Extending Explorer Views by Customizing Hypertext Template Fileshttp://msdn.microsoft.com/msdnmag/issues/0600/w2kui2/default.aspx

posted on 2004-06-19 20:24:00 by jiangsheng  评论(6) 阅读(4468)

Powered by: Joycode.MVC引擎 0.5.2.0