Monday, January 31, 2005

 

Some notes on IE related codes

Below are some weblinks I read to build a special tool. You can guess what kind of tool I build. ^_^

1.
MyIE and GreenBrowser
http://www.morequick.com/indexgb.htm

2.
IE的模态对话框里的问题还真是不少
http://www.cnblogs.com/birdshome/archive/2005/01/14/91586.html

3.
Advanced customization of WebBrowser Control in Dialog based app.
By Greg Ellis
http://www.codeproject.com/internet/CustomBrowser.asp

4.
HTTP header and source extraction tool
By Code4Food
http://www.codeproject.com/tools/hextract.asp

5.
MIME Type Detection in Internet Explorer
http://msdn.microsoft.com/library/default.asp?url=/workshop/networking/moniker/overview/appendix_a.asp

6.
Viewing the IE Document Object Model
Tony Juricic December 13, 2001 (a little bit old actually)
http://www.codeguru.com/Cpp/COM-Tech/atl/misc/article.php/c3619/

7.
IE & Delphi
http://www.euromind.com/iedelphi/

8.
Custom WebBrowser Context Menus
http://www.beginthread.com/Article/Ehsan/Custom%20WebBrowser%20Context%20Menus/

IE Spy
http://www.beginthread.com/Article/Ehsan/IE%20Spy/

WebBrowser Goodies
http://www.beginthread.com/Article/Ehsan/WebBrowser%20Goodies/

9.
Style Inspector
By Mircea Puiu
http://www.codeproject.com/tools/StyleInspector.asp

10.
HTTPeep - an HTTP inspector
By Ashley van Gerven
http://www.codeproject.com/csharp/HTTPeep.asp

11.
Web Replay 2 - Automated Web Testing
By Emmanuel Kartmann
http://www.codeproject.com/tools/WebReplay2.asp

12.
Automating Internet Explorer
By Leslie Hanks
http://www.codeproject.com/csharp/AutomatingInternetExplore.asp

13.
A Simple protocol to view aspx pages without IIS implemented in C#
By Andy Brummer
http://www.codeproject.com/aspnet/AspxProtocol.asp

14.
Several tools, samples, and wizards
http://www.cheztabor.com/projects.htm

Sunday, January 30, 2005

 

Some notes on IE memory leaking

I.
Understanding and Solving Internet Explorer Leak Patterns
Justin Rogers
Microsoft Corporation
June 2005
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp

II.
Memory Leakage in Internet Explorer - revisited
By volkan.ozcelik
http://www.codeproject.com/useritems/LeakPatterns.asp

Thursday, January 27, 2005

 

Some notes on IE and cookie

1.
使用代码解析ViewSate的Base64值
From http://pierce.cnblogs.com/archive/2005/08/01/204725.html

ViewState的值的编码是Base64,默认状况下,是没有加密的,很容易读出。
ViewState的值可以加密,首先,确保Page的EnableViewStatMac=true,然后在Machine.Config中配置machineKey。
默认Machine.Config中的machineKey:
!-- validation="[SHA1|MD5|3DES]" -->
machineKey
validationKey="AutoGenerate,IsolateApps"
decryptionKey="AutoGenerate,IsolateApps"
validation="SHA1" />
可以修改machineKey来使用某种加密方式,注意:加密由Machine Layer完成,要消耗系统资源。本人关于加密ViewState没有测试。

通过使用浏览器,可以获取ViewState的隐藏内容,使用下面的代码,可以解析:
private string Base2String(string message)
{
byte[] by=System.Convert.FromBase64String(message);

string dest=System.Text.Encoding.ASCII.GetString(by);
return dest;

}
//如果ViewState的值为"dDw5NDA0MTAzOTY7dDxwPGw8cGFzczs+O2w8RmlzaDs
+Pjs7PjtsPF9jdGwwO2NoZWNrO19jdGwxO19jdGwyO19jdGwzO2NiOz4+";
string source="dDw5NDA0MTAzOTY7dDxwPGw8cGFzczs
+O2w8RmlzaDs
+Pjs7PjtsPF9jdGwwO2NoZWNrO19jdGwxO19jdGwyO19jdGwzO2NiOz4+";
Response.Write(Base2String(source));可以获得:t<940410396;t;l>;;>;l<_ctl0;check;_ctl1;_ctl2;_ctl3;cb;>>
其中,cb是指动态生成的CheckBox,共动态生成5个CheckBox,check是动态生成的第2个CheckBox的Id,其他的没有指定Id。

如果在Page的后台代码中完成上面的操作,需要重写SavePageStateToPersistenceMedium():
protected override void SavePageStateToPersistenceMedium(object viewState)
{
// 调用基类的方法,完成基本操作
base.SavePageStateToPersistenceMedium(viewState);
// 获取ViewState的Base64值
LosFormatter format = new LosFormatter();
StringWriter writer = new StringWriter();
format.Serialize(writer, viewState);
string vsRaw = writer.ToString();
Response.Write("ViewState Raw: " + Server.HtmlEncode(vsRaw));
// 解析内容
byte[] buffer = Convert.FromBase64String(vsRaw);
string vsText = Encoding.ASCII.GetString(buffer);
Response.Write("ViewState Text: " + Server.HtmlEncode(vsText));
}
通过获取ViewState的值,可以有助于理解ViewState的目的和作用,毕竟ViewState中的StateBag,可以存储页面级的变量,通过PostBack发送,是非常有用的。


2.
使用混合脚本编程来实现的Base64编码
From http://www.cnblogs.com/birdshome/archive/2005/01/12/89185.html

在近来的工作中,需要在Web页上制作复杂的逻辑和框架以及后台之间交换数据,特别是和后台交换数据,编码是个必须考虑的问题。否则可能会因为编码不同,把脚本的执行给搞得乱七八糟,根本得不到想要的结果。Base64是一种常用而又简单的编码,就先从它下手弄弄了。

关于Base64的详细定义可以查看RFC 2045,如果简单的说一下呢:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式(The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.)。好玩,弄来不被人识别?不识别就不识别嘛,反正程序能之别就行了。

http://www.faqs.org/rfcs/rfc2045.html

这个编码为什么叫Base64呢?这是应为它的转换需要依赖一张64个字符的转换表,叫做The Base64 Alphabet。 Base64以3个字节为一个转换单位,把这24bits分为4份,高位补零,再查前面说的那个转换表,就编码完毕了。如果被转换的数据(以byte为单位)不能被3整除,按余数补"="(pad),当然最多也就只有两种可能,不是补一个pad就是补两个pad。

例如转换"博客园",这三个字的内码十六进制为:B2A9 BFCD D4B0
二进制为:10110010 10101001 10111111 11001101 11010100 10110000
六个一拨:00101100 00101010 00100110 00111111 00110011 00011101 00010010 00110000,再按新的编码转为十进制查表后得到"博客园"的base64编码为:"sqm/zdSw"。
// 蓝色的0是补位的

之前有人用JavaScript来做过Base64编码,结果居然使用escape来获取字符的编码,这样当遇到被转换的字符有汉字时就faint掉了,escape在基于NT的32位系统下得到的是汉字的Unicode编码。但是JavaScript却真的没有办法得到汉字的GB码:( 我也郁闷了半天,后来在mozart0的帮助下使用VBScript加JScript混合搞定了这个编码算法实现。

http://www.unicode.org/

附1:The Base64 Alphabet
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 16 Q 32 g 48 w
1 B 17 R 33 h 49 x
2 C 18 S 34 i 50 y
3 D 19 T 35 j 51 z
4 E 20 U 36 k 52 0
5 F 21 V 37 l 53 1
6 G 22 W 38 m 54 2
7 H 23 X 39 n 55 3
8 I 24 Y 40 o 56 4
9 G 25 Z 41 p 57 5
10 K 26 a 42 q 58 6
11 L 27 b 43 r 59 7
12 M 28 c 44 s 60 8
13 N 29 d 45 t 61 9
14 O 30 e 46 u 62 +
15 P 31 f 47 v 63 /

附2:base64编码源代码

script language="javascript">
var Base64Alphabet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'];

function EncodeBase64(string)
{
var hexString = string.getGBCode();
window.status = hexString;
var base64 = '';
var B64A = Base64Alphabet;
var padCount = hexString.length%3;
var count = parseInt(hexString.length/6);
var i = 0;
for ( i=0 ; i < count ; ++i )
{
var intA = parseInt(hexString.charAt(i*6+0)+hexString.charAt(i*6+1), 16);
var intB = parseInt(hexString.charAt(i*6+2)+hexString.charAt(i*6+3), 16);
var intC = parseInt(hexString.charAt(i*6+4)+hexString.charAt(i*6+5), 16);
var part1 = intA >> 2;
var part2 = ((intA & 0x03) << 4) | (intB >> 4);
var part3 = ((intB & 0x0f) << 2) | (intC >> 6);
var part4 = intC & 0x3f;
base64 += B64A[part1] + B64A[part2] + B64A[part3] + B64A[part4];
}
if ( padCount == 1 )
{
var intA = parseInt(hexString.charAt(i*6+0)+hexString.charAt(i*6+1), 16);
var intB = parseInt(hexString.charAt(i*6+2)+hexString.charAt(i*6+3), 16);
var part1 = intA >> 2;
var part2 = ((intA & 0x03) << 4) | (intB >> 4);
var part3 = ((intB & 0x0f) << 2);
base64 += B64A[part1] + B64A[part2] + B64A[part3] + '=';
}
if ( padCount == 2 )
{
var intA = parseInt(hexString.charAt(i*6+0)+hexString.charAt(i*6+1), 16);
var part1 = intA >> 2;
var part2 = ((intA & 0x03) << 4);
base64 += B64A[part1] + B64A[part2] + '==';
}
return base64;
}
/script>
script language="vbscript">
function vbGetGBCode(str)
dim i, length, s
length = len(str)
for i=1 to length
hexCode = hex(asc(str.charAt(i-1)))
if (len(hexCode) mod 2) = 0 then
s = s & hexCode
else
s = s & "0" & hexCode
end if
next
vbGetGBCode = s
end function
/script>
script language="javascript">
String.prototype.getGBCode = function()
{
return vbGetGBCode(this);
}
/script>

3.
JavaScript实现的Base64编码和解码
From http://bbs.mscommunity.com/Forums/ShowThread.aspx?PostID=2349

script language=javascript>

var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

var base64DecodeChars = new Array(

  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,

  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,

  -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,

  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,

  -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,

  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);

function base64encode(str) {

  var out, i, len;

  var c1, c2, c3;

  len = str.length;

  i = 0;

  out = "";

  while(i < len) {

c1 = str.charCodeAt(i++) & 0xff;

if(i == len)

{

   out += base64EncodeChars.charAt(c1 >> 2);

   out += base64EncodeChars.charAt((c1 & 0x3) << 4);

   out += "==";

   break;

}

c2 = str.charCodeAt(i++);

if(i == len)

{

   out += base64EncodeChars.charAt(c1 >> 2);

   out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));

   out += base64EncodeChars.charAt((c2 & 0xF) << 2);

   out += "=";

   break;

}

c3 = str.charCodeAt(i++);

out += base64EncodeChars.charAt(c1 >> 2);

out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));

out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6));

out += base64EncodeChars.charAt(c3 & 0x3F);

  }

  return out;

}

function base64decode(str) {

  var c1, c2, c3, c4;

  var i, len, out;

  len = str.length;

  i = 0;

  out = "";

  while(i < len) {

/* c1 */

do {

   c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];

} while(i < len && c1 == -1);

if(c1 == -1)

   break;

/* c2 */

do {

   c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];

} while(i < len && c2 == -1);

if(c2 == -1)

   break;

out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));

/* c3 */

do {

   c3 = str.charCodeAt(i++) & 0xff;

   if(c3 == 61)

 return out;

   c3 = base64DecodeChars[c3];

} while(i < len && c3 == -1);

if(c3 == -1)

   break;

out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));

/* c4 */

do {

   c4 = str.charCodeAt(i++) & 0xff;

   if(c4 == 61)

 return out;

   c4 = base64DecodeChars[c4];

} while(i < len && c4 == -1);

if(c4 == -1)

   break;

out += String.fromCharCode(((c3 & 0x03) << 6) | c4);

  }

  return out;

}

function utf16to8(str) {

  var out, i, len, c;

  out = "";

  len = str.length;

  for(i = 0; i < len; i++) {

c = str.charCodeAt(i);

if ((c >= 0x0001) && (c <= 0x007F)) {

   out += str.charAt(i);

} else if (c > 0x07FF) {

   out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));

   out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));

   out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));

} else {

   out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));

   out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));

}

  }

  return out;

}

function utf8to16(str) {

  var out, i, len, c;

  var char2, char3;

  out = "";

  len = str.length;

  i = 0;

  while(i < len) {

c = str.charCodeAt(i++);

switch(c >> 4)

{

  case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:

   // 0xxxxxxx

   out += str.charAt(i-1);

   break;

  case 12: case 13:

   // 110x xxxx  10xx xxxx

   char2 = str.charCodeAt(i++);

   out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));

   break;

  case 14:

   // 1110 xxxx 10xx xxxx 10xx xxxx

   char2 = str.charCodeAt(i++);

   char3 = str.charCodeAt(i++);

   out += String.fromCharCode(((c & 0x0F) << 12) |

    ((char2 & 0x3F) << 6) |

    ((char3 & 0x3F) << 0));

   break;

}

  }

  return out;

}



function doit() {

  var f = document.f

  f.output.value = base64encode(utf16to8(f.source.value))

  f.decode.value = utf8to16(base64decode(f.output.value))

}
/script>

4.
.Net/C# 应用程序直接读取本地 Cookies 文件 (由于 WinXP SP2 调用 API: InternetGetCookie 无果)
From http://blog.csdn.net/playyuer/archive/2004/12/03/203431.aspx

using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.Win32;
public class Class1
{
static void Main(string[] args)
{
System.Console.WriteLine(GetCookiesFromFiles("et8")); //支持 WinXP SP2
System.Console.WriteLine(GetCookie("http://bbs.et8.net"));
System.Console.ReadLine();
}

[System.Runtime.InteropServices.DllImport("wininet.dll", CharSet=System.Runtime.InteropServices.CharSet.Auto, SetLastError=true)]
public static extern bool InternetGetCookie(string lpszUrlName, string lpszCookieName, StringBuilder lpszCookieData, ref int lpdwSize);

[System.Runtime.InteropServices.DllImport("kernel32.dll")]
internal static extern Int32 GetLastError();

public static string GetCookie(string url) //Win32 API
{
int size = 1000;
StringBuilder sb = new StringBuilder(size);
if (!InternetGetCookie(url,"", sb,ref size))
{
Console.WriteLine("Error code:{0}", GetLastError());
}
return sb.ToString();
}

public static string GetCookiesFromFiles(string MasterDomain) //Cookies File
{
string S = null;
RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders", false);
if (key != null)
{
string val = null;
// foreach(string s in key.GetValueNames())
// {
// if (s.ToUpper() == "COOKIES")
// {
// val = (string) key.GetValue(s);
// break;
// }
// }
val = (string) key.GetValue("cooKies");
val = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Cookies);
// pay attention here

if (val!= null)
{
System.Console.WriteLine("用户 Cookies 文件目录: " + val);
string[] F = Directory.GetFiles(val);
string s = null;
int i;
Regex r = new Regex(@".*@" + MasterDomain + @"(\[\d+\])?\.txt");

for (i = 0; i < F.Length; i++)
{
if (r.IsMatch(F[i]))
{
s = F[i];
System.Console.WriteLine("用户 Cookies 文件: " + s);
}
}
if (s != null) //s 就是最新文件
{
StreamReader sr = new StreamReader(s);
s = null;
i = 1;
while ((s = sr.ReadLine())!= null)
{
if (s == "*" || s == "\n")
{
i = 0;
}
//每节只读两行
if (i == 1)
{
S += s;
}
else if (i == 2)
{
S += "=" + s + "; ";
}
i++;
}
}
}
}
return S;
}
}

Wednesday, January 26, 2005

 

Some notes on SaveAs MHTML

正好被人问及这个问题,所以讨论一下

首先,当然是看微软得相关文档

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cdosys/html/_cdosys_mime_encapsulation_of_aggregate_html_documents_mhtml_.asp

如果是VC操作IE,则可以参见

Automated IE SaveAs MHTML
By Stephane Rodriguez.
http://www.codeproject.com/shell/iesaveas.asp

Save As MHTML (whole web page, images, ... in a single file)
Save As Full HTML (additional folder for images, ...)
Save HTML code only
Save As Text
等几个功能都实现了,很不错得文章

如果是ASP.Net,则可以看

Convert HTML to MHTML using ASP.NET
By Partenon
http://www.codeproject.com/aspnet/aspnethtml2mht.asp
代码很简单直白。

得到的文件可以打成二进制包放进数据库,这个比较简单,不多说。

当然,对于某些网页,上述方法还是可能有些问题。基本上是“it flashed some scripting errors And unable to load and show some .gif images.”这两个原因造成的。前一个问题可以用Edit模式解决,后一个问题不知那位高手有办法。

Tuesday, January 25, 2005

 

Some notes on IE Favorites

1.
FavIconizer
By SteveKing
http://www.codeproject.com/tools/faviconizer.asp

A small utility which refreshes the icons in your IE favorites menu

2.
Creating an Internet Explorer Favorites Control
By Jeff Bramwell
http://www.codeproject.com/cs/miscctrl/favoritescontrol.asp

How to create an Internet Explorer favorites control using C#

3.
A sample class to get the favorites of IE
By rayyang2000
http://www.codeproject.com/shell/favoriteengine.asp

This is a class to get the folders and urls of the IE.

4.
实现浏览历史菜单
关键字:ITravelLogStg, IEnumTravelLogEntry, ITravelLogEntry

By CathyEagle
http://blog.csdn.net/CathyEagle/archive/2005/03/03/308620.aspx

4.1、概述

Internet Explorer的浏览历史菜单在4.0版本开始出现,但直到5.5之前,微软都未公布用于访问浏览历史的COM接口,如今已是IE6.0大行其道的年代,用于访问浏览历史的接口也早已公布多时,本文的目的则是试图抛砖引玉,简单介绍用于访问浏览历史的Travel Log接口,并用一个小小的类CIETravelLog来实现对Travel Log的封装。



4.2、IOmHistory接口

在早些时候的MSDN中,我们能够查阅到关于浏览历史的接口仅有IOmHistory,而该接口实际上对应的是浏览器中可以通过脚本访问的“history”对象。对于“history”对象,MSDN中是这样说的:



For security reasons, the history object does not expose the actual URLs in the browser history. It does allow navigation through the browser history by exposing the back, forward, and go methods. A particular document in the browser history can be identified as an index relative to the current page. For example, specifying -1 as a parameter for the go method is the equivalent of clicking the Back button.



This object is available in script as of Microsoft Internet Explorer 3.0.



即为了安全的原因,IOmHistory接口仅提供了有限的几个方法来完成在浏览器中前进、后退等操作,并没有提供访问历史列表Url的能力。这也难怪,该接口在IE 3.0时代已经存在,而当时IE并不成熟,可编程能力也不甚强大。一直到IE 4.0通过与Windows 98捆绑销售一统天下之后,相关的文档才逐渐丰富,多窗口浏览器等基于Internet Explorer/WebBrowser Control的应用软件也才铺天盖地开来。但在IE 5.5接口公布之前,要完全模拟IE的Travel Log行为,并不是一件容易的事。最容易想到的方法就是在BeforeNavigate、DocumentComplete等事件发生之时记录/修改Url并加以保存(我在早些时候也这样做过),但是效果不甚理想,尤其是浏览包含Frame的网页时,处理更是麻烦。当然,要完全模拟亦非难事,只不过开发人员都知道微软公布接口是早晚的事,所以也没有人花大力气在模拟IE的Travel Log行为上。



4.3、Travel Log简介

Internet Explorer 5.5推出以后,Travel Log接口也就开始出现在MSDN中,它是专门为OLE嵌入WebBrowser Control的应用程序设计的,其目的是“提高和加强用户的访问日志体验”(improve and enhance the user's travel log experience)。事实上,稍后我会提到,Travel Log接口正日益成为应用程序中的重要接口之一。

微软公布的Travel Log共包含三个接口:ITravelLogStg, IEnumTravelLogEntry和ITravelLogEntry。



ITravelLogStg——该接口提供了用于在Travel Log中添加、删除、枚举日志(浏览历史)的方法,本文需要用到的几个方法列举如下:
方法名 用途

EnumEntries 为访问日志项创建枚举器(IEnumTravelLogEntry接口指针)

GetRelativeEntry 返回一个日志项

TravelTo 访问一个日志项

IEnumTravelLogEntry——该接口提供用于枚举日志项所必需的方法,本文只用到一个方法:
方法名 用途

Next 枚举下一个日志项(返回ITravelLogEntry接口指针)

ITravelLogEntry——该接口只有两个方法,分别用于返回日志项的Title和Url:
方法名 用途

GetTitle 返回日志项的Title

GetURL 返回日志项的Url



接口准备好了,我们也就很容易得知它们之间的关系:

要得到相对于当前页面的日志项列表,首先应通过ITravelLogStg接口创建一个枚举器(IEnumTravelLogEntry接口)。
通过IEnumTravelLogEntry枚举器的Next方法枚举出一个个的日志项(ITravelLogEntry接口)。
由ITravelLogEntry接口获取日志项所代表的网页的Title和Url并加以处理。
访问相对于当前页面的某个日志项时,首先由ITravelLogStg的GetRelativeEntry方法根据与当前页的距离得到ITravelLogEntry接口,再将后者传入ITravelLogStg的TravelTo方法以达到访问日志项的目的(如前进和后退)。


也许不是太恰当,我对UML也不熟悉,借用一个伪UML序列图表示其关系如下:








4.4、封装Travel Log

接下来,我们就用一个简单的类来完成对Travel Log的封装。如下所示,tlogstg.h包含了Travel Log的相关接口声明,该头文件可以在Platform SDK中找到。



#include "tlogstg.h"



class CIETravelLog

{

private:

ITravelLogStg *m_pTravelLogStg;

IEnumTravelLogEntry *m_pEnumLogEntry;

ITravelLogEntry *m_pTravalLogEntry;

IWebBrowser2* m_pWebBrowser;

public:

CIETravelLog(void);

~CIETravelLog(void);

void SetWebBrowser(IWebBrowser2* pWebBrowser);

void BuildHistoryMenu(CMenu * pMenu, unsigned char nCount, bool bForward);

void TravelTo(int nPosition);

};



CIETravelLog::CIETravelLog(void)

: m_pTravelLogStg(NULL), m_pEnumLogEntry(NULL), m_pTravalLogEntry(NULL), m_pWebBrowser(NULL)

{

}



CIETravelLog::~CIETravelLog(void)

{

if ( m_pTravelLogStg != NULL )

{

m_pTravelLogStg->Release();

}

if ( m_pEnumLogEntry != NULL )

{

m_pEnumLogEntry->Release();

}

if ( m_pTravalLogEntry != NULL )

{

m_pTravalLogEntry->Release();

}

if ( m_pWebBrowser != NULL )

{

m_pWebBrowser->Release();

}

}



//将浏览器的IWebBrowser2接口指针赋予CIETravelLog的实例

void CIETravelLog::SetWebBrowser(IWebBrowser2* pWebBrowser)

{

if ( (m_pWebBrowser == pWebBrowser) || (m_pWebBrowser == NULL) )

{

return;

}

if ( m_pWebBrowser != NULL )

{

m_pWebBrowser->Release();

}

m_pWebBrowser = pWebBrowser;



IServiceProvider *pSP;

HRESULT hr = m_pWebBrowser->QueryInterface(IID_IServiceProvider, (LPVOID*)&pSP);

m_pWebBrowser->Release();

if (SUCCEEDED(hr))

{

hr = pSP->QueryService(SID_STravelLogCursor, IID_ITravelLogStg, (LPVOID*)&m_pTravelLogStg);

pSP->Release();

}

}



//创建浏览历史菜单,bForward指明是前进还是后退菜单

void CIETravelLog::BuildHistoryMenu(CMenu * pMenu, unsigned char nCount, bool bForward)

{

if ( m_pTravelLogStg == NULL )

{

return;

}

TLENUMF eFlag = bForward ? TLEF_RELATIVE_FORE : TLEF_RELATIVE_BACK;

if ( FAILED(m_pTravelLogStg->EnumEntries( eFlag, &m_pEnumLogEntry ) ) )

{

return;

}



ULONG uFetched;

int i=0;

if ( m_pEnumLogEntry !=NULL )

{

while ( SUCCEEDED( m_pEnumLogEntry->Next( 1, &m_pTravalLogEntry, &uFetched ) ) &&

m_pTravalLogEntry && i<10 )//我们最多只需要10条历史菜单,可根据实际情况修改

{

LPOLESTR pszTitle;

m_pTravalLogEntry->GetTitle( &pszTitle );

CString strTitle = pszTitle;

if ( bForward )

{

//ID_IEHISTORY_MIDDLE是预定义的某个菜单项ID,从该ID开始前后可以创建10个菜单项,参见下一节

pMenu->InsertMenu( 0, MF_STRING, ID_IEHISTORY_MIDDLE + ++i, strTitle );

}

else

{

pMenu->InsertMenu( 0, MF_STRING, ID_IEHISTORY_MIDDLE - ++i, strTitle );

}

CoTaskMemFree( pszTitle );

m_pTravalLogEntry->Release();

}

}

}



//根据与当前页面的相对距离来访问历史网页

void CIETravelLog::TravelTo(int nPosition)

{

if ( m_pTravelLogStg == NULL )

{

return;

}

if SUCCEEDED(m_pTravelLogStg->GetRelativeEntry( nPosition, &m_pTravalLogEntry ))

{

m_pTravelLogStg->TravelTo( m_pTravalLogEntry );

}

}



4.5、使用CIETravelLog

假设是在我们自己编写的多窗口浏览器中使用Travel Log。为简单起见,我们声明一个CIETravelLog的全局对象g_IETravelLog,以便在任何地方调用。然后在适当的地方,如CMainFrame的TBN_DROPDOWN消息(工具条菜单下拉消息)处理函数OnDropDown中,添加下面的代码,用以创建浏览历史菜单:

//GetActiveWebBrowserPtr返回活动的浏览器IWebBrowser2接口指针

IETravelLog.SetWebBrowser( GetActiveWebBrowserPtr );

//bForward为true则创建“前进”菜单,否则创建“后退”菜单

IETravelLog.BuildHistoryMenu( &Menu, 10, bForward);



以下定义为菜单项ID的范围,前后共可以容纳10个菜单项,可根据实际情况修改。

#define ID_IEHISTORY_FIRST 60200

#define ID_IEHISTORY_MIDDLE 60210

#define ID_IEHISTORY_LAST 60220



添加命令处理函数OnTravelHistoryUrl用以响应从ID_IEHISTORY_FIRST到ID_IEHISTORY_LAST的菜单命令。



ON_COMMAND_RANGE(ID_IEHISTORY_FIRST, ID_IEHISTORY_LAST, OnTravelHistoryUrl)



void CMainFrame::OnTravelHistoryUrl(UINT nID /* Command ID */)

{

//nID - ID_IEHISTORY_MIDDLE即为要访问的浏览历史到当前页面的距离

g_IETravelLog.TravelTo( nID - ID_IEHISTORY_MIDDLE );

}



4.6、再谈Travel Log

前面我提到“Travel Log接口正日益成为应用程序中的重要接口之一”,此处加以说明。从微软平台的开发模式及导向来看,基于Internet Explorer/WebBrowser Control的应用势必会成为主流。在下一代的操作系统Longhorn中,应用程序界面的描述将完全由XML的一个特化——XAML来完成,而XAML的解析将由浏览器完成。微软说未来应用程序的部署将会十分容易,本地应用和基于浏览器的应用之间的差异将会被逐渐淡化,而实现这一目标的一个重要表现就是,在将来的操作系统平台上,应用程序实际上时刻都将运行在Internet Explorer中,Internet Explorer在某种程度上来说变成了一个容器。

于是,扎根于Internet Explorer的Travel Log自然而然地就被整合到了我们的应用程序中。君不见,我们每天在资源管理器和浏览器上完成的工作,不就是在Travel Log中来来回回地跑吗?如果所有的应用程序都嵌入到Internet Explorer中运行,那么我们在应用程序中所作的操作便自然得到了记录,“前进”和“后退”也就很Easy了。

Monday, January 24, 2005

 

Some notes on IE Error Codes

1.
By 蒋晟
From http://blog.joycode.com/jiangsheng/archive/2005/04/08/47320.aspx

IE6.0之前的版本浏览器控件没有获得HTTP状态代码的接口。一个很依赖于网站设置的方法是,捕获TitleChange事件,在页面标题包含"找不到页面"或者"Page Not Found"之类的字符串时,认为浏览失败。使用这种方法基本只对特定语言的网站有效,也可能受在浏览时使用的代理服务器影响而造成判断不准确。另一个方法是假定短时间内两次连接的结果相同,通过捕获浏览器的BeforeNavigate2事件,在事件处理代码中用winhttp api单独和服务器连接来测试服务器的回应。连接之后可以使用HttpQueryInfo来查询信息,相应参数是HTTP_QUERY_STATUS_CODE。在这之前,可能要在打开URL时用INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS标志来防止服务器的重定向。这种方法会造成每个页面被下载两次,一次由手动测试连接代码发起,一次由浏览器控件发起。根据网络和服务器的状况,两次下载也可能有不同的结果,所以这种方法也未必准确。

IE6.0版本的浏览器控件可以触发DWebBrowserEvents2::NavigateError事件来通知浏览错误及提供错误代码。但是,这个事件只在使用代码触发了浏览错误之后触发一次。在用户点击链接触发浏览错误时不会触发这个事件。

HTML文档对象不支持使用IBindStatusCallback接口自定义URL Moniker绑定过程,因此获得IWinInetHttpInfo接口之后查询信息的方法不能用。InternetGetLastResponseInfo在浏览失败时可能仍然成功,因为服务器可能自定义访问错误的页面。

参考

http://www.microsoft.com/mind/0796/protocol/protocol.asp

DWebBrowserEvents2::NavigateError

http://www.microsoft.com/mind/0396/sweeper/sweeper.asp

http://www.microsoft.com/mind/1096/activex/activex.asp

http://msdn.microsoft.com/workshop/networking/moniker/overview/overview.asp

Sunday, January 23, 2005

 

Some notes on cookie viewer

1.
Karen's Cookie Viewer

VB version

Discover the information that web sites store on your computer. This Power Tool automatically scans your computer, looking for "cookies" created by Microsoft's Internet Explorer and Netscape's Navigator. It can then display the data stored in each one. It can also delete Internet Explorer cookies.

Bonus: Visit Karen's Cookie Dispenser, to create your own web browser cookies!

From http://www.karenware.com/powertools/ptcookie.asp

2.
Cookie Viewer/Killer

By Roger McElfresh March 5, 2003
From http://www.codeguru.com/Cpp/W-D/dislog/miscellaneous/article.php/c5085/

VC Version

Saturday, January 22, 2005

 

Clean IE Spyware

1.
剖析各类恶意网页和IE漏洞对策分析
By 一孔之见 2003-11-26
From http://www.ykzj.org/static/2004010211251.html

以前经常听到有朋友说,我上网只看新闻,查一些资料,我不下载东西,我不接收邮件,看病毒奈我何?而今,互联网利用IE等的漏洞完全可以让你通过浏览网页让你的电脑面目全非,或者格盘,甚至中下木马,传播病毒,而且这种形式的传播愈演愈烈,闲话少说了,现在来分析一下各类恶意网页。

分析前先介绍一下注册表的修改方法,因为注册表在网页病毒中是中枢,就是通过它让你的电脑面目全非。
第一种方法:直接修改法
就是在运行里敲入regedit,然后进行编辑,这是大家通常修改注册表的方法。
第二种方法:reg包导入法
现在以解锁注册表为例(其实解锁用兔子等工具更好更方便,这里只是说明如何建立reg包)
对于WIN 9x/ME/NT 4.0来说,在记事本把下面的内容另存为*.reg文件,导入即可

REGEDIT4
;这里一定要空一行,否则将修改失败
[HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionPoliciesSystem]
"DisableRegistryTools"=dword:00000000

对于WIN 2000或XP,把 REGEDIT4 改为Windows Registry Editor Version 5.00即可

第三种方法:inf安装法
对于98/ME,把下面的内容保存为.inf后缀文件,右键单击给文件选择安装即可

[version]
signature="$CHICAGO$"
[DEFAULTINSTALL]
ADDREG=unlock.ADD.REG
DELREG=unlock.DEL.REG
[unlock.ADD.REG]
HKCU,SoftwareMicrosoftWindowsCurrentVersionPoliciessystem
[unlock.DEL.REG]
HKCU,SoftwareMicrosoftWindowsCurrentVersionPoliciessystem

若为2000或XP,将CHICAGO修改为Windows NT
至于其他修改格式,这里不多说,可以自己找找资料,真的不会建立其它的inf包可以和我联系:)

第四种方法:vbs脚本法
把下面的内容保存为.vbs后缀文件
Dim unlock
Set unlock = WScript.CreateObject("WScript.Shell")
unlock.Popup "将为您解开注册表"
unlock.RegWrite
"HKCUSoftwareMicrosoftWindowsCurrentVersionPoliciesSystemDisableRegistryTools",0,"REG_DWORD"


第五种方法:呵呵,是以其人之道还治其人之身的方法,这里不介绍(自己去网上找找资料)
至于在DOS下编辑注册表,这里不再举例说明
请大家切记,修改注册表前一定要备份注册表!!切记!!

知道了方法,现在就来分析各类恶意网站和对付的方针

恶意网站大致可以分成以下几类:

一 利用IE的文本漏洞通过编辑的脚本程序修改注册表的行为
1。轻度修改注册表:比如标题拦,默认主页,搜索页,添加广告等,先来看看其中的一段原代码
//a.setCLSID("{F935DC22-1CF0-11D0-ADB9-00C04FD58A0B}");恶意网页就是通过这个ID修改注册表的。
//Shl.RegWrite("HKCUSoftwareMicrosoftWindowsCurrentVersion
PoliciesExplorerNoRun", 01, "REG_BINARY"); 这一句代码可以让你的运行菜单消失。
清除方法:
本文对一般的被修改浏览器的解决方案不作提供,因为现在网上关于如何通过修复注册表来恢复的文章很多 ,大家可以自己找来看看
我认为这一类的修改一般可以通过注册表修复工具来修复,不必手动去修改。
常用工具有:超级兔子魔法,优化大师,3721魔宝石,杀毒王自带的IE修复器等
瑞星的注册表修复工具:http://it.rising.com.cn/newSite/Channels/anti_virus/Antivirus_Base/TopicExplorerPagePackage/spite
ful.htm
毒霸的注册表修复工具:http://sh.duba.net/download/other/tool_011027_RegSolve.htm
推荐一个很好的在线修复网站:www.j3j4.com
补丁:WINDOWS 2000:http://www.microsoft.com/china/windows2000/SP2.htm
WINDOWS 9X用户 :http://www.microsoft.com/downloads/release.asp?ReleaseID=32558

2。修改注册表禁止命令形式的修改,目的是不让用户通过注册表修复回去。
最通常的修改是锁住注册表,还有破坏关联:比如.reg,.vbs,.inf等
关于解锁注册表,在前面已经介绍了方法,至于被修改关联,只要我前面说的注册表修改的方法里的关联还
能用,就可以用其中的任意一个,但如果.reg,.vbs,.inf都被修改了,怎么办啊?,也不用怕,把 .exe
后缀改为.com后缀,我一样可以编辑注册表,.com也被改了,怎么办?没那么狠吧,行,我再改后缀为.scr 。嘿嘿,一样还可以修改。
最好的最简单的办法,马上重新启动,按F8进入DOS下,敲入SCANREG/RESTORE,选择以前的正常时的注册表
还原就可以,注意了,一定要选择没被修改时的注册表!如果发现连scanreg都被删除了(一些网站就是这么
狠的,用A盘COPY一个scanreg.exe到COMMAN下即可
有必要在这里说说常见的文件关联的默认值
正常的exe关联为[HKEY_CLASSES_ROOTexefileshellopencommand]
默认的键值为:"%1 %*" 将此关联改回去即可使用exe文件

3。修改注册表后留后门,目的让你修改注册表好像成功,重新启动后又恢复到被修改的状态。
这主要是在启动项里留了后门,大家可以打开注册表到(也可以用一些工具比如优化大师等来察看)
HKCUSoftwareMicrosoftWindowsCurrentVersionRun
HKCUSoftwareMicrosoftWindowsCurrentVersionRunOnce
HKCUSoftwareMicrosoftWindowsCurrentVersionRunServices
HKCUSoftwareMicrosoftWindowsCurrentVersionRun-
看看有没有可疑的启动项目,这一点最多朋友忽略,哪些启动可疑呢?
我这里给出几个大家需要注意的,启动项里键值有出现.hml和.htm后缀的,最好都去掉,还有有.vbs后缀的
启动项也去掉,还有一个很重要的,如果有这一个启动项,出现有类似键值的,比如:
system 键值是regedit -s c:windows……请注意,这个regedit -s 是注册表的一个后门参数,是用来导
入注册表的,这样的选项一定要去掉
还有一类修改会在c:windows产生.vbs后缀的文件,或是.dll文件,其实.dll文件实际是.reg文件
此时你要看看c:windowswin.ini文件,看看load=,run=,这两个选项后面应该是空的,如果有其他程序
修改load=,run=,将=后面程序删除,删除前看看路径和文件名,删除后在到system下删除对应的文件
还有一种方法,大家如果屡次修改重启又恢复回去,可以搜索C盘下所有的.vbs文件,可能有隐藏的,用记
事本打开,看到里面有关于修改注册表的都把它删除或保险起见把后缀改掉,你可以按中恶意网页的病毒的 时间来搜索文件:)
下面的这个漏洞大家非常值得注意,很多朋友说,你说的方法我都试了,启动项里绝对没有什么可疑的,也
没有什么vbs文件,呵呵,大家在启动IE时还有一个陷阱,就是IE主界面的工具的菜单里的广告,一定要去
掉,因为这些会在你启动IE时启动,所以你修改完其他的先别着急打开IE窗口,否则白费力气,方法:打开
注册表HKEY_LOCAL_MACHINESoftwareMicrosoftInternet ExplorerExtensions看到广告就删,别留情
一个很重要的问题,在中了恶意网页的陷阱后一定要先清空IE所有临时文件,切记!

说了那么多废话,那如何防御这类恶意网页呢?
一个一劳永逸的方法,把F935DC22-1CF0-11D0-ADB9-00C04FD58A0B这个ID删掉
在注册表的路径为HKEY_CLASSES_ROOTCLSID{F935DC22-1CF0-11D0-ADB9-00C04FD58A0B}
记住,看清楚了再删除,千万别删错其他。删掉这个F935DC22-1CF0-11D0-ADB9-00C04FD58A0B对系统不会有 影响的。
在IE的选单栏中选择“工具”→“Internet选项”,在弹出的对话框中切换到“安全”标签,选择“
Internet”后点击“自定义级别”按钮,在“安全设置”对话框中,把“ActiveX控件和插件”、“脚本”
中的相关选项全部选择“禁用”或“提示”即可。但如果选择了“禁用”,一些正常使用ActiveX和脚本的
网站可能无法完全显示。建议选择:提示。遇到警告时,看看该网站的原代码,如果发现有出现
Shl.RegWrite等的代码,就不要去了,如果是加密的原代码,不是自己熟悉的网站也不要去,如果连右键都用不了的,也要小心为好(看看原码有什么所谓啊,除非有什么好的JAVA或是恶意代码)

对于Windows98用户,请打开C:WINDOWSJAVAPackagesCVLV1NBB.ZIP,把其中的“ActiveXComponent.class删掉,对于WindowsMe用户,请打开C:WINDOWSJAVAPackages5NZVFPF1.ZIP,把其中的“ActiveXComponent.class”删掉,这些删掉不会影响正常浏览网页

在Windows 2000/XP,可以通过禁用“远程注册表服务”来阻挡部分恶意脚本。具体方法是:在“控制面板”→“管理工具”→“服务”中右键单击“Remote
Registry Service”,在弹出选单中选择“属性”,打开属性对话框,在“General”内将“Startup
ype”设为“Disabled”。这样也可以拦截部分恶意脚本程序。
嘿嘿,不用IE。用其他浏览器也可以……
大家在中了恶意网页的陷阱后,先不要立即重新启动计算机,到启动项里看看,有没有什么危险的启动项,不如deltree之类的

二 利用IE漏洞直接破坏Windows系统
如今利用浏览网页格式化硬盘已经不是什么新鲜事了,当某一天,你上网时突然跳出警告说当前页面包含 不安全的页面,如果你选择“是”,很可能硬盘被格式化掉
看看它的部分原代码:
// object ……id=wsh……F935DC22-1CF0-11D0-ADB9-00C04FD58A0B……>wsh(……)/object>
防御这一类网页,可以用下面的方法:
删掉F935DC22-1CF0-11D0-ADB9-00C04FD58A0B这个ID,因为这个ID可以用来生成命令格式,可以执行硬盘 的可执行文件,具体路径
HKEY_CLASSES_ROOTCLSID{F935DC22-1CF0-11D0-ADB9-00C04FD58A0B} 再次提醒,别删错了。
建议大家都把deltree.com和format.com命令改掉,比如用优化大师后改为deltree.wom和format.wom
把C盘WINDOWS下的Wscript.exe改名也是一个办法。
也可以卸载WSH:
98/ME:进入“控制面板”,选择“添加/删除程序”,选“Windows安装程序”,选择“附件”,再选 择“详细资料”中的Windows Scripting
Host,确定卸载。
在Windows 2000中禁用WSH的方法是,双击"我的电脑"图标,然后执行"工具/文件夹选项"命令,选择"
文件类型"选项卡,找到"VBS VBScript Script File"选项,并单击[删除]按钮,最后单击[确定]即可
或者升级WSH到WSH 5。6
IE浏览器可以被恶意脚本修改,原因就是IE 5.5以及以前版本中的WSH允许攻击者利用JavaScript中的 Getobject函数以及htmlfilr
Activex对象读取浏览者的注册表。微软最新的Microsoft Windows Script 5.6已经修正了这个问 题。
WSH 5.6 For Win9x/NT官方下载:www.microsoft.com
WSH 5.6 For Win2000官方下载:http://www.microsoft.com/devonly/

三 安全性漏洞问题

现在通过注册表可以在硬盘生成文件,可以读取注册表
利用IE漏洞可以传播病毒,目前的浏览网页可以感染新欢乐时光等脚本病毒,很多是通过IE漏洞入侵的,
还有目前的网页木马的问题,其实也是利用了IE的MIME头错误漏洞,让用户自动运行木马程序,这一类程序制作容易,很容易传播,这一类的MIME头错误对策:打补丁或升级http://www.microsoft.com/windows/ie/download/critical/Q290108/default.asp

1。看看IE 5.0的一个漏洞:可以写一段错误的HTML代码使你的IE当掉,代码这里就不便贴出来了。
再来看看这个ID:0D43FE01-F093-11CF-8940-00A0C9054228就是用来生成文件的
2。IE现在还有IFRME漏洞,通过这个漏洞可以让IE浏览页面后自动执行.exe文件
防御对策:最好升级IE到SP2上”,或者安装PATCH
Q290108(谢谢飘飘斑竹指出这里的错误),如果你真的不想用高版本IE,怕占用资源大,就一定要记住把补丁打上。因为目前很多病毒都是利用IE和OE的这个漏洞进行传播,爱情森林病毒是其中一个。

还有删除HKEY_CLASSES_ROOTCLSID{0D43FE01-F093-11CF-8940-00A0C9054228} 这个ID
3。在IE6(build
2600)版本中,可以用一段javascript脚本代码让IE拒绝服务,98中能造成IE的不响应,当试图终止任务的时候,将造成操作系统的崩溃,2000中能造成50%的CPU被长时间利用,之后浏览器会询问是否让用。

防御对策:把JAVA和脚本禁止掉,建议是升级IE或打补丁(看来不打补丁就是不行)
4。IE中的框架(Frame)漏洞,IE 5.01,5.5.6.0都受到影响,利用这个漏洞可以泄露用户的信息。
对策:打补丁:http://www.microsoft.com/Windowsupdate
http://www.microsoft.com/technet/security/bulletin/MS02-009.asp

获取控制权限此类黑手会利用IE执行Actives时候发生,虽然说IE提供对于"下载已签名的ActiveX控件"进行提示的功能,但是恶意攻击代码会绕过IE,在无需提示的情况下下载和执行ActiveX控件程序,而这时恶意攻击者就会取得对系统的控制权限。如果要屏蔽此类黑手,可以打开注册表编辑器,然后展开如下分支:

解决方法是在注册表分支HKEY_LOCAL_MACHINESOFTWAREMicrosoftInternet ExplorerActiveX
Compatibility 下为Active Setup
controls创建一个基于CLSID的新键值{6E449683_C509_11CF_AAFA_00AA00
B6015C},然后在新键值下创建一个REG_DWORD 类型的键Compatibility,并设定键值为0x00000400即可。

四 无聊恶意网页
这一类网页是利用编写JAVASCRIPT代码,比如弹出无数关不完的窗口,只能让CPU资源耗尽重新启动,说句实话,现在国内的杀毒软件的网页监控对这类恶意网页根本没法拦截(国外的我没试过)

这一类网页编写并不难,都是通过写一些死循环来达到目的。
防御方法:将JAVA禁用。升级IE到高版本
还有是利用WIN98的漏洞让你掉线或者是死机的,防御对策,给98拼命打补丁(不要用98了,2000稳定)

大家上网时切记把网页监控或注册表监控打开,现在国内杀毒软件对写入注册表的行为的拦截的成功率都不错

通过上面的分析可以看出一个很重要的问题:一定要时常给自己的系统打补丁,微软一般出了补丁,很快就有新的病毒代码来攻击的,所以切记时常打补丁!

以上若有错误之处,还请大家不吝赐教!

2.
3721等免疫程序的秘密

2.1.
发信人: Quaful (夸父§提升人品中), 信区: NewSoftware
标 题: [笔记]3721驻留机制简单研究
发信站: BBS 水木清华站 (Sat Feb 28 18:50:00 2004), 转信

简单研究了一下3721的机制,写在这里,作为心得笔记吧。大部分收获都来自
Softice + 反汇编,不一定适用于某些版本。

2.1.1. CnsMin.dll的驻留方式

3721的核心文件:CnsMin.dll
通常存在于Windows Directory>\Downloaded Program Files下。

通过注册表Run键值加载:Rundll32 dir>\CnsMin.dll, Rundll32

CnsMin.dll提供了一个函数Rundll32供Rundll32.exe调用
但这个函数只是调用一个真正的驻留函数Rundll32Main()。

Rundll32Main()伪代码:

void Rundll32Main()
{
hMutex = CreateMutex("CNSMINMUTEX");
if(ERROR_ALREADY_EXISTS)
{
CloseHandle(hMutex);
exit;
}
if(IsWindowsNT()) {
SetProcessSecurityInfo();
}
else {
RegisterProcessAsService();
}
CheckVersion();

// CnsMinKP.sys/vxd 内核驱动程序,保护3721关键文件和注册表项不被删除
ContactWithCnsMinKPDriver();

// 关键的hook,负责将CnsMin.dll注入其他进程空间
InstallCBTHook();

// 关键的hook,负责将CnsMin.dll注入其他进程空间
InstallCallWndProcHook();

// CnsMinIO.dll 负责IE地址栏下方的提示
InitCnsMinIO();

// 一些注册表信息
InitRegistry();

// 保护CnsMin.dll的钩子不被卸载或抢先
InstallGuardTimer();

CreateMsgWindow();

// Message loop
while (true)
{
GetMessage(&msg);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

CnsMin主要是通过WH_CBT和WH_CALLWNDPROC两个全局钩子注入IE进程空间的。注入
IE后,又安装了WH_KEYBOARD,WH_DEBUG等钩子。其中对3721实现其“实名转换”
有用的是WH_KEYBOARD。这是一个本地钩子。

CnsMin为了保证自己的优先级最高,用了一个定时器函数反复安装钩子,无疑会造成
系统性能的下降。

我曾经尝试过自己安装一个WH_DEBUG钩子阻止3721钩子的调用,确实起到了效果,
立即可以使3721失效。但这种方法3721仍然驻留IE进程内,属于指标不治本的方法。

强制结束Rundll32进程,可以暂时卸载3721的驻留代码。但CnsMin.dll通过COM注册已经
嵌入IE组件中,重新启动IE后,该进程又会重新启动。

2.1.2. 3721的防删除手段
文件系统驱动:CnsMinKP*.sys 针对NT/2000/XP有不同版本(98下面是CnsMinKP.vxd)
通常存在于System directory>\drivers\目录。

驱动程序,由Windows启动时加载。

该驱动程序过滤了对文件和注册表的删除操作。试图删除3721的关键文件和注册表项时,
直接返回一个TRUE,使Windows认为删除已经成功,但文件和注册表实际上还是在那里。
该驱动程序还有一个黑名单(内建的黑名单主要针对百度和一些卸载程序,另外还有
一个保存在某个外部文件中的黑名单,文件格式未知),阻止Windows读取其他3721的
竞争对手的插件文件。

目前还没有找到停止该驱动的方法。

删除方法:在Windows启动前(例如,98下面退出到DOS)删除CnsMinKP*.sys文件。
注意:3721具有自恢复能力。某些关键文件被删除后,其它模块会试图从3721网站重新
下载。所以彻底删除前需要断开网络连接。

2.1.3. 针对目前版本的删除步骤:
a) 运行3721自己提供的删除程序。可以删掉大部分的文件。
b) 从DOS启动,删除残存文件,如CnsMin.dll,CnsMinKP*.*等
可能的目录:Downloaded Program Files目录,Program Files\3721目录,drivers目录
c) 启动Windows,进入桌面时Windows会报告一些模块找不到的错误,不用理会,删除
注册表中3721的值。
可能的位置:HKEY_CURRENT_USER: Software\3721
HKEY_LOCAL_MACHINE: Windows\CurrentVersion\Run
SYSTEM\CurrentControlSet
另外还零散的藏了一些,用关键字查找。

2.2.
发信人: cygwin (难道真的有沧海?), 信区: NewSoftware
标 题: 总结几种反3721的方法。
发信站: BBS 水木清华站 (Fri Feb 27 22:57:23 2004), 转信

2.2.1. 使用广告过滤软件。以adfilter为例,只需在广告过滤的正则表达式中加入cnsmin.*\.cab即可。
2. 使用专用免疫软件,以前曾经出过只反3721的软件,现在有banactivex等。
3. 修改hosts文件,这一招并不好使,一旦使用了代理,很可能就被装上。
4. 将证书装入不信任证书列表。这一招在有的系统上并不好使。
5. winXP sp2提供了一个永不安装的选项,大快人心。
6. 利用自动代理配置脚本实现过滤。

就是ccboy推荐的那个程序
当前版本v2.14
下载地址http://hre.iphy.ac.cn/zmb/download.asp
本来还以为是压缩加密了,没想到,随便一打开就有。

结构非常简单,核心秘密就是
SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{B83FC273-3522-4CC6-92EC-75CC86678DA4}
SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{9A578C98-3C2F-4630-890B-FC04196EF420}
SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{9BBC1154-218D-453C-97F6-A06582224D81}
SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{BC207F7D-3E63-4ACA-99B5-FB5F8428200C}
SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{4EDBBAEA-F509-49F6-94D1-ECEC4BE5B686}
SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{98FA5667-513F-4F15-8A15-C171477B8847}
SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{15DDE989-CD45-4561-BF99-D22C0D5C2B74}
SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{7CA83CF1-3AEA-42D0-A4E3-1594FC6E48B2}
(按:上面的键值都对应什么请查看原软件即可)

所用函数就是
RegDeleteKeyA
RegDeleteValueA
RegOpenKeyExA
RegCloseKey
RegSetValueExA
RegQueryValueExA
RegCreateKeyExA (按:ADVAPI32.dll)

不过很简洁,还是不错的。
(按:没有反向工程,不算违法,呵呵)

(按:最近又更新啦,版本2.15
加上了
SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{484FF54A-CC44-467E-9C31-5B89FC753007}
SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{8D898B17-976D-44c1-84E6-AF38842AC9EC}
呵呵,作者还是很勤劳的
3/8/2004/补充


(按:在绿盟看见了zhege
http://silence.hao-8.com/block.reg
不知以后会不会更新
3/9/2004/补充)

发现最勤奋的是
http://www.fswinway.cn/upiea/
在水木不是更新

Friday, January 21, 2005

 

Some notes on IE proxy

1.
By srj
From http://www.3d-vr.com/LunTan/bmb/topic.php?forumid=4&filename=f_42

最近有很多朋友都在讨论如何改变IE的代理服务器设置,刚好我最近做的一个东西里面用到了这样的功能. 拿出来和大家共享一下.

用到的关键函数是wininet库里面的InternetSetOption. msdn里面有对它详细的介绍, 可以自己去看看. 当把参数dwOption设置为INTERNET_OPTION_SETTINGS_CHANGED的时候. 他就会促使IE在下一次打开网页的时候重新到注册表里面去取代理的设置信息. 所以我们就可以先将注册表里面的代理信息更改掉, 然后调用InternetSetOption函数, 从而达到使自己想要的代理设置马上生效的目的.

下面的函数可以实现改变IE的http代理服务器设置的目的. 里面加了少许的注释以帮助大家理解.

BOOL SetHttpProxy(CString ip, UINT port)
{

CString l_just;
l_just.Format("http=%s:%d", ip.LockBuffer(), port);


//下面的代码将注册表项HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ProxyServer
//的内容取出来
HKEY hKeyIn = HKEY_CURRENT_USER, hKeyOut;
if( ERROR_SUCCESS != RegOpenKeyEx(hKeyIn, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", 0, KEY_CREATE_LINK | KEY_WRITE | KEY_READ | KEY_NOTIFY, &hKeyOut))
{
return FALSE;
}


ULONG regsize = 0;
if(ERROR_SUCCESS != RegQueryValueEx(hKeyOut, "ProxyServer", NULL, NULL, NULL, ®size))
{
return FALSE;
}

LPBYTE pValue = new BYTE[regsize];
memset(pValue, 0x00, regsize);

if(ERROR_SUCCESS != RegQueryValueEx(hKeyOut, "ProxyServer", NULL, NULL, pValue, ®size))
{
return FALSE;
}

CString oldproxy((char *)pValue);
delete [] pValue;
pValue = NULL;

//从注册表中读出来的数据格式为:http=111.111.111.111:80;ftp=222.222.222.222:21;......,
//如果你只想改变http的代理的话, 就只要把其中的111.111.111.111:80换成你想要的代理就行了,
//类似的你可以改变其他的代理.

//下面的代码就替换http代理成为参数所指定的代理.
int pos = 0;
//如果没有字符串中没有找到"http="说明用户没有设置http代理,这时候直接加在最前面.
if(-1 == (pos = oldproxy.Find("http=")))
{
pos = 0;
}

int pos1 = 0;
if(-1 == (pos1 = oldproxy.Find(";", pos)))
{
pos1 = oldproxy.GetLength();
}

oldproxy.Delete(pos, pos1 - pos);
oldproxy.Insert(pos, l_just);

if(ERROR_SUCCESS != RegSetValueEx(hKeyOut, "ProxyServer", 0, REG_SZ, (const unsigned char *)oldproxy.LockBuffer(), oldproxy.GetLength() + 1))
{
return FALSE;
}

RegCloseKey(hKeyOut);

//使设置生效
if(!InternetSetOption(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0))
{
return FALSE;
}

return TRUE;
}

最后在使用此函数的时候不要忘记包含头文件 #include 和lib: wininet.lib

Thursday, January 20, 2005

 

Some notes on IE ExecWB

The following collections are a little bit messy. However I have no time to rearrange them.

本文根据资料收集整理而成

首先是函数声明,参见
http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/webbrowser/reference/ifaces/iwebbrowser2/execwb.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/vcrefCHtmlViewExecWB.asp
http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/webbrowser/reference/methods/execwb.asp

命令ID列表在
http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/mshtml/reference/commandids.asp

我们常用的命令有

1.实现clipboard use:

ExecWB(OLECMDID_CUT, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);

ExecWB(OLECMDID_COPY,OLECMDEXECOPT_DONTPROMPTUSER,NULL,NULL);

ExecWB(OLECMDID_PASTE,OLECMDEXECOPT_DONTPROMPTUSER,NULL,NULL);

ExecWB(OLECMDID_SELECTALL, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);

2.实现查找:

MSHTML::IHTMLDocument2Ptr pdoc;
_variant_t varinput,varoutput;
IOleCommandTarget *pCmd;
HRESULT hr;
pdoc=GetHtmlDocument();
hr=pdoc.QueryInterface(IID_IOleCommandTarget,&pCmd);
if(SUCCEEDED(hr))
{
varinput=_T("");
hr=pCmd->Exec(&CGID_MSHTML,IDM_FIND,OLECMDEXECOPT_DODEFAULT,&varinput,&varoutput);
}

详见
http://www.codeproject.com/tips/mshtmlfind.asp

3.
How to Print Preview
by Frank W. Wu
from http://www.codeproject.com/miscctrl/wbp.asp

Add print preview functionality
In the print preview method, I start by verifying the WebBrowser control is valid. Then, I retrieve a pointer to the IDispatch interface pointer to the HTMLDocument, from which I query the IOleCommandTarget interface, and store the pointer in lpTarget. You can find information on the IOleCommandTarget interface in MSDN. I won't repeat the instructions here. Finally, I execute the print preview command by calling IOleCommandTarget::Exec with the appropriate parameters. The command id OLECMDID_PRINTPREVIEW is defined in "docobj.h". The GUI of the print preview is handled by the WebBrowser control.

Following is the source code of the method:

void CWBPDlg::OnDemoPrintpreview()
{
// Verify the WebBrowser control is valid.
LPDISPATCH lpDispApp = m_wndBrowser.GetApplication();
if(lpDispApp)
{
// Get the HTMLDocument interface.
LPDISPATCH lpDispDoc = m_wndBrowser.GetDocument();
if (lpDispDoc != NULL)
{
// Get the IOleCommandTarget interface so that
// we can dispatch the command.
LPOLECOMMANDTARGET lpTarget = NULL;
if (SUCCEEDED(lpDispDoc->
QueryInterface(IID_IOleCommandTarget,
(LPVOID*) &lpTarget)))
{
// Execute the print preview command. The
// control will handle the print preview
// GUI.
// OLECMDID_PRINTPREVIEW is defined in
// "docobj.h".
lpTarget->Exec(NULL,
OLECMDID_PRINTPREVIEW, 0, NULL, NULL);
lpTarget->Release();
}
lpDispDoc->Release();
}
lpDispApp->Release();
}
}

Now you can compile and run the application. The GUI of print preview is the same as that you have seen in IE.

Use WebBrowser::ExecWB method - Alexander Tsarfin's contribution
The WebBrowser class implements a wrapper that allows you to execute a command on an OLE object using the IOleCommandTarget::Exec method.

void CWBPDlg::OnDemoPrintpreview()
{
m_wndBrowser.ExecWB(OLECMDID_PRINTPREVIEW,
OLECMDEXECOPT_PROMPTUSER, NULL, NULL);
}

4.实现显示源程序:

MSHTML::IHTMLDocument2Ptr pdoc;
_variant_t varinput,varoutput;
IOleCommandTarget *pCmd;
HRESULT hr;
pdoc=GetHtmlDocument();
hr=pdoc.QueryInterface(IID_IOleCommandTarget,&pCmd);
if(SUCCEEDED(hr))
{
varinput=_T("");
hr=pCmd->Exec(&CGID_MSHTML,IDM_VIEWSOURCE,OLECMDEXECOPT_DODEFAULT,&varinput,&varoutput);
}

5.实现显示Internet选项:

MSHTML::IHTMLDocument2Ptr pdoc;
_variant_t varinput,varoutput;
IOleCommandTarget *pCmd;
HRESULT hr;
pdoc=GetHtmlDocument();
hr=pdoc.QueryInterface(IID_IOleCommandTarget,&pCmd);
if(SUCCEEDED(hr))
{
varinput=_T("");
hr=pCmd->Exec(&CGID_MSHTML,IDM_OPTIONS,OLECMDEXECOPT_DODEFAULT,&varinput,&varoutput);
}

6.
JAVAScript的调用方式
from http://www.csdn.net/develop/article/16/16938.shtm

我对IEWebBrowser这个组件的execWB方法整理了一下﹐希望对大家有所帮助。
1. object id="WebBrowser" width=0 height=0 classid="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2">/object>
2. 调用方法。
WebBrowser.ExecWB nCmdID, nCmdExecOpt, [pvaIn], [pvaOut]
3. 参数说明。
(a).nCmdID
OLECMDID_OPEN = 1,
OLECMDID_NEW = 2,
OLECMDID_SAVE = 3,
OLECMDID_SAVEAS = 4,
OLECMDID_SAVECOPYAS = 5,
OLECMDID_PRINT = 6,
OLECMDID_PRINTPREVIEW = 7,
OLECMDID_PAGESETUP = 8,
OLECMDID_SPELL = 9,
OLECMDID_PROPERTIES = 10,
OLECMDID_CUT = 11,
OLECMDID_COPY = 12,
OLECMDID_PASTE = 13,
OLECMDID_PASTESPECIAL = 14,
OLECMDID_UNDO = 15,
OLECMDID_REDO = 16,
OLECMDID_SELECTALL = 17,
OLECMDID_CLEARSELECTION = 18,
OLECMDID_ZOOM = 19,
OLECMDID_GETZOOMRANGE = 20
OLECMDID_UPDATECOMMANDS = 21
OLECMDID_REFRESH = 22
OLECMDID_STOP = 23
OLECMDID_HIDETOOLBARS = 24
OLECMDID_SETPROGRESSMAX = 25
OLECMDID_SETPROGRESSPOS = 26
OLECMDID_SETPROGRESSTEXT = 27
OLECMDID_SETTITLE = 28
OLECMDID_SETDOWNLOADSTATE = 29
OLECMDID_STOPDOWNLOAD = 30
上面的关键词都可以在浏览器的菜单里面找到对应的选项﹐大家一看就明白的﹗
(b).nCmdExecOpt
OLECMDEXECOPT_DODEFAULT = 0,
OLECMDEXECOPT_PROMPTUSER = 1,
LECMDEXECOPT_DONTPROMPTUSER = 2,
OLECMDEXECOPT_SHOWHELP = 3
对于这个参数﹐一般来说﹐选1就可以了。

这是调用IE的”另存为”功能的示例﹕

object id="WebBrowser" width=0 height=0 classid="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2">/object>
A href="javascript:WebBrowser.ExecWB(4,1);">Save-存储/A>

7.
另一种Javascript调用方式
from http://www.csdn.net/develop/Read_Article.asp?Id=14981

在不是js打开的页面上按window.close(),会有提示框,很烦,现在可以不用了,没有提示框直接关闭窗口。

试试下面代码:

object id="WebBrowser" width=0 height=0 classid="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2">
/object>
input type="button" name="Button" value="关闭窗口" onClick="document.all.WebBrowser.ExecWB(45,1)">

试着改变参数会得到其他一些功能:

WebBrowser.ExecWB(1,1) 打开
WebBrowser.ExecWB(2,1) 关闭现在所有的IE窗口,并打开一个新窗口
WebBrowser.ExecWB(4,1) 保存网页
WebBrowser.ExecWB(6,1) 打印
WebBrowser.ExecWB(6,6) 无选择打印机对话框直接打印
WebBrowser.ExecWB(7,1) 打印预览
WebBrowser.ExecWB(8,1) 打印页面设置
WebBrowser.ExecWB(10,1) 查看页面属性
WebBrowser.ExecWB(15,1) 好像是撤销,有待确认
WebBrowser.ExecWB(17,1) 全选
WebBrowser.ExecWB(22,1) 刷新
WebBrowser.ExecWB(45,1) 关闭窗体无提示

8.
改变字体

this article was contributed by sriram.

a sample code to change the fonts in your web browser using webbrowser control.

void cmybrowser::setfont(int nfontsize)
{ m_pdisp = null; // idispatch pointer
lpolecommandtarget pcmdtarg = null;

m_pdisp = m_webbrowser2.getdocument(); // get the idispatch pointer from webbrowser control
assert(m_pdisp); //check for validity

m_pdisp->queryinterface(iid_iolecommandtarget, (lpvoid*)&pcmdtarg); //query for iid_iolecommandtarget interface
assert(pcmdtarg); // check for validity

variant vafontsize; // input argumentsvariantinit(&vafontsize);
v_vt(&vafontsize) = vt_i4;
v_i4(&vafontsize) = nfontsize; //size of the font you want
variant vafontoutput;

pcmdtarg->exec(null, // execute just change the font
olecmdid_zoom,
olecmdexecopt_promptuser,
&vafontsize,
&vafontoutput);

variantclear(&vafontsize); //clear the variant variable before freeing its memory

if (pcmdtarg) pcmdtarg->release(); // release document's command target
if (m_pdisp) m_pdisp->release(); // release document's dispatch interface
}

Wednesday, January 19, 2005

 

Javascript talks with

1.
JavaScript 和 Flash 的通信

发信人: oldnine.bbs@bbs.ustc.edu.cn (老九·哦也), 信区: Flash
标 题: JavaScript 和 Flash 的通信 z
发信站: 瀚海星云 (Mon Mar 15 02:56:32 2004)
转信站: YTHT!news.happynet.org!news.uestc.edu.cn!netnews.sdu.edu.cn!USTC

http://www.blueidea.com/tech/multimedia/2004/1712.asp

JavaScript和Macromedia Flash的通信示例


原文地址: http://www.macromedia.com/support/flash/ts/documents/java_script_comm.htm
说明: 略作修改,主要是一些很初级的操作; 又很多相似的文章,不过这个很权威

下面是一些在Flash和使用Javascript的HTML文件直接通信的示例,每个示例都有简略的步


本文讨论了3种基本的Flash/Javascript通信方式:
Javascript 到 Flash的通信----使用Flash播放器的javascript方法
Flash 到 Javascript的通信----使用Flash的fscommand
Flash 到 Flash的通信----------使用本地连接对象或综合上2种技术

并不是所有的浏览器都很重视脚本.为了和Flash播放器通信,浏览器必须有内置的钩子以便
Flash播放器可以'监听'.浏览器必须是下列的几种:
Netscape Navigator 3.0-4.7x, 和 Netscape 6.2或更高
(Windows 95/98/NT/2000/XP 或 MacOS; 允许Java和LiveConnect)
Internet Explorer 3.0 或更高
(仅Windows 95/98/NT/2000/XP; 允许ActiveX)

注意:Macintosh上的Internet Explorer和早期版本的Netscape6不支持这种方法.请查看本
文的附加信息

Javascript到Flash的通信

这个例子演示了如何使用Flash的method把变量从HTML的input text 发送到该页面中的Fla
sh文件中.HTML input的数据通过Flash的SetVariable方法传送到Flash文件中.

查看示例:示例
http://www.macromedia.com/support/flash/ts/documents/java_script_comm/javascr
ipt_to_flash.html
下载源文件: javascript_to_flash.zip(17k)
http://www.blueidea.com/articleimg/2004/03/1712/javascript_to_flash.zip

步骤:

Flash中
1.新建一个文件,保存为javascript_to_flash.fla
2.用文字工具在舞台上创建一个文本域
3.选择这个文本域,在属性面板中,从下拉列表中选择动态文本(Dynamic Text),在变量(var
iable)栏填上"myVar"
注意:最好的习惯是使用Instance,用myVar.text更改myVar的值.为了简单起见和兼容Flash
4和Flash5,我们使用的是变量名的形式.
4.保存文件
5.发布HTML文件和SWF文件

Dreamweaver中
下一步的工作转移到Dreamweaver中了,当然也可以是其他的HTML编辑器
1.打开上一步发布的HTML文件
2.插入生成的SWF文件和OBJECT/EMBED标签
(1) Insert>Media>Flash,并选择这个Flash
(2) 切换到代码视图,我们需要修改被选中的OBJECT>和EMBED>标签
(3) 在OBJECT标签中,插入id="myFlash"

object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/
flash/swflash.cab#version=5,0,0,0"
width=366 height=142 id="myFlash">

注意:如果你是粘贴复制代码的话,确保删除不必要的换行.否则可能会引起错误; id也可以
在属性面板里直接输入
(4) 在EMBED标签中,插入name="myFlash"和swLiveConnect="true",确保没有使用id属性!
代码应当是这样子的:

embed src="http://www.blueidea.com/javascript_to_flash.swf" quality=high
width=366 height=142
type="application/x-shockwave-flash"
pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?
P1_Prod_Version=ShockwaveFlash"
name="myFlash" swLiveConnect="true">
/embed>

3.创建表单域
(1) 回到设计视图
(2) 插入文本域(Insert> Form Object> Text Field),如果询问是否添加表单域,选择是
(3) 把文本域的HTML标签修改成这样:

input type="text" name="sendText" maxlength="45" onChange="doPassVar(this)">
每当文本域内容发生变化时,onChange就被触发,doPassVar()函数就被调用

4.创建传递变量值的Javascript函数
复制下面的Javascript到head/head>标签内

SCRIPT LANGUAGE=JavaScript>
!--
function doPassVar(args){
var sendText = args.value;
window.document.myFlash.SetVariable("myVar", sendText);
}
//-->
/SCRIPT>
5.保存文件,测试一下(F12)

Flash到Javascript的通信
从HTML可以发送数据到Flash,反过来也可以. 这个例子演示了如何应用Flash的Fscommand
来发送数据到Javascript.

查看示例:示例2
http://www.macromedia.com/support/flash/ts/documents/java_script_comm/flash_to
_javascript.html

下载源文件: flash_to_javascript.zip(10K)
http://www.blueidea.com/articleimg/2004/03/1712/flash_to_javascript.zip

简要步骤:
Flash中
新建一个文件,保存为flash_to_javascript.fla
创建一个文本域,设置成输入文本(Input Text),选择"border"以便我们能看到他,指定他的
变量为inputVar
创建一个按钮,在按钮上添加如下的as:

on (release) {
fscommand ("send_var", inputVar);
}

保存文件,导出HTML和SWF

Dreamweaver中
1.打开导出HTML文件,修改OBJECT>和EMBED>标签,结果同上:
object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/
flash/swflash.cab#version=5,0,0,0"
width=366 height=142 id="myFlash">

embed src="http://www.blueidea.com/javascript_to_flash.swf" quality=high
width=366 height=142
type="application/x-shockwave-flash"

pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?
P1_Prod_Version=ShockwaveFlash" name="myFlash" swLiveConnect="true">
/embed>

2. 插入如下的Javascript到Body>标签内:
SCRIPT LANGUAGE=JavaScript>
!--
var InternetExplorer = navigator.appName.indexOf("Microsoft") != -1;
function myFlash_DoFSCommand(command, args) {
var myFlashObj = InternetExplorer ? myFlash : document.myFlash;
alert (args);
}
if (navigator.appName && navigator.appName.indexOf("Microsoft") != -1 &&
navigator.userAgent.indexOf("Windows") != -1 &&
navigator.userAgent.indexOf("Windows 3.1") == -1) {
document.write('SCRIPT LANGUAGE=VBScript\> \n');
document.write('on error resume next \n');
document.write('Sub myFlash_FSCommand(ByVal command, ByVal args)\n');
document.write(' call myFlash_DoFSCommand(command, args)\n');
document.write('end sub\n');
document.write('/SCRIPT\> \n');
}
//-->
/SCRIPT>

Flash和Flash的通信
通过上面两种方法的混和使用,同一HTML中两个或者更多的Flash直接可以相互传送消息.
从一个flash使用fscommand传送消息给Javascript,使用Flash的Javascript methods把消
息传给另外一个flash

详细的看这里:Flash影片之间的通信示例
http://www.macromedia.com/support/flash/ts/documents/flash_to_flash_comm.htm

从Flash MX开始,local connection对象可以用来在flash之间传送消息. 这使得同一HTML
中的或者位于两个浏览器窗口中的两个flash影片可以相互发送消息,而不必使用Javascrip
t或者fscommand
详细的看这里:在Flash MX中使用local connection对象(英文)
http://www.macromedia.com/support/flash/action_scripts/local_connection_objec
ts/index.html


本站的localConnection教程:http://www.blueidea.com/tech/multimedia/2003/739.asp


附可控制Flash Player的Javascript方法:
一览表:
Play() ---------------------------------------- 播放动画
StopPlay()------------------------------------停止动画
IsPlaying()----------------------------------- 动画是否正在播放
GotoFrame(frame_number)---------------- 跳转到某帧
TotalFrames()------------------------------- 获取动画总帧数
CurrentFrame()------------------------------回传当前动画所在帧数-1
Rewind()-------------------------------------使动画返回第一帧
SetZoomRect(left,top,right,buttom)-------放大指定区域
Zoom(percent)------------------------------改变动画大小
Pan(x_position,y_position,unit)------------使动画在x,y方向上平移
PercentLoaded()----------------------------返回动画被载入的百分比
LoadMovie(level_number,path)----------- 加载动画
TGotoFrame(movie_clip,frame_number)- movie_clip跳转到指定帧数
TGotoLabel(movie_clip,label_name)------ movie_clip跳转到指定标签
TCurrentFrame(movie_clip)--------------- 回传movie_clip当前帧-1
TCurrentLabel(movie_clip)-----------------回传movie_clip当前标签
TPlay(movie_clip)---------------------------播放movie_clip
TStopPlay(movie_clip)----------------------停止movie_clip的播放
GetVariable(variable_name)-----------------获取变量
SetVariable(variable_name,value)-----------变量赋值
TCallFrame(movie_clip,frame_number)---call指定帧上的action
TCallLabel(movie_clip,label)----------------call指定标签上的action
TGetProperty(movie_clip,property)--------获取movie_clip的指定属性
TSetProperty(movie_clip,property,number)-设置movie_clip的指定属性


--
╔━═━═━═━╗
╔━╝ 探讨FLASH技术╚━╗
┈┈┈═╣ ╠═┈┈┈
╚━╗ 评析FLASH作品╔━╝
╚━═━═━═━╝
欢迎光临 4区 [ FLASH ] 闪客部落
※ 修改:·oldnine 於 03月15日02:56:14 修改本文·[FROM: 202.38.69.100]
※ 来源:·瀚海星云 bbs.ustc.edu.cn·

2.
JavaScript和ASP.NET的传值

JavaScript和ASP.NET的传值
作者:陈缘
联系:luandao2000@21cn.com
网页:http://blog.csdn.net/luandao2000

因项目需要,最近一段时间里对于js的开发有了一定的了解。在基于ASP.NET的开发中,经常性的需要JS脚本来增加一些客户端的控制,比如限制输入字符,日期控件等等。一般这样的控制基本上在客户端完成就比较好,无需回传到服务端。总结了最近的开发中使用的一些js的技巧,提供给大家

2.1、js脚本如何访问服务器控件的值
界面上有一个TextBox控件,ID为Name,js里可以采用如下脚本取Name的值
var myvalue=document.all('Name').value;

2.2、服务器控件如何取js中变量的值
目前未发现比较好的办法,我通常采用的方法是在界面上放一个隐藏的控件HtmlInputHidden,然后设置为以服务器控件运行,这样在js脚本中和ASP.NET代码里都可以访问到该控件的值
js中给服务器控件赋值:
var bt=document.all('Name').value;
bt.value='名称';
ASP.NET中使用Name.Value来访问。

2.3、如何遍历界面上所有TextBox元素
var inputList = document.body.getElementsByTagName("INPUT");
for(var i=0;i inputList.length;i++)
{
if(inputList[i].disabled==false && (inputList[i].type=='text' || inputList[i].type=='password'))
{
inputList[i].value="";
}
}

2.4、让dropdownlist选择到指定项
选择dropdownlist中值为“我得选择”得项
var handl=document.all('List1');
var my_value='我得选择';
for(var index=0;index handle.options.length;index++)
{
if(handle.options[index].text==my_value)
{
handle.selectedIndex=index;
}
}

3.
如何在ASP.NET中获得JavaScript弹出窗口Yes/No值

作者:hanlei
出处:http://blog.hanlei.name/archive/2003/11/06/147.aspx

The sample code?is on the most frequently asked query on "How to get the confirmation of Yes/No from a javascript pop up and display the value on the page using ASP.NET"?
Create a webpage main.aspx
Drag and drop a?hidden control and asp:button> control on the web form.
Step 1. main.aspx.vb

Write the following code on page load event

Button1.Attributes.Add("onclick", "getMessage()")

Step 2.In main.aspx

Add the client side-script block

SCRIPT language=javascript>
function getMessage()
{
var ans;
ans=window.confirm('Is it your confirmation.....?');
//alert (ans);
if (ans==true)
{
//alert('Yes');
document.Form1.hdnbox.value='Yes';
}
else
{
//alert('No');
document.Form1.hdnbox.value='No';}

}
/SCRIPT>

Step 3. main.aspx.vb

To display the value of the value selected by the user in the pop up write the following code

Response.Write(Request.Form("hdnbox"))

4.
Java与JavaScript的通信

原文:http://www.codeproject.com/jscript/javatojs.asp
翻译:lixiaolong3456

信任

1. 聊天演示程序内在的想法,连同这篇文章一起都是我自己的。我所见过的所有聊天程序不是完全基于JAVA就是HTML。我的方法是这两种方法的一个很好的平衡。

2. 我通过在Netscape开发者站点阅读大量的文章后收集了在JAVA和JAVASCRIPT间通信的技术信息。

3. 我第一次在读Danny Goodman的文章时(The JavaScript Apostle on the Netscape site)偶然遇到术语“不知名的applet(Faceless applet)”。因此出于对Danny的信任我使用了这个非常切题的术语。

放弃

1. 这篇文章中讨论的技术已经在Windows 2000 Professional机器上使用Internet Explorer 5.0和 Netscape Navigator 4.7测试过了。在我所知道的最佳作品中,这些技术应该在任一浏览器4.0以上的版本上运行,但我不能保证我这样做,因为我没有时间用这些版本将它测试出来。

2. 因为JAVASCRIPT是唯一一种在两种主要浏览器都得到支持的语言,所有的脚本代码使用这种语言。我先前在http://www.ncompasslabs.com上使用了一个可用的商业插件,这个插件可以让Netscape Navigator支持VBScript,但我去他们的站点核实这个信息的时候,这个产品已经没有列出了。

引言

我一直从事现代COM的工作两年了,现在是我公司的e化商业产品团队的技术领导。我明白好的界面设计和在不同环境像Visual C++, Visual Basic 还有脚本下都能很好执行程序的重要性。基于界面的程序设计的能力在我的头脑中已经永远确立,并且作为一个软件工程师我试着将它应用到我所涉及的每件事情中。

在过去的一年里,当ASP+脚本就要被当作这些对象的黏合剂使用的时候,经验告诉我们的勤奋:所有的商业逻辑应该被压缩在COM对象之内。设计和开发典型的基础设施和商业对象要求一个更高的技术设备,它用来比较什么是要求实际使用同一个事物的。开发这些对象的首选环境(至少在我的团队中)是Visual C++ / ATL / STL。微软也鼓励Visual Basic成为这些对象可选择的开发环境。

这些对象被代表性的称为“不知名的”,因为他们实现许多逻辑但用户界面除外。它的表现层次(presentation tier)不是一个充足的客户就是一个不充足的客户(这个客户有从最终用户表达信息和聚集信息的逻辑)。然后这样的一个客户用这些信息通过使用不知名的对象做一些有意义的事情。这整个想法是当商业对象改变不频繁时表现层次会代表性的要求许多客户定制。表现层次要求的改变也可以通过使用较少的经验程序来实现。

应用这些相同的原理到浏览器环境,当使用一种脚本语言处理表现方面时,在“不知名的”二进制模块中压缩高度发展的客户方的逻辑看起来是合乎逻辑的。在Windows平台上这些模块的选项是Java applet和ActiveX 控件/服务器。这篇文章的焦点是使用Java applet完成这个目标,因为applet是独立于浏览器,平台和处理器的(对大部分而言)。

Applet的简短历史

SUN Microsystems1995年在嘹亮的号角声中引入了Java applet。Applet立即博得WEB世界的欢心,因为它们增加了在原来是一个静态HTML的世界的浏览器中动态地显示WEB内容的能力。

在最初的日子里,使用Java applet作为最好的一种在网页中增加动态内容的方式出现了。最初Microsoft 试图使用他们的ActiveX Control技术反对SUN提供的Java applet,但是在网页内部使用控件存在两个主要问题:

● 二进制模块是处理器指定的,因此不适合作为网页的一部分运行。万维网(World Wide Web)如此成功的一个主要原因是使用W3C标准HTML写出的大部分网页对浏览器和处理器是不可知的事实。ActiveX控件正好不符合这个范例。

● 安全是一个大问题,因为控件编写者有足够的权利在客户机器上存取资源。签了名的控件允许任何一个人查看网页并聪明地作出是否应该在他/她的机器上下载一个特定控件的决定,但是所有他进行的是一个按钮意外的点击(或者是高兴地忽略),这样就留下了易受攻击的客户机,这也正符合恶意控件编写者的意图。

当动态HTML终于开始成型时,事情彻底地改变了。文档对象模型(Document Object Model )作为可以设计的组件,它们用它们自己的属性和方法揭露了网页元素。即使Internet Explorer和Netscape Navigator浏览器执行动态HTML有许多不同,但使用脚本代码程序化的改变显示页内容本身的根本主题就是是一个巨大的成功。Applet突然开始看起来是又旧又粗糙的。W3C对动态HTML的认可最终对高度发展的,动态网页的新种类调整了语气。

在浏览器内是使用Java applet有以下列出的几种优点:

● Applet(对大多数Applet而言)可以在多浏览器,平台和处理器上工作。

● JAVA语言是典型的一种强大的概念性语言。

● JDK有许多典型的且只在高层类库中创建的有用的类。

● 技术中已经构思了安全,applet只能用默认值在方框中运行。如果它们要打破方框的限制则Applet必须是已经签了名的。

● Applet可以就发回用户化信息,上传/下载文件等而与网页服务器取得联系。签了名的applet可以与任何一个服务器联系,而不仅仅是一个它们的主机。

● 通过“查看源文件”选项不能看到applet代码,因此保护了知识产权。

● JAVA的.class文件非常小,结果是下载非常快。

使用Java apple的缺点:

● 在一次浏览器对话中,下载applet不是网页使用它们的第一时间显示就是网页随后刷新后显示。Applet在浏览器对话中不长驻客户机。事实上在大多数场合下这可以作为一种优势考虑。

● Applet要花很长时间初始化。

● 因为JAVA的.class文件是被JAVA虚拟机(Java virtual machine ,JVM)解释的字节代码,所以applet运行比本地代码慢。

● 一个applet只是浏览器上真正状态的一部分,它不会无缝完好地出现在网页内容中。层叠样式单(Cascading style sheets ,CSS)也不会直接影响applet占有的矩形区域。

● Netscape Navigator 4.x有十个活动applet的限制。我不知道Internet Explorer 4.0+有任何一种这样的限制。

使用Java applets的快速回顾

Java applets通过使用用applet标签被包含进一个HTML网页中。W3C 站点上HTML 4.01说明书的13.4节详细地说明了这个标记。它也提到赞成object>,而不赞成使用这个标记。

一个简单地包含applet的HTML网页如下所示:

html>
head>
title>Calculator/title>
/head>
body>
applet id="Calculator" width="300" height="500" code ="Calculator.class" codebase=".">
param name="InitialMode" value="Normal">
/applet>
/body>
/html>
上例中用到的属性解释如下:

Id
Applet实例的标识符。客户方脚本代码能知道使用这个id的applet。

Width
这个属性指定了applet显示域的初始宽度(不包括applet创建的窗口或者对话框)。即使我经成功使用了宽度0用 “放弃”一节中提到的浏览器,还是推荐使用值1作为最小的可能宽度。

Height
这个属性指定了applet显示域的初始高度(不包括applet创建的窗口或者对话框)。就像用宽度属性一样,推荐使用值1作为最小的可能宽度。

Code
这个属性指定了任一类文件(包含applet编译的applet子类或者能够得到类的路径,包括类文件自身)的名字,它在谈到applet的codebase时会作出解释。

Codebase
这个属性指定applet的基本URI. 如果这个属性没有指定,那么它默认最近的文档为同一个基本URI。

只有code, width和height 属性是必须的。

Param标记包含一对名字的值,它允许applet第一次运行时安装自己。

在上面的applet调用一个方法的JAVASCRIPT函数如下,它非常简单:

script language=Javascript>
function SetCalculatorMode(Mode)
{
document.Calculator.SetCalculatorMode (Mode);
// Alternative way to reference the applet.
// document.applets[0].SetCalculatorMode(Mode);
}
/script>
劳动力的分工

在这篇文章的引言部分,我暗示当通过JavaScript代码处理表现形式时,高度发展的浏览器方正处理的一个方法是被压缩进不知名的Java applets中的。这个方法要求在Java和JavaScript间双向通信。下面几章会研究可用的选项。

通过JAVASCRIPT代码存取Java applet暴露的成员和函数是直截了当的,像上一节中的SetCalculatorMode()函数说明的一样。文档内的applet不是通过使用它的Id / Name就是使用applet收集的索引来查询。

例如:

document.Calculator.SetCalculatorMode(Mode);// or document.applets[0].SetCalculatorMode(Mode);

使用netscape.javascript.JSObject类和netscape.javascript.JSException类完成了其它方向(Java to JavaScript)的通信。为了找到这些类在什么位置,我在我的硬盘驱动器上寻找所有包含字符串“JSObject”的文件。令我吃惊的是,这些文件在许多不同的程序中得到广泛地使用,包括是Visual Interdev工程一部分的库。

如果Netscape Navigator 4.0+安装在你的机器上,这些.class文件在 Navigator Installation Directory>\communicator\program\java\classes 目录下的Java40.jar 文件中可用。

我也在Windows Installation Directory>\Java\Packages目录下的四个不同的.zip文件中寻找这些.class文件。这些.zip文件显然是Microsoft产品安装的,因为它们包含许多com.ms包。它们的用途是这两个类对任一浏览器都是可用的,你可以设置你的CLASSPATH环境变量给任一个上述路径。一个可选的方法是使用一个程序像WINZIP从.jar或者.zip文件中解压缩这些文件到你的applet目录下。

JSObject类

引用JSObject类成员函数的简短描述是为了更好的理解这个类的用途。

public static JSObject getWindow (Applet applet )

这个静态方法对含有给出的applet窗口返回一个JSObject。例如:JSObject MainWindow = JSObject.getWindow ( this );

public Object call ( String methodName, Object args[ ] )

这个函数从Java applet内部调用一个JavaScript方法。例如:

JSObject MainWindow = JSObject.getWindow ( this );
String Arguments[ ] = {"90", "2"}; // {"Percent complete", "Time remaining"}
MainWindow.call ( "UpdateProgressIndicator", Arguments );
public Object eval ( String s )

这个方法求一个JavaScript表达式的值。表达式是这个对象上下文中待求的JavaScript源代码的一个字符串。例如:

JSObject MainWindow = JSObject.getWindow ( this );
JSObject UserName = MainWin.eval ( "document.UserInfoForm.UserName" );
public Object getMember ( String name )
这个方法检索JavaScript对象的一个索引成员,等价于JavaScript对象的this.name。:
JSObject MainWindow = JSObject.getWindow ( this );
JSObject DocumentPage = (JSObject)MainWindow.getMember ( "document" );
JSObject UserInfoForm = (JSObject) DocumentPage.getMember ( "UserInfoForm" );
JSObject UserName = (JSObject) UserInfoForm.getMember ( "UserName" );
public Object getSlot ( int index)
这个方法检索JavaScript对象的一个索引成员,等价于JavaScript对象的this [index]。例如:
JSObject MainWindow = JSObject.getWindow ( this );
JSObject DocumentPage = (JSObject)MainWindow.getMember ( "document" );
JSObject Applets = (JSObject) DocumentPage.getMember ( "applets" );
Object theApplet = Applets.getSlot ( index );
public void removeMember ( String name )
这个方法删除一个JAVASCRIPT对象的指定成员。
public void setMember ( String name, Object value )
这个方法设置一个JAVASCRIPT对象的指定成员。它等价于JavaScript对象的this.name = value。例如:
JSObject MainWin = JSObject.getWindow ( this );
JSObject DocumentPage = (JSObject) MainWin.getMember ( "document" );
JSObject UserInfoForm = (JSObject) DocumentPage.getMember ( "UserInfoForm" );
JSObject UserName = (JSObject) UserInfoForm.getMember ( "UserName" );
UserName.setMember ( "value", "Jeremiah S. Talkar" );
public void setSlot ( int index, Object value )
这个方法设置一个JAVASCRIPT对象的索引成员。它等价于JavaScript对象的this[index] = value。
public String toString ()

这个方法将JSObject转换成一个字符串。

上面的例子是很清楚的。JSObject类的公共方法试图在JavaApplet中调用JavaScript函数时是不受限制的。他们也可以使一个applet直接处理文档对象模型元素。

这些类完整的文档可以在http://developer.netscape.com/docs/manuals/communicator/jsref/pkg.htm上得到。

文档也解释了怎样在Java和JavaScript间处理数据类型。

MAYSCRIPT属性的意义

即使applet使用JSObject调用JavaScript函数,或者直接访问文档对象模型,如果applet标签没有包含在MAYSCRIPT属性中的话JSObject的方法就会失败。这一点能使网页设计者测定一个applet是否能唤起JavaScript。

不知名的applet间的通信

在网页内使用不知名的,但可以再度使用的Java applet时,一个applet需要与另一个applet直接通信是可能的。这样的一个呼叫也可以通过一个媒介JavaScript函数通信,但熟悉所有可用的选项总是比较好的。

java.applet包的AppletContext接口对applet的上下文实行一个访问限制,像插入applet的浏览器,一个applet在网页上还有其它的applet也在同样一个网页上。

例如,下面是一个HTML页包含两个applet:

html>
head>
title>Communication between applets/title>
/head>
body>
applet code="CircleArea.class" name="CircleArea" width=1 height=1>
/applet>
applet code="PICalculator.class" name="PICalculator" width=1 height=1>
/applet>
...
/body>
/html>

下面的代码表明了AppletContext对象的用法:

AppletContext context = getAppletContext();
PICalculator PIApplet = (PICalculator) context.getApplet ( "PICalculator" );
PIApplet.getValueOfPI();

另一个选项是使用AppletContext::getApplets()方法,它返回了一个访问文档内所有applet的枚举类型。即使applet间的通信是标准Java applet API的一部分,它也不会在所有允许JAVA的浏览器中得到支持。其它applet的核心编码也是坚定不移的。最好的方法可以是使用JAVASCRIPT函数来处理这种通信。

JAVA的IUnknown::QueryInterface类对象是类层次的根。每个类有一个超类对象。所有对象,包括数组,实现这个类的方法。Object::getClass()方法返回有许多能探索JAVA类自身详细资料的有用的函数的“类”。虽然在这篇文章的前面部分已经作过详细的解释,我还是想指出getInterfaces()方法使动态接口的发现通过一个JAVA类实现。

我没有试过在JAVASCRIPT内调用getClass()方法,因此不能评论它的可行性。但是使用基础类型的applet,这种功能性可以轻易地使它对脚本代码可用。

安装示例文件

这篇文章的示例代码已经在Java2JavaScript.zip文件中压缩。示例文件演示了一个已经在客户方自身简单地发送消息的一个聊天程序。用户在不同的机器上加入这个聊天中,一条消息发送给服务器,然后广播给所有的参加者。

组成示例的文件是:

ISession.java
定义ISession 接口的源文件

ISession.class
Isession接口的Java字节代码

ChatClient.java
演示ChatClient applet的源文件

ChatClient.class
ChatClient applet类的Java字节代码

CompileChatClient.bat
简单的JAVA源文件的批处理文件

TestChatClient.htm
支持ChatClient applet HTML文件

JSObject.class
JSObject类的字节代码

JSException.class
JSException类的字节代码


安装和运行示例程序的步骤是:

● 在运行有Personal Web Server或者Internet Information Server的机器上解压缩Java2JavaScript.zip到你所选择的目录。

● 确保安装目录下的netscape\javascript 子目录中的JSObject和JSException类文件是可用的。

● 右击安装目录选择“属性”。

● 点击“网页共享”标签,选定“共享这个文件夹”单选按钮,在弹出的对话框中接受默认值“虚拟目录”。

● 最后,启动Internet Explorer 4.0+ 或者 Netscape Navigator 4.0+程序,然后输入URL http:// 机器名>/虚拟目录>/TestChatClient.htm。

在输入框中输入一些文本,然后点击相应的“SEND”按钮,你就会看到消息在聊天窗口中出现。

示例代码解释

聊天程序是网页上流行的合作机制。我见过的聊天程序有两种类型:

● 一种是管理用户界面和服务器通信的Java applet。

● 另一种是每隔几秒就通过自动刷新来显示最后一次刷新后的所有新消息的HTML网页。

最近我不得不为我们E化商业产品的聊天程序实现产品质量。经过许多考虑后,我决定使用一个混合的方法。首先最重要的,Java applet是执行Isession接口的一个不知名的applet。

public interface ISession
{
// Type is used to differentiate the actual message string
// and can be set to ‘Text’, Hyperlink’ etc.

// Should be invoked first to indicate to the server that a
// new person has joined the chat.
public int BeginSession(String strAuthor, String strOptions, String strType, String strMessage);

// Should be invoked when the author wants to exit the chat.
public int EndSession(String strAuthor, String strType, String strMessage);

// Used to send the chat messages.
public int SendMessage(String strAuthor, String strType, String strMessage);
}
我已经把聊天程序产品版本中的这个接口作了轻微地修改,包括EndSession()和SendMessage()的Author参数。这是因为我的演示程序使用一个applet在两个不同聊天者间传递聊天消息。

ChatClient.java文件是Isession接口的实际执行文件。如果它们执行时浏览器就调用函数init(), start()和stop()。描述文档窗口的JSObject是在执行init()方法后得到的。

// Get the JavaScript window that will have the various scripts that this applet will call.
m_JScriptWin = JSObject.getWindow(this);

因为Java applet调用两个不同的JavaScript函数,我决定使WEB开发者能像applet的参数一样指定这些函数的名字,直到为同一个applet提供默认值。

m_strMessageHandler = getParameter("MessageHandler");
m_strErrorHandler = getParameter("ErrorHandler");
BeginSession()和EndSession()是只执行SendMessage()的虚拟执行函数。
SendMessage()呼叫在m_strMessageHandler成员变量中指定的JavaScript函数名字。默认值是“HandleSessionMessage”。相关代码如下所示:
if (m_JScriptWin != null)
{
String Arguments[] = {strAuthor, strType, strMessage};
m_JScriptWin.call(m_strMessageHandler, Arguments);
}
HandleSessionError()调用一个在m_strErrorHandler成员变量中指定的JavaScript函数名字。默认值是“HandleSessionError”.
TestChatClient.htm文件处理聊天的表现方面。applet使用applet>标记包含在网页中。
applet id="ChatApplet" width="1" height="1" code="ChatClient.class" codebase="." VIEWASTEXT mayscript>
param name="MessageHandler" value="HandleSessionMessageEx">
param name="ErrorHandler" value="HandleSessionErrorEx">
/applet>
参数指定applet调用的两个JavaScript函数的名字。我只表明名字除默认值外说明了这个方法是多么灵活,网页中的两个窗体模拟两个人正与对方聊天。相关的HTML也是简单易懂的。
实际上消息本身是在DIV>上显示的。在Internet Explorer中,我使用表格对象模型在单个的行中显示每条消息。因此ChatMessagesTable是在DIV>上定义的。
最后,HandleSessionMessagesEx()JavaScript函数处理所有的表现方面。在Internet Explorer内,每条消息发出后ChatMessagesTable表就增加新行。如果需要也将显示滚动条。在Netscape Navigator内,我给Messages变量附加新消息,并使用后者更新ChatMessages DIV>。既然滚动条不会自动在Netscape DIV>(是一个真正的LAYER)上显示,那么我在顶部显示最后一条接收到的消息。我已经找到了在Navigator内怎样支持LAYER滚动条的文章,但是与这个范例无关。
最后的思考
这篇文章努力介绍浏览器方逻辑的一些(优雅的)技术。像我早先在这篇文章中提到的,JSObject在许多程序中使用广泛,包括微软公司。同样,你需要考虑你的个人环境来确定这里介绍的技术是否可用。
至于这篇文章所附的示例程序,我觉得允许JavaScript / DHTML实现聊天的介绍使这个代码能够通过入门水平/低级程序员维护。用户界面的定制使用DHTML / JavaScript也很容易。加之,它允许看上去与余下的网页内容相一致,且更强大的表现技术。
在这个程序的产品版本中,我增加了在参与者机器上交换打开的超连接,使用层叠样式单动态的选择消息颜色等的支持。

5.
在Winform里怎么调用WebBrowser控件里的脚本

作者:思归
出处:http://blog.joycode.com/saucer/archive/2004/10/16/35628.aspx

这是在CSDN论坛上的一个问题,感觉也许对其他人也会有点用处,所以贴出来

JScript是建立在COM之上的,设置变量/调用函数是通过IDispatch来实现的。在.NET里,调用IDispatch里的方法是通过反射来实现的,即,通过System.Type.InvokeMember 。该方法调用 IDispatch::GetIDsOfNames 以及IDispatch::Invoke来调用COM Automation 对象里的方法和属性。参考

Binding for Office automation servers with Visual C# .NET
http://support.microsoft.com/default.aspx?kbid=302902

假如有下列HTML,

script language="javascript">
var var1 = 'yes';
function testx(obj)
{
alert(obj);
alert(var1);
}

input type=button value="click me" onclick="testx('hello');">

在C#里,假设axWebBrowser1是你的WebBrowser控件对象,你已经装载了上述HTML,你可以这么做,

mshtml.IHTMLDocument2 doc = (mshtml.IHTMLDocument2)axWebBrowser1.Document;
mshtml.IHTMLWindow2 win = (mshtml.IHTMLWindow2)doc.parentWindow;

//读变量值
object o = win.GetType().InvokeMember ("var1", BindingFlags.GetProperty, null, win, new Object [] {});

//写变量值
win.GetType().InvokeMember ("var1", BindingFlags.SetProperty, null, win, new Object [] {"新的值"});

//调用方法
win.GetType().InvokeMember("testx",BindingFlags.InvokeMethod,null,win,new object[]{1});

比较麻烦,对么?幸运的是,我们不用这么麻烦,因为IHTMLWindow2里有个现成方法,execScript,我们可以这么做:

win.execScript("var1 = 'abc';","javascript");
win.execScript("testx(12)","javascript");

(按:VC中的类似例子很多,例如Eugene Khodakovsky的一篇很好玩的文章《JavaScript Calls from C++》,
http://www.codeproject.com/com/jscalls.asp


(按:Javascript真是好东西)

Tuesday, January 18, 2005

 

Some notes on IE printing

1.
IE6.0打印机制解析

(按:不错的老贴)

from http://www.ccidnet.com/school/net/2001/09/18/70_5148.html

网页打印,可以通过浏览器的"打印"功能实现,但"打印模板"机制,却是 IE 5.5 /6.0 以及 Netscape 6.0 所独有的;准确一点, IE 5.5 只是一个机制雏形,在 IE 6.0 中才得以完全体现。IE 6.0 的打印功能模块,在精确控制页面边界,文本间隔,以及打印的统一性上,功能更为完备。

通过创建打印模板,你可以精确控制:

网页打印及预览时的页面风格与内容编排风格;
打印属性,如自动为打印的页面添加卷标或编号;
精确控制打印预览界面的各个元素与变量。

通过打印模板,你可以:

自动为所有打印页面添加固定内容,如公司标识,版权申明,或者指定广告;
自定义页面标头与尾注等元素,比如页码或卷标;
指定打印历史与任务;
书本化奇偶分页映射打印......

打印模板机制是建立在动态 HTML 语言基础上的,涉及到主要两个行为:DeviceRect, LayoutRect ,下面我们就这两个行为深入地探讨 IE 6.0 的打印机制。

另外需要说明的是,DHTML (动态超文本标识语言)的行为跟其他语言的"行为"一样,都是一种应用编程接口,初始状态下有自己的默认属性,在一定的事件下,由用户决定调用其承认的功能模块,从而产生相对应的"行为"。而且,"行为"可以自己编写,不过得以".htc"为其扩展名以供调用。

一.DeviceRect ,定义打印总体风格:

打印总体风格,包括为打印页面添加如公司标识的固定内容(网页上不一定有,只体现在打印纸张上或预览页面上,后同);打印页面的颜色风格;打印页面的边缘属性或图案;等等。

在进行 DeviceRect 引用前,先得确定页面风格,方法是用<Style>进行设置。

例一:我们来定制如下的打印模板
8.5 inch 宽
11 inch 高
黄色背景
1 pixel 宽的黑色实心左边界
1 pixel 宽的黑色实心上边界
4 pixels 宽的黑色实心右边界
4 pixels 宽的黑色实心下边界
所有边界与纸张边缘为 10 pixels 的距离

现在我们用 Style 进行设定,假设这个 Style 名为 Mystyle1:



<STYLE TYPE="text/css">
.Mystyle1
{
width:8.5in;
height:11in;
background:#FFFF99;
border-left:1 solid black;
border-top:1 solid black;
border-right:4 solid black;
border-bottom:4 solid black;
margin:10px;
}
</STYLE>

下面我们给出 DeviceRect 引用的完全页面代码,

<HTML XMLNS:IE>
<HEAD>
<?IMPORT NAMESPACE="IE" IMPLEMENTATION="#default">
<STYLE TYPE="text/css">
.Mystyle1
{
width:8.5in;
height:11in;
background:#FFFF99;
border-left:1 solid black;
border-top:1 solid black;
border-right:4 solid black;
border-bottom:4 solid black;
margin:10px;
}
</STYLE>
</HEAD>
<BODY>

<IE:DEVICERECT ID="page1" CLASS="Mystyle1" MEDIA="print">
</IE:DEVICERECT>

<IE:DEVICERECT ID="page2" CLASS="Mystyle1" MEDIA="print">
</IE:DEVICERECT>

</BODY>
</HTML>

在这个页面中,共进行了两个 DeviceRect 引用。作为一种规则,每一个单独的打印页面,必须有一个相对应的 DeviceRect 标记,如果有 1000 个页面,那就得有 1000 个 DeviceRect 标记!吓住了?别担心,后面我们会教你一个方法,让所有的 DeviceRect 标记自动完成!

在上面的代码中,ID 是标志属性,不同的页面必须有自己不同的标识;CLASS 引用了 Style 属性;MEDIA 属性则指明了本页面的最终用途是进行打印;<?IMPORT NAMESPACE="IE" IMPLEMENTATION="#default">这句话则是指输入默认的行为,它们分别是 DeviceRect, LayoutRect。

二.LayoutRect ,定义页面内容风格:

跟 DeviceRect 一样,不同的页面,要进行 LayoutRect 引用时都需要添加 LayoutRect 标记,其智能添加方法将在后面介绍; LayoutRect 与 DeviceRect 如果在同一个页面中同时出现,则前者需放在后者之内;另外, LayoutRect 对内容风格的设定,也通过 Style 得以实现。

例二:我们来定制如下的内容风格的打印模板:

5.5 inches 宽
8 inches 高
与打印纸张边缘,四边保持 1 inch 的宽度(加上页面本身的边缘宽度,为实际的打印边缘宽度)
白色背景
1 inch 宽的虚线边界

先定制名为 contentstyle 的风格:

<STYLE TYPE="text/css">
.contentstyle
{
width:5.5in;
height:8in;
margin:1in;
background:white;
border:1 dashed gray;
}
</STYLE>

然后下面是进行引用的完整网页代码:

<HTML>
<HEAD>
<?IMPORT NAMESPACE="IE" IMPLEMENTATION="#default">
<STYLE TYPE="text/css">
.contentstyle
{
width:5.5in;
height:8in;
margin:1in;
background:white;
border:1 dashed gray;
}
</STYLE>
</HEAD>

<BODY>
<IE:LAYOUTRECT ID="layoutrect1" CONTENTSRC="2.html" CLASS="contentstyle" NEXTRECT="layoutrect2"/>

<IE:LAYOUTRECT ID="layoutrect2" CLASS="contentstyle"/>
</BODY>
</HTML>


跟例一中的源代码相比,例二中只是以 LayoutRect 代替了原来的 DeviceRect 标记;DeviceRect 定制的是模板整体风格,而 LayoutRect 定制的是具体内容的版面风格;LayoutRect 的 ID 属性也具有唯一性; CONTENTSRC 属性则指明了具体的将起作用网页文件;CLASS 指明了风格的引用对象;跟 DeviceRect 不同,在进行 LayoutRect 引用时,必须在每个页面指定 NEXTREC ,即依次排列的下一个内容风格,这里的"下一个内容"用其页面的相应 ID 进行标识,如本例中的 LayoutRect2 。

三.DeviceRect 与 LayoutRect 的协同作战:

上面我们分别讨论了 DeviceRect 与 LayoutRect 的作用与引用方法,现在我们来看一下,如何在同一个打印模板中进行定制与引用。

在每一个打印模板上,必然包含两方面的内容,一个是整体的模板风格(DeviceRect),另一个是内容风格(LayoutRect);第一个打印页面跟其他页面是不同的,因为第一个页面中必须指明 CONTENTSRC 属性,而同一打印任务中的其他页面不再需要进行 CONTENTSRC 的指定。

例三:

下面是第一个页面中的 DeviceRect 代码:

<IE:DEVICERECT ID="page1" CLASS="masterstyle" MEDIA="print">
<IE:LAYOUTRECT ID="layoutrect1" CONTENTSRC="2.html" CLASS="contentstyle" NEXTRECT="layoutrect2"/>
</IE:DEVICERECT>

下面是其他页面中的 DeviceRect 代码:

<IE:DEVICERECT ID="page2" CLASS="masterstyle" MEDIA="print">
<IE:LAYOUTRECT ID="layoutrect2" CLASS="contentstyle"/>
</IE:DEVICERECT>

下面我们将 DeviceRect 与 LayoutRect 结合起来使用,其源代码如下:

<HTML XMLNS:IE>
<HEAD>
<?IMPORT NAMESPACE="IE" IMPLEMENTATION="#default">
<STYLE TYPE="text/css">
.contentstyle
{
width:5.5in;
height:8in;
margin:1in;
background:white;
border:1 dashed gray;
}
.Mystyle1
{
width:8.5in;
height:11in;
background:#FFFF99;
border-left:1 solid black;
border-top:1 solid black;
border-right:4 solid black;
border-bottom:4 solid black;
margin:10px;
}
</STYLE>
</HEAD>

<BODY>
<IE:DEVICERECT ID="page1" CLASS="Mystyle1" MEDIA="print">
<IE:LAYOUTRECT ID="layoutrect1" CONTENTSRC="2.html" CLASS="contentstyle" NEXTRECT="layoutrect2"/>
</IE:DEVICERECT>

<IE:DEVICERECT ID="page2" CLASS="Mystyle1" MEDIA="print">
<IE:LAYOUTRECT ID="layoutrect2" CLASS="contentstyle"/>
</IE:DEVICERECT>

</BODY>
</HTML>

四.DeviceRect 与 LayoutRect 标记的动态自动添加:

前面我们说到,每个单独的打印页面都需要各自的 DeviceRect 与 LayoutRect 标记,那么,如果我们有 1000 个页面需要打印,是否就要在每个页面上重复繁琐的 Copy & Paste 操作?

答案是否定的,我们完全可以通过 JavaScript 脚本来完成这一繁琐的工作。

要实现 HTML 声明的动态创建,关键在于 <DIV> 标记的定义,下面是其定义规则。

<DIV ID="devicecontainer">
......
</DIV>

<DIV>与</DIV>之间,采用 insertAdjacentHTML() 方式,并主要利用了其 afterBegin 与 BeforeEnd 两个变量,现在我们将第一个页面"插入"到<DIV></DIV>之间:

devicecontainer.insertAdjacentHTML("afterBegin", newHTML);

具有继承属性的后续页面,调用 beforeEnd 变量:

devicecontainer.insertAdjacentHTML("beforeEnd", newHTML);

要装载 devicecontainer 页面,还需在 <Body>中添加:

<BODY ONLOAD="addFirstPage()">

现在我们在 JavaScript 中添加包含前面详细介绍的 LayoutRect 与 DeviceRect 元素,用到的命令是 addFirstPage() 。需要注意的是,newHTML 标记后使用的是双引号,而 LayoutRect 与 DeviceRect 标记后的变量使用单引号。如下:

function addFirstPage() {
newHTML = "<IE:DEVICERECT ID='devicerect1' MEDIA='print' CLASS='mystyle1'>";
newHTML += "<IE:LAYOUTRECT ID='layoutrect1' CONTENTSRC='2.html'" + "ONLAYOUTCOMPLETE='onPageComplete()' NEXTRECT='layoutrect2'" + "CLASS='contentstyle'/>";
newHTML += "</IE:DEVICERECT>";

devicecontainer.insertAdjacentHTML("afterBegin", newHTML);
}

细心的读者一定会发现,LayoutRect 后出现了一个新的属性:LayoutRect:onLayoutComplete ,这个属性主要指定了 LayoutRect 停止响应的后续事件,如系统资源消耗殆尽而停止响应,或者 LayoutRect 指定的变量溢出。

好了,有了上面的原理,下面我们来编写具有自动"插入"功能的 JavaScript 代码:

function onPageComplete() {
if (event.contentOverflow) {
newHTML = "<IE:DEVICERECT ID='devicerect" + (lastPage + 1) + "' MEDIA='print' CLASS='mystyle1'>";
newHTML += "<IE:LAYOUTRECT ID='layoutrect" + (lastPage + 1) + "' ONLAYOUTCOMPLETE='onPageComplete()' NEXTRECT='layoutrect" + (lastPage + 2) + "' CLASS='contentstyle'/>";
newHTML += "</IE:DEVICERECT>";

devicecontainer.insertAdjacentHTML("beforeEnd", newHTML);
lastPage++;
}

在上面的代码中,contentOverflow 代表的是由于页面信息过长,本页的 LayoutRect 停止响应,则直接跳到下一个页面,让 LayoutRect 重新定义下一个页面的版面;onPageComplete() 则不管页面是否过长,LayoutRect 是否停止响应,只要到了页面尾部则自动跳到下一页,这也是最常见的情况。

在编写本脚本时,关键处在于保持清醒,不能让任意一个变量出错。其中,ID 不仅针对 DeviceRect 与 LayoutRect ,还为 NextRect 所引用,页面指向不能出错;当前页面的页码应该是 lastPage+1 ,下一个页面的页码应该是 lastPage+2 ;NextRect 标记需要下一个页面的 LayoutRect 属性支持,因此它的值应该为 "layoutRect"+(lastPage+2);打开第一个页面时,这个 LastPage 初始值为 1 。

2.
Print preview for IE the easiest way

ExecWB(OLECMDID_PRINTPREVIEW, OLECMDEXECOPT_PROMPTUSER, NULL, NULL);

Monday, January 17, 2005

 

Syntax coloring and folding in HTML

1.
使用js正则表达式格式化加亮源代码

来源:http://www.98xj1.com/users/mmkk/dhtml/FormatCsharpCodeByjs.html

一些站点上也有对某种语言的关键字进行加亮显示,比如CodeProject或者dotnetjunkies等,不过他们都是定义了特定的css样式,然后逐一进行样式应用来进行加亮显示,如果这种技术没有后台支持的话,将会有产生相当大的工作量,利用Javascript强大的正则表达式功能,我们可以在没有后台支持的情况下以少量的工作来完成这个功能,String.Replace()将会为我们完成所有核心工作
[code]
//替换关键字
for (thiskey in CsharpKeyword)
{
reg = new RegExp("\\b("+CsharpKeyword[thiskey].toString()+"){1}\\b","g");
text = text.replace(reg,"font color=blue>$1/font>");
}
//替换"..."字符串中可能被加亮的关键字
text = text.replace(/\"([^\"]*)\"/g,function($1){return $1.replace(/\/?font.*?>/gi,"")});
//.号表示除换行符或其他Unicode中止符之外的所有字符(替换单行注释符)
text = text.replace(/(\/\/.*)/g,function($1){return "font color=green>"+$1.replace(/\/?font.*?>/gi,"")+"/font>"});
text = text.replace(/(\/\*[\S\s]*\*\/)/g,function($1){return "font color=green>"+$1.replace(/\/?font.*?>/gi, "")+"/font>"});//替换多行注释符
[/code]

基本上,这里替换加亮特殊代码需要按照这样的步骤:替换关键字->替换字符串("")中的关键字(第一个步骤可能将某些字符串中的关键字加亮了,这个步骤需要把它们转回去)->替换//单行注释->替换/**/多行注释,每一个替换都要先擦掉原来的font>标记,才能解决嵌套的情况,否则有可能//afont color=red>b/font>c最终显示的是//abc而不是期望中的//afont color=red>b/font>c;这是最关键的地方.
需要注意的是,String.Replace(regex,replacement)方法;如果replacement是一个函数的话,必须要Javascript1.2或者Jscript5.5(IE5.5)以上才能实现

下面是HTC文件

[code]
PUBLIC:COMPONENT NAME="FormatCsharpCodeHTC">
PUBLIC:ATTACH EVENT="ondocumentready" ONEVENT="FormatCsharpCode()"/>
script language="Jscript">
//所有C#关键字
var CsharpKeyword = ["abstract","as","base","bool","break","byte","case","catch","char","checked",
"class","const","continue","decimal","default","delegate","do","double","else",
"enum","event","explicit","extern","false","finally","fixed","float","for","foreach",
"get","goto","if","implicit","in","int","interface","interal","is","lock","long",
"namespace","new","null","object","operator","out","override","params","private",
"protected","public","readonly","ref","return","sbyte","sealed","set","short",
"sizeof","stackalloc","static","string","struct","switch","this","throw","true",
"try","typeof","uint","ulong","unchecked","unsafe","ushort","using","value",
"virtual","void","while"];

function FormatCsharpCode()
{
var obj = eval(element.id);
var reg;
var text = obj.innerHTML;


for (thiskey in CsharpKeyword)
{
reg = new RegExp("\\b("+CsharpKeyword[thiskey].toString()+"){1}\\b","g");
text = text.replace(reg,"font color=blue>$1/font>");

}
//替换"..."字符串中可能被加亮的关键字
text = text.replace(/\"([^\"]*)\"/g,function($1){return $1.replace(/\/?font.*?>/gi,"")});
//.号表示除换行符或其他Unicode中止符之外的所有字符(替换单行注释符)
text = text.replace(/(\/\/.*)/g,function($1){return "font color=green>"+$1.replace(/\/?font.*?>/gi,"")+"/font>"});
text = text.replace(/(\/\*[\S\s]*\*\/)/g,function($1){return "font color=green>"+$1.replace(/\/?font.*?>/gi, "")+"/font>"});//替换多行注释符
obj.innerHTML = text;
obj.style.backgroundColor = "#F7F3F7";
obj.style.border = "1px solid #696969";
obj.style.padding = "2px;"
obj.style.margin = "2px";
}

/PUBLIC:COMPONENT>
[/code]

2.
原理相近,但更加复杂的例子可以参见Jonathan de Halleux的文章,这家伙看起来闲散时间极多。

Multiple Language Syntax Highlighting, Part 1: JScript
http://www.codeproject.com/jscript/highlight.asp?target=syntax%7Ccoloring
Multiple Language Syntax Highlighting, Part 2: C# Control
http://www.codeproject.com/csharp/highlightcs.asp )

3.
http://www.actiprosoftware.com/Products/DotNet/CodeHighlighter/PasteCode.aspx
这个更强,use DHTML to enable outlining (IE only) 类似VS.NET中的折叠效果。但是需要特定的图片,而且生成的html代码多了很多的img标签。
最后,需要把生成的html代码放入一个pre标签中,一段美观的code snippet就生成了。
5/8/2004补充

4. 搜查结果关键词的加亮
我们知道Lucene和Lucene.Net是预先生成好了相应的加亮code,以HTML的方式传给用户。这其实是一个比较简单的字符串替换问题,可以参见Lucene.Net的相关代码
https://sourceforge.net/projects/lucenedotnet/

当然,我们也可以使用后期着色的方法。比如Google的方法就是参照下面的文档写的
http://www.kryogenix.org/code/browser/searchhi/

5. 以前的blog讨论了highliting,现在folding正在成为越来越多网站上的基本功能。其实现手法主要有两种:

第一种是使用javascript,这个速度慢,实现代码也比较困难。
另一种广为使用的方法是使用高版本的IE所具有的Table处理功能来实现。这种方式将代码分层插入一个嵌一个的Table Cell中,再加上合适的几个图片,就可以相对容易的实现folding,就像IE显示XML文件一般。这种方法还是比较巧妙的,其关键还是原始code文档的XML化和分隔符号的寻找。这方面的代码可以从多个地方看到,actiprosoftware公司的产品旧很不错。

http://www.actiprosoftware.com/Products/DotNet/Default.aspx

不过,由于XML化的速度不高,代码量大的话,速度肯定低,内存也耗的多(因为要把数据全部读入内存)。下面是一个例子

By Teddy
From http://www.cnblogs.com/teddyma/archive/2005/01/10/89466.html

写了一个全文本的C#代码着色器,不采用任何图片,因为事先没有参考任何已有着色器源码,可能有些地方实现的不是很优雅,如果谁手里有其他着色器的源码,望多交流!

using System;

using System.Text.RegularExpressions;



namespace CN.Teddy.Util.HtmlCodeColor

{

/// summary>

/// C#代码着色适配器

/// /summary>

public class CSharpAdapter : ICodeColorAdapter

{

_ #region Constructors



public CSharpAdapter()

{

//null

}



- #endregion



_ #region Private Members



/// summary>

/// 为//和/**/类型的注释着色

/// /summary>

/// param name="src">输入源码/param>

/// returns>格式化后的源码/returns>

private string ColorBasicComment(string src)

{

string retCode = src;



Regex r1 = new Regex(@"(^|;)([ \t]*)(//.*$)", RegexOptions.Multiline);

retCode = r1.Replace(retCode, "$1$2 span style=\"color: green\">$3/span>");

Regex r2 = new Regex(@"(^|[ \t]+)(/\*[^\*/]*\*/[ \t\r]*$)", RegexOptions.Multiline);

retCode = r2.Replace(retCode, new MatchEvaluator(this.ColorBasicComment2Evaluator));



return retCode;

}



/// summary>

/// 为///类型的注释着色

/// /summary>

/// param name="src">输入源码/param>

/// returns>格式化后的源码/returns>

private string ColorXmlComment(string src)

{

string retCode = src;



Regex r1 = new Regex(@"(/// *)<(.*)>", RegexOptions.Multiline);

retCode = r1.Replace(retCode, new MatchEvaluator(this.ColorXmlCommentEvaluator));

Regex r2 = new Regex(@"(/// *)(.*$)", RegexOptions.Multiline);

retCode = r2.Replace(retCode, "span style=\"color: gray\">$1/span>$2");



return retCode;

}



/// summary>

/// 为折叠显示代码构建HtmlTable框架

/// /summary>

/// param name="src">输入源码/param>

/// returns>格式化后的源码/returns>

private string DrawCollapseFrameTable(string src)

{

System.Text.StringBuilder retCode = new System.Text.StringBuilder();



string frameHeader = "table border=0 cellpadding=0 cellspacing=0 width=95% style='border: windowtext 0.5pt solid; background-color:#fefefe'>tr>td valign=top align=center style='border-right-color: #808080; border-right-style: solid; border-right-width: 1px'>table border=0 cellpadding=0 cellspacing=0>tr>td> /td>td> /td>/tr>/table>/td>td>table border=0 cellpadding=1 cellspacing=0 width=100%>";

string frameTailer = "/table>/td>/tr>/table>";



retCode.Append(frameHeader);



string[] lines = src.Split('\n');



foreach (string line in lines)

{

string formatedLine = line.Trim();



string lineHeader = "tr>td style='width: 0px'>table style='width: 9px; height: 9px'>tr>td>/td>/tr>/table>/td>td style='width: 0px'>/td>td style='width: 100%'>code style='font: 9pt Tahoma'>";

string lineTailer = "/code>/td>/tr>";



formatedLine = lineHeader + formatedLine + lineTailer;



retCode.Append(formatedLine);

}



retCode.Append(frameTailer);



return retCode.ToString();

}



/// summary>

/// 折叠Region

/// /summary>

/// param name="src">输入源码/param>

/// returns>格式化后的源码/returns>

private string CollapseRegion(string src)

{

string retCode = src;



string lineHeader = "tr>td style='width: 0px'>table style='width: 9px; height: 9px'>tr>td>/td>/tr>/table>/td>td style='width: 0px'>/td>td style='width: 100%'>code style='font: 9pt Tahoma'>";



Regex r = new Regex(lineHeader + @"( )*span style=\""color: blue\"">#region.*$", RegexOptions.Multiline);

while (r.Match(retCode).Success)

{

//add "+" tag

retCode = r.Replace(retCode, new MatchEvaluator(this.CollapseRegionEvaluator));

}



return retCode;

}

/// summary>

/// 为一行源码中的关键字着色

/// /summary>

/// param name="codeLine">某一行源码/param>

/// param name="keywordList">关键字列表/param>

/// returns>格式化后的源码/returns>

/// summary>

private string ColorKeyword(string codeLine, string[] keywordList)

{

string retCode = codeLine;



if (!retCode.StartsWith("//"))

{

foreach (string keyword in KEYWORD_LIST)

{

Regex r = new Regex(@"(^|\s+|,|\)|\(|\{|\}|\[|\]|\.|=|;)(" + keyword + @")(\s+|,|\)|\(|\{|\}|\[|\]|\.|=|;|$)");



retCode = r.Replace(retCode, "$1span style=\"color: blue\">$2/span>$3");

}

}



retCode = ClearColoredKeyworsInString(retCode);



return retCode.Trim();

}



/// summary>

/// 清除字符串中的被着色的关键字

/// /summary>

/// param name="codeLine">某一行源码/param>

/// returns>格式化后的源码/returns>

private string ClearColoredKeyworsInString(string codeLine)

{

System.Text.StringBuilder retCode = new System.Text.StringBuilder();



string str = codeLine.Trim();



int indexOfQuot = str.IndexOf(""");

int lengthOfQuot = """.Length;



if (indexOfQuot >= 0)

{

while (indexOfQuot >= 0)

{

retCode.Append(str.Substring(0, indexOfQuot + lengthOfQuot));

str = str.Substring(indexOfQuot + lengthOfQuot);



indexOfQuot = str.IndexOf(""");



if (indexOfQuot >= 0)

{

string inStr = str.Substring(0, indexOfQuot + lengthOfQuot);



inStr = inStr.Replace("\"color: blue\"", "\"\"");



retCode.Append(inStr);

str = str.Substring(indexOfQuot + lengthOfQuot);

}



indexOfQuot = str.IndexOf(""");

}

}



retCode.Append(str);



return retCode.ToString();

}





public static string[] KEYWORD_LIST = {

"abstract", "event", "new", "struct", "as", "explicit", "null", "switch",

"base", "extern", "object", "this", "bool", "false", "operator", "throw",

"break", "finally", "out", "true", "byte", "fixed", "override", "try",

"case", "float", "params", "typeof", "catch", "for", "private", "uint",

"char", "foreach", "protected", "ulong", "checked", "goto", "public",

"unchecked", "class", "if", "readonly", "unsafe", "const", "implicit",

"ref", "ushort", "continue", "in", "return", "using", "decimal", "int",

"sbyte", "virtual", "default", "interface", "sealed", "volatile",

"delegate", "internal", "short", "void", "do", "is", "sizeof", "while",

"double", "lock", "stackalloc", "else", "long", "static", "enum",

"namespace", "string", "get", "set", "#region", "#endregion", "true",

"false"

};



private string ColorXmlCommentEvaluator(Match m)

{

Regex r = new Regex("(^.*>)(.*)(</.*$)");

if (r.Match(m.Value).Success)

{

return r.Replace(m.Value, "span style=\"color: gray\">$1/span>$2span style=\"color: gray\">$3/span>");

}

else

{

return "span style=\"color: gray\">" + m.Value + "/span>";

}

}



private string ColorBasicComment2Evaluator(Match m)

{

System.Text.StringBuilder retCode = new System.Text.StringBuilder();



string[] lines = m.Value.Split('\n');



foreach (string line in lines)

{

retCode.Append("span style=\"color: green\">" + line + "/span>" + "\n");

}



return retCode.ToString();

}



private string CollapseRegionEvaluator(Match m)

{

//get region code block



string retCode = m.Value;



string lineHeader = "tr>td style='width: 0px'>table style='width: 9px; height: 9px'>tr>td>/td>/tr>/table>/td>td style='width: 0px'>/td>td style='width: 100%'>code style='font: 9pt Tahoma'>";

string lineTailer = "/code>/td>/tr>";



Regex r = new Regex("^" + lineHeader + @"( )*span style=\""color: blue\"">#region/span>[^]*" + lineTailer, RegexOptions.Multiline);

retCode = r.Replace(retCode, new MatchEvaluator(this.CollapseRegionEvaluator2));



//find out #region - #endregion block & add collapse code

string endRegionLinePattern = "tr>td style='width: 0px'>table style='width: 9px; height: 9px'>tr>td>/td>/tr>/table>/td>td style='width: 0px'>/td>td style='width: 100%'>code style='font: 9pt Tahoma'>( )*span style=\"color: blue\">#endregion/span>/code>/td>/tr>";

Regex r2 = new Regex(endRegionLinePattern);

string endRegionLine = r2.Match(retCode).Value;

string formatedEndRegionLine = endRegionLine.Replace("td style='width: 0px'>/td>td style='width: 100%'>", "td style='width: 0px'>span style='position: relative; left: -12px; font: 12px'>font color=#808080 face='Tahoma'>-/font>/span>/td>td style='width: 100%'>");

string regionBlock = retCode.Substring(0, retCode.IndexOf(endRegionLine)) + formatedEndRegionLine;



string spaces = new Regex("( )+").Match(regionBlock).Value;

string regionDescWidthTag = new Regex("#region/span> ([^]*)/code>").Match(regionBlock).Value;

string regionDesc = regionDescWidthTag.Substring(15, regionDescWidthTag.Length - ("#region/span> ").Length - ("/code>").Length);



regionBlock = regionBlock.Replace("/tr>tr>td style='width: 0px'>", "/tr>tr style='display: none'>td style='width: 0px'>");

regionBlock = regionBlock.Substring(0, regionBlock.IndexOf("code style='font: 9pt Tahoma'>") + "code style='font: 9pt Tahoma'>".Length) +

"span>" + spaces + "/span>" + "span style='border: 1px solid gray'>font color=gray>" + regionDesc + "/font>/span>" +

regionBlock.Substring(regionBlock.IndexOf("/code>"));



retCode = regionBlock + retCode.Substring(retCode.IndexOf(endRegionLine) + endRegionLine.Length);



return retCode;

}





private string CollapseRegionEvaluator2(Match m)

{

string retCode = m.Value;



//add rectangle

retCode = retCode.Replace("style='width: 9px; height: 9px'", "style='position: relative; left: -6px; top: 0px; border-color: #808080; border-style: solid; border-width: 1px; background: white; width: 9px; height: 9px'");



string spaces = new Regex("( )+").Match(m.Value).Value;

string regionDescWidthTag = new Regex("#region/span> ([^]*)/code>").Match(m.Value).Value;

string regionDesc = regionDescWidthTag.Substring(15, regionDescWidthTag.Length - ("#region/span> ").Length - ("/code>").Length);



//add "+" tag

retCode = retCode.Replace("td style='width: 0px'>/td>", "td style='width: 0px'>span style='position: relative; left: -16px; top: -1px; font: 12px; cursor: hand' onclick='if (this.childNodes[0].innerHTML == \"_\") { this.childNodes[0].innerHTML = \"+\"; this.style.top = \"-1px\"; this.parentNode.nextSibling.childNodes[0].innerHTML = \"span>" + spaces + "/span>span>font color=gray>" + regionDesc + "/font>/span>\"; this.parentNode.nextSibling.childNodes[0].childNodes[1].style.border = \"1px solid gray\"; for (var i = 1 + this.parentNode.parentNode.rowIndex; i this.parentNode.parentNode.parentNode.childNodes.length; i++) { this.parentNode.parentNode.parentNode.childNodes[i].style.display=\"none\"; if ( this.parentNode.parentNode.parentNode.childNodes[i].childNodes[1].innerText.length > 0 ) { break; } } } else { this.childNodes[0].innerHTML = \"_\"; this.style.top = \"-6px\"; var oldDesc = this.parentNode.nextSibling.childNodes[0].childNodes[1].childNodes[0].innerHTML; this.parentNode.nextSibling.childNodes[0].innerHTML = \"span>" + spaces + "/span>span>font color=blue>#region /font>/span>span>/span>\"; this.parentNode.nextSibling.childNodes[0].childNodes[2].innerHTML = oldDesc; for (var i = 1 + this.parentNode.parentNode.rowIndex; i this.parentNode.parentNode.parentNode.childNodes.length; i++) { this.parentNode.parentNode.parentNode.childNodes[i].style.display=\"block\"; if ( this.parentNode.parentNode.parentNode.childNodes[i].childNodes[1].innerText.length > 0 ) { break; } } }'>font color=#808080 face='Tahoma'>+/font>/span>/td>");



return retCode;

}



- #endregion



_ #region ICodeColorAdapter 成员



/// summary>

/// 为注释着色,例如:对C#,包括///型、//型和/**/的注释

/// /summary>

/// param name="src">输入源码/param>

/// returns>格式化后的源码/returns>

public string ColorComment(string src)

{

string retCode = src;

retCode = ColorBasicComment(retCode);

retCode = ColorXmlComment(retCode);

return retCode;

}



/// summary>

/// 为关键字着色

/// /summary>

/// param name="src">输入源码/param>

/// returns>格式化后的源码/returns>

public string ColorKeyword(string src)

{

System.Text.StringBuilder retCode = new System.Text.StringBuilder();



string[] lines = src.Split('\n');



if (lines != null && lines.Length > 0)

{

bool isInComment = false;



foreach (string line in lines)

{

string formatedLine = line.Trim();



if (new Regex(@"(^|[ \t]+)(/\*)").Match(line).Success)

{

isInComment = true;

}



if (!isInComment)

{

formatedLine = ColorKeyword(line, KEYWORD_LIST);

}



if (new Regex(@"\*/[ \t\r]*$").Match(line).Success)

{

isInComment = false;

}



retCode.Append(formatedLine + "\n");

}

}



return retCode.ToString();

}



/// summary>

/// 使代码支持折叠显示

/// /summary>

/// param name="src">输入源码/param>

/// returns>格式化后的源码/returns>

public string CollapseCode(string src)

{

string retCode = src;

retCode = DrawCollapseFrameTable(retCode);

retCode = CollapseRegion(retCode);

return retCode;

}



/// summary>

/// 代码缩进

/// /summary>

/// param name="src">输入源码/param>

/// returns>格式化后的源码/returns>

public string IndentCode(string src)

{

System.Text.StringBuilder retCode = new System.Text.StringBuilder();



int indent = 0;

string [] lines = src.Split('\n');



foreach (string line in lines)

{

string formatedLine = line.Trim();



Regex r = new Regex(@"\}(\}|\s)*;?\s*$");

if (r.Match(line).Success)

{

indent--;

}



for (int i = 0; i indent; i++)

{

formatedLine = "      " + formatedLine;

}



retCode.Append(formatedLine + "\n");



if (line.EndsWith("{"))

{

indent++;

}

else if (line.StartsWith("{"))

{

indent++;

}

}



return retCode.ToString();

}

- #endregion

}

}

这里显然缺少关键字着色的部分。加上最前面说得代码就完美啦。

Another one
Library Code2HTML
From DotNetJunkie XL on the 7th Floor
http://dotnetjunkies.com/WebLog/kris/archive/2003/11/04/3171.aspx

BTW, if you have only Vision 2003 or below at hand and you need to draw UML. You have

Visio Stencil and Template for UML 2.0
http://www.phruby.com/stencildownload.html

This page is powered by Blogger. Isn't yours?