雷's profileAbbeyGong's SpacesPhotosBlog Tools Help

雷 龚

Occupation
Location
一个男人不一定每次都成功,但是每一次都要全力以赴!
Photo 1 of 1
More albums (1)
There are no music lists on this space.

AbbeyGong's Spaces

梦想离欲望远一点,快乐靠自己近一点!
4/26/2009

C#读取修改配制文件(Framework2.0)

在VS 2005中设置和读取配置文件已经变的很简单了,而且是强类型的,读取的值可以直接赋值给相应的变量,无需强制转换。
例如:DateTime userDateTime1 = Properties.Settings.Default.userDateTime1; 真是方便了很多。但是你有没有发现,使用 Properties.Settings.Default.Save() 保存了设置后,Application 范围的设置为什么没有保存成功,User 范围的设置的变化为什么没有体现到 app.config 文件中去呢?
1. 在VS 2005中进行应用程序设置
    打开 项目属性 » 设置,如下图:

   输入名称,选择类型和范围,输入值保存即完成设置。
   类型:int,string,DateTime等各种数据类型;
   范围:Application  范围的设置对所有用户都有效;
           User 范围的设置对当前用户(当前 Windows 登录的用户)有效,同一个设置每个用户可以有不同的值,而且互不影响。
2. 读取配置文件(读取应用程序设置)
     无论是Application  范围的设置,还是User 范围的设置,读取的方法都是一样的。

// 读取设置
this.appSetting1TextBox.Text = Properties.Settings.Default.appSetting1;
this.userSetting1TextBox.Text = Properties.Settings.Default.userSetting1;

3. 保存 User 范围配置文件(保存 User 范围的应用程序设置)

// 保存 User 范围的设置
    Properties.Settings.Default.userSetting1 = this.userSetting1TextBox.Text;
    Properties.Settings.Default.Save();

    User 范围配置文件没有保存在应用程序文件夹下,而是保存在这里:X:\Documents and Settings\Windows登录用户\Local Settings\Application Data。
4. 保存 Application 范围配置文件(保存 Application 范围的应用程序设置)
    保存 Application 范围配置文件可没有保存 User 范围配置文件那样简单,直接 Properties.Settings.Default.Save() 是不行的。因为 Application 范围的设置在运行时是“只读”的。这里使用的方法是使用 XmlDocument 来直接保存 config 文件,然后在 Reload 设置。

// 保存 Applicationi 范围的设置
string configFileName = Application.ExecutablePath + ".config";
    System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
    doc.Load(configFileName);
string configString = @"configuration/applicationSettings/SetConfig.Properties.Settings/setting[@name='appSetting1']/value";
    System.Xml.XmlNode configNode = doc.SelectSingleNode(configString);
if (configNode != null)
    {
        configNode.InnerText = this.appSetting1TextBox.Text;
        doc.Save(configFileName);
// 刷新应用程序设置,这样下次读取时才能读到最新的值。
        Properties.Settings.Default.Reload();
    }

顺便说一下:使用 Properties.Settings.Default.Reset() 可以恢复 User 范围设置的默认值(从 app.config 中恢复)。
源代码下载:SetConfig.rar

转自:http://www.cnblogs.com/anjou/archive/2007/03/27/690465.html

这下面两个方法也类似,摘抄下来做个备份学习:

private void SaveConfig(string ConnenctionString)
{
XmlDocument doc=new XmlDocument();
//获得配置文件的全路径
string strFileName=AppDomain.CurrentDomain.BaseDirectory.ToString()+".exe.config";
doc.Load(strFileName);
//找出名称为“add”的所有元素
XmlNodeList nodes=doc.GetElementsByTagName("add");
for(int i=0;i<nodes.Count;i++)
{
//获得将当前元素的key属性
XmlAttribute att=nodes[i].Attributes["key"];
//根据元素的第一个属性来判断当前的元素是不是目标元素
if (att.Value=="ConnectionString")
{
//对目标元素中的第二个属性赋值
att=nodes[i].Attributes["value"];
att.Value=ConnenctionString;
break;
}
}
//保存上面的修改
doc.Save(strFileName);
}
==============================================================================
public static void SetValue(string AppKey,string AppValue)
{
XmlDocument xDoc = new XmlDocument();
xDoc.Load(System.Windows.Forms.Application.ExecutablePath + ".config");
XmlNode xNode;
XmlElement xElem1;
XmlElement xElem2;
xNode = xDoc.SelectSingleNode("//appSettings");
xElem1 = (XmlElement)xNode.SelectSingleNode("//add[@key='" + AppKey + "']");
if ( xElem1 != null ) xElem1.SetAttribute("value",AppValue);
else
{
xElem2 = xDoc.CreateElement("add");
xElem2.SetAttribute("key",AppKey);
xElem2.SetAttribute("value",AppValue);
xNode.AppendChild(xElem2);
}
xDoc.Save(System.Windows.Forms.Application.ExecutablePath + ".config");
}

2/18/2009

tor + privoxy

Tor用户在本机运行一个洋葱代理服务器(onion proxy),这个代理周期性地与其他Tor交流,从而在Tor网络中构成虚拟环路(virtual circuit)。 Tor是在7层protocol stack中的application layer进行加密(也就是按照'onion'的模式)而它之所以被称为onion是因为它的结构就跟洋葱相同,你只能看出它的外表而想要看到核心就必须把它层层的剥开。即每个router间的传输都经过symmetric key来加密,形成有层次的结构。它中间所经过的各节点,都好像洋葱的一层皮,把客户端包在里面,算是保护信息来源的一种方式,这样在洋葱路由器之间可以保持通讯安全。同时对于客户端,洋葱代理服务器又作为SOCKS接口。一些应用程序就可以将Tor作为代理服务器,网络通讯就可以通过Tor的虚拟环路来进行。进入Tor网络后,加密信息在路由器间传递,最后到达“退出节点”(exit node),明文数据从这个节点直接发往原来的目的地。对于目的主机而言,是从“退出节点”发来信息。由于在TCP数据流的级别通讯,Tor显得卓然独立于其他匿名网络。通过使用Tor,一般的应用程序都可以实现匿名,比如IRC、即时通讯,以及浏览网页。浏览网页时,Tor常常与Privoxy联合使用,Privoxy是一个代理服务器,可以在应用层增加保护隐私。 
    Tor启动以后将在本地监听9050端口,进行Socks代理,不进行HTTP代理,设置代理服务器为:127.0.0.1:9050 类型socks 简单的说就是通过其他使用tor用户的网络上网 因为目前国外用户较多 所以可以起到绕过gfw 代理访问的作用 用户切换频率很快 好像几分钟就变一次     其实严格来说TOR只支持SOCKS而已,不过两个组合使用支持的就多了。只是想浏览网页的话设置也不难,浏览器的话就设置通过Privoxy的127.0.0.1:8118,其它QQ啊MSN啊可以直接设置通过Tor的127.0.0.1:9050。其实道理很简单,Tor是在9050端口监听,代理协议是SOCKS,所以支持SOCKS协议代理的软件都可以直接设置通过Tor的127.0.0.1:9050的代理连接。Privoxy监听的端口是8118,可以支持代理协议转换。其实它的功能不只是这样,其介绍就是Privoxy is a web proxy with advanced filtering capabilities for protecting privacy, modifying web page content, managing cookies, controlling access, andremoving ads, banners, pop-ups and other obnoxious Internet junk. Privoxy has avery flexible configuration and can be customized to suit individual needs andtastes. Privoxy has application for both stand-alone systems and multi-user networks。

其实明白这个就好:Privoxy是支持HTTP、SOCKS代理以及HTTP转换为SOCKS代理,Tor支持SOCKS。所以要通过tor浏览就要通过Privoxy的HTTP转SOCKS。也可以只使用Privoxy上网,相当于过滤,其过滤功能也很突出,如果会用的话,各种广告、弹出窗口啊都可以过滤,超强的说。

注意几点:

1、Privoxy里面要设置协议转换:forward-socks4a / localhost:9050 .。后面一点不能漏掉。因为原始格式是forward-socks4a / socks_proxy[:port] http_parent[:port]。最后那一点是http_parent[:port],表示直接连接,也可以再加上了个HTTP代理来跳转。

2、Privoxy里面可以关掉日志记录,不然每一个连接都会记录下来,在配置里面屏蔽以下两行即可。

#logfile privoxy.log

#jarfile jar.log
原帖来自于网易社区:http://club.163.com/viewArticleByWWW.m?boardId=v-sea&articleId=v-sea_1117288744d7266_0

2/8/2009

解决WGA(xp)、OGA方法(office2003)

最新可以用的Windows和Office序列号
Windows XP VLK:MRX3F-47B9T-2487J-KWKMF-RPWBY
更改方法:运行regedit,随意修改OOBETimer的二进制数据
运行%systemroot%\system32\oobe\msoobe.exe /a
选择电话激活,更改产品密钥,更新选择以后提醒我,重新启动后即可。
Microsoft Office 2003 Professional:
OFFICE:FTYBP-J2B4K-K7JHY-3JG2K-MT9VM
FrontPage/OneNote:WFDWY-XQXJF-RHRYG-BG7RQ-BBDHM
更改方法:
删除[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\11.0\Registration\{90110804-6000-11D3-8CFE-0150048383C9}]
键中ProductID和DigitalProductID两项。
运行Office,输入序列号即可。
验证网页:
http://www.microsoft.com/resources/howtotell/zh-chs/office/default.mspx
http://www.microsoft.com/genuine/default.aspx?displaylang=zh-cn&PartnerID=4

2/5/2009

[案例分析]用博弈论解5海盗分100宝石问题

  5个海盗抢到了100颗宝石,每一颗都一样的大小和价值连城。他们决定这么分:
      1. 抽签决定自己的号码(1,2,3,4,5)
      2. 首先,由1号提出分配方案,然后大家5人进行表决,当且仅当超过半数(注意是超过)的人同意时,按照他的提案进行分配,否则将被扔入大海喂鲨鱼。
      3. 如果1号死后,再由2号提出分配方案,然后大家4人进行表决,当且仅当超过半数的人同意时,按照他的提案进行分配,否则将被扔入大海喂鲨鱼。
      4. 以次类推
      条件: 每个海盗都是很聪明的人,都能很理智的判断得失,从而做出选择。
      问题:第一个海盗提出怎样的分配方案才能够使自己的收益最大化?
  解答此题的关键在于每个海盗存在最优策略均衡,从而使得第一个海盗能够预测出其他海盗的策略,从而采取对自己利益最大化且能够通过的策略
  第一个海盗在做出策略选择时,他通过分析可以得出其他海盗存在最优策略,对于本题,需要从后面往前分析:
  1.假设最后只剩下第四第五个海盗,则第四个海盗只能提出0,100方案让第五个海盗独吞宝石,但第五个海盗也可能反对,尽管第五个海盗反对不反对都可以得到这100个宝石,所以当只剩下两个海盗时,第四个海盗死亡的概率是50%,所以第四个海盗绝对不会让第三个海盗死
  2.正是因为如此,第三个海盗存在最优策略均衡100,0,0,即分给自己100个,第四个第五个海盗0个,由于自己同意,第四个海盗同意(不死概率100%>50%),从而方案一定能通过。当然其它任何方案都能通过,但是只有分给自己100个宝石,才能使自己利益最大化,从而只有100,0,0是最优的
  3.正是因为如此,第三个海盗会想方设法让第二个海盗死,这样就可以独吞宝石了,所以第二个海盗需要拉拢第四个第五个海盗来支持自己(拉拢第三个海盗代价太高,不会是最优策略),因此需要给出一种策略,这种策略使第四个第五个海盗能够得到更大的利益,由于第三个海盗的分配方案是使第四个第五个海盗得0颗宝石,所以可以提出98,0,1,1方案,这样第四个第五个海盗肯定会同意,因为若否决该方案而让第三个海盗来分,则自己将一无所有。至于99,0,0,1或99,0,1,0将分别可能使(概率50%)第四或第五个海盗投反对票,所以第二个海盗不会冒这个险,尽管可以多得一个宝石,至于100,0,0,0被否决的概率更大,从而对于第二个海盗来说,得98颗宝石就达到了利益最大化
  4.正是因为如此,第二个海盗会想方设法让第一个海盗死,这样就可以得到98颗宝石了,所以第一个海盗需要拉拢第三个第四个或第三个第五个海盗来支持自己(拉拢第二个海盗代价太高,拉拢第四第五个海盗代价要比拉第3,4或第3,5个海盗多一颗宝石,后面会分析,而全部拉拢代价更高,均不会是最优策略)。为了拉拢这两个海盗,需要给出一种策略,这种策略使第三个第四个或第三个第五个海盗能够得到更大的利益,由于第二个海盗的分配方案是98,0,1,1,即使得第三个海盗得0,第四个第五个分别得1,这样只需分配给第三个海盗1颗宝石就可以拉拢,所以第三个海盗必须拉拢,而分配给第四个第五个海盗中的一人2颗宝石,即97,0,1,0,2或97,0,1,2,0就可以获得自己,第三个海盗,第五个海盗或者自己,第三个海盗,第四个海盗的支持而分得97颗宝石。分得超过97颗宝石的方案都有可能失败或者一定失败,所以97颗宝石就达到了利益最大化。从而97,0,1,0,2或97,0,1,2,0方案是能够使得自己利益最大化并且一定会通过的方案,其它任何使第一个海盗分得宝石数低于97颗的方案可以直接排除,绝对不会使自身利益最大化,而高于97颗的方案将存在被否决的风险,第一个海盗不会选择,而等于97颗且不同于这两个方案的方案也将存在被否决的风险,所以第一个海盗只能在这两个方案中选一个,才能使自己以无风险水平获得最大利益

10/27/2008

[案例分析]震惊全国的“四年赚十亿的惊人内幕”(转载)

《智囊》杂志曾经登过一篇文章:“‘空手道’四年赚十亿元方案”,我们来看看他们是怎样设计的,对我们有什么启发?
    内容要点:四年赚十亿元,最终收购一家上市公司;一分钱不花,只要学会资源整合;加盟经销商、银行、生产厂家,如何使他们心甘情愿地为我所用?
    一封信引起的思考
    赵总并陈副总、肖副总:
    在香港这段时间,结识了不少企业界人士,开阔了视野和思路,同时也在琢磨人家为什么能做强做大,尤其是北京过来的中资公司×××、×××等的经验非常值得学习。这些人最早都是玩空手道的,倒批文、圈土地,后来摇身一变,都成了实业家。我们以前对企业的理解还是太简单,似乎做生意必须要有厂房、机器、人员、实物等等。现在看来这种观念太落后了,香港这边“谈生意”的很多,在谈话中交易,就完成了资金、资本、股份、所有权的转化,这和我们经常见到的“做生意”区别很大,而且越是大企业,越是这样。而我们折腾了很多年,总让人觉得还是一个皮包公司。静思公司几年来的发展历程,总觉得我们少了一点什么,在国内时天天想着找贷款、找项目,拆东墙、补西墙,从早到晚应酬喝酒,无暇反思,静下来后我才意识到,我们缺少的是一套长远的发展战略,缺少的是能让公司跳跃式发展的思路,说得实际一点,就是一个赚钱的模式。我们现在用的那些操作平台太落后、太保守了。
    国美与苏宁的模式是否适合我们?三联入主郑百文意欲何为?麦当劳长兴不衰秘诀何在?牟其中仅仅是一个狂人吗?……这些问题我想了很多。国内市场经济发展到今天,我们如果还是停留在传统的经营和积累模式上,显然是行不通的。我正在急切地寻找一个能在短短三五年内赚到八亿、十亿元的方法,现在我觉得已经找到了。
    现在,我提出一个思路,发给诸位同事,大家讨论一下可行性。同时注意保密,谢谢!我们的资源和优势:
    我们在商业流通领域积累了为数不少的客户资源,尤其是在本省,近30%的中小商业企业和我们有过多种形式的合作或生意往来,这是我们目前为止最大的资源优势;另外,我们和国内著名家电厂商也建立了良好的合作关系,这两点是我们实现下面思路的最大优势,只有加强和巩固这两个优势,才能顺利实施以下计划,否则一切都是空谈。和政府、银行的关系一定要搞好,这一点一直是我们的弱项,我们总是缺钱,有时甚至连周转资金都没有了。我们在资金方面一直没有大的靠山,这是我最大的心病,这也是中国所有企业都头疼的事情,以后我们一定要在银行界找到支持,这是头等大事。没有钱,什么项目都做不好。
    关于我们的资源和优势,我建议列一个表出来,这就是我们的关系网,此事速办。
    操作方法:
    1、选定200家左右家电零售商家,地区选择上以本省为主,以外地企业为辅(做大以后可以扩张),现在比例大致为80:20。入选商家规模以中小型为主,家电类专营商优先。
    2、投入资金对其进行统一的形象设计,这个资金尽量不要自己出,要么让经销商出,从以后货款中扣,要么由装修公司垫付,可委托专业广告策划公司出方案。这些前期投入原则上我们都不付钱,要求对方垫资,最后我们可以用易货贸易,把积压的一些产品换出去。
    3、这些小经销商不可能独立得到的超低进货价向其提供进货清单,以定金的方式确定进货品种与额度,也可采取承兑汇票形式,贴息部分酌情商量。
    4、将所得进货订单汇总后统一向相应厂家下单订货,以量取胜,获取最低进货价(和我的方案比起来,国美和苏宁其实是选了一个笨办法,处处自己布点设摊儿,所有的风险都押在自己身上了)。
    5、统一订货,统一发货,加收1%手续费后将货物转给加盟商家(此处我们的目标是保本,不求赢利,甚至可以以进价转给经销商,我们可以让厂家给一点广告支持作为利润)。
    6、在银行开立统一结算户头,在与加盟商家和进货厂家的往来中,制造巨量现金流(每月都要上亿),配合财务部门在银行的资信关系(注意选择银行,要有长期打算)。
    7、通过新闻报道、政府行业排序、上缴税利排名、资助公益事业等立体化方式,力争使统一品牌的知名度得到最大限度的扩大与传播。
    8、以品牌美誉度和巨额现金流争取得到目标银行对我公司财务信用度的高定级(在此阶段之前,我们都有可能是负债经营,日子很紧)。
    9、分别在几家目标银行获取大额银行贷款。
    10、通过财务运作和营销运作的配合,将银行资金转为企业自有经营资金(有两个方式可选:一是用自有股份置换上市公司股份,不足部分用现金补齐,但要少于25%的比例;二是用银行贷款投资办一家公司,再由新公司出面收购上市公司。前者较可行)。
    11、以这笔资金做后盾,进入国内A股市场,收购一家ST上市公司,以商业类或综合类上市公司为主要目标。
    12、将经过精心培育的这一部分资产装入上市公司中,以配股、增发新股或出让法人股的方式在股市融资,用这笔资金偿还银行贷款。
  ------------
  什么是商业模式(2)
  ------------
    13、在巨额资金和知名品牌双全的情况下,重回本行,做一个高层次的、实实在在的商业连锁巨头。
    协作人员:
    财务:以财务部为主要力量,由负责财务的赵总牵头,必要时找几个注册会计师做财务顾问,银行方面的工作主要由这一块负责。给赵总要单独留出活动经费。
    营销:业务部门负责具体的营销工作,为了配合整体思路的全面贯彻,建议业务部重新制定业务员考评体系,减少赢利额在其中所占比例,加大销售额的奖励比例。
    公关:配合财务、营销、总裁办等部门,巩固加强和厂家、加盟商家、银行、政府有关部门以及媒体、消费者之间的关系,配合整体计划的实施。我拟成立一个文化传播公司,可否?
    危机处理:考虑到整个计划牵涉范围广、时间跨度大、参与人员部门多,为了应付随时出现的不测情况,应该成立专门的危机处理部门,该部门直接由王总管理,具有对整个公司资源的调配权。
    证券:这一方面是我们的弱项,建议招聘专业人员予以充实,从选择目标上市公司到上市融资都有大量工作要做,这部分人员暂挂在财务部,待股份制改造完成后成立专门部门。
    几个关键概念:
    中间商:
    传统意义上的中间商是指生产厂家与消费者之间的经销商,我们则定位于生产厂家与经销商之间的中间商,而这个中间商又不同于批发商,批发商与零售商之间的关系是松散的,我们是对传统零售、批发商资源的整合与提升。也可以说,我们是将特许经营的模式嫁接到流通领域,是连锁店与特许经营的结合。
    现金流:
    钱只有动起来才是钱,上述运作过程的关键是提高现金流量。从财务分析的角度来讲,通常现金流量的计算不涉及权责发生制,会计几乎造不了假,若硬要造假也容易被发现。虚假的合同能签出利润,但签不出现金流量,银行和投资商方面重视的就是这方面。为了配合这个思路,我们就必须坚持留利润给商家,促进更多商家加盟,实现良性循环。
    特许经营:
    如前所述,我们所创造的这个模式是连锁店与特许经营模式的结合,可以将之比喻为“国美+麦当劳”,因此,我们就要对加盟商家进行严格的考评筛选,对入选商家也要进行统一的CI设计,例如:统一店面、统一标志、统一服务标准,包括对店员的统一培训等等内容,总之,要以统一的形式面对消费者与厂家。
    资本运营:
    资本运营是此次计划成败的关键所在,如何成功地借壳上市?如何成功地上市融资?这两步走好了,全盘棋就活了,这两步有了闪失,将前功尽弃。选择目标上市公司的原则有几个:1商业类或综合类;2资质或者说是市场形象不能太差;3没有失去配股或新股发行资格;4股权分散,减少重组难度。
    大厂小商:
    在选择加盟商家和厂家上,厂家要选国内外的著名厂家、名牌产品,一方面保证产品质量,创一块金字招牌,另一方面表现我们的实力。这一块现在就可以做些铺垫工作,向这些大厂家吹风,其实现在他们比我们还急,他们手里有大量的货卖不出去。商家方面以中小型商家为主,一方面可以精诚合作,另一方面对方也愿意放弃原有的品牌和我们同舟共济,再有一点就是合作起来麻烦少,不会出现内乱。
    运作周期
    第一阶段:为期一年,争取10到20家商家加盟,并对其进行统一形象设计。
    第二阶段:为期一年,继续扩大加盟商家,开始全面的品牌宣传,与银行建立良好的合作关系和大额的业务往来,完成股份制改造(注意,我们前两步不是为了赚钱,只要大造声势即可)。
    第三阶段:为期两年,完成借壳上市目标,上市融资。
  ------------
  什么是商业模式(3)
  ------------
    第四阶段:为期一年,以自有资金重新调整和定位公司主业,形成在华中地区的商业垄断地位。
    这四个阶段不是分开的,如果运作得好的话,可以同时进行,最理想的情况是,四年就可以上市。史玉柱的脑白金不就是四五年就上市了吗?
    以上只是将思路整理了一下,请赵总、陈总、肖总过目,并提出意见,有关公司发展的长远规划,请诸位从具体事务中跳出来多想想,我回来后会安排时间与诸位面议。
    王××
    2001年12月于香港
    另附:我现在需要如下资料:1、国内壳资源;2、苏宁、国美的进货价格;3、经销商名单。
    点评:
    写此信的人用这种思路来对企业现有模式加以改造:
    1、采取加盟连锁,用“统购分销”方式集中向厂家下单购货,然后低价快速套现。这样一方面可以获得厂家优惠,另一方面可以笼住加盟商;
    2、用制造的巨额现金流获得银行支持,获取贷款,来回几个回合,贷款数放大;
    3、用银行贷款和部分回笼资金,收购上市公司(壳公司);
    4、向上市公司注入优质资产,拉高股价;
    5、用上市公司配股或是用股权质押给银行贷款还贷;
    6、将连锁网络注入上市公司套现,用套现资金做大做强连锁,形成更强大的连锁网络,贷更多的钱,如此完成循环;
    7、方案中提到了打造银行、企业、经销商产业链的概念,并希望通过提高整个产业链的运行效率来提高整个产业链的利润和价值。的确,现在企业从某种意义上说已经不单单是企业间的竞争了,而更多的是反映在整个产业链之间的竞争。
    信中提出的一套思路是否可行,我们先不讨论,重要的是,该信谈到了商业模式的设计问题,在思路上与传统的思维相比有重大突破。他们已经有了将商业资本和金融资本结合、产品经营与资本经营结合的意识,系统而全面地来思考问题,而且也懂得挖掘企业现有资源,并将其整合形成优势的想法。应该说其思路是有参考价值的,最起码是一个进步,是一个使企业摆脱困境走向成功的出路,是对现有商业模式的一个改造。当然,这个改造是否成功,这个思路到底还有什么问题,是否真的四年就可以走完平时几十年才能走完的路,就让我们看完商业模式后再来论证吧。
    上面信中所描述的情景有没有成为现实,我们无从得知,但国内几家大型连锁零售集团公司的确是借助商业资本与金融资本的结合,仅用十几年时间就从几百万元发展到今天上百亿元的规模,走完了别人用几十年、甚至上百年也没有走完的扩张之路。
   究竟什么是商业模式,商业模式的构成构成与设计如何进行等问题,

9/24/2008

什么是美国次贷危机,看后你就明了

在美国,贷款是非常普遍的现象,从房子到汽车,从信用卡到电话账单,贷款无处不在。当地人很少全款买房,通常都是长时间贷款。可是我们也知道,在这里失业和再就业是很常见的现象。这些收入并不稳定甚至根本没有收入的人,他们怎么买房呢?因为信用等级达不到标准,他们就被定义为次级贷款者。
大约从10年
前开始,那个时候贷款公司漫天的广告就出现在电视上、报纸上、街头,抑或在你的信箱里塞满诱人的传单:
“你想过中产阶级的生活吗?买房吧!”
“积蓄不够吗?贷款吧!”
“没有收入吗?找阿牛贷款公司吧!”
“首付也付不起?我们提供零首付!”
“担心利息太高?头两年我们提供3%的优惠利率!”
“每个月还是付不起?没关系,头24个月你只需要支付利息,贷款的本金可以两年后再付!想想看,两年后你肯定已经找到工作或者被提升为经理了,到时候还怕付不起!”
“担心两年后还是还不起?哎呀,你也真是太小心了,看看现在的房子比两年前涨了多少,到时候你转手卖给别人啊,不仅白住两年,还可能赚一笔呢!再说了,又不用你出钱,我都相信你一定行的,难道我敢贷,你还不敢借?”
在这样的诱惑下,无数美国市民毫不犹豫地选择了贷款买房。(你替他们担心两年后的债务?向来自我感觉良好的美国市民会告诉你,演电影的都能当上州长,两年后说不定我还能竞选总统呢。)
阿牛贷款公司短短几个月就取得了惊人的业绩,可是钱都贷出去了,能不能收回来呢?公司的董事长——阿牛先生,那也是熟读美国经济史的人物,不可能不知道房地产市场也是有风险的,所以这笔收益看来不能独吞,要找个合伙人分担风险才行。于是阿牛找到美国经济界的带头大哥——投行。这些家伙可都是名字响当当的主儿(美林、高盛、摩根),他们每天做什么呢?就是吃饱了闲着也是闲着,于是找来诺贝尔经济学家,找来哈佛教授,用上最新的经济数据模型,一番鼓捣之后,弄出几份分析报告,从而评价一下某某股票是否值得买进,某某国家的股市已经有泡沫了,一群在风险评估市场里面骗吃骗喝的主儿,你说他们看到这里面有风险没?用脚都看得到!可是有利润啊,那还犹豫什么,接手搞吧!于是经济学家、大学教授以数据模型、老三样评估之后,重新包装一下,就弄出了新产品——CDO(注: Collateralized Debt Obligation,债务抵押债券),说穿了就是债券,通过发行和销售这个CDO债券,让债券的持有人来分担房屋贷款的风险。
光这样卖,风险太高还是没人买啊,假设原来的债券风险等级是6,属于中等偏高。于是投行把它分成高级和普通CDO两个部分,发生债务危机时,高级CDO享有优先赔付的权利。这样两部分的风险等级分别变成了4和8,总风险不变,但是前者就属于中低风险债券了,凭投行三寸不烂“金”舌,当然卖了个满堂彩!可是剩下的风险等级8的高风险债券怎么办呢?
于是投行找到了对冲基金,对冲基金又是什么人,那可是在全世界金融界买空卖多、呼风唤雨的角色,过的就是刀口舔血的日子,这点风险小意思!于是凭借着老关系,在世界范围内找利率最低的银行借来钱,然后大举买入这部分普通CDO债券,2006年以前,日本央行贷款利率仅为1.5%;普通CDO利率可能达到12%,所以光靠利息差对冲基金就赚得盆满钵满了。
这样一来,奇妙的事情发生了,2001年末,美国的房地产一路飙升,短短几年就翻了一倍多,这样一来就如同阿牛贷款公司开头的广告一样,根本不会出现还不起房款的事情,就算没钱还,把房子一卖还可以赚一笔钱。结果是从贷款买房的人,到阿牛贷款公司,到各大投行,到各个银行,到对冲基金人人都赚钱,但是投行却不太高兴了!当初是觉得普通CDO风险太高,才扔给对冲基金的,没想到这帮家伙比自己赚的还多,净值一个劲地涨,早知道自己留着玩了,于是投行也开始买入对冲基金,打算分一杯羹了。这就好像“老黑”家里有馊了的饭菜,正巧看见隔壁邻居那只讨厌的小花狗,本来打算毒它一把,没想到小花狗吃了不但没事,反而还越长越壮了,“老黑”这下可蒙了,难道馊了的饭菜营养更好,于是自己也开始吃了!
这下又把对冲基金乐坏了,他们是什么人,手里有1块钱,就能想办法借10块钱来玩的土匪啊,现在拿着抢手的CDO还能老实?于是他们又把手里的CDO债券抵押给银行,换得10倍的贷款,然后继续追着投行买普通CDO。嘿,当初可是签了协议,这些CDO都归我们的!!!投行心里那个不爽啊,除了继续闷声买对冲基金之外,他们又想出了一个新产品,就叫CDS

(注:Credit Default Swap,信用违约交换)好了,华尔街就是这些天才产品的床:不是都觉得原来的CDO风险高吗,那我投保好了,每年从CDO里面拿出一部分钱作为保金,白送给保险公司,但是将来出了风险,大家一起承担。
保险公司想,不错啊,眼下CDO这么赚钱,1分钱都不用出就分利润,这不是每年白送钱给我们吗?干了!
对冲基金想,不错啊,已经赚了几年了,以后风险越来越大,光是分一部分利润出去,就有保险公司承担一半风险,干了!
于是再次皆大欢喜,CDS也卖火了!但是事情到这里还没有结束:因为“聪明”的华尔街人又想出了基于CDS的创新产品!我们假设CDS已经为我们带来了50 亿元的收益,现在我新发行一个“三毛”基金,这个基金是专门投资买入CDS的,显然这个建立在之前一系列产品之上的基金的风险是很高的,但是我把之前已经赚的50亿元投入作为保证金,如果这个基金发生亏损,那么先用这50亿元垫付,只有这50亿元亏完了,你投资的本金才会开始亏损,而在这之前你是可以提前赎回的,首发规模500亿元。天哪,还有比这个还爽的基金吗?1元面值买入的基金,亏到0.90元都不会亏自己的钱,赚了却每分钱都是自己的!评级机构看到这个天才设想,简直是毫不犹豫:给予AAA评级!
结果这个“三毛”可卖疯了,各种养老基金、教育基金、理财产品,甚至其他国家的银行也纷纷买入。虽然首发规模是原定的500亿元,可是后续发行了多少亿,简直已经无法估算了,但是保证金50亿元却没有变。如果现有规模5000 亿元,那保证金就只能保证在基金净值不低于0.99元时,你不会亏钱了。
当时间走到了2006年年底,风光了整整5年的美国房地产终于从顶峰重重摔了下来,这条食物链也终于开始断裂。因为房价下跌,优惠贷款利率的时限到了之后,先是普通民众无法偿还贷款,然后阿牛贷款公司倒闭,对冲基金大幅亏损,继而连累保险公司和贷款的银行,花旗、摩根相继发布巨额亏损报告,同时投资对冲基金的各大投行也纷纷亏损,然后股市大跌,民众普遍亏钱,无法偿还房贷的民众继续增多……最终,美国次贷危机爆发。

9/19/2008

“老头子,我要走了,抱抱我吧。”

老太太醒过来了,心脏跳的忽快忽慢的,让她有些吃不消了。
老太太就想:差不多喽,自己要走,也就在这一两天喽。
老太太已经76岁了,身体倒还好,只是今年,大冷大热,对他们这些老年人,是很致命的伤害呢。这不,自己就觉得从春节后,身体一天不如一天了。
老太太转头,看见旁边的暖椅上,躺着自己78岁的老头子,心里,稍稍安慰了些。
太阳暖暖的,正在向天边垂落,老太太就想起了和老头子,这一辈子的时光。
年轻时候,老太太是四邻八乡有名的美人儿。说媒的人,踏破了她家好几块门槛。可是,可是她早就心有所属。她,看中了村中那个小学校里,唯一的教书先生。
那是个斯斯文文的年轻人,长着很好看的一双眼睛,看着你的时候,满满的笑,让人就心醉的不行。
两个人曾经多次在村中的小道上迎面走过,都只是短短的对视一眼,然后双双红了脸,低了头,匆匆的擦肩而过。短短的相遇,却是两个人,最幸福的期待。
谁知那一年,她的父亲去外面采办年货,回来时遇到了土匪,危急关头,被一个五大三粗的过路客,舍命救了下来,还替父亲挨了深深的一刀。
在她家里养伤的时候,她在床前端茶递饭,完全是出于报答这个陌生男人,对父亲的救命之恩。
等到这个汉子伤势渐好的时候,这个汉子就开始忙里忙外的,几乎包揽了所有的农活和家务活。别看他粗枝大叶的样子,竟是个全能手,洗衣做饭,田间地头,春耕夏种,修修弄弄,竟没有他不会的活计,把她的父母给欢喜的不行,就经常陶醉在四邻的夸奖和羡慕声中。
这让她非常心焦,因为她在一个晚上,偶然在父母的门外,听到了父母亲,有意要招这个汉子入赘。她就软软的靠在门边,没了主意。
第二天,故意去那条和教书先生经常偶遇的巷子,徘徊了很久,都没有见到。后来问了村里的一个孩子,才知道那个教书先生,已经回城多日,说是家中有事,要三个月后,才能回来。
那个教书先生再回来的时候,匆匆的跑到她家门口,就看到了她家门上,醒目而刺眼的大红喜字,看见了院子里,一身红衣,满眼幽怨的她。
从那天起,那个教书先生,就彻底的消失在她的生活中。
后来,后来就跟着那个汉子,安安心心的过起了日子。
新中国成立,三年自然灾害,十年文革,改革开放,风风雨雨,雨雨风风。两个人从农村来到城市,相依为命,相互扶持,生儿育女,开枝散叶,就到了现在,老态龙钟的样子。
不容易,实在不容易啊!
老太太这样想着,胸中有些发闷,就咳嗽起来,惊醒了一旁午睡的老头子。
那老头子赶紧起身,关切的看着老太太,就手到了一杯水。老太太就捧了暖暖的水杯,看着自己的男人,想自己,和这个男人过了这一辈子,还有什么遗憾吗?好象没有吧?
这个男人,心思实在细腻的可以。对这个家,也实在没话可说。再苦再难,都把她们娘几个,照顾的妥妥当当的。两个人虽然在一起,极少有什么话,却有着多年培养出来的默契。有时候,就默默的坐在一起,手握着手,什么也不说,都能静静的,坐上那么一天。
老太太就想起老头子为了这个家,付出的一切。
还记得一年秋天,二小子要上学,学费成了问题,家里也好久没有见到荤腥了。老头子就在屋子里坐了很久,然后起身说,去找人借。找谁借?其时他们在那个城市,一个亲戚也没有。寥寥的几家朋友,也都是一穷二白。谁知到了傍晚,老头子果然就带回来了儿子的学费,手里还破天荒的拎了一只活鸡!
那个晚上,一家人,暖暖活活的在一起,好象过年一样的快乐。
可是,可是她却在晚上给老头子换衣服时,发现了袖弯里,有淡淡的一点血迹。就赶紧去看熟睡中老头子的胳膊,就看见了他肘弯处,一个醒目的针眼,还有好大一片淤青。
啊!这个汉子!这个男人!这个老头子!!
为了这个家,也是一身的病了。快八十岁的人了,却每天依旧忙忙碌碌的,仿佛是一台不知疲倦为何物的机器。
而自己,自己当初嫁给他的时候,是多么多么的伤心,多么多么的不情愿啊。现在牵手走了这么多年,却只有他一直陪在自己身边,不离不弃,始终如一。
老太太这样想着,眼睛里就渐渐的潮湿起来。忽然,就有些孩子气,就轻声的问眼前这个男人:“老头子,说说看,如果有下辈子,还愿意和我做夫妻吗?”
老头子被老太太这个突兀的问题,弄的愣了一下,就展开满脸的核桃纹,笑的很神秘:“不一定喽,如果下辈子,我托生成了大官财主,就去找你,让你好好的跟我享享福。如果,如果还是这么穷,就不喽,就帮着你,帮着你找一个有钱的人家。我呢,我就在你家附近,远远的看着你,只要你能过得好,就成了。”
老太太很感动,就幸福的笑着说:“你个臭老头子,还在我家附近,在我家附近干什么?”
老头子就转头,认认真真的看着心爱的女人,认认真真的说:“不干什么,就,就做个教书先生吧。”
老太太就突然愣住了,哀伤地看着这个和自己共渡了一生的男人。想说什么,却什么也说不出来,眼里的泪,却无休无止的流了下来。
过了很久,老太太深情的说:“老头子,我要走了,抱抱我吧。”
老头子就慢慢的起了身,轻轻的,轻轻的把老太太搂在怀里。老太太就在老头子耳边,呢喃着说:“老头子,下辈子,咱,还做夫妻啊……
老太太和老头子的小孙女儿,放学回家的时候,看到夕阳西下,火红的霞光,将老头子和老太太满满的笼罩在一起。就说:“羞羞,爷爷,奶奶,看不出你们还这么浪漫啊。”于是惊讶地发现,老太太和老头子,幸福的相拥着,已经双双去了。
相濡以沫,相爱一生,平淡却不平凡,爱不一定要轰轰烈烈,一样可以感人至深荡气回肠,希望许多年以后,我也能这样离开这个世界

9/17/2008

sqlserver 提取一定范围记录

select top N * from table
前N条数据
select top N * from table where id in
(select top M id from table order by id desc)
第M-N条 到第M条数据

9/13/2008

MCP68 主板开启AHCI模式攻略

1、在SATA普通状态安装Windows XP(或Windows 2003)。
2、安装成功后在设备管理器中做如下操作:
   1)在磁盘驱动器中找到“硬盘”,双击显示属性框->进入详细信息选项卡->记下“设备范例ID“
   2)在IDE ATA/ATAPI控制器中的四“主要IDE通道“与”次要IDE通道“中的->属性->详细信息->总线关系 中找到与刚才对应的设备范例ID,然后记下这个IDE通道的设备范例ID.
   3)在IDE ATA/ATAPI控制器中有两个“标准双通道PCI IDE控制器“,在其中找到->详细信息->总线关系,其中会有一个与上面记下的"IDE通道的设备范例ID"相同。
3、通过上面第2大步的三个步骤已经找到了SATA控制器,它的设备范例ID可能会是“PCIVEN_10DE&DEV_0550&SUBSYS_CB8410DE&REV_A2..."
4、将七彩虹安装盘放入光驱,在上面找的“标准双通道PCI IDE控制器“上按鼠标右键-->更新驱动程序-->从列表或指定位置安装-->浏览到:光驱: vbitmcp68XP IDEWinXPsata_ide ,更新驱动程序为:NVIDIA nForce...。完成后重启。
5、进入BIOS,把STATA改成AHCI模式,启动系统。
6、系统启动后会提示找到新硬件,等待它完成即可。

9/6/2008

英文地址翻译

翻译原则:先小后大。
中国人喜欢先说大的后说小的,如 ** 区 ** 路 ** 号
而外国人喜欢先说小的后说大的,如 ** 号 ** 路 ** 区,因此您在翻译时就应该先写小的后写大的。
例如:中国广东深圳市华中路 1023 号 5 栋 401 房,您就要从房开始写起, Room 401, Buliding 5, No.1023, HuaZhong Road , ShenZhen , GuangDong Prov., China (逗号后面有空格)。注意其中路名、公司名、村名等均不用翻译成同意的英文,只要照写拼音就行了。因为您的支票是中国的邮递员送过来,关键是要他们明白。技术大厦您写成 Technology Building ,他们可能更迷糊呢。
现在每个城市的中国邮政信件分拣中心都有专人负责将外国来信地址翻译成中文地址 , 并写在信封上交下面 邮递员 送过来 .
重要 : 你的邮政编码一定要写正确 , 因为外国信件中间的几道邮政环节都是靠邮政编码区域投递的。
常见中英文对照:
*** 室 / 房
Room ***
*** 村
*** Vallage
*** 号
No. ***
*** 号宿舍
*** Dormitory
*** 楼 / 层
*** /F
*** 住宅区 / 小区
*** Residential Quater
甲 / 乙 / 丙 / 丁
A / B / C / D
*** 巷 / 弄
Lane ***
*** 单元
Unit ***
*** 号楼 / 栋
*** Building
*** 公司
***Com./*** Crop/***CO.LTD
*** 厂
*** Factory
*** 酒楼 / 酒店
*** Hotel
*** 路
*** Road
*** 花园
*** Garden
*** 街
*** Stree
*** 信箱
Mailbox ***
*** 区
*** District
*** 县
*** County
*** 镇
*** Town
*** 市
*** City
*** 省
*** Prov.
*** 院
***Yard
*** 大学
***College
** 表示序数词,比如 1st 、 2nd 、 3rd 、 4th ……如果不会,就用 No.*** 代替,或者直接填数字吧!
另外有一些 *** 里之类难翻译的东西,就直接写拼音 *** Li 。而 *** 东(南、西、北)路,直接用拼音也行,写 *** East ( South 、 West 、 North ) Road 也行。还有,如果地方不够可以将 7 栋 3012 室写成: 7-3012 。
201 室 : Room 201
12 号 : No.12
2 单元 : Unit 2
3 号楼 : Building No.3
长安街 : Chang An street
南京路 : Nanjing road
长安公司 : Chang An Company
宝山区 : BaoShan District
赵家酒店 : ZhaoJia hotel
钱家花园 : Qianjia garden
孙家县 : Sunjia county
李家镇 : Lijia town
广州市 : Guangzhou city
广东省 : Guangdong province
中国 : China
实例:
宝山区南京路 12 号 3 号楼 201 室
room 201 , building No.3,No.12 , nan jing road , BaoShan District
如果地方不够可以将 3 号楼 201 室写成: 3-201
宝山区示范新村 37 号 403 室
Room 403,No.37,SiFan Residential Quarter,BaoShan District
中华人民共和国民政部政策研究中心北京河沿大街 147 号
No.147# HeiYian Street the policy center of civil administration department the People'Republic of China
虹口区西康南路 125 弄 34 号 201 室
Room 201,No.34,Lane 125, XiKang Road (South),HongKou District
北京市崇文区天坛南里西区 20 楼 3 单元 101
Room 3-101 building No.20,TianTan-NanXiLi Residential ChongWen District BeiJing City
中国新疆喀什市东苑小区3号楼1单元501室
Room 1-501,Buliding No.3,Dongyuan Residential,Kashi city,Xinjiang ,China
江苏省扬州市宝应县泰山东村 102 栋 204 室
Room 204 building No.102, East TaiShan Residential BaoYin County JiangSu Province
473004 河南省南阳市中州路 42 号 周旺财
Zhou Wangcai
Room 42 ,
Zhongzhou Road , Nanyang City ,
Henan Prov.China 473004
中国四川省江油市川西北矿区采气一队
1 Team CaiQi ChuanXiBei Mining Area JiangYou City SiChuan Province China
中国河北省邢台市群众艺术馆
The Masses Art Centre XinTai City HeBei Prov. China
江苏省吴江市平望镇联北村七组
7 Group LiBei Village PingWang Town WeJiang City JiangSu Province
434000 湖北省荆州市红苑大酒店 周旺财
Zhou Wangcai
Hongyuan Hotel,
Jingzhou city,
Hubei Prov. China 434000
473000 河南南阳市八一路 272 号特钢公司 周旺财
Zhou Wangcai
Special Steel Corp , No.272 ,
Bayi Road , Nanyang City ,
Henan Prov. China 473000
528400 广东中山市东区亨达花园 7 栋 702 周旺财
Zhou Wangcai
Room 702, 7th Building,
Hengda Garden, East District,
Zhongshan, China 528400
361012 福建省厦门市莲花五村龙昌里 34 号 601 室 周旺财
Zhou Wangcai
Room 601, No.34 Long Chang Li,
Xiamen, Fujian, China 361012
361004 厦门公交总公司承诺办 周旺财
Mr. Zhou Wangcai
Cheng Nuo Ban, Gong Jiao Zong Gong Si
Xiamen, Fujian, China 361004
266042 山东省青岛市开平路 53 号国棉四厂二宿舍 1 号楼 2 单元 204 户甲 周旺财
Mr. Zhou Wangcai
NO. 204, A, Building NO. 1,
The 2nd Dormitory of the NO. 4 State-owned Textile Factory,
53 Kaiping Road, Qingdao ,
Shandong , China 266042

9/3/2008

动态链接库

什么是动态链接库?DLL三个字母对于你来说一定很熟悉吧,它是Dynamic Link Library 的缩写形式,动态链接库 (DLL) 是作为共享函数库的可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个 DLL 副本的内容。

和大多数程序员一样,你一定很使用过DLL吧。也曾感受到它的带给你程序设计和编码上的好错吧今天我想和大家探讨一个主题:如何在C#创建和调用DLL(动态链接库), 其实在很大意义上而讲,DLL让我更灵活的组织编写我们的应用程序,作为软件设计者,可一个根据它来达到很高的代码重用效果。下面我来介绍一下在C#中如何创建和调用DLL。

二、准备工作

我们需要对我们接下来要做的事情做个简单的介绍,在本文我们将利用C#语言创建一个名为 MyDLL.DLL的动态链接库,在这个动态链接库文件中我们将提供两个功能一个是对两个参数交换他们的值,另一个功能是求两个参数的最大公约数。然后创建一个应用程序使用这个DLL。运行并输出结果。

三、创建DLL

让我们创建以下三个C#代码文件:

1、  MySwap.cs

using System;

namespace MyMethods

{

     public class SwapClass

     {

          public static bool Swap(ref long i,ref long j)

          {

  i = i+j;

  j = i-j;

  i = i-j;

  return true;

          }

     }

}

2、  MyMaxCD.cs

using System;

namespace MyMethods

{

     public class MaxCDClass

     {

          public static long MaxCD(long i, long j)

          {

  long a,b,temp;

  if(i>j)

  {

       a = i;

       b = j;

  }

  else

  {

       b = i;

       a = j;

  }

  temp = a % b;

  while(temp!=0)

  {

       a = b;

       b = temp;

       temp = a % b;

  }

  return b;

          }

     }

}

}需要注意的是:我们在制作这两个文件的时候可以用Visual Studio.NET或者其他的文本编辑器,就算是记事本也可以。这两个文件虽然不在同一个文件里面,但是他们是属于同一个namespace(名称空间)这对以后我们使用这两个方法提供了方便。当然他们也可以属于不同的名称空间,这是完全可以的,但只是在我们应用他们的时候就需要引用两个不同的名称空间,所以作者建议还是写在一个名称空间下面比较好。
接下来的任务是把这两个cs文件变成我们需要的DLL文件。方法是这样的:
在安装了Microsoft.NET Framework的操作系统上,我们可以在Windows所在目录下找到Microsoft.NET目录。在这个目录下面提供了C#的编译器,CSC.EXE
运行:csc /target:library /out:MyDLL.DLL MySwap.cs MyMaxCD.cs
完成后可在本目录下面找到我们刚才生成的MyDLL.DLL文件
/target:library 编译器选项通知编译器输出 DLL 文件而不是 EXE 文件。后跟文件名的 /out 编译器选项用于指定 DLL 文件名。
如果/out后面不跟文件名编译器使用第一个文件 (MySwap.cs) 作为 DLL 文件名。生成的文件为MySwap.DLL文件
OK!我们创建动态链接库文件的任务完成了,现在是我们享受劳动成果的时候了,下面我将介绍如何使用我们所创建的动态链接库文件。
四、   使用DLL
我们简单写一个小程序来测试一下我们刚才写的两个方法是否正确,好吧,跟我来:
MyClient.cs
using System;

using MyMethods;

//这里我们引用刚才定义的名称空间,如果刚才的两个文件我们写在两个不同的名称空间
class MyClient

{

     public static void Main(string[] args)

     {

         if (args.Length != 2)

         {

Console.WriteLine("Usage: MyClient <num1> <num2>");

return;

         }

          long num1 = long.Parse(args[0]);

          long num2 = long.Parse(args[1]);

          SwapClass.Swap(ref num1,ref num2);

// 请注意,文件开头的 using 指令使您得以在编译时使用未限定的类名来引用 DLL 方法

          Console.WriteLine("The result of swap is num1 = {0} and num2 ={1}",num1, num2);

          long maxcd = MaxCDClass.MaxCD(num1,num2);

          Console.WriteLine("The MaxCD of {0} and {1} is {2}",num1, num2, maxcd);

     }

}

若要生成可执行文件 MyClient.exe,请使用以下命令行:

csc /out:MyClient.exe /reference:MyLibrary.DLL MyClient.cs

/out 编译器选项通知编译器输出 EXE 文件并且指定输出文件名 (MyClient.exe)。/reference 编译器选项指定该程序所引用的 DLL 文件。

五、执行

若要运行程序,请输入 EXE 文件的名称,文件名的后面跟两个数字,例如:

MyClient 123 456

六、输出

The result of s

wap is num1 = 456 and num2 = 123

The MaxCD of 456 and 123 is 3

七、小结

动态链接具有下列优点:

节省内存和减少交换操作。很多进程可以同时使用一个 DLL,在内存中共享该 DLL 的一个副本。相反,对于每个用静态链接库生成的应用程序,Windows 必须在内存中加载库代码的一个副本。
节省磁盘空间。许多应用程序可在磁盘上共享 DLL 的一个副本。相反,每个用静态链接库生成的应用程序均具有作为单独的副本链接到其可执行图像中的库代码。
升级到 DLL 更为容易。DLL 中的函数更改时,只要函数的参数和返回值没有更改,就不需重新编译或重新链接使用它们的应用程序。相反,静态链接的对象代码要求在函数更改时重新链接应用程序。
提供售后支持。例如,可修改显示器驱动程序 DLL 以支持当初交付应用程序时不可用的显示器。
支持多语言程序。只要程序遵循函数的调用约定,用不同编程语言编写的程序就可以调用相同的 DLL 函数。程序与 DLL 函数在下列方面必须是兼容的:函数期望其参数被推送到堆栈上的顺序,是函数还是应用程序负责清理堆栈,以及寄存器中是否传递了任何参数。
提供了扩展 MFC 库类的机制。可以从现有 MFC 类派生类,并将它们放到 MFC 扩展 DLL 中供 MFC 应用程序使用。
使国际版本的创建轻松完成。通过将资源放到 DLL 中,创建应用程序的国际版本变得容易得多。可将用于应用程序的每个语言版本的字符串放到单独的 DLL 资源文件中,并使不同的语言版本加载合适的资源。
使用 DLL 的一个潜在缺点是应用程序不是独立的;它取决于是否存在单独的 DLL 模块

文章引用自:

c#调用DLL

每种编程语言调用DLL的方法都不尽相同,在此只对用C#调用DLL的方法进行介绍。首先,您需要了解什么是托管,什么是非托管。一般可以认为:非托管代码主要是基于win 32平台开发的DLL,activeX的组件,托管代码是基于.net平台开发的。如果您想深入了解托管与非托管的关系与区别,及它们的运行机制,请您自行查找资料,本文件在此不作讨论。

(一) 调用DLL中的非托管函数一般方法

首先,应该在C#语言源程序中声明外部方法,其基本形式是:

[DLLImport(“DLL文件”)]

修饰符 extern 返回变量类型 方法名称 (参数列表)

其中

DLL文件:包含定义外部方法的库文件。

修饰符: 访问修饰符,除了abstract以外在声明方法时可以使用的修饰符。

返回变量类型:在DLL文件中你需调用方法的返回变量类型。

方法名称:在DLL文件中你需调用方法的名称。

参数列表:在DLL文件中你需调用方法的列表。

注意:需要在程序声明中使用System.Runtime.InteropServices命名空间。

      DllImport只能放置在方法声明上。

DLL文件必须位于程序当前目录或系统定义的查询路径中(即:系统环境变量中Path所设置的路径)。

返回变量类型、方法名称、参数列表一定要与DLL文件中的定义相一致。

若要使用其它函数名,可以使用EntryPoint属性设置,如:

[DllImport("user32.dll", EntryPoint="MessageBoxA")]

static extern int MsgBox(int hWnd, string msg, string caption, int type);

其它可选的 DllImportAttribute 属性:

CharSet 指示用在入口点中的字符集,如:CharSet=CharSet.Ansi;

SetLastError 指示方法是否保留 Win32"上一错误",如:SetLastError=true;

ExactSpelling 指示 EntryPoint 是否必须与指示的入口点的拼写完全匹配,如:ExactSpelling=false;

PreserveSig指示方法的签名应当被保留还是被转换, 如:PreserveSig=true;

CallingConvention指示入口点的调用约定, 如:CallingConvention=CallingConvention.Winapi;

此外,关于“数据封送处理”及“封送数字和逻辑标量”请参阅其它一些文章[2]。

C#例子:

1. 启动VS.NET,新建一个项目,项目名称为“Tzb”,模板为“Windows 应用程序”。

2. 在“工具箱”的“ Windows 窗体”项中双击“Button”项,向“Form1”窗体中添加一个按钮。

3. 改变按钮的属性:Name为 “B1”,Text为 “用DllImport调用DLL弹出提示框”,并将按钮B1调整到适当大小,移到适当位置。

4. 在类视图中双击“Form1”,打开“Form1.cs”代码视图,在“namespace Tzb”上面输入“using System.Runtime.InteropServices;”,以导入该命名空间。

5. 在“Form1.cs[设计]”视图中双击按钮B1,在“B1_Click”方法上面使用关键字 static 和 extern 声明方法“MsgBox”,将 DllImport 属性附加到该方法,这里我们要使用的是“user32.dll”中的“MessageBoxA”函数,具体代码如下:

[DllImport("user32.dll", EntryPoint="MessageBoxA")]

static extern int MsgBox(int hWnd, string msg, string caption, int type);

然后在“B1_Click”方法体内添加如下代码,以调用方法“MsgBox”:

MsgBox(0," 这就是用 DllImport 调用 DLL 弹出的提示框哦! "," 挑战杯 ",0x30);

6. 按“F5”运行该程序,并点击按钮B1,便弹出如下提示框:

(二) 动态装载、调用DLL中的非托管函数

在上面已经说明了如何用DllImport调用DLL中的非托管函数,但是这个是全局的函数,假若DLL中的非托管函数有一个静态变量S,每次调用这个函数的时候,静态变量S就自动加1。结果,当需要重新计数时,就不能得出想要的结果。下面将用例子说明:

1. DLL的创建

1) 启动Visual C++ 6.0;

2) 新建一个“Win32 Dynamic-Link Library”工程,工程名称为“Count”;

3) 在“Dll kind”选择界面中选择“A simple dll project”;

4) 打开Count.cpp,添加如下代码:

// 导出函数,使用“ _stdcall ” 标准调用

extern "C" _declspec(dllexport)int _stdcall count(int init);

int _stdcall count(int init)

{//count 函数,使用参数 init 初始化静态的整形变量 S ,并使 S 自加 1 后返回该值

static int S=init;

S++;

return S;

}

5) 按“F7”进行编译,得到Count.dll(在工程目录下的Debug文件夹中)。

2. 用DllImport调用DLL中的count函数

1) 打开项目“Tzb”,向“Form1”窗体中添加一个按钮。

2) 改变按钮的属性:Name为 “B2”,Text为 “用DllImport调用DLL中count函数”,并将按钮B1调整到适当大小,移到适当位置。

3) 打开“Form1.cs”代码视图,使用关键字 static 和 extern 声明方法“count”,并使其具有来自 Count.dll 的导出函数count的实现,代码如下:

[DllImport("Count.dll")]

static extern int count(int init);

4) 在“Form1.cs[设计]”视图中双击按钮B2,在“B2_Click”方法体内添加如下代码:

MessageBox.Show(" 用 DllImport 调用 DLL 中的 count 函数, n 传入的实参为 0 ,得到的结果是: "+count(0).ToString()," 挑战杯 ");

MessageBox.Show(" 用 DllImport 调用 DLL 中的 count 函数, n 传入的实参为 10 ,得到的结果是: "+count(10).ToString()+"n 结果可不是想要的 11 哦!!! "," 挑战杯 ");

MessageBox.Show(" 所得结果表明: n 用 DllImport 调用 DLL 中的非托管 n 函数是全局的、静态的函数!!! "," 挑战杯 ");

5) 把Count.dll复制到项目“Tzb”的binDebug文件夹中,按“F5”运行该程序,并点击按钮B2,便弹出如下三个提示框:

第1个提示框显示的是调用“count(0)”的结果,第2个提示框显示的是调用“count(10)”的结果,由所得结果可以证明“用DllImport调用DLL中的非托管函数是全局的、静态的函数”。所以,有时候并不能达到我们目的,因此我们需要使用下面所介绍的方法:C#动态调用DLL中的函数。

3. C#动态调用DLL中的函数

因为C#中使用DllImport是不能像动态load/unload assembly那样,所以只能借助API函数了。在kernel32.dll中,与动态库调用有关的函数包括[3]:

①LoadLibrary(或MFC 的AfxLoadLibrary),装载动态库。

②GetProcAddress,获取要引入的函数,将符号名或标识号转换为DLL内部地址。

③FreeLibrary(或MFC的AfxFreeLibrary),释放动态链接库。

它们的原型分别是:

HMODULE LoadLibrary(LPCTSTR lpFileName);

FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);

BOOL FreeLibrary(HMODULE hModule);

现在,我们可以用IntPtr hModule=LoadLibrary(“Count.dll”);来获得Dll的句柄,用IntPtr farProc=GetProcAddress(hModule,”_count@4”);来获得函数的入口地址。

但是,知道函数的入口地址后,怎样调用这个函数呢?因为在C#中是没有函数指针的,没有像C++那样的函数指针调用方式来调用函数,所以我们得借助其它方法。经过研究,发现我们可以通过结合使用System.Reflection.Emit及System.Reflection.Assembly里的类和函数达到我们的目的。为了以后使用方便及实现代码的复用,我们可以编写一个类。

1) dld类的编写:

1. 打开项目“Tzb”,打开类视图,右击“Tzb”,选择“添加”-->“类”,类名设置为“dld”,即dynamic loading dll 的每个单词的开头字母。

2. 添加所需的命名空间及声明参数传递方式枚举:

using System.Runtime.InteropServices; // 用 DllImport 需用此命名空间

using System.Reflection; // 使用 Assembly 类需用此 命名空间

using System.Reflection.Emit; // 使用 ILGenerator 需用此命名空间

在“public class dld”上面添加如下代码声明参数传递方式枚举:

/// <summary>

/// 参数传递方式枚举 ,ByValue 表示值传递 ,ByRef 表示址传递

/// </summary>

public enum ModePass

{

ByValue = 0x0001,

ByRef = 0x0002

}

3. 声明LoadLibrary、GetProcAddress、FreeLibrary及私有变量hModule和farProc:

/// <summary>

/// 原型是 :HMODULE LoadLibrary(LPCTSTR lpFileName);

/// </summary>

/// <param name="lpFileName">DLL 文件名 </param>

/// <returns> 函数库模块的句柄 </returns>

[DllImport("kernel32.dll")]

static extern IntPtr LoadLibrary(string lpFileName);

/// <summary>

/// 原型是 : FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);

/// </summary>

/// <param name="hModule"> 包含需调用函数的函数库模块的句柄 </param>

/// <param name="lpProcName"> 调用函数的名称 </param>

/// <returns> 函数指针 </returns>

[DllImport("kernel32.dll")]

static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

/// <summary>

/// 原型是 : BOOL FreeLibrary(HMODULE hModule);

/// </summary>

/// <param name="hModule"> 需释放的函数库模块的句柄 </param>

/// <returns> 是否已释放指定的 Dll</returns>

[DllImport("kernel32",EntryPoint="FreeLibrary",SetLastError=true)]

static extern bool FreeLibrary(IntPtr hModule);

/// <summary>

/// Loadlibrary 返回的函数库模块的句柄

/// </summary>

private IntPtr hModule=IntPtr.Zero;

/// <summary>

/// GetProcAddress 返回的函数指针

/// </summary>

private IntPtr farProc=IntPtr.Zero;

4. 添加LoadDll方法,并为了调用时方便,重载了这个方法:

/// <summary>

/// 装载 Dll

/// </summary>

/// <param name="lpFileName">DLL 文件名 </param>

public void LoadDll(string lpFileName)

{

hModule=LoadLibrary(lpFileName);

if(hModule==IntPtr.Zero)

throw(new Exception(" 没有找到 :"+lpFileName+"." ));

}

若已有已装载Dll的句柄,可以使用LoadDll方法的第二个版本:

public void LoadDll(IntPtr HMODULE)

{

if(HMODULE==IntPtr.Zero)

throw(new Exception(" 所传入的函数库模块的句柄 HMODULE 为空 ." ));

hModule=HMODULE;

}

5. 添加LoadFun方法,并为了调用时方便,也重载了这个方法,方法的具体代码及注释如下:

/// <summary>

/// 获得函数指针

/// </summary>

/// <param name="lpProcName"> 调用函数的名称 </param>

public void LoadFun(string lpProcName)

{ // 若函数库模块的句柄为空,则抛出异常

if(hModule==IntPtr.Zero)

throw(new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !"));

// 取得函数指针

farProc = GetProcAddress(hModule,lpProcName);

// 若函数指针,则抛出异常

if(farProc==IntPtr.Zero)

throw(new Exception(" 没有找到 :"+lpProcName+" 这个函数的入口点 "));

}

/// <summary>

/// 获得函数指针

/// </summary>

/// <param name="lpFileName"> 包含需调用函数的 DLL 文件名 </param>

/// <param name="lpProcName"> 调用函数的名称 </param>

public void LoadFun(string lpFileName,string lpProcName)

{ // 取得函数库模块的句柄

hModule=LoadLibrary(lpFileName);

// 若函数库模块的句柄为空,则抛出异常

if(hModule==IntPtr.Zero)

throw(new Exception(" 没有找到 :"+lpFileName+"." ));

// 取得函数指针

farProc = GetProcAddress(hModule,lpProcName);

// 若函数指针,则抛出异常

if(farProc==IntPtr.Zero)

throw(new Exception(" 没有找到 :"+lpProcName+" 这个函数的入口点 "));

}

6. 添加UnLoadDll及Invoke方法,Invoke方法也进行了重载:

/// <summary>

/// 卸载 Dll

/// </summary>

public void UnLoadDll()

{

FreeLibrary(hModule);

hModule=IntPtr.Zero;

farProc=IntPtr.Zero;

}

用Visual C#调用Windows API函数

Api函数是构筑Windws应用程序的基石,每一种Windows应用程序开发工具,它提供的底层函数都间接或直接地调用了Windows API函数,同时为了实现功能扩展,一般也都提供了调用WindowsAPI函数的接口, 也就是说具备调用动态连接库的能力。Visual C#和其它开发工具一样也能够调用动态链接库的API函数。.NET框架本身提供了这样一种服务,允许受管辖的代码调用动态链接库中实现的非受管辖函数,包括操作系统提供的Windows API函数。它能够定位和调用输出函数,根据需要,组织其各个参数(整型、字符串类型、数组、和结构等等)跨越互操作边界。

下面以C#为例简单介绍调用API的基本过程:

动态链接库函数的声明

 动态链接库函数使用前必须声明,相对于VB,C#函数声明显得更加罗嗦,前者通过 Api Viewer粘贴以后,可以直接使用,而后者则需要对参数作些额外的变化工作。

 动态链接库函数声明部分一般由下列两部分组成,一是函数名或索引号,二是动态链接库的文件名。

  譬如,你想调用User32.DLL中的MessageBox函数,我们必须指明函数的名字MessageBoxA或MessageBoxW,以及库名字User32.dll,我们知道Win32 API对每一个涉及字符串和字符的函数一般都存在两个版本,单字节字符的ANSI版本和双字节字符的UNICODE版本。

 下面是一个调用API函数的例子:

[DllImport("KERNEL32.DLL", EntryPoint="MoveFileW", SetLastError=true,

CharSet=CharSet.Unicode, ExactSpelling=true,

CallingConvention=CallingConvention.StdCall)]

public static extern bool MoveFile(String src, String dst);

 其中入口点EntryPoint标识函数在动态链接库的入口位置,在一个受管辖的工程中,目标函数的原始名字和序号入口点不仅标识一个跨越互操作界限的函数。而且,你还可以把这个入口点映射为一个不同的名字,也就是对函数进行重命名。重命名可以给调用函数带来种种便利,通过重命名,一方面我们不用为函数的大小写伤透脑筋,同时它也可以保证与已有的命名规则保持一致,允许带有不同参数类型的函数共存,更重要的是它简化了对ANSI和Unicode版本的调用。CharSet用于标识函数调用所采用的是Unicode或是ANSI版本,ExactSpelling=false将告诉编译器,让编译器决定使用Unicode或者是Ansi版本。其它的参数请参考MSDN在线帮助.

 在C#中,你可以在EntryPoint域通过名字和序号声明一个动态链接库函数,如果在方法定义中使用的函数名与DLL入口点相同,你不需要在EntryPoint域显示声明函数。否则,你必须使用下列属性格式指示一个名字和序号。

[DllImport("dllname", EntryPoint="Functionname")]

[DllImport("dllname", EntryPoint="#123")]

值得注意的是,你必须在数字序号前加“#”

下面是一个用MsgBox替换MessageBox名字的例子:

[C#]

using System.Runtime.InteropServices;

public class Win32 {

[DllImport("user32.dll", EntryPoint="MessageBox")]

public static extern int MsgBox(int hWnd, String text, String caption, uint type);

}

许多受管辖的动态链接库函数期望你能够传递一个复杂的参数类型给函数,譬如一个用户定义的结构类型成员或者受管辖代码定义的一个类成员,这时你必须提供额外的信息格式化这个类型,以保持参数原有的布局和对齐。

C#提供了一个StructLayoutAttribute类,通过它你可以定义自己的格式化类型,在受管辖代码中,格式化类型是一个用StructLayoutAttribute说明的结构或类成员,通过它能够保证其内部成员预期的布局信息。布局的选项共有三种:

布局选项

描述

LayoutKind.Automatic

为了提高效率允许运行态对类型成员重新排序。

注意:永远不要使用这个选项来调用不受管辖的动态链接库函数。

LayoutKind.Explicit

对每个域按照FieldOffset属性对类型成员排序

LayoutKind.Sequential

对出现在受管辖类型定义地方的不受管辖内存中的类型成员进行排序。

传递结构成员

下面的例子说明如何在受管辖代码中定义一个点和矩形类型,并作为一个参数传递给User32.dll库中的PtInRect函数,

函数的不受管辖原型声明如下:

BOOL PtInRect(const RECT *lprc, POINT pt);

注意你必须通过引用传递Rect结构参数,因为函数需要一个Rect的结构指针。

[C#]

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]

public struct Point {

public int x;

public int y;

}

[StructLayout(LayoutKind.Explicit]

public struct Rect {

[FieldOffset(0)] public int left;

[FieldOffset(4)] public int top;

[FieldOffset(8)] public int right;

[FieldOffset(12)] public int bottom;

}

class Win32API {

[DllImport("User32.dll")]

public static extern Bool PtInRect(ref Rect r, Point p);

}

类似你可以调用GetSystemInfo函数获得系统信息:

? using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]

public struct SYSTEM_INFO {

public uint dwOemId;

public uint dwPageSize;

public uint lpMinimumApplicationAddress;

public uint lpMaximumApplicationAddress;

public uint dwActiveProcessorMask;

public uint dwNumberOfProcessors;

public uint dwProcessorType;

public uint dwAllocationGranularity;

public uint dwProcessorLevel;

public uint dwProcessorRevision;

}

[DllImport("kernel32")]

static extern void GetSystemInfo(ref SYSTEM_INFO pSI);

SYSTEM_INFO pSI = new SYSTEM_INFO();

GetSystemInfo(ref pSI);

类成员的传递

同样只要类具有一个固定的类成员布局,你也可以传递一个类成员给一个不受管辖的动态链接库函数,下面的例子主要说明如何传递一个sequential顺序定义的MySystemTime类给User32.dll的GetSystemTime函数, 函数用C/C++调用规范如下:

void GetSystemTime(SYSTEMTIME* SystemTime);

不像传值类型,类总是通过引用传递参数.

[C#]

[StructLayout(LayoutKind.Sequential)]

public class MySystemTime {

public ushort wYear;

public ushort wMonth;

public ushort wDayOfWeek;

public ushort wDay;

public ushort wHour;

public ushort wMinute;

public ushort wSecond;

public ushort wMilliseconds;

}

class Win32API {

[DllImport("User32.dll")]

public static extern void GetSystemTime(MySystemTime st);

}

回调函数的传递:

从受管辖的代码中调用大多数动态链接库函数,你只需创建一个受管辖的函数定义,然后调用它即可,这个过程非常直接。

如果一个动态链接库函数需要一个函数指针作为参数,你还需要做以下几步:

首先,你必须参考有关这个函数的文档,确定这个函数是否需要一个回调;第二,你必须在受管辖代码中创建一个回调函数;最后,你可以把指向这个函数的指针作为一个参数创递给DLL函数,.

回调函数及其实现:

回调函数经常用在任务需要重复执行的场合,譬如用于枚举函数,譬如Win32 API 中的EnumFontFamilies(字体枚举), EnumPrinters(打印机), EnumWindows (窗口枚举)函数. 下面以窗口枚举为例,谈谈如何通过调用EnumWindow 函数遍历系统中存在的所有窗口

分下面几个步骤:

1. 在实现调用前先参考函数的声明

BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARMAM IParam)

显然这个函数需要一个回调函数地址作为参数.

2. 创建一个受管辖的回调函数,这个例子声明为代表类型(delegate),也就是我们所说的回调,它带有两个参数hwnd和lparam,第一个参数是一个窗口句柄,第二个参数由应用程序定义,两个参数均为整形。

  当这个回调函数返回一个非零值时,标示执行成功,零则暗示失败,这个例子总是返回True值,以便持续枚举。

3. 最后创建以代表对象(delegate),并把它作为一个参数传递给EnumWindows 函数,平台会自动地 把代表转化成函数能够识别的回调格式。

[C#]

using System;

using System.Runtime.InteropServices;

public delegate bool CallBack(int hwnd, int lParam);

public class EnumReportApp {

[DllImport("user32")]

public static extern int EnumWindows(CallBack x, int y);

public static void Main()

{

CallBack myCallBack = new CallBack(EnumReportApp.Report);

EnumWindows(myCallBack, 0);

}

public static bool Report(int hwnd, int lParam) {

Console.Write("窗口句柄为");

Console.WriteLine(hwnd);

return true;

}

}

指针类型参数传递:

 在Windows API函数调用时,大部分函数采用指针传递参数,对一个结构变量指针,我们除了使用上面的类和结构方法传递参数之外,我们有时还可以采用数组传递参数。

 下面这个函数通过调用GetUserName获得用户名

BOOL GetUserName(

LPTSTR lpBuffer, // 用户名缓冲区

LPDWORD nSize // 存放缓冲区大小的地址指针

);

[DllImport("Advapi32.dll",

EntryPoint="GetComputerName",

ExactSpelling=false,

SetLastError=true)]

static extern bool GetComputerName (

[MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer,

  [MarshalAs(UnmanagedType.LPArray)] Int32[] nSize );

 这个函数接受两个参数,char * 和int *,因为你必须分配一个字符串缓冲区以接受字符串指针,你可以使用String类代替这个参数类型,当然你还可以声明一个字节数组传递ANSI字符串,同样你也可以声明一个只有一个元素的长整型数组,使用数组名作为第二个参数。上面的函数可以调用如下:

byte[] str=new byte[20];

Int32[] len=new Int32[1];

len[0]=20;

GetComputerName (str,len);

MessageBox.Show(System.Text.Encoding.ASCII.GetString(str));

 最后需要提醒的是,每一种方法使用前必须在文件头加上:

 using System.Runtime.InteropServices;

8/9/2008

sqlserver 只显示日期不显示时间

try:  
  select   convert(varchar(10),   getdate(),120)   --不要时间2003-08-04  
  select   convert(char(8),getdate(),112)   ----20030804  
  select   convert(char(8),getdate(),108)     ---06:05:05  
  使用   CONVERT:  
  CONVERT   (data_type[(length)],   expression   [,   style])  
  参数  
  expression  
  是任何有效的   Microsoft&reg;   SQL   Server&#8482;   表达式。有关更多信息,请参见表达式。    
  data_type  
  目标系统所提供的数据类型,包括   bigint   和   sql_variant。不能使用用户定义的数据类型。有关可用的数据类型的更多信息,请参见数据类型。    
  length  
  nchar、nvarchar、char、varchar、binary   或   varbinary   数据类型的可选参数。    
  style  
日期格式样式,借以将   datetime   或   smalldatetime   数据转换为字符数据;或者字符串格式样式,借以将   float、real、money   或   smallmoney   数据转换为字符数据。  
  SQL   Server   支持使用科威特算法的阿拉伯样式中的数据格式。  
  在表中,左侧的两列表示将   datetime   或   smalldatetime   转换为字符数据的   style   值。给   style   值加   100,可获得包括世纪数位的四位年份   (yyyy)。  
  不带世纪数位   (yy)   带世纪数位   (yyyy)    
  标准    
  输入/输出**    
  -   0   或   100   (*)     默认值   mon   dd   yyyy   hh:miAM    
  1     101   美国   mm/dd/yyyy    
  2     102   ANSI   yy.mm.dd    
  3     103   英国/法国   dd/mm/yy    
  4     104   德国   dd.mm.yy    
  5     105   意大利   dd-mm-yy    
  6     106   -   dd   mon   yy    
  7     107   -   mon   dd,   yy    
  8     108   -   hh:mm:ss    
  9     9   或   109   (*)     默认值   +   毫秒   mon   dd   yyyy   hh:mi:ss:mmmAM    
  10   110   美国   mm-dd-yy    
  11   111   日本   yy/mm/dd    
  12   112   ISO   yymmdd    
  13   13   或   113   (*)     欧洲默认值   +   毫秒   dd   mon   yyyy   hh:mm:ss:mmm(24h)    
  14   114   -   hh:mi:ss:mmm(24h)    
  15   20   或   120   (*)     ODBC   规范   yyyy-mm-dd   hh:mm:ss[.fff]    
  16   21   或   121   (*)     ODBC   规范   yyyy-mm-dd   hh:mm:ss[.fff]    
  17   126(***)   ISO8601   yyyy-mm-dd   Thh:mm:ss:mmm    
  18   130*   科威特   dd   mon   yyyy   hh:mi:ss:mmmAM    
  19   131*   科威特   dd/mm/yy   hh:mi:ss:mmmAM    
  *     默认值始终返回世纪数位   (yyyy)。  
  **   当转换为   datetime   时输入;当转换为字符数据时输出。  
  *** 专门用于   XML。对于从   datetime   或   smalldatetime   到   character   数据的转换,输出格式如表中所示。对于从   float、money   或   smallmoney   到   character   数据的转换,输出等同于   style   2。对于从   real   到   character   数据的转换,输出等同于   style   1。  

7/20/2008

微软的正则表达式教程(五):选择/编组和后向引用

选择与编组

选择允许使用 '|' 字符来在两个或多个候选项中进行选择。通过扩展章节标题的正则表达式,可以将其扩充为不仅仅适用于章节标题的表达式。不过,这可没有想象的那么直接。在使用选择时,将匹配'|' 字符每边最可能的表达式。你可能认为下面的 JScript 和 VBScript 表达式将匹配位于一行的开始和结束位置且后跟一个或两个数字的 'Chapter' 或 'Section':

/^Chapter|Section [1-9][0-9]{0,1}$/ "^Chapter|Section [1-9][0-9]{0,1}$"

不幸的是,真正的情况是上面所示的正则表达式要么匹配位于一行开始处的单词 'Chapter',要么匹配一行结束处的后跟任何数字的 'Section'。如果输入字符串为 'Chapter 22',上面的表达式将只匹配单词 'Chapter'。如果输入字符串为 'Section 22',则该表达式将匹配 'Section 22'。但这种结果不是我们此处的目的,因此必须有一种办法来使正则表达式对于所要做的更易于响应,而且确实也有这种方法。

可以使用圆括号来限制选择的范围,也就是说明确该选择只适用于这两个单词 'Chapter' 和 'Section'。不过,圆括号同样也是难处理的,因为它们也用来创建子表达式,有些内容将在后面关于子表达式的部分介绍。通过采用上面所示的正则表达式并在适当位置添加圆括号,就可以使该正则表达式既可以匹配 'Chapter 1',也可以匹配 'Section 3'。

下面的正则表达式使用圆括号将 'Chapter' 和 'Section' 组成一组,所以该表达式才能正确工作。对 JScript 为:

/^(Chapter|Section) [1-9][0-9]{0,1}$/

对 VBScript 为:

"^(Chapter|Section) [1-9][0-9]{0,1}$"

这些表达式工作正确,只是产生了一个有趣的副产品。在 'Chapter|Section' 两边放置圆括号建立了适当的编组,但也导致两个待匹配单词之一都被捕获供今后使用。由于在上面所示的表达式中只有一组圆括号,因此只能有一个捕获的 submatch。可以使用 VBScript 的Submatches 集合或者JScript 中RegExp 对象的 $1-$9 属性来引用这个子匹配。

有时捕获一个子匹配是所希望的,有时则是不希望的。在说明所示的示例中,真正想做的就是使用圆括号对单词 'Chapter' 或 'Section' 之间的选择编组。并不希望在后面再引用该匹配。实际上,除非真的是需要捕获子匹配,否则请不要使用。由于不需要花时间和内存来存储那些子匹配,这种正则表达式的效率将更高。

可以在正则表达式模式圆括号内部的前面使用 '?:'来防止存储该匹配供今后使用。对上面所示正则表达式的下述修改提供了免除子匹配存储的相同功能。对 JScript:

/^(?:Chapter|Section) [1-9][0-9]{0,1}$/

对 VBScript:

"^(?:Chapter|Section) [1-9][0-9]{0,1}$"

除了 '?:' 元字符,还有两个非捕获元字符用于称之为预查的匹配。一个为正向预查,用 ?= 表示, 在任何开始匹配圆括号内的正则表达式模式的位置来匹配搜索字符串。一个为负向预查,用 '?!' 表示,在任何开始不匹配该正则表达式模式的位置来匹配搜索字符串。

例如,假定有一个包含引用有 Windows 3.1、Windows 95、Windows 98 以及 Windows NT 的文档。进一步假设需要更新该文档,方法是查找所有对 Windows 95、Windows 98 以及 Windows NT 的引用,并将这些引用更改为 Windows 2000。可以使用下面的 JScript 正则表达式,这是一个正向预查,来匹配 Windows 95、Windows 98 以及 Windows NT:

/Windows(?=95 |98 |NT )/

在 VBScript 要进行同样的匹配可以使用下述表达式:

"Windows(?=95 |98 |NT )"

找到一个匹配后,紧接匹配到的文字(而不包括预查中使用的字符)就开始对下一次匹配的搜索。例如,如果上面所示的表达式匹配到 'Windows 98',则将从 'Windows' 而不是 '98' 之后继续查找。

后向引用

正则表达式一个最重要的特性就是将匹配成功的模式的某部分进行存储供以后使用这一能力。请回想一下,对一个正则表达式模式或部分模式两边添加圆括号将导致这部分表达式存储到一个临时缓冲区中。可以使用非捕获元字符 '?:', '?=', or '?!' 来忽略对这部分正则表达式的保存。

所捕获的每个子匹配都按照在正则表达式模式中从左至右所遇到的内容存储。存储子匹配的缓冲区编号从 1 开始,连续编号直至最大 99 个子表达式。每个缓冲区都可以使用 '\n' 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。

后向引用一个最简单,最有用的应用是提供了确定文字中连续出现两个相同单词的位置的能力。请看下面的句子:

Is is the cost of of gasoline going up up?

根据所写内容,上面的句子明显存在单词多次重复的问题。如果能有一种方法无需查找每个单词的重复现象就能修改该句子就好了。下面的 JScript 正则表达式使用一个子表达式就可以实现这一功能。

/\b([a-z]+) \1\b/gi

等价的 VBScript 表达式为:

"\b([a-z]+) \1\b"

在这个示例中,子表达式就是圆括号之间的每一项。所捕获的表达式包括一个或多个字母字符,即由'[a-z]+' 所指定的。该正则表达式的第二部分是对前面所捕获的子匹配的引用,也就是由附加表达式所匹配的第二次出现的单词。'\1'用来指定第一个子匹配。单词边界元字符确保只检测单独的单词。如果不这样,则诸如 "is issued" 或 "this is" 这样的短语都会被该表达式不正确地识别。

在 JScript 表达式中,正则表达式后面的全局标志 ('g') 表示该表达式将用来在输入字符串中查找尽可能多的匹配。大小写敏感性由表达式结束处的大小写敏感性标记 ('i') 指定。多行标记指定可能出现在换行符的两端的潜在匹配。对 VBScript 而言,在表达式中不能设置各种标记,但必须使用 RegExp 对象的属性来显式设置。

使用上面所示的正则表达式,下面的 JScript 代码可以使用子匹配信息,在一个文字字符串中将连续出现两次的相同单词替换为一个相同的单词:

var ss = "Is is the cost of of gasoline going up up?.\n"; var re = /\b([a-z]+) \1\b/gim; //创建正则表达式样式. var rv = ss.replace(re,"$1"); //用一个单词替代两个单词.

最接近的等价  VBScript 代码如下:

Dim ss, re, rv ss = "Is is the cost of of gasoline going up up?." & vbNewLine Set re = New RegExp re.Pattern = "\b([a-z]+) \1\b" re.Global = True re.IgnoreCase = True re.MultiLine = True rv = re.Replace(ss,"$1")

请注意在 VBScript 代码中,全局、大小写敏感性以及多行标记都是使用 RegExp 对象的适当属性来设置的。

replace 方法中使用 $1 来引用所保存的第一个子匹配。如果有多个子匹配,则可以用 $2, $3 等继续引用。

后向引用的另一个用途是将一个通用资源指示符 (URI) 分解为组件部分。假定希望将下述的URI 分解为协议 (ftp, http, etc),域名地址以及页面/路径:

http://msdn.microsoft.com:80/scripting/default.htm

下面的正则表达式可以提供这个功能。对 JScript,为:

/(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/

对 VBScript 为:

"(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)"

第一个附加子表达式是用来捕获该 web 地址的协议部分。该子表达式匹配位于一个冒号和两个正斜杠之前的任何单词。第二个附加子表达式捕获该地址的域名地址。该子表达式匹配不包括 '^'、 '/' 或 ':' 字符的任何字符序列。第三个附加子表达式捕获网站端口号码,如果指定了该端口号。该子表达式匹配后跟一个冒号的零或多个数字。最后,第四个附加子表达式捕获由该 web 地址指定的路径以及\或者页面信息。该子表达式匹配一个和多个除'#' 或空格之外的字符。

将该正则表达式应用于上面所示的 URI 后,子匹配包含下述内容:

RegExp.$1 包含 "http"

RegExp.$2 包含 "msdn.microsoft.com"

RegExp.$3 包含 ":80"

RegExp.$4 包含 "/scripting/default.htm"

微软的正则表达式教程(四):限定符和定位符

限定符

有时候不知道要匹配多少字符。为了能适应这种不确定性,正则表达式支持限定符的概念。这些限定符可以指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。

下表给出了各种限定符及其含义的说明:

字符
描述

*
匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。 * 等价于{0,}。

+
匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。

?
匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。

{n}
n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。

{n,}
n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。

{n,m}
mn 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。刘, "o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。

对一个很大的输入文档而言,章节数很轻易就超过九章,因此需要有一种方法来处理两位数或者三位数的章节号。限定符就提供了这个功能。下面的JScript 正则表达式可以匹配具有任何位数的章节标题:

/Chapter [1-9][0-9]*/

下面的 VBScript 正则表达式执行同样的匹配:

"Chapter [1-9][0-9]*"

请注意限定符出现在范围表达式之后。因此,它将应用于所包含的整个范围表达式,在本例中,只指定了从 0 到 9 的数字。

这里没有使用 '+' 限定符,因为第二位或后续位置上并不一定需要一个数字。同样也没有使用 '?' 字符,因为这将把章节数限制为只有两位数字。在 'Chapter' 和空格字符之后至少要匹配一个数字。

如果已知章节数限制只有99 章,则可以使用下面的 JScript 表达式来指定至少有一位数字,但不超过两个数字。

/Chapter [0-9]{1,2}/

对 VBScript 可以使用下述正则表达式:

"Chapter [0-9]{1,2}"

上述表达式的缺点是如果有一个章节号大于 99,它仍只会匹配前两位数字。另一个缺点是某些人可以创建一个 Chapter 0,而且仍能匹配。一个更好的用来匹配两位数的 JScript 表达式如下:

/Chapter [1-9][0-9]?/

或者

/Chapter [1-9][0-9]{0,1}/

对 VBScript 而言,下述表达式与上面等价:

"Chapter [1-9][0-9]?"

或者

"Chapter [1-9][0-9]{0,1}"

'*'、 '+'和 '?' 限定符都称之为贪婪的,也就是说,他们尽可能多地匹配文字。有时这根本就不是所希望发生的情况。有时则正好希望最小匹配。

例如,你可能要搜索一个 HTML 文档来查找一处包含在 H1 标记中的章节标题。在文档中该文字可能具有如下形式:

<H1>Chapter 1 – Introduction to Regular Expressions</H1>

下面的表达式匹配从开始的小于号 (<) 到 H1 标记结束处的大于号之间的所有内容。

/<.*>/

VBScript 的正则表达式为:

"<.*>"

如果所要匹配的就是开始的 H1 标记,则下述非贪婪地表达式就只匹配 <H1>。

/<.*?>/

或者

"<.*?>"

通过在 '*'、 '+' 或 '?' 限定符后放置 '?',该表达式就从贪婪匹配转为了非贪婪或最小匹配。

定位符

到现在为止,所看到的示例都只考虑查找任何地方出现的章节标题。出现的任何一个字符串 'Chapter' 后跟一个空格和一个数字可能是一个真正的章节标题,也可能是对其他章节的交叉引用。由于真正的章节标题总是出现在一行的开始,因此需要设计一个方法只查找标题而不查找交叉引用。

定位符提供了这个功能。定位符可以将一个正则表达式固定在一行的开始或结束。也可以创建只在单词内或只在单词的开始或结尾处出现的正则表达式。下表包含了正则表达式及其含义的列表:

字符
描述

^
匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。

$
匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。

\b
匹配一个单词边界,也就是指单词和空格间的位置。

\B
匹配非单词边界。

不能对定位符使用限定符。因为在一个换行符或者单词边界的前面或后面不会有连续多个位置,因此诸如 '^*' 的表达式是不允许的。

要匹配一行文字开始位置的文字,请在正则表达式的开始处使用 '^' 字符。不要把 '^' 的这个语法与其在括号表达式中的语法弄混。它们的语法根本不同。

要匹配一行文字结束位置的文字,请在正则表达式的结束处使用 '$' 字符。

要在查找章节标题时使用定位符,下面的 JScript 正则表达式将匹配位于一行的开始处最多有两个数字的章节标题:

/^Chapter [1-9][0-9]{0,1}/

VBScript 中相同功能的正则表达式如下:

"^Chapter [1-9][0-9]{0,1}"

一个真正的章节标题不仅出现在一行的开始,而且这一行中也仅有这一个内容,因此,它必然也位于一行的结束。下面的表达式确保所指定的匹配只匹配章节而不会匹配交叉引用。它是通过创建一个只匹配一行文字的开始和结束位置的正则表达式来实现的。

/^Chapter [1-9][0-9]{0,1}$/

对 VBScript 则使用:

"^Chapter [1-9][0-9]{0,1}$"

匹配单词边界有少许不同,但却给正则表达式增加了一个非常重要的功能。单词边界就是单词和空格之间的位置。非单词边界就是其他任何位置。下面的 JScript 表达式将匹配单词 'Chapter' 的前三个字符,因为它们出现在单词边界后:

/\bCha/

对 VBScript 为:

"\bCha"

这里 '\b' 操作符的位置很关键。如果它位于要匹配的字符串的开始,则将查找位于单词开头处的匹配;如果它位于改字符串的末尾,则查找位于单词结束处的匹配。例如,下面的表达式将匹配单词 'Chapter' 中的 'ter',因为它出现在单词边界之前:

/ter\b/

以及

"ter\b"

下面的表达式将匹配 'apt',因为它位于 'Chapter' 中间,但不会匹配 'aptitude' 中的'apt':

/\Bapt/

以及

"\Bapt"

这是因为在单词 'Chapter' 中 'apt' 出现在非单词边界位置,而在单词 'aptitude' 中位于单词边界位置。非单词边界操作符的位置不重要,因为匹配与一个单词的开头或结尾无关。

微软的正则表达式教程(三):字符匹配

普通字符

普通字符由所有那些未显式指定为元字符的打印和非打印字符组成。这包括所有的大写和小写字母字符,所有数字,所有标点符号以及一些符号。

最简单的正则表达式是一个单独的普通字符,可以匹配所搜索字符串中的该字符本身。例如,单字符模式 'A' 可以匹配所搜索字符串中任何位置出现的字母 'A'。这里有一些单字符正则表达式模式的示例:

/a/ /7/ /M/

等价的 VBScript 单字符正则表达式为:

"a" "7" "M"

可以将多个单字符组合在一起得到一个较大的表达式。例如,下面的 JScript 正则表达式不是别的,就是通过组合单字符表达式 'a'、'7'以及 'M' 所创建出来的一个表达式。

/a7M/

等价的 VBScript 表达式为:

"a7M"

请注意这里没有连接操作符。所需要做的就是将一个字符放在了另一个字符后面。

特殊字符

有不少元字符在试图对其进行匹配时需要进行特殊的处理。要匹配这些特殊字符,必须首先将这些字符转义,也就是在前面使用一个反斜杠 (\)。下表给出了这些特殊字符及其含义:

特殊字符
说明

$
匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字符本身,请使用 \$。

( )
标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 \( 和 \)。

*
匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*。

+
匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+。

.
匹配除换行符 \n之外的任何单字符。要匹配 .,请使用 \。

[
标记一个中括号表达式的开始。要匹配 [,请使用 \[。

?
匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。

\
将下一个字符标记为或特殊字符、或原义字符、或后向引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '\\' 匹配 "\",而 '\(' 则匹配 "("。

^
匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 \^。

{
标记限定符表达式的开始。要匹配 {,请使用 \{。

|
指明两项之间的一个选择。要匹配 |,请使用 \|。

非打印字符

有不少很有用的非打印字符,偶尔必须使用。下表显示了用来表示这些非打印字符的转义序列:

字符
含义

\cx
匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。 x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。

\f
匹配一个换页符。等价于 \x0c 和 \cL。

\n
匹配一个换行符。等价于 \x0a 和 \cJ。

\r
匹配一个回车符。等价于 \x0d 和 \cM。

\s
匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。

\S
匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。

\t
匹配一个制表符。等价于 \x09 和 \cI。

\v
匹配一个垂直制表符。等价于 \x0b 和 \cK。

字符匹配

句点 (.) 匹配一个字符串中任何单个的打印或非打印字符,除了换行符 (\n) 之外。下面的 JScript 正则表达式可以匹配 'aac'、'abc'、'acc'、'adc'如此等等,同样也可以匹配 'a1c'、'a2c'、a-c'以及 a#c':

/a.c/

等价的 VBScript 正则表达式为:

"a.c"

如果试图匹配一个包含文件名的字符串,其中句点 (.) 是输入字符串的一部分,则可以在正则表达式中的句点前面加上一个反斜杠 (\) 字符来实现这一要求。举例来说,下面的 JScript 正则表达式就能匹配 'filename.ext':

/filename\.ext/

对 VBScript 而言,等价的表达式如下所示:

"filename\.ext"

这些表达式仍然是相当有限的。它们只允许匹配任何单字符。很多情况下,对从列表中匹配特殊字符十分有用。例如,如果输入文字中包含用数字表示为Chapter 1, Chapter 2诸如此类的章节标题,你可能需要找到这些章节标题。

括号表达式

可以在一个方括号 ([ 和 ]) 中放入一个或多个单字符,来创建一个待匹配的列表。如果字符被放入括号中括起来,则该列表称为括号表达式。括号内和其他任何地方一样,普通字符代表其本身,也就是说,它们匹配输入文字中出现的一处自己。大多数特殊字符在位于括号表达式中时都将失去其含义。这里有一些例外:

  • ']' 字符如果不是第一项,则将结束一个列表。要在列表中匹配 ']' 字符,请将其放在第一项,紧跟在开始的 '[' 后面。
  • '\' 仍然作为转义符。要匹配 '\' 字符,请使用 '\\'。

括号表达式中所包含的字符只匹配该括号表达式在正则表达式中所处位置的一个单字符。下面的 JScript 正则表达式可以匹配 'Chapter 1'、'Chapter 2'、'Chapter 3'、'Chapter 4' 以及 'Chapter 5':

/Chapter [12345]/

在 VBScript 中要匹配同样的章节标题,请使用下面的表达式:

"Chapter [12345]"

请注意单词 'Chapter' 及后面的空格与括号内的字符的位置关系是固定的。因此,括号表达式只用来指定满足紧跟在单词 'Chapter' 和一个空格之后的单字符位置的字符集合。这里是第九个字符位置。

如果希望使用范围而不是字符本身来表示待匹配的字符,则可以使用连字符将该范围的开始和结束字符分开。每个字符的字符值将决定其在一个范围内的相对顺序。下面的 JScript 正则表达式包含了一个等价于上面所示的括号列表的范围表达式。

/Chapter [1-5]/

VBScipt 中相同功能的表达式如下所示:

"Chapter [1-5]"

如果以这种方式指定范围,则开始和结束值都包括在该范围内。有一点特别需要注意的是,在 Unicode 排序中起始值一定要在结束值之前。

如果想在括号表达式中包括连字符,则必须使用下述方法之一:

  • 使用反斜杠将其转义:
    [\-]
  • 将连字符放在括号列表的开始和结束位置。下面的表达式能匹配所有的小写字母和连字符:
    [-a-z] [a-z-]
  • 创建一个范围,其中开始字符的值小于连字符,而结束字符的值等于或大于连字符。下面两个正则表达式都满足这一要求:
    [!--] [!-~]

同样,通过在列表开始处放置一个插入符(^),就可以查找所有不在列表或范围中的字符。如果该插入符出现在列表的其他位置,则匹配其本身,没有任何特殊含义。下面的 JScript 正则表达式匹配章节号大于 5 的章节标题:

/Chapter [^12345]/

对 VBScript 则使用:

"Chapter [^12345]"

在上面所示的示例中,表达式将匹配第九个位置处除1, 2, 3, 4, or 5 之外的任何数字字符。因此, 'Chapter 7' 为一个匹配,同样 'Chapter 9' 也是如此。

上面的表达式可以使用连字符 (-) 表示。对 JScript 为:

/Chapter [^1-5]/

或者,对 VBScript 为:

"Chapter [^1-5]"

括号表达式的典型用法是指定对任何大写或小写字母字符或任何数字的匹配。下面的 JScript 表达式给出了这一匹配:

/[A-Za-z0-9]/

等价的 VBScript 表达式为:

"[A-Za-z0-9]"

微软的正则表达式教程(二):正则表达式语法和优先权顺序

正则表达式语法

一个正则表达式就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。

这里有一些可能会遇到的正则表达式示例:

JScript
VBScript
匹配

/^\[ \t]*$/
"^\[ \t]*$"
匹配一个空白行。

/\d{2}-\d{5}/
"\d{2}-\d{5}"
验证一个ID 号码是否由一个2位数字,一个连字符以及一个5位数字组成。

/<(.*)>.*<\/\1>/
"<(.*)>.*<\/\1>"
匹配一个 HTML 标记。

下表是元字符及其在正则表达式上下文中的行为的一个完整列表:

字符
描述

\
将下一个字符标记为一个特殊字符、或一个原义字符、或一个 后向引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\\' 匹配 "\" 而 "\(" 则匹配 "("。

^
匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。

$
匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。

*
匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。 * 等价于{0,}。

+
匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。

?
匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。

{n}
n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。

{n,}
n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。

{n,m}
mn 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。刘, "o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。

?
当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。

.
匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。

(pattern)
匹配pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。

(?:pattern)
匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。

(?=pattern)
正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如, 'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

(?!pattern)
负向预查,在任何不匹配Negative lookahead matches the search string at any point where a string not matching pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始

x|y
匹配 xy。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。

[xyz]
字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。

[^xyz]
负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。

[a-z]
字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。

[^a-z]
负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。

\b
匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。

\B
匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。

\cx
匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。 x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。

\d
匹配一个数字字符。等价于 [0-9]。

\D
匹配一个非数字字符。等价于 [^0-9]。

\f
匹配一个换页符。等价于 \x0c 和 \cL。

\n
匹配一个换行符。等价于 \x0a 和 \cJ。

\r
匹配一个回车符。等价于 \x0d 和 \cM。

\s
匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。

\S
匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。

\t
匹配一个制表符。等价于 \x09 和 \cI。

\v
匹配一个垂直制表符。等价于 \x0b 和 \cK。

\w
匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。

\W
匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。

\xn
匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如, '\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可以使用 ASCII 编码。.

\num
匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)\1' 匹配两个连续的相同字符。

\n
标识一个八进制转义值或一个后向引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为后向引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。

\nm
标识一个八进制转义值或一个后向引用。如果 \nm 之前至少有is preceded by at least nm 个获取得子表达式,则 nm 为后向引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的后向引用。如果前面的条件都不满足,若  nm 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm

\nml
如果 n 为八进制数字 (0-3),且 ml 均为八进制数字 (0-7),则匹配八进制转义值 nml。

\un
匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。

正则表达式的优先权顺序

在构造正则表达式之后,就可以象数学表达式一样来求值,也就是说,可以从左至右并按照一个优先权顺序来求值。

下表从最高优先级到最低优先级列出各种正则表达式操作符的优先权顺序:

操作符
描述

\
转义符

(), (?:), (?=), []
圆括号和方括号

*, +, ?, {n}, {n,}, {n,m}
限定符

^, $, \anymetacharacter
位置和顺序

|
“或”操作

正则表达式基础知识

一个正则表达式就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。如:

JScript
VBScript
匹配

/^\[ \t]*$/
"^\[ \t]*$"
匹配一个空白行。

/\d{2}-\d{5}/
"\d{2}-\d{5}"
验证一个ID 号码是否由一个2位数字,一个连字符以及一个5位数字组成。

/<(.*)>.*<\/\1>/
"<(.*)>.*<\/\1>"
匹配一个 HTML 标记。

下表是元字符及其在正则表达式上下文中的行为的一个完整列表:

字符
描述

\
将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\\' 匹配 "\" 而 "\(" 则匹配 "("。

^
匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。

$
匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。

*
匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。

+
匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。

?
匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。

{n}
n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。

{n,}
n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。

{n,m}
mn 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。

?
当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。

.
匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。

(pattern)
匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。

(?:pattern)
匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。

(?=pattern)
正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

(?!pattern)
负向预查,在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始

x|y
匹配 xy。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。

[xyz]
字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。

[^xyz]
负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。

[a-z]
字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。

[^a-z]
负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。

\b
匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。

\B
匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。

\cx
匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。

\d
匹配一个数字字符。等价于 [0-9]。

\D
匹配一个非数字字符。等价于 [^0-9]。

\f
匹配一个换页符。等价于 \x0c 和 \cL。

\n
匹配一个换行符。等价于 \x0a 和 \cJ。

\r
匹配一个回车符。等价于 \x0d 和 \cM。

\s
匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。

\S
匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。

\t
匹配一个制表符。等价于 \x09 和 \cI。

\v
匹配一个垂直制表符。等价于 \x0b 和 \cK。

\w
匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。

\W
匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。

\xn
匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,'\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可以使用 ASCII 编码。.

\num
匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)\1' 匹配两个连续的相同字符。

\n
标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。

\nm
标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 nm 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm

\nml
如果 n 为八进制数字 (0-3),且 ml 均为八进制数字 (0-7),则匹配八进制转义值 nml。

\un
匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (©)。

下面看几个例子:
"^The":表示所有以"The"开始的字符串("There","The cat"等);
"of despair$":表示所以以"of despair"结尾的字符串;
"^abc$":表示开始和结尾都是"abc"的字符串——呵呵,只有"abc"自己了;
"notice":表示任何包含"notice"的字符串。
'*','+'和'?'这三个符号,表示一个或一序列字符重复出现的次数。它们分别表示“没有或
更多”,“一次或更多”还有“没有或一次”。下面是几个例子:

"ab*":表示一个字符串有一个a后面跟着零个或若干个b。("a", "ab", "abbb",……);
"ab+":表示一个字符串有一个a后面跟着至少一个b或者更多;
"ab?":表示一个字符串有一个a后面跟着零个或者一个b;
"a?b+$":表示在字符串的末尾有零个或一个a跟着一个或几个b。

也可以使用范围,用大括号括起,用以表示重复次数的范围。

"ab{2}":表示一个字符串有一个a跟着2个b("abb");
"ab{2,}":表示一个字符串有一个a跟着至少2个b;
"ab{3,5}":表示一个字符串有一个a跟着3到5个b。

请注意,你必须指定范围的下限(如:"{0,2}"而不是"{,2}")。还有,你可能注意到了,'*','+'和
'?'相当于"{0,}","{1,}"和"{0,1}"。
还有一个'¦',表示“或”操作:

"hi¦hello":表示一个字符串里有"hi"或者"hello";
"(b¦cd)ef":表示"bef"或"cdef";
"(a¦b)*c":表示一串"a""b"混合的字符串后面跟一个"c";

'.'可以替代任何字符:

"a.[0-9]":表示一个字符串有一个"a"后面跟着一个任意字符和一个数字;
"^.{3}$":表示有任意三个字符的字符串(长度为3个字符);

方括号表示某些字符允许在一个字符串中的某一特定位置出现:

"[ab]":表示一个字符串有一个"a"或"b"(相当于"a¦b");
"[a-d]":表示一个字符串包含小写的'a'到'd'中的一个(相当于"a¦b¦c¦d"或者"[abcd]");
"^[a-zA-Z]":表示一个以字母开头的字符串;
"[0-9]%":表示一个百分号前有一位的数字;
",[a-zA-Z0-9]$":表示一个字符串以一个逗号后面跟着一个字母或数字结束。

你也可以在方括号里用'^'表示不希望出现的字符,'^'应在方括号里的第一位。(如:"%[^a-zA-Z]%"表
示两个百分号中不应该出现字母)。

为了逐字表达,必须在"^.$()¦*+?{\"这些字符前加上转移字符'\'。

请注意在方括号中,不需要转义字符。

7/15/2008

修改远程桌面端口

打开注册表,进入以下路径:
[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlTerminal Server WdsrdpwdTdstcp],看见PortNamber值了吗?其默认值是3389,修改成所希望的端口即可,例如6111。
再打开[HKEY_LOCAL_MACHINE SYSTEMCurrentContro1SetControlTenninal ServerWinStationsRDPTcp],将PortNumber的值(默认是3389)修改成端口6111。
修改完毕,重新启动电脑,以后远程登录的时候使用端口6111就可以了
打开客户端管理连接器,单击已经建好的某个连接,单击“文件(file)”→“导出(Export)”……
用记录本或其它文本编辑软件找开刚导出的这个.cns文件,找到“Server Port =3389”这一行了吗?
把这个默认的3389改成与服务器一样的端口号就行了
Windows XP/2003 下的修改办法
使用XP或2003的客户端,它可以显示多彩,还可以有声音,功能更强大。但终端客户端连接端口的修改方法与WIN2000有一定区别:
按照原来更改2000的客户端的思路,把XP、2003的默认配置另存(在连接界面上单击“另存为”),和2000不一样的是:XP、2003的配置文件后缀是.rdp,WIN2000的是.cns
用记事本打开这个地default.rdp文件,在里面没有发现什么3389的东东(2000的配置文件是有的),没有这句端口的配置我们就给它加上,假定现在的端口为8933,如下:
server port:i:8933 保存,退出即可。

6/19/2008

C#中的字符串格式String.Format

String.Format()和ToString()是一回事。就是给个参数,再给个字符串格式,然后按照给定的格式输出参数。详细信息可以在这个链接看到,

http://msdn.microsoft.com/zh-cn/library/fbxft59x.aspx Topic: Formatting Types

1. 标准数字格式

----- C 或者c , 货币。 默认是小数点后两位,有时候后面跟个数字,比如C3,就是小数点后三位的意思。不同的文化设置,前面的货币符号是不同的。

double money = 123.456;

money.ToString("C", CultureInfo.CreateSpecificCulture("en-US" ))); //输出是$123.45

money.ToString("C3", CultureInfo.CreateSpecificCulture("en-US" ))); //输出是$123.456
---- D 或者 d Decimal,就是10进制整数。后面可以跟数字,表示整个的位数,不足的位数用左侧的零补齐。

int value = 12345;

value.ToString(" D" ); //输出是12345

value.ToString(" D7" );//输出是0012345

---- E 或者 e 科学计数法,就是前面是一个1-10的小数,后面跟着10的多少次方的表达形式。后面跟着个数,表示小数点后有几位的意思,不足的位数用零补齐。

double data = 12345.678;

data.ToString ( " e " ); //输出是1.2345678E+004

data.ToString( “ e4" );//输出是1.2345E+004

---- F 或者 f 就是小数点后固定几位。写个数,就表示位数。只写f,表示默认两位。

double data = 12345.678;
data.ToString( " f " ); //输出是12345.67;
data.ToString( “ f4" );//输出是12345.6780;

---- G 或者 g 表示General
即复杂,又不太常用,就不详述了

---- N 或者 n 就是按照千位,三个三个分组那种。后面接的数字表示小数点后的位数

doule data = 123456789.1234;
data .ToString( " N", CultureInfo.InvariantCulture));//输出是123,456,789.1234;
data .ToString( "N1", CultureInfo.InvariantCulture));//输出是123,456,789.1;

---- P 或者 p,百分比形式输出
doule data = 0.12345;
data .ToString("P", CultureInfo.InvariantCulture));//输出是12.34%
data .ToString("P1", CultureInfo.InvariantCulture));//输出是12.3%

---- R 或者 r Round UP

--- X 或者 x   十六进制
2. 用户自定义数字格式

基本思想就是用占位符写个字符串格式,然后照着填写就是了。

0 代表 0-9,就是不足位数,用零补齐的意思,也包括在左侧的零。

# 代表空格,0-9,包括前后的零自动抹去。

,是千位分隔符

% 百分号

; 区间分割符。在这个之前的,是正数的表达格式,后面是负数的表达格式。

说明白了,下面就举例子

格式            

0.00                数值是1.1                       输出是 1.10

00.00              数值是1.1                      输出是 01.10

#.##                数值是1.1                        输出是1.1

(###)###-####     数值是1234567890 输出是(123)456-7890

[##-##-##]     数值是123456     输出是[12-34-56]

#0.###%    数值是 .086     输出是8.6%

#,#    数值是12345678    输出是12,345,678

##;(##)          数值是23          输出是 23

##;(##)        数值是-23         输出是 (23)

3. Datetime的常用格式

用法大致如下,

DateTime curDate;

curDate.ToString(" D" ); 输出时间格式 2008年5月3日
curDate.ToString(" d" ); 输出时间格式 2008-5-3
curDate.ToString("F" ); 输出时间格式 2008年5月3日 3:14:52
curDate.ToString("f" ); 输出时间格式 2008年5月3日 3:14
curDate.ToString("G" ); 输出时间格式 2008-5-3 3:14:52
curDate.ToString("g" ); 输出时间格式 2008-5-3 3:14
curDate.ToString("M" ); 输出时间格式 5月3日
curDate.ToString("m" ); 输出时间格式 5月3日
curDate.ToString("O" ); 输出时间格式 2008-05-03T03:14:52.8125000-05:00
curDate.ToString("o" ); 输出时间格式 2008-05-03T03:14:52.8125000-05:00
curDate.ToString("R" ); 输出时间格式 Sat, 03 May 2008 03:14:52 GMT
curDate.ToString("r" ); 输出时间格式 Sat, 03 May 2008 03:14:52 GMT
curDate.ToString("s" ); 输出时间格式 2008-05-03T03:14:52
curDate.ToString("T" ); 输出时间格式 3:14:52
curDate.ToString("t" ); 输出时间格式 3:14
curDate.ToString("U" ); 输出时间格式 2008年5月3日 8:14:52
curDate.ToString("u" ); 输出时间格式 2008-05-03 03:14:52Z
curDate.ToString("Y" ); 输出时间格式 2008年5月
curDate.ToString("y" ); 输出时间格式 2008年5月

4. DateTime 自定义格式

就是用一些参数组合起来的意思。相关参数如下

d 就是日期。 如1,2,20等。

dd就是二位数日期,如01, 02, 22等

ddd 就是三位字母的星期。如: Mon,Tue等

dddd就是星期的全名,如Monday, Sunday 等。

f 就是秒的小数部分。 如 SS.f,就是几秒几的意思。

ff就是秒的两位小数部分。fff, fffff,以及FF,FFF意思都差不多,就是几位小数的意思。

g就是在时间后面的额外部分,如B.C, A.D等等

h,0-12的小时。hh,两位表述的小时。

H,0-23的小时。HH,两位表述的小时。

K,表示当前的时区号。

m,mm,表示不限位和两位表示的分钟。

M,MMM,MMMM表示月份。分别如: 1, Jan, January

s, ss 表示不限位和两位的秒。如1, 01等

t, tt,表示上午下午, AM, 或者PM

y, yy, yyyy,yyyyy不同位数的年份

z,zz,zzzz不同位数的时区

4/22/2008

远程控制 RemotelyAnywhere v8.0.605 附注册码

RemotelyAnywhere是一个小巧的,利用浏览器进行远程控制的小程序。把它安装在NT计算机上。然后你就可以通过任何浏览器对远程计算机进行控制了。通过它,你可以管理远程计算机上的各种服务、进程、用户和文件,甚至远程重启。这一软件的可贵之处是,你不需要安装任何客户端软件,只要具备兼容javascript的浏览器就可以。
一般情况下要实现远程控制,都是要分别在服务端和客户端安装控制软件,如果你要在不同的地方远程控制一台电脑,每次都在客户端安装软件确实有点麻烦,而这款RemotelyAnywhere正是解决这个问题,只要被控制的电脑上安装了这款软件,那么你就可以在任何一台能上网的电脑上通过浏览器(如IE)对装有RemotelyAnywhere的电脑进行远程控制了。 
  但要注意的是远程客户端的浏览器要支持 Java才能控制服务器端。 
  一、激活RemotelyAnywhere 
  第一步:双击打开任务栏托盘里的RemotelyAnywhere图标,会弹出RemotelyAnywhere界面(图1),单击“RemotelyAnywhere is not activated”下的“Please click here to activate RemotelyAnywhere”蓝色字样。
Fast, secure system administration FROM ANYWHERE. RemotelyAnywhere 8 offers industry leading security and performance for remote administration. Join the thousands of enterprises that trust RemotelyAnywhere for ensuring total access to the systems they manage. 
» Vista Compatible - New
» Disk Mapping - New
» 64-bit Compatible - New
» System Dashboard 
» Guest Invite
» Public Key improvements
» PDA Remote Control 
» Access via Any Web browser 
» Easy Enterprise Deployment
» SSH & FTP
» File Transfer & Synchronization
» Automatic Alerts 
官网:http://www.remotelyanywhere.com
官方下载:
http://www.remotelyanywhere.com/files/RemotelyAnywhereNH.msi
http://www.remotelyanywhere.com/files/RemotelyAnywhereNH.zip
KeyGen:
-----BEGIN LICENSE-----
PRODUCT           RemotelyAnywhere
PRODUCTTYPE       SERVER EDITION
VALIDFORVERSION   7
ISSUER            3am Labs, Inc.
ISSUERID          1060-4b81-0781-f51c
ISSUEDATE         2006-03-16
ISSUEREASON       PURCHASE
LICENSEID         1D50-7922-AEB1-E085
LICENSETYPE       COUNTED
UPG.INS.UNTIL     2007-03-16
LICENSECOUNT      5
LICENSEETYPE      CORPORATE
LICENSEE          francis t deconcini
LICENSEE          francis t deconcini
LICENSEE          715 cornell ave
-----END LICENSE-----
-----BEGIN PKCS7-----
MIHbBgkqhkiG9w0BBwKggc0wgcoCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEH
ATGBqjCBpwIBATBGMEExCzAJBgNVBAYTAkhVMRwwGgYDVQQKExMzYW0gTGFib3Jh
dG9yaWVzIFBMMRQwEgYDVQQDEwtNYXJ0b24gQW5rYQIBADAJBgUrDgMCGgUAMA0G
CSqGSIb3DQEBAQUABEDQdpilRyqcpdbxLMc2zvKv9C5aBtDUjMH+k17cwUsECEx9
j2FbjNgI0HFLHrpRJHoBBc2MF5xB6FUxQmMx9m12
-----END PKCS7----- 

4/9/2008

Alcohol 120%右键菜单没了

  我用的是Alcohol 120%虚拟光驱,不知道为什么在映像文件的右键菜单中的加载映像文件选项没有了,只能在Alcohol120%主程序中进行加载和卸载映像文件。非常不方便,请问如何修复?

【答】:这是由于Alcohol 120%的一个组件没有被成功注册而导致。单击“开始/运行”,"regsvr32 c:\Program Files\Alcohol Soft\Alcohol 120\AXShlEx.dll"重新注册此组件程序即可。另外,安装最新版的Alcohol 120%也可以解决这个问题。

3/31/2008

Visual Studio 2005 开发WPF应用程序系列文章——什么是WPF

      你也许听说过Avalon(现在被称为Windows Presentation Foundation,或WPF),也许看过相关的屏幕截图或demo,但是现在你可以亲手尝试了。让我们开始创建下一代Windows应用程序吧。

  微软公司早在2003年洛杉矶的PDC上就公布了Avalon,他们将其视为下一代用户界面技术,并且得到了开发者和用户的一致赞同。

  在2005年的PDC上,微软公司展示了比2003年更加完整的Avalon版本,并给它取了一个官方新名称:Windows Presentation Foundation(WPF)。在此之前,它已经完成了从演示软件到开始阶段alpha版本的API的转变。到了几个月之后的今天,它又成长成为更加先进的beta版本--你可以使用它来开发你的下一代用户界面程序了。

  那么,WPF是什么,为什么它那么重要呢?

  首先,它清晰而又有效的将用户界面和程序实现分开。它使得设计可视化的用户界面的设计者和编写内部核心代码的开发人员可以并行工作。这是非常重要的:

  ·将两者分开,软件开发公司可以使得设计者们集中精力将设计工作做得更好,同时让开发者支持他们。

  ·随着软件外包和订购的逐渐风行,WPF使得一些商业的设计者们能够更好的从事界面设计工作,并集成一些简单的功能,而购买的核心代码能够独立的完成内部的一些关键逻辑而不干扰设计过程。

  ·它更好的支持应用软件的国际化。不同的独立的界面可以使用不同的本地化方案,而内部的代码是通用的。

  ·它支持软件的"空标签":可以为不同的用户采用定制的界面而保持核心的逻辑不变。开发者们创建程序逻辑,然后为不同的用户使用不同的界面并贴上他们的商标等。

  WPF使用一种基于XML的语言来定义用户界面从而完成上述的工作。这种语言被称为XAML,XML应用程序标记语言。

  其次,WPF使用一种基于向量而不是基于光栅的绘制引擎,这和曹其的Windows的绘制引擎是截然不同的。光栅绘制引擎通过在屏幕上绘制象素点来绘制表面。象素只是点;这样的话,如果屏幕分辨率(DPI,每英寸点)增加了,它的效果就会变差。随着现在屏幕都采用超高DPI的分辨率,字体必须使用成百上千个DPI来达到一定的浏览效果。比如微软Word里缺省的英文字体12号的Times New Roman,在现在的普通分辨率情况下效果还可以但是到了超高分辨率的显示器上效果就不行了。管理这些基于光栅的图像的点将会消耗大量的处理能力,同时也是很浪费的。而采用基于向量的方式来替代象素,在一个可扩展的坐标系里绘制字体和其他线型,使得它们可以独立于DPI。想想Windows Metafile(WMF)和位图文件(BMP)之间的差距你就明白了。同时,向量图也使得一些变换如3D,旋转和动画变得更加方便和易于操作。

  好,下面开始我们的第一个基于WPF的应用程序之旅吧。

首先你需要安装一下一些软件:
1. 首先你需要安装.NET Framework 3.0。
2. 你需要安装WinFX runtime components。
3. 还需要安装VS2005
4. 最后你需要下载Visual Studio development tools(Orcas)来进行WinFX开发。它包含了VS里的"Cider"设计器来编辑XAML。
5. 最后你需要下载Expression Designer for XAML

  作为程序员你可以使用Cider工具来在VS.NET里创建基本的XAML用户界面,这样的方式你会感到很熟悉,和在VS中进行一般的Windows 窗体设计差不多。但是,如果要是用一些XAML提供的高级特性,我建议你还是研究一下Expression Designer for XAML。

第一个WPF Windows Application:

  如果所有的工具都安装正确,你就可以开发你的第一个WPF程序了。打开VS2005,选择文件->新建工程。你将会看到工程对话框,如图1所示。


  在图1中,你可以看到一套新的工程类型,名为Windows Application,包括Windows Application(WPF),服务库,XAML Browser Application (WPF)浏览器程序和控件库。它们分别用来创建XAML客户端程序,Indigo服务,XAML浏览器(Web窗体)程序,和控件库。
  这篇文章里,我主要讲解创建一个Windows windows应用程序的流程,所以我们选择和其对应的工程模板。

  当你第一次创建这个程序的时候,你将会看到和标准的VS设计环境类似的界面,但是事实上它是一个VS的新的XAML设计器,代号"Cider"。如图2所示。


  如果你仔细看图2,你会发现在设计面板的下部有一个新tab,名为"Xaml"。点击它,你会看到当前设计的XAML,这个XAML包含了一个button,一个textbox:

  当你改变Cider可视化编辑器里的对话框的布局的时候,工具会自动更新XAML的内容。

  对控件的基于设计者的事件添加机制还没有被Cider所支持,不过如果手工对XML进行一些修改就可以很容易的增加一些事件。比如,你可以手工为"Click"属性增加一个点击事件处理:

<Button Margin="124,125,93,119" Name="btnClick" Click="ButtonClick"  >I Click</Button>

  你可以看到,这里做的就是为按钮增加了一个新的"Click"属性,并且给出了点击按键事件句柄的名称。如果你选择了"Source"那个tab,你可以为这个事件创建处理句柄。

  Avalon使用一种被称为"Routed Events"的机制来绑定XAML和后端代码,如同其名--事件在运行时在独立的XAML UI和代码之间相互传递。

  这样的话,你需要声明事件句柄来使用RoutedEventArgs参数:

void ButtonClick(object sender, RoutedEventArgs e)
{
System.Windows.MessageBox.Show("Hello World to:" +
textBox1.Text);
}
  如果你此时运行程序,你将看到WPF基于向量的引擎已经开始工作了,如图3所示。


  这样你就完成了你的第一次Avalon的学习之旅,也许它没有想象中的激动人心,但是毕竟你已经开始掌握这一先进技术了。
  Microsoft Expression是一个比基本的Cider工具更加强大的XAML设计工具,它包含在VS.NET的WinFX工具集中。有兴趣的朋友可以自己 使用Expression来设计XAML 这个应用程序。

在C#隐藏主窗口的几种方法

写过一个程序,要求在程序启动的时候主窗口隐藏,只在系统托盘里显示一个图标。一直以来采用的方法都是设置窗口的ShowInTaskBar=false, WindowState=Minimized。但是偶然发现尽管这样的方法可以使主窗口隐藏不见,但是在用Alt+Tab的时候却可以看见这个程序的图标并把这个窗口显示出来。因此这种方法其实并不能满足要求。

经过研究,又找到两个方法。

方法一: 重写setVisibleCore方法

protected override void SetVisibleCore(bool value)
{
     
base.SetVisibleCore(false);
}

这个方法比较简单,但是使用了这个方法后主窗口就再也不能被显示出来,而且在退出程序的时候也必须调用Application.Exit方法而不是Close方法。这样的话就要考虑一下,要把主窗口的很多功能放到其他的地方去。

方法二: 不创建主窗口,直接创建NotifyIcon和ContextMenu组件
这种方法比较麻烦,很多代码都必须手工写

static void Main()
{
             Application.EnableVisualStyles();
             Application.SetCompatibleTextRenderingDefault(
false);

             System.Resources.ResourceManager resources
=
                
new System.Resources.ResourceManager("myResource",   System.Reflection.Assembly.GetExecutingAssembly());
             NotifyIcon ni
= new NotifyIcon();

             ni.BalloonTipIcon
= System.Windows.Forms.ToolTipIcon.Warning;
             ni.BalloonTipText
= "test!";
             ni.BalloonTipTitle
= "test.";
            
//ni.ContextMenuStrip = contextMenu;
             ni.Icon = ((System.Drawing.Icon)(resources.GetObject("ni.Icon")));
             ni.Text
= "Test";
             ni.Visible
= true;
             ni.MouseClick
+= delegate(object sender, MouseEventArgs e)
             {
                 ni.ShowBalloonTip(
0);
             };

             Application.Run();
}

如果需要的组件太多,这个方法就很繁琐,因此只是做为一种可行性研究。

方法三:前面两种方法都有一个问题,主窗口不能再显示出来。现在这种方法就没有这个问题了

private bool windowCreate=true;
...
protected override void OnActivated(EventArgs e)
         {
            
if (windowCreate)
             {
                
base.Visible = false;
                 windowCreate
= false;
             }

            
base.OnActivated(e);
         }

private void notifyIcon1_DoubleClick(object sender, EventArgs e)
         {
            
if (this.Visible == true)
             {
                
this.Hide();
                
this.ShowInTaskbar = false;
             }
            
else
             {
                
this.Visible = true;
                
this.ShowInTaskbar = true;
                
this.WindowState = FormWindowState.Normal;
                
//this.Show();
                this.BringToFront();
             }