RSS

Monthly Archives: 十二月 2003

Hello, 2004!

再过几个小时就是2004年了,我的生日恰巧是1月1日,呵呵,所以每到元旦,长大一岁的感觉就特别强烈了。

今天在办公室把SharePoint服务器端的用于文件接收的WebService写完了,然后在自己写的客户端上试着调用了一下,传了几个文件到SharePoint服务器的文档库里面,呵呵,速度还不错。下一步就是把“续传”的功能加上,就是说,上传的过程中断线、出错,下次上传的时候文件可以从断掉的地方续传。我怀疑这种上传方式的速度肯定比不上普通的文件上传,但是续传的功能对于大文件的上传又很重要。

有时候想起自己写Blog的目的,可能是因为“写作是最好的记忆”吧,觉得看到了什么好玩的东东写下来可能就不会很快的忘掉。平时总有很多东西都想写下来,但写作的确和心情很有关系,而且人总是懒惰的。

今天下班的时候,部门里面两个玩得不错的PLMM跑出去到Baleno买了件衣服,然后回办公室送给了我。所以心情比较愉快。希望2004好心情能一直陪伴我。

 

Posted by on 2003/12/31 in 未分类

5 Comments

ASP.NET Pre-Compilation and Keep-Alive

1、Pre-Compilation in Whidbey

ASP.NET一大特色就是Dynamic Compilation,但是有些场合Pre-Compilation却是更好的选择,比如,你不想访问你的站点的第一个用户痴痴的等待,或者你根本不想把任何源码(包括HTML的内容)给你的用户。

Pre-Compilation在ASP.NET 2.0中支持得很彻底,你可以选择In-Place Pre-Compilation,只需要你访问一下:
http://站点名称/WebApp名称/PreCompile.axd
系统就会将WebApp里面所有的页面先给你编译一遍。

或者,更加彻底的方式,PreCompilation for Deployment,.Net Framework 2.0提供了一个命令行的工具(aspnet_compiler.exe),让你将WebApp中所有的代码、页面(包括HTML)、静态文件全部编译进dll,然后给你一个“Deployment-Ready WebApp”,No Code、No Html,呵呵,但是浏览起来和普通的WebApp没有区别。

这篇文章包含了更多的信息。

2、Pre-Compilation and Keep-Alive in .NET Framework 1.1

Whidbey毕竟是明年的事,其实在现在,我们也可以想一些办法。

Global.asax里面的那个Global类是继承自HttpApplication的,我们可以自己插入一个中间层,来做一些自己的事情。比如我们创建一个PreGlobal类,继承自HttpApplication,在PreGlobar.Init()方法中,创建一个新的线程,让这个线程遍历访问WebApp中所有的.aspx和.ascx(对ascx就LoadControl(),对aspx就HttpWebRequest.Create(url).GetResponse()),这样可以实现我们自己的“Pre-Compilation”,然后再让Global继承自我们自己的这个PreGlobal就可以了。

我们可以感觉到,如果一段时间没有访问WebApp,那么当再次访问时,速度大大降低,这是因为Clr会自动将站点的Assembly从内存中Unload,当再次访问时,再载入Assembly,而这个动作是相当耗时的(想想在电脑上运行一个WinForm,它的启动时间)。我们需要想一个办法让我们的WebApp始终Keep-Alive,这样Clr就不会将它Unload了。方法还是PreGlobal.Init()方法,我们在这个方法中创建一个Timer对象,定时时间小于默认的Session过期时间即可,在其Elapsed事件中调用一下“HttpWebRequest.Create(站点url).GetResponse()”就可以让我们的站点始终Alive了。

这个方法是从ASPAliance上看来的,具体出处已经找不到了。

3、Delphi8

D8的文章在CSDN上也渐渐多了起来。如果不讨厌Pascal的语法,那么D8安装目录的source目录下的文件实在是一个不错的学习.NET的资源,里面有D8的RTL、VCL.NET、Indy.NET、Web数据感知控件实现的源码,至少可以看看D8是如何将它的东西和.NET的东西结合起来的。

比如,在Borland.Delphi.System.pas里面,我看到了TObject = System.Object,呵呵,和我们想象的一样。在Borland.Vcl.Classes.pas里面,我看到了TList有一个private成员FList是System.Collections.ArrayList类型的,于是显然TList是通过聚合ArrayList来实现的。而在Borland.Vcl.Forms.pas里面,可以看到TForm是从TCustomForm继承下来,然后上面依次是TScrollingWinControl、TWinControl、TControl…和System.Windows.Forms.Form没什么关系,这也就是D8要分VCL.NET App和Win App的原因,VCL.NET很多控件仍然是Borland按自己的方式写的(虽然都是Managed Code写的),他们和WinForms不一定完全兼容的。

 

Posted by on 2003/12/28 in 未分类

4 Comments

Delphi8 is out !

昨晚把Delphi8安装上并试用了一下,Delphi8是一个完全面向.NET平台的开发工具,而Win32平台仍然由Delphi7支撑,明年还将发布Delphi 7.1。就是说,Delphi7和Delphi8将成为两条平行的产品线。当然随着Win32市场的逐渐缩小,Delphi7不会再有后续的继承版本。

下面是我的第一印象:

1、Delphi8很耗内存,和VS.NET不相上下,但是编译速度快不少。安装目录是BDS\2.0,而C# Builder是BDS\1.0,而且Delphi8运行的进程里面也是那个相同的“bds.exe”。可以想象Delphi8和C#Builder共用的一个IDE,不知道以后会不会把他们两个集成起来。他们的界面也是非常非常相似的。

2、新建立了一个Web Application,同样的Code-Behind,只不过后台文件是.pas了,和VS的没什么两样,编译,浏览,然后去“Temporary ASP.NET Files”目录下面看生成的编译后的临时文件,果然仍然也是从.aspx生成.cs的C#代码文件,然后编译成dll。Delphi8只是将.pas代码文件编译成dll,然后通过继承让页面文件使用。从这个观点看Delphi8的ASP.NET设计,和其他语言Effiel、Python的VS插件所做的没太多区别。

3、打开.aspx的html视图,顶上仍然是那句“Page language=”c#””,试着在.aspx里面手工写上一个C#语法的函数,然后在下面Form的OnLoad中调用,没任何问题。更加证实了上面第2点所说的。

4、Delphi8新增的一些控件:BDP(Borland Data Provider,一组符合ADO.NET接口的数据提供组件,号称性能更好)、Web数据感知控件(Delphi的老传统,通过一个DBWebDataSource,将数据直接映射到DBWebLabel、DBWebListBox之类的控件上)、ECO(Enterprise Core Objects,Borland力推的一组MDA架构的组件,这个应该是重头戏,可Delphi产品网页上的ECO Tutorial居然还是“come soon…”,晕)。

Delphi8面对的挑战不小,基于.Net Framework 1.2的Whidbey明年春季就会发布beta了,而且VS的稳定性显然胜过Delphi8(Delphi8的IDE稳定性的确是个问题,我用了一阵子之后,代码提示就莫名其妙的不起作用了)。我觉得Borland不要再花费力气去搞什么C# Builder(显然C#程序员几乎都会选择VC#),认真的将Delphi8做得更加稳定、更具弹性,将Pascal语言的编译器做得速度更快更有效率。显然Delphi8的后续开发还在紧张进行(在C# Builder中出现过的可以引用J2EE Components的功能好像在Delphi8中还没有实现,不少论坛上都引用了李维的话,说Delphi Team过完圣诞就得加班)。希望Borland能带给我们一个优秀的.NET开发工具。

 

Posted by on 2003/12/26 in 未分类

29 Comments

Disk-Based Caching in Whidbey, Longhorn…

在2004年春天发布的Whidbey beta中的ASP.NET 2.0,将增加一个特性,可以将Output Cache写到硬盘或者数据库中。这样我们可以将缓存在磁盘上保留很长一段时间,并且当后台数据变化后自动重新生成缓存。并且缓存也不再会因为工作进程的重启而消失。我们甚至可以设定使用多大的磁盘空间来放置缓存内容。

但是,Whidbey不会提供类似于支持Session的State Server一样的集中式的缓存服务器(这个特性对于服务器集群很有利),ASP.NET小组推荐在各个服务器上保留不同的缓存实例,而且他们认为这种模式的缓存的性能也会大打折扣。

这里是一篇很不错的介绍Longhorn三个主要编程模型Avalon、WinFS、Indigo的文章。其中对WinFS介绍了很多。其中提到在Longhorn PDC预览版本中,WinFS并未完成,在beta 1中将完成基础模型,在beta 2中将基本完成。而PDC预览中Indigo完成度就比较高了,而且微软也承诺在WinXP和Win2003中提供Indigo技术的实现,而且最终版的Longhorn里面,Indigo Message Server之间也没有信息交换的能力。(Otherwise, the release version of the Longhorn client wouldn’t have Indigo-compliant servers with which to trade messages. 难道我理解错了??)相对于现在创建WebService的简单性来说,Indigo也存在一个比较陡的学习曲线。(但Microsoft也在致力改善)

文章最后的两句话很有指导性。If you want a shorter-term payoff for the time you invest in exploring Longhorn, concentrate on Indigo’s MessageBus. Otherwise, make the effort to gain an equal working knowledge of all three pillars. If Microsoft’s bet on Longhorn pays off, you’ll be amply rewarded by the demand for competent Longhorn programmers. 如果你想马上从学习Longhorn编程模型中获益,那么就先学习Indigo,但是如果努力学习所有的这三个主要编程模型,一旦微软在Longhorn上的赌注兑现,那么你将从对Longhorn程序员的需求中大大获益。

 

Posted by on 2003/12/25 in 未分类

评论关闭

加入定制的WebService到SharePoint站点中

今天和SharePoint奋斗了一整天。因为我要加一些自己定制的WebService到SharePoint站点中,但是SharePoint Service接管了.asmx文件的处理(即屏蔽了.NET自己的处理.asmx的httpHandler),把这个问题搞定,然后发现用“.asmx?wsdl”的方式不能得到我的WebService的WSDL,但是SharePoint自己的“_vti_bin”虚拟目录下(SharePoint用来放自己的WS的地方)的WS则没有这个问题,然后发现SharePoint也接管了WSDL获取的方式,而且根本绕不开,只能再研究它用的什么方法来获取WSDL的…最后终于把自己的一个实验的WS调试通过,用自己本地的一个ConsoleApp连上并取回数据了…累啊…

 

Posted by on 2003/12/23 in 未分类

19 Comments

Tags:

一个很Cool的特性

在C# 2.0中:
public class StringList : System.Collection.Generic.List<String> {}
类似的,我们可以直接创建出符合我们要求的IntList、UserControlList,呵呵。

 

Posted by on 2003/12/19 in 未分类

评论关闭

给IBuySpy构建一个PlugIn系统

话说公元2003年12月17日,MSDN Library网站上悄无声息的多了一篇文章,介绍了关于构建一个PlugIn Framework的一些基础知识,于是,有了这篇随笔…

PlugIn,很COOL的特性,下面将演示如何给我们的IBuySpy定制一个Page Start PlugIn,这个PlugIn可以让用户自己来创建PlugIn,嵌入到IBuySpy的Page Start PlugIn里面,在网站页面载入的时候,会执行用户嵌入的PlugIn。

可我们为什么要给IBuySpy创建PlugIn接口呢?我们要实现同样的功能,可以直接的修改它的代码,岂不是直接很多?原因:IBuySpy只是用来演示PlugIn的,你可以把同样的技术应用到其他的WebForm甚至WinForm,而它们可能并不会像IBuySpy一样是免费的,我们交付的产品里面不会附上代码,如果我们提供了PlugIn的接口,无疑会让我们的产品更加具有扩展性。何况很多功能可能可以直接作成PlugIn来嵌入到原有的系统中,这个时候无需再改动原有的代码,再去编译它。

1、构建IBuySpy的PlugIn所需的接口,这些接口就是可以公开给用户代码的:

首先需要的是一个通用的IPlugIn接口,所有具体的插件将实现这个接口:

namespace ASPNetPortal.PlugIns {

 public interface IPlugIn {
  String Name {get;}
  String Version {get;}
  void DoAction(IPlugInArgs args);    
 }
}

这个接口有三个成员:
Name属性,公开插件的名称
Version属性,公开插件的版本
DoAction()方法,执行插件要做的操作,这个方法还有一个IPlugInArgs的参数,需要传递给方法所参数可以通过它传递出去。

然后就是这个IPlugInArgs接口:

namespace ASPNetPortal.PlugIns {

 public interface IPlugInArgs { 
  System.Web.HttpContext Context {get;}
  Object Data {get;}
 }
}

它有两个成员:
Context属性,一个HttpContext类型的对象,如果我们要让插件能够在页面上做些事,不给它HttpContext肯定不行。
Data属性,一个Object类型的对象,预留的,什么地方需要就什么地方用上。

接着是一个接口集合类:

namespace ASPNetPortal.PlugIns {

 public class PlugInCollection : CollectionBase {

  public Int32 Add(IPlugIn plugIn) {
   return this.List.Add(plugIn);
  }

  public IPlugIn this[Int32 index] {
   get {
    return (IPlugIn) this.List[index];
   }
  }
 }
}

很简单明了。用户可能不止嵌入一个插件。

PlugIn也可以有很多类型,比如我们这里要实现的Page Start PlugIn,是一个在页面载入的时候可以让嵌入的PlugIn执行的。当然你也可以创建各种类型的PlugIn。

namespace ASPNetPortal.PlugIns {

 public interface IPageStartPlugIn : IPlugIn {}
}

这个PlugIn接口不需要再做任何事,直接继承IPlugIn就可以了。

2、修改IBuySpy,让它支持执行PlugIn:

根据我们的需求,我们创建一个实际的插件参数类,这个类继承自IPlugInArgs:

namespace ASPNetPortal.PlugIns {

 public class PlugInArgs : IPlugInArgs {
  private System.Web.HttpContext _context;
  private Object _data;

  public PlugInArgs(System.Web.HttpContext context, Object data) {
   _context = context;
   _data = data;
  }

  public System.Web.HttpContext Context {
   get {
    return _context;
   }
  }

  public Object Data {
   get {
    return _data;
   }
  }
 }
}

我们需要地方来标示用户嵌入的PlugIn的列表,我们放在web.config里面的里面,我们加上一项,来表示我们要添上的Page Start PlugIn:

《ADD key=”PageStartPlugIns” value=”” /》

value里面可以写入嵌入的PlugIn的列表,格式像这样:Value = “插件一的类名, 插件一的程序集名; 插件二的类名, 插件二的程序集名”

然后,我们构建一个PlugInHelper类,来执行获取PlugIn、执行PlugIn的操作:

namespace ASPNetPortal.PlugIns {

 public class PlugInHelper {

 private PlugInHelper() {}

 public static PlugInCollection GetPlugIns(String plugInType) {
  PlugInCollection plugIns = new PlugInCollection();
  String sPageStartPlugIns = System.Configuration.ConfigurationSettings.AppSettings[plugInType];
  if ((sPageStartPlugIns != null) && (sPageStartPlugIns != “”)) {
   String[] asPlugInStr = sPageStartPlugIns.Split(‘;’);    foreach(String plugInStr in asPlugInStr) {
    plugIns.Add( (IPageStartPlugIn) System.Activator.CreateInstance(System.Type.GetType(plugInStr)));
   }
  }
  return plugIns;
 }

 public static void ExecutePlugIns(PlugInCollection plugIns, IPlugInArgs args) {
  foreach(IPlugIn plugIn in plugIns) {
   plugIn.DoAction(args);
  }
 }
 }
}

GetPlugIns()方法返回指定类型的PlugIn的列表,返回类型是PlugInCollection,ExecutePlugIns()用来执行参数中的PlugIn。

最后,我们要把执行插件的代码加入到页面的执行队列中。为了在每个页面开始的时候能够执行用户嵌入的Page Start Plug,标准方法是在Global.asa里面来实现,更标准的方法是构建一个httpModule,然后在这个httpModule中来执行这个PlugIn(关于构建自定义的httpModule,辣椒是个中高手)。我这里就偷懒了,因为IBuySpy几乎所有的内容页面都是DesktopDefault.aspx这个页面中载入,所以我们先在这个页面里面创建一个方法来执行插件:

private void PerformPlugIns() {
 PlugInCollection plugIns = PlugInHelper.GetPlugIns(“PageStartPlugIns”);
 PlugInArgs args = new PlugInArgs(Context, null);
 PlugInHelper.ExecutePlugIns(plugIns, args);
}

第一句得到所有的Page Start PlugIn,第二句创建一个传递给插件的PlugInArgs对象,第三句调用PlugInHelper.ExecutePlugIns()来执行第一句得到的PlugIn队列。

在DesktopDefault.aspx的Page_Init事件中调用上面的这个PerformPlugIns()方法就OK了。

3、演示如何创建一个Page Start PlugIn:

前面两步已经让IBuySpy可以嵌入用户自定义的Page Start PlugIn了,现在我们来做一个实际的PlugIn嵌进去。

启动VS,创建一个“C#类库”项目,引入IBuySpy的程序集Portal.dll,这是因为我们需要用到IBuySpy里面的PlugIn相关的那些接口,更好的方法是把IBuySpy中与PlugIn相关的公共接口放在一个单独的程序集里面。

namespace WelcomeMessage {

 public class ShowWelcome : ASPNetPortal.PlugIns.IPageStartPlugIn {

  public string Name {
   get {
    return “Show Page Welcome Message”;
   }
  }

  public string Version {
   get {
    return “1.0.0.1”;
   }
  }

  public void DoAction(IPlugInArgs args) {
   args.Context.Response.Write(“<_script_>alert(‘Hello, world!’);”);  // 故意写错了
,不然…
}
}
}

这个ShowWelcome类继承自IPageStartPlugIn,表示它是一个Page Start PlugIn,用来具体执行操作的DoAction()方法只做了一件事,从参数中得到页面相关的HttpContext对象,然后输出一段字符以在页面内容载入之前弹出一个“Hello,world!”的提示框。

然后我们修改IBuySpy的web.config里面相关的那句设定:

《ADD value=”WelcomeMessage.ShowWelcome, WelcomeMessage” key=”PageStartPlugIns” /》

OK了,编译,把生成的dll放到IBuySpy的bin目录,打开浏览器浏览IBuySpy网站,你会看到每次载入页面内容时,都会弹出一个“Hello,world!”的提示框。

 

Posted by on 2003/12/18 in 未分类

评论关闭

昨晚上写的关于IBuySpy里面用户权限验证方面的东西

ASP.NET在页面的Context.User里面放了一个实现IPrincipal的对象,用来实现对已验证用户的管理。ASP.NET系统中,通常采用的方式就是扩展这个Context.User,让它里面保存定制的信息。

 

1、扩展方式

扩展方式基本上有两种:直接利用GenericPrincipal和自己写一个实现IPrincipal的类。IBuySpy用的前者,优点就是N简单。

 

Context.User = new GenericPrincipal(Context.User.Identity, roles);

 

roles是一个保存了当前用户的角色信息的String,各个角色间用“;”分隔,由前面的代码调用数据层中的UserDB.GetRoles()方法来得到。

 

自己写一个实现IPrincipal的类其实也是N简单,你只需要实现两个接口:Identity属性返回一个IIdentity的用户标识对象,IsInRole(String role)判断用户是否具有参数中的角色。下面是我写的一个替代IBuySpy中原有扩展模式的类:

 

 

public class IBSPrincipal : IPrincipal {

 

private IIdentity _identity;

private String[] _asRole;

 

下面是两个构造函数:

 

public IBSPrincipal(IIdentity identity, String roles) {

_identity = identity;

_asRole = roles.Split(‘;’);

}

 

public IBSPrincipal(IIdentity identity, String[] roles) {

_identity = identity;

_asRole = roles;

}

 

然后是用来实现IPrincipal的一个属性和一个方法:

 

public IIdentity Identity {

get {

return _identity;

}

}

 

public bool IsInRole(string role) {

    // 下面一行幸得“JGTM’2003”告知Array有一个static的IndexOf()

    // 原来是用循环查询_asRole….土不可及…

    return (System.Array.IndexOf(_asRole, role) > -1);

}

 

OK,然后我们就可以用下面这句替代上面IBuySpy原有的那句了:

 

Context.User = new IBSPrincipal(Context.User.Identity, roles);

 

看起来好像自己创建这个IBSPrincipal并不划算,它没有提供比GenericPrincipal更多的功能,但好处是我们以后可以随时扩展它,而且实现的成本也很低。

 

2、时机

我们在什么时候进行上面所说的这样的扩展行为呢?

 

IBuySpy选择在Global.asax里面的Application_AuthenticateRequest事件里面进行这些动作,只要ASP.NET程序需要进行用户验证,那么肯定要经过这里,这个地方不错。

 

另一个好地方就是在“页面基类”的Page_Init方法中,我们在构造网站的时候就可以先构建一个“页面基类”(即使一开始里面什么都没有),所有的页面都从这个基类继承下来而不是从默认的System.Web.UI.Page,这样做的好处是我们可以随时把类似的动作放在基类中。可惜IBuySpy本身并没有应用这种“页面基类”的方式。

 

3、FormsAuthenticationTicket

这个类是一个“验证票据”类,我们可以利用这个票据来保存用户的信息,并把这个票据写到客户端的Cookie里面,以后客户再来时,从Cookie中把这个票据取回来,就可以得到用户的信息了。

 

上面这一段说的就是IBuySpy做的,但是一定要注意,我们自己做这些操作,和ASP.NET内置的Forms验证没有任何关系,虽然它也是通过类似的保存票据到Cookie来实现的。

 

用这个票据来写到Cookie与我们自定义一个Cookie去写相比有什么好处呢,首先可以设定票据的过期时间、决定是否永久在Cookie保存票据、票据中可以写入自定义的信息(比如用户所具有的角色),而且,.NET内置的FormsAuthentication.Encrypt()方法和FormsAuthentication.Decrypt()方法可以把一个票据加密成一个字符串,和从一个字符串解密出一个票据,这样省掉了我们很多的工作了。

 

来看看IBuySpy里面的代码,创建一个票据并写到Cookie:

 

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(

1,  // version

Context.User.Identity.Name,  // user name

DateTime.Now,  // issue time

DateTime.Now.AddHours(1),  // expires every hour

false,  // don’t persist cookie

roleStr  // roles

);

 

// Encrypt the ticket

String cookieStr = FormsAuthentication.Encrypt(ticket);

 

// Send the cookie to the client

Response.Cookies[“portalroles”].Value = cookieStr;

Response.Cookies[“portalroles”].Path = “/”;

Response.Cookies[“portalroles”].Expires = DateTime.Now.AddMinutes(1);

 

从Cookie中读出票据,再从票据中得到用户具有的角色:

 

// Get roles from roles cookie

FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(Context.Request.Cookies[“portalroles”].Value);

 

//convert the string representation of the role data into a string array

ArrayList userRoles = new ArrayList();

 

foreach (String role in ticket.UserData.Split( new char[] {‘;’} )) {

userRoles.Add(role);

}

 

roles = (String[]) userRoles.ToArray(typeof(String));

 

Posted by on 2003/12/16 in 未分类

9 Comments

工作、SOA、MBF…

1、上周在部门的SharePoint项目主要里面加入了两个特性,“用户个人文档库”和“文档库多级权限”。

用户个人文档库很简单,就是给用户一个单独的“私人的”文档库,虽然可以让管理员手工给每个用户建立一个文档库,然后让这个文档库只能给一个用户访问,但步骤太繁琐,我把这个步骤做成了自动的。

SharePoint默认的文档库权限只针对于每个文档库,下面的文件夹是不能再单独授权不同权限的。有些用户使用时,一个项目使用一个文档库,但是有些项目文档是只能给特定用户访问的,所以这样的单级权限就做不到了。在建立子文件夹时,偶给用户两个选择,“普通文件夹”和“高级可管理文件夹”,后者是可以单独进行授权的(后面实际是用SPList来管理的…),建立是的默认权限直接继承上层的。

2、Microsoft Business Framework,微软正在做的一个东东,随Whidbey会发布一个可用的版本。

什么是MBF?MBF是一个包含了建立在.Net Framework之上的中间件层的在一个大的代码基础层之上的应用程序集(is that the suite of applications will be based on a global code base, with the middleware layer the Microsoft Business Framework, which builds on top of .Net Framework)。看看一篇专访

这里还有一篇,Microsoft Business Framework: The 10-year plan,嗯,看来微软是“蓄谋已久”了。

当然还有微软自己的ppt,Developing Applications Using the Microsoft Business Framework

3、SOA,面向服务的架构。第一次听说是从ccboy的blog上。ZDNet China上有几篇不错的文章。

微软已经作出了一个SOA的东东了,Shadowfax,现在的版本是Pre-Alpha,呵呵,怎么名字听着有点想《魔戒》里面甘道夫骑的那匹马的名字?

 

Posted by on 2003/12/13 in 未分类

9 Comments

Tags:

今天才知道原来IE扩展了一个showModalDialog()

看了孟子E章的一篇文章,才知道原来IE4里面就已经扩展了一个DHTML Method,showModalDialog(),可以让IE弹出一个模式的显示HTML的窗体。

MSDN Library中的介绍:
http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/reference/methods/showmodaldialog.asp

不会有人骂偶土吧?…:(

 

Posted by on 2003/12/13 in 未分类

14 Comments