Category Archives: Tech

Snip-It Pro 1.0.1.9

一个比较有意思的保存代码片断的东西。启动后位于桌面的一侧的sidebar,可以作用于任何编辑器。比如你在Visual studio写东西,可以从这里面将常用的一些代码方便的拉入vs中。官方网站在http://www.snipitpro.com/。下载的试用版本有30天试用期。

目前snipit pro工作于dotnet 2.0,除了dotfuscator保护关键代码外,还使用了一个的license保护组件(来自Interactive Studio Inc.)。license组件包括QlmLicenseLib.dll和IsLicense30.dll,后者是一个c++ native PE,前者由于调用后者,ildasm出来的il代码编译后无法通过ilasm使用。

然而问题是,snipit pro是保护十分脆弱,尽管dotfuscator使得reflector反编译后的代码无法编译,比如它将类里的方法名和变量名命名为一样,而c#编译器不允许这样。然后这种情况ilasm是可以编译的。反编译snipitpro.exe,可以看到以下类似代码:

        public aa(SnipItConfig A_0)
        {
            this.a = new QlmLicense();
            this.a.DefineProduct(1, "Snip-It Pro", 1, 0, "SkunkyFo78!", "{24EAA3C1-3DD7-40E0-AEA3-D20AA17A6005}");

            bool flag = false;
            string licenseKey = A_0.LicenseKey;
            this.a.ValidateLicense(licenseKey);
            int status = (int)this.a.GetStatus();
            if ((this.a(status, 8) || this.a(status, 0x10)) || ((this.a(status, 0x20)
                || this.a(status, 0x100)) || this.a(status, 0x80)))
            {
                flag = false;
                this.a(r.d);
            }
            else if (this.a(status, 4))
            {
                if (this.a(status, 0x40))
                {
                    this.a(r.b);
                    flag = false;
                }
                else
                {
                    this.a(r.a);
                    flag = true;
                }
            }
            else if (this.a(status, 2))
            {
                this.a(r.c);
                flag = true;
            }
            this.a(flag);
        }

关键在于status的判断,无论license key是如何被保护,只要status被设置为2,保护即被解除。

int status = (int) this.a.GetStatus();  对应的MSIL代码是,

IL_0045:  ldarg.0
IL_0046:  ldfld      class [QlmLicenseLib/*23000007*/]InteractiveStudios.QlmLicenseLib.QlmLicense/*010000F0*/ aa/*02000022*/::a /* 0400013B */
IL_004b:  callvirt   instance valuetype [QlmLicenseLib/*23000007*/]InteractiveStudios.QlmLicenseLib.ELicenseStatus/*010000F1*/ [QlmLicenseLib/*23000007*/]InteractiveStudios.QlmLicenseLib.QlmLicense/*010000F0*/::GetStatus() /* 0A000266 */
IL_0050:  stloc.2

我们注释掉 IL_0045~IL004b,在IL_004f处添加 ldc.i4.2,即达到以上status设置为2的效果。为了保证文件大小一致,0045~004e IL用nop来填充。修改后的MSIL代码如下,

    //IL_0045:  ldarg.0
    //IL_0046:  ldfld      class [QlmLicenseLib/*23000007*/]InteractiveStudios.QlmLicenseLib.QlmLicense/*010000F0*/ aa/*02000022*/::a /* 0400013B */
    //IL_004b:  callvirt   instance valuetype [QlmLicenseLib/*23000007*/]InteractiveStudios.QlmLicenseLib.ELicenseStatus/*010000F1*/ [QlmLicenseLib/*23000007*/]InteractiveStudios.QlmLicenseLib.QlmLicense/*010000F0*/::GetStatus() /* 0A000266 */
    IL_0045: nop
    IL_0046: nop
    IL_0047: nop
    IL_0048: nop
    IL_0049: nop
    IL_004a: nop
    IL_004b: nop
    IL_004c: nop
    IL_004d: nop
    IL_004e: nop
    IL_004f:    ldc.i4.2
    IL_0050:  stloc.2

Patch后的snip-it pro 1.0.1.9保护成功解除。在原SnipItpro.exe文件的0x0000d5b1开始的027b3b0100046f6602000a,代替成027b3b0100046f66020018,保存。

讨厌的垃圾评论

space上已经数度被恶意加了很多的垃圾评论,以前有几十条的,自己辛苦一点给删除掉。而今天发现上面被加了上百条的垃圾评论。明显是机器所为,而且评论内容不一,是随机增加到某些blog条目下(看来是专门针对space本身提供的打勾选择删除而设置的),目前好像在网上没有找到很好的批量删除的方法。微软space团队也是垃圾,没有任何过滤删除的功能。等有时间了我写个东西看看能不能根据条件删除。先让它们搁着吧。

 image

Vista x64下使用ODBC 32位 Text Driver

目前Vista x64下没有可用的ODBC Text Driver。为了使得已有的32位程序使用32位的ODBC Text Driver,需要对原程序的编译选项进行修改。将默认的Any CPU设置为x86,然后编译后。放到x64下将自动寻找32位的驱动。

费了我好多时间来figure out此问题。

读取网站的Alexa排名/Get Alexa ranking data for your site

南卓铜(Zhuotong Nan, [email protected])

由于网站自己设置的网站访问数有时不真实,为了比较网站的访问量,我们一般使用权威的第三方网站来比较访问量。Alexa网站提供被大家认可的排名数据。比如,访问http://www.alexa.com/data/details/traffic_details/westdc.westgis.ac.cn,可以看到“西部数据中心”目前排名访问。

Alexa提供了收费的Web service允许大家使用其数据,大概是每1000次请求0.15美金(见这里)。收费并不高,而且包括众多的功能。

然而作为程序员,有时候宁愿挑战一下自己的能力。比如有没有一种免费而且合法的手段来获取它的排名数据,比如Westdc.westgis.ac.cn目前排名1,080,823里的这个名次(May 06 2008)。

Alexa为了挣钱,使用了一些方法来防止简单的页面数据获取。比如我们看排名的HTML片断:

<span class=”descBold”> &nbsp;<!–Did you know? Alexa offers this data programmatically.  Visit http://aws.amazon.com/awis for more information about the Alexa Web Information Service.–><span class=”c669″>1,</span><span class=”cbf1″>34</span>0<span class=”cd05″>80</span><span class=”c9d1″>,8</span><span class=”c2e8″>23</span></span>

直接从Web页面拷贝的结果是1,34080,823,而不是正确的1,080,823。这是因为Alexa增加了一些<span>标签来混淆HTML代码,这些<span>的CSS被设置成display:none,所以在浏览器里显示却是正确的。而且这些混淆的<span>标签是随机任何组合的。

解决方案可以从模拟浏览器显示出发,逐步剥离没用的信息,最终获取排名数字。

a. 获取整个HTML源代码;分析获取源代码中有关排名的HTML片断;
b. 下载干扰的CSS表,取得display属性为none的全部css类名;
c. 利用css类名列表,从HTML片断中移去对应的<span>标签和标签内的数字;
d. 移去剩余的HTML标签;
e. 转成数值输出。

以下代码演示了此方法,使用了c# 2.0,在Visual Studio 2005编译运行通过。代码里使用了正则表达式。

/* Purpose: to get Alexa ranking data by using c#
* Author: Zhuotong Nan ([email protected])
* Date: May 06 2008
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace wml.stat
{
class AlexaRanking
{
public static int Rank(string url)
{
int ret = -1;

Uri uri = new Uri(url);
string newUrl = “http://www.alexa.com/data/details/traffic_details/” + uri.Host;
System.Net.WebClient wc = new System.Net.WebClient();
string html=wc.DownloadString(newUrl);

//pattern for obtaining html codes in relation to ranking data
string htmlpattern = @” about the Alexa Web Information Service.–>(.+?)</span><!–“;
string snipet = Regex.Match(html, htmlpattern).Groups[1].Value;

//get css file which store css classes preventing from scrambling
string cssUrl = “http://client.alexa.com/common/css/scramble.css”;
string cssfile = wc.DownloadString(cssUrl);

//css class pattern for getting CSS class listing with no display to the browse
string cssclassPattern=@”.(.*?) {“;
MatchCollection cssmc = Regex.Matches(cssfile, cssclassPattern);
//css classes without display, forming reg patterns
List<string> css_nodisp_patterns = new List<string>();
foreach (Match m in cssmc)
{
css_nodisp_patterns.Add( “<span class=”” + m.Groups[1].Value
+””>.*?</span>”);
}
//remove those classes from html snippet
foreach (string p in css_nodisp_patterns)
{
snipet=Regex.Replace(snipet, p, “”);
}

//see html snippet left
//remove span tags
string tagPattern = “<[^>]*>”;
snipet=Regex.Replace(snipet, tagPattern, “”);

ret = Int32.Parse(snipet, System.Globalization.NumberStyles.AllowThousands);
return ret;
}

static void Main(string[] args)
{
AlexaRanking.Rank(“http://westdc.westgis.ac.cn”);
}
}
}

本文独立实现,但后来google发现有人利用了差不多的方法,只不过在实现上用了PHP,最终产生的结果稍有不同,见 http://plice.net/?p=10

MSN Live Messenger产生大量ignored contacts的问题

Zhuotong Nan (南卓铜, [email protected])

不知道从几时起,我笔记本上的Live Messenger就出现这个问题。每次登陆十分慢,或者干脆无法连接到server。一些初步的观察,可以看到:

在C:Documents and Settings<your name>Contacts<your email>下会产生0KB的.WindowsLiveContact或.WindowsLiveGroup的文件。同时该目录下有隐藏的Ignored目录,其下有几千甚至几万个这些0KB的.WindowsLiveContact或.WindowsLiveGroup的文件。Ignored目录同时可以找到一个IgnoredReason.txt文件,有时此文件达数百MB。

在C:Documents and Settings<your name>Local SettingsApplication DataMicrosoftWindows Live Contacts<your email>real和shadow(两目录是隐藏的)下面,也有大量的0KB联系人文件,并有隐藏的Ignored目录,目录下有几千甚至几万个0KB的.WindowsLiveContact或.WindowsLiveGroup的文件。同样Ignored目录下有IgnoredReason.txt文件,有时达数百MB之大。

如果有多个帐号,每个帐号的上述目录下面都有一样的大量0KB文件。

将这些文件删除,经过一段时间的Live Messenger使用,又会积累很多0KB文件。

Google检索无果。个别人也提到Large number of contacts问题,但都没有解决。

今天使用Filemon进行了详细的检查,终于发现了原因所在。Live Messenger在登录成功时,会首先检查Contacts和Live Contacts目录下的联系人文件,因为这些文件为0KB,打开失败,会将它们移入各自目录下的Ignored目录,并记录到IgnoredReason.txt文件。在稍后会尝试在Contacts和Live Contacts目录下新建全部联系人的文件以加速以后Messenger的打开速度。Messenger试图从服务器上下载数据,并调用本机C:Documents and Settings<your name>Application DataMicrosoftCryptoRSA<current account id>下的加密钥匙文件(如,34a80763996ffdc408b119337fc93131_0923ce10-ed9d-4fa5-baba-146a7f733203文件)。Messenger在此时可能调用密钥失败,生成0KB的联系人文件。每次Messenger登录都重复这个过程,从而产生了无数的0KB联系人文件。

重新安装或升级Live Messenger都无法解决此问题。

解决方法,RSA密钥文件错误或不完整,将C:Documents and Settings<your name>Application DataMicrosoftCryptoRSA<current account id>目录下的全部文件删除(如果不放心,可以先备份到另一目录)。重新登录Live Messenger,可以看到Contacts和Windows Live Contacts两目录下成功生成联系人文件。这时,可以删除Ignored目录下的全部文件。

Issue: large number of 0KB contacts files produced by Live Messenger

A very large number of contacts files with 0KB in size (with extension of .WindowsLiveContact or .WindowsLiveGroup) can be found at "C:Documents and Settings<your name>Contacts<your email>", and real and shadow directories under "C:Documents and Settings<your name>Local SettingsApplication DataMicrosoftWindows Live Contacts<your email>". Also we noticed there would be also very large amount of 0KB contacts files under the Ignored directories of all above-mentioned directories.  A file named IgnoredReason.txt under each Ignored directory may be large up to several hundreds MB.

This problem will seriously slow down the login of Live Messenger. Re-install or upgrading will not fix this problem.

This is due to the failure of crypt procedure called by Live Messenger when attempting to save contact files. Go to C:Documents and Settings<your name>Application DataMicrosoftCryptoRSA<current account id>, and remove all files under this directory (or just move them to another directory, for your safety consideration). The applications who need them will regenerate in case of their absence. Feel free to remove all useless 0KB contact files, as well as all stupid Ignored directories.

Win XP sp2远程桌面并发登陆补丁

sp2最终版本只支持同时一个在使用远程桌面,很不方便。以下方法可以使得3用户同时使用。

1. 下载这里的termserv.zip,解压缩

2. 在safe模式下启动机器,将c:windowssystem32termsrv.dll改名为 termsrv_sp2.dll,将这里的termsrv.dll拷贝到c:windowssystem32下。这里提供的termsrv.dll是sp2第一版本带的,所以足够安全。

3. 运行带的Concurrent Remote Sessions SP2.reg,对注册表打补丁

4. 需要打开“快速用户切换”

5. 打开组策略编辑器,开始菜单,运行,gpedit.msc,到Computer Configuration > Administrative Templates > Windows Components > Terminal Services这里,将Limit Number of Connection设为enable,并设为3(多了没用)。

6. 重启机器。现在你可以登陆3个用户了,比如一个控制台,2个远程(远程需为不同用户名)。

我在台式机上试了,好用。而且应该不涉及版权,反正不会很严重。

下载补丁包

http://sig9.com/node/110

Enable delayed content loading for Cuyahoga Module

南卓铜([email protected])

Cuyahoga is a powerful and well designed Web-based Content Management System. In current version, however, there is not yet Ajax supported. This brief article will show you how we can implement an Ajax based delayed content loading for its module.

The project I am doing will achieve Asian water news from an external website, Global Water News. To do this, I developed a set of classes to download content from external page and then parse them. However, in a synchronous way, the content downloading and parsing process is rather slow, consequently affecting the display of our homepage.  A delayed loading of this part of content will be ideal for circumventing this problem. 

Figure below shows the schema we developed for Cuyahoga framework.

See www.asian-gwadi.org homepage for online demonstration.

image

1. Enable Ajax support

Download latest ASP.net Ajax toolkit for framework 2.0 and install it. Add reference to System.Web.Extensions in Web project.

Open a brand new Ajax based web project. This will generate necessary configuration for Ajax support in a Web project.  Merge web.config created in this new project to Cuyahoga’s root web.config.

2. Add a Cuyahoga module for your purpose

image

AsianWaterNewsModule is just derived on ModuleBase and simple leave everything blank.

AsianWaterNewsControl.ascx is the user control working together with the module. It’s based on BaseModuleControl. It simply defines the container where we will populate data later.

AsianWaterNewsControl_Under.ascx is the underlying user control who download data from external web page, parse them and then fill up a repeater control.

AsianWaterNewsFristPage.cs, WaterItem.cs, and WaterNewsPageContent.cs are business logic codes to help AsianWaterNewsContol_Under control to realize its functionality.

AsianWaterNewsService.asmx define a web service, which renders the underlying user control, AsianWaterNewsControl_Under.ascx, to HTML codes. The output of this web services is expected to populate the placeholder contained in Cuyahoga user control, i.e., AsianWaterNewsControl.ascx.

Default.js and jquery-1.2.2.min.js are essential callback javascripts to be called in client side.

Install directory contains sql scripts for database structure.

3. Procedure

When a module is loaded by Cuyahoga framework, user controls derived upon BaseModuleControl (here is AsianWaterNewsControl.ascx ) will be asked to display themselves. In AsianWaterNewsControl.ascx , Ajax script manager was instantiated to wrap webservices as well as to register necessary javascripts. Javascripts were then downloaded to client together with other HTML. The page were displayed.  At the same time, callback javascripts were activated to call web service (here AsianWaterNewsService.asmx), which returns HTML representation of underlying user control (here, AsianWaterNewsControl_Under.ascx) actually retrieving data from external web pages. Then a div placeholder in  AsianWaterNewsControl.ascx will be populated with data retrieved.

See my previous post to get understand how to realize delayed content loading. For English original article, see here.

Download source codes of the AsianWaterNewsModule project.

Note, CSS and images should be defined in the template currently applied to your site. I did not include those stuff in the source code package.

See http://www.asian-gwadi.org/ for the operational demo.

Web内容滞后装载的另一可行方法

原文在 http://www.codeproject.com/KB/ajax/DelayedContentLoading.aspx
大概思路是:在user control里实现ajax updatepanel和timer。首先下载到客户端的是user control的装载状态view,下载完后,自动启动timer的ontick,通过updatepanel调用user control的另一view正式装载数据。由于采用ajax所以可以实现页面的部分更新。
这方法也是可以考虑的。

通过异步页面内容装载提升ASP.NET页面反应速度

原文:Boost ASP.NET performance with deferred content loading

翻译:南卓铜 ([email protected])

clip_image002[4]

在设计一个ASP.NET Web页面时,其反应速度取决于各组成部分的性能,比如在上图,红色条所在的GetRSSReader(从其它网站上读取RSS)功能会导致整个页面反应速度很慢。不管你如何去优化该页面的其它部分,只有其中有一部分反应慢就会导致用户感觉整个Web页面速度呆滞。

在本文,我将给大家演示一种规避这个问题的方法。通过将内容放置到用户控件(User control),直到整个核心内容都显示完后才去装载用户控件内容,这样就可以大幅提升可观察的性能。

我们可以将页面内容细致的分解,通过上述方法可以方便的提升应用程序反应速度,这是用户最关心的。包括下面四个步骤:建立用户控件,将用户控件内容输出成HTML(通过Webservice),提供进程指示条,以及应用ASP.NET AJAX请求在客户端插入此HTML。

1. 建立用户控件

首先,我们需要将装载速度慢但不是核心的内容包装在用户控件(User control)。在这个例子里,我们实现一个简单的RSS聚合阅读器来显示最新的用户帖子。

这里的关键是获取RSS聚合的基本信息。我在这里使用ASP.NET 3.5的一个新功能:LINQ to XML。LINQ使得读取关系数据库、XML等数据源的繁杂工作大为简化。我每次使用它都心动不已。(译者注,不懂LINQ或者ASP.NET 3.5并不会妨碍理解这里讲述的方法)

protected void Page_Load(object sender, EventArgs e)
{
  XDocument feedXML = 
    XDocument.Load("http://feeds.encosia.com/Encosia");
  var feeds = from feed in feedXML.Descendants("item")
              select new
              {
                Title = feed.Element("title").Value,
                Link = feed.Element("link").Value,
                Description = feed.Element("description").Value
              };
  PostList.DataSource = feeds;
  PostList.DataBind();
}

使用ASP.NET 3.5的另一个新控件 ListView来显示聚合的内容。(译者注,可以不管ASP.NET 3.5,这里仅是一个User control的例子。)

<asp:ListView runat="server" ID="PostList">
  <LayoutTemplate>
    <ul>
      <asp:PlaceHolder runat="server" ID="itemPlaceholder" />
    </ul>
  </LayoutTemplate>
  <ItemTemplate>
    <li><a href='<%# Eval("Link") %>'><%# Eval("Title") %></a><br />
      <%# Eval("Description") %>         
    </li>
  </ItemTemplate>
</asp:ListView>

通过使用一点CSS(包括在源代码,在下面可以下载),聚合的结果可以很好的显示出来,如下图。

clip_image004[4]

ListView可以很方便的演示下面步骤,因为通过它,我们基本不需要太多的代码就可以生成HTML,最后将这些生成的HTML代码插入到页面。

2. 将用户控件润色成HTML

本步我们创建一个Web service将用户控件生成HTML字符串。这里,我们需要在ASP.NET页面实例之外生成HTML字符串。一般情况下,用户控件都是被装载到Page实例上。

为解决这个问题,我们可以创建一个临时的ASP.NET Page类,动态加载用户控件,然后在Web service里执行它。实际实现比起描述要简单易懂的多。

[WebMethod]
public string GetRSSReader()
{
  // 创建新Page类,并加载用户控件
  Page page = new Page();
  UserControl ctl =
    (UserControl)page.LoadControl("~/RSSReaderControl.ascx");
  page.Controls.Add(ctl);
 
  //将动态页生成HTML
  StringWriter writer = new StringWriter();
  HttpContext.Current.Server.Execute(page, writer, false);
 
  //生成的HTML返回为字符串
  return writer.ToString();
}

你可能在担心创建一个新的页面实例是否会有性能上的影响。一开始,我也是这么考虑的。但,因为我们的Page实例是创建在Web service上,而不是在ASP.NET HTTP管道(pipeline)上,而且只包括一个用户控件,此额外的开支可以被忽略不计。Page实例本身的开支相对于整个HTTP进程来讲是微不足道的。

3. 创建演示页面

我们需要一个演示页面来快速显示核心内容。在该页上,定义一个DIV标签。该标签在核心内容显示完后再异步从服务器端装载内容。

<asp:ScriptManager runat="server">
  <Services>
    <asp:ServiceReference Path="~/RSSReader.asmx" />
  </Services>
  <Scripts>
    <asp:ScriptReference Path="~/Default.js" />
  </Scripts>
</asp:ScriptManager>
<div id="Container">
  <div id="RSSBlock" class="loading"></div>
  <div id="Content">
    <p>Lorem ipsum dolor sit amet, consectetuer adipiscing...</p>
  </div>
</div>

如你看着的,RSSBlock定义的这个DIV标签分配有一个CSS类“loading”。这个CSS类显示进度指示条,一直到异步加载的内容被下载到客户端。

.loading { 
  background: url('progress-indicator.gif') no-repeat center; 
}

clip_image006[4]

所以,这里其实不是一个真实的指示条,无法计算进程进度。但用户是无法知道这是不是真实的。你不说没人会知道。

4. 从Javascript里调用Web service

现在我们已经有了一个空位置,我们需要将真实的HTML填充这个位置。ASP.NET AJAX为我们做好了大部分的事情。

Sys.Application.add_init(AppInit);
 
function AppInit() {
  RSSReader.GetRSSReader(OnSuccess, OnFailure);
}
 
function OnSuccess(result) {
  // .loading CSS类从div上移去,效果上看是移去了进程条
  Sys.UI.DomElement.removeCssClass($get('RSSBlock'), 'loading');
 
  // 将生成的HTML填充这个div位置
  $get('RSSBlock').innerHTML = result;
}
 
function OnFailure() {
  // 如果失败了,要做点什么。比如重试,等
}

因为这里我们用了CSS类来实现进度条,只要简单移去该loading类就可以了。这里我们使用removeCssClass方法。更多关于该方法的信息,可以见这里

动画的背景移去后,是时候在div中插入HTML内容了。最终的结果正是我们期待的,前面我们设计的用户控件已经显示在div指定的位置上了,而且不会妨碍到整个页面的反应速度。

5. 结论

我想大家可能发现这个方法是很有用的。它可以让你利用现有的ASP.NET知识,结合服务器控件,实现一个轻量级的基于AJAX的模板方案。同时,它使一些繁琐、不易维护的工作变得简单。

注意我们这里没有使用UpdatePanel。使用以上描述的技术,不需要使用Partial Postback。它不仅可以提升性能,而且即使在内容延后被装载的时候,也不影响页面其它使用了UpdatePanel的正常工作。

源码

Firefox下Live ID登录问题

Live Messenger我更新成8.5,自动给安装了Live Sign-in Assistant。用IE时可以自动登录Passport,挺方便。但在Firefox下发现需要两次密码才能登录。第一次总是提示说错误(我确认密码是对的)。Google也检索不到答案。
我第一感觉是否中木马了。对机器进行了仔细的检查,应该不是。
所以这里报告一下,有人有类似的问题吗?