<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Architecting Life &#187; Develop</title>
	<atom:link href="http://www.xujiwei.com/blog/posts/develop/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.xujiwei.com/blog</link>
	<description>Just do it</description>
	<lastBuildDate>Wed, 21 Jul 2010 05:56:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
	<atom:link rel='hub' href='http://www.xujiwei.com/blog/?pushpress=hub'/>
		<item>
		<title>Snow Leopard Server 上配置 Gitosis 笔记</title>
		<link>http://www.xujiwei.com/blog/2010/07/21/configure-gitosis-on-snow-leopard-server/</link>
		<comments>http://www.xujiwei.com/blog/2010/07/21/configure-gitosis-on-snow-leopard-server/#comments</comments>
		<pubDate>Wed, 21 Jul 2010 05:56:04 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Management]]></category>
		<category><![CDATA[Notes]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Gitosis]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[VCS]]></category>

		<guid isPermaLink="false">http://www.xujiwei.com/blog/?p=313</guid>
		<description><![CDATA[为了迁移项目 Git 仓库到 Mini Server 上，需要在 Snow Leopard Server 上配置一下 Gitosis，但是 Mac OS X 和 Linux 不太一样，有些地方需要特殊处理一下。 安装 Gitosis Gitosis 的安装就不多说，在参考文档2中有。 添加 Git 用户组及用户 添加用户可以用参考文档1中的方法来创建，没有尝试直接用 OSX 的用户管理来创建是否可用。 # 这里的用户组和用户ID 用 401，但是实际用时需要根据服务器上的情况来创建 # 我在使用时 401 这个 gid 就已经被占用了，可以使用以下两个命令看看要用的 # ID 是否已经被用了。 sudo dscl . list /Users uid sudo dscl . list groups gid &#160; # 创建用户组 <a href="http://www.xujiwei.com/blog/2010/07/21/configure-gitosis-on-snow-leopard-server/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>为了迁移项目 Git 仓库到 Mini Server 上，需要在 Snow Leopard Server 上配置一下 Gitosis，但是 Mac OS X 和 Linux 不太一样，有些地方需要特殊处理一下。</p>
<h3>安装 Gitosis</h3>
<p>Gitosis 的安装就不多说，在参考文档2中有。</p>
<h3>添加 Git 用户组及用户</h3>
<p>添加用户可以用参考文档1中的方法来创建，没有尝试直接用 OSX 的用户管理来创建是否可用。</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># 这里的用户组和用户ID 用 401，但是实际用时需要根据服务器上的情况来创建</span>
<span style="color: #666666; font-style: italic;"># 我在使用时 401 这个 gid 就已经被占用了，可以使用以下两个命令看看要用的</span>
<span style="color: #666666; font-style: italic;"># ID 是否已经被用了。</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . list <span style="color: #000000; font-weight: bold;">/</span>Users uid
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . list <span style="color: #c20cb9; font-weight: bold;">groups</span> gid
&nbsp;
<span style="color: #666666; font-style: italic;"># 创建用户组 git</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create groups<span style="color: #000000; font-weight: bold;">/</span>git
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create groups<span style="color: #000000; font-weight: bold;">/</span>git gid <span style="color: #000000;">401</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># 创建用户 git</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create users<span style="color: #000000; font-weight: bold;">/</span>git
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create users<span style="color: #000000; font-weight: bold;">/</span>git uid <span style="color: #000000;">401</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create users<span style="color: #000000; font-weight: bold;">/</span>git NFSHomeDirectory <span style="color: #000000; font-weight: bold;">/</span>Users<span style="color: #000000; font-weight: bold;">/</span>git
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create users<span style="color: #000000; font-weight: bold;">/</span>git gid <span style="color: #000000;">401</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create users<span style="color: #000000; font-weight: bold;">/</span>git UserShell <span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">bash</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create users<span style="color: #000000; font-weight: bold;">/</span>git Password <span style="color: #ff0000;">'*'</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># 创建用户主目录，Git 仓库就要放在里面</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">mkdir</span> <span style="color: #000000; font-weight: bold;">/</span>Users<span style="color: #000000; font-weight: bold;">/</span>git
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">chown</span> git <span style="color: #000000; font-weight: bold;">/</span>Users<span style="color: #000000; font-weight: bold;">/</span>git
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">chgrp</span> git <span style="color: #000000; font-weight: bold;">/</span>Users<span style="color: #000000; font-weight: bold;">/</span>git
&nbsp;
<span style="color: #666666; font-style: italic;"># 下面这一句是把 git 用户添加到可以使用 ssh 访问的用户组里面</span>
<span style="color: #666666; font-style: italic;"># 如果不执行这句的话，git push 或者 git pull 等等的时候会出错</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . <span style="color: #660033;">-append</span> <span style="color: #000000; font-weight: bold;">/</span>Groups<span style="color: #000000; font-weight: bold;">/</span>com.apple.access_ssh GroupMembership git</pre></div></div>

<h3>配置 Gitosis</h3>
<p>这个在参考文档2中都有详细说明。</p>
<h3>参考文档</h3>
<ol>
<li><a href="http://blog.ardes.com/2008/5/19/git-hosting-with-leopard">git hosting with Leopard</a>, Ian White</li>
<li><a href="http://progit.org/book/zh/ch4-7.html">权限管理器 Gitosis</a>, Pro Git
</li>
<li><a href="http://punk-apple.livejournal.com/261072.html">Adduser for Mac OS X = dscl + niutil + nicl</a>, otaku ramblings</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.xujiwei.com/blog/2010/07/21/configure-gitosis-on-snow-leopard-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Cocoa学习］格式化日期和解析日期字符串</title>
		<link>http://www.xujiwei.com/blog/2010/05/26/format-date-and-parse-date/</link>
		<comments>http://www.xujiwei.com/blog/2010/05/26/format-date-and-parse-date/#comments</comments>
		<pubDate>Wed, 26 May 2010 04:57:04 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[NSDate]]></category>
		<category><![CDATA[NSDateFormatter]]></category>

		<guid isPermaLink="false">http://www.xujiwei.com/blog/?p=308</guid>
		<description><![CDATA[在应用程序中，显示消息的时候一般都需要附带一个消息接收的时间，使用 NSDate 和 NSDateFormatter 即可完成格式化输出日期的任务，但是在使用时会比较麻烦，通过 Category 的方式来给 NSDate 类直接添加两个类方法来做这些事情会比较好，在以后需要格式化字符串时不需要每次都去创建一个 NSDateFormatter 对象。 对于解析日期时间也是同理。 @interface NSDate &#40;FormatString&#41; &#160; - &#40;NSString*&#41;stringWithFormat:&#40;NSString*&#41;fmt; + &#40;NSDate*&#41;dateFromString:&#40;NSString*&#41;str withFormat:&#40;NSString*&#41;fmt; &#160; @end &#160; @implementation NSDate &#40;FormatString&#41; &#160; - &#40;NSString*&#41;stringWithFormat:&#40;NSString*&#41;fmt &#123; static NSDateFormatter *fmtter; &#160; if &#40;fmtter == nil&#41; &#123; fmtter = &#91;&#91;NSDateFormatter alloc&#93; init&#93;; &#125; &#160; if &#40;fmt == nil &#124;&#124; &#91;fmt isEqualToString:@&#34;&#34;&#93;&#41; &#123; <a href="http://www.xujiwei.com/blog/2010/05/26/format-date-and-parse-date/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>在应用程序中，显示消息的时候一般都需要附带一个消息接收的时间，使用 NSDate 和 NSDateFormatter 即可完成格式化输出日期的任务，但是在使用时会比较麻烦，通过 Category 的方式来给 NSDate 类直接添加两个类方法来做这些事情会比较好，在以后需要格式化字符串时不需要每次都去创建一个 NSDateFormatter 对象。</p>
<p>对于解析日期时间也是同理。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@interface</span> <span style="color: #400080;">NSDate</span> <span style="color: #002200;">&#40;</span>FormatString<span style="color: #002200;">&#41;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>stringWithFormat<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>fmt;
<span style="color: #002200;">+</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSDate</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>dateFromString<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>str withFormat<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>fmt;
&nbsp;
<span style="color: #a61390;">@end</span>
&nbsp;
<span style="color: #a61390;">@implementation</span> <span style="color: #400080;">NSDate</span> <span style="color: #002200;">&#40;</span>FormatString<span style="color: #002200;">&#41;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>stringWithFormat<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>fmt <span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">static</span> <span style="color: #400080;">NSDateFormatter</span> <span style="color: #002200;">*</span>fmtter;
&nbsp;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>fmtter <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        fmtter <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDateFormatter</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>fmt <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span> || <span style="color: #002200;">&#91;</span>fmt isEqualToString<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;&quot;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        fmt <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;HH:mm:ss&quot;</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
    <span style="color: #002200;">&#91;</span>fmtter setDateFormat<span style="color: #002200;">:</span>fmt<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>fmtter stringFromDate<span style="color: #002200;">:</span>self<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">+</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSDate</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>dateFromString<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>str withFormat<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>fmt <span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">static</span> <span style="color: #400080;">NSDateFormatter</span> <span style="color: #002200;">*</span>fmtter;
&nbsp;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>fmtter <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        fmtter <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDateFormatter</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>fmt <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span> || <span style="color: #002200;">&#91;</span>fmt isEqualToString<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;&quot;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        fmt <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;HH:mm:ss&quot;</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
    <span style="color: #002200;">&#91;</span>fmtter setDateFormat<span style="color: #002200;">:</span>fmt<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>fmtter dateFromString<span style="color: #002200;">:</span>str<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>

<p>在这里，dataFromString 和 stringWithFormat 如果没有指定格式字符串参数的话，默认会使用 HH:mm:ss 来格式日期，当然，如果实际应用场景不一样，这里也可以修改。</p>
<p>如果需要更强大的功能，也可以去修改两个方法来符合自己的需要。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">// 获取当前时间的字符串</span>
<span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>now <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDate</span> date<span style="color: #002200;">&#93;</span> stringWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;HH:mm:ss&quot;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
<span style="color: #11740a; font-style: italic;">// 将一个字符串解析成 NSDate 对象</span>
NSStirng <span style="color: #002200;">*</span>recvTime <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;2010-05-25 16:58:34 +0800&quot;</span>;
<span style="color: #400080;">NSDate</span>  <span style="color: #002200;">*</span>recv <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDate</span> dateFromString<span style="color: #002200;">:</span>recvTime withFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;yyyy-MM-dd HH:mm:ss Z&quot;</span><span style="color: #002200;">&#93;</span>;</pre></div></div>

<p>使用 Category 给 NSDate 类添加这两个方法后，再要格式化日期或者解析日期时间字符串，就不需要额外去创建 NSDateFormatter 对象了，可以省不少力气。 </p>
<p><strong>参考资料</strong></p>
<ul>
<li><a href="http://stackoverflow.com/questions/399527/parsing-unsupported-date-formats-in-via-cocoas-nsdate">Parsing unsupported date formats in via Cocoa’s NSDate</a></li>
<li><a href="http://stackoverflow.com/questions/822417/why-cant-i-correctly-parse-this-date-string-with-nsdateformatter">Why can’t I correctly parse this date string with NSDateFormatter?</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.xujiwei.com/blog/2010/05/26/format-date-and-parse-date/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[Cocoa学习] 限制 NSTextField 中输入文本的长度</title>
		<link>http://www.xujiwei.com/blog/2010/05/25/limit-text-length-of-nstextfield/</link>
		<comments>http://www.xujiwei.com/blog/2010/05/25/limit-text-length-of-nstextfield/#comments</comments>
		<pubDate>Tue, 25 May 2010 07:36:39 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[NSTextField]]></category>

		<guid isPermaLink="false">http://www.xujiwei.com/blog/?p=299</guid>
		<description><![CDATA[需求 NSTextField 作为一个常用的输入控件，有些在使用时需要去限制其中可以输入文本的长度，而 NSTextField 本身并没有提供这个功能，这就需要我们自己去想办法来实现了。 方法 在网上找了一下，发现可以通过继承 NSFormatter 实现一个子类来实现这个功能，参考了一下找到的代码[1]，再将主要的 isPartialStringValid 方法根据自己的需要改了一下。 &#160; - &#40;BOOL&#41;isPartialStringValid:&#40;NSString **&#41;partialStringPtr proposedSelectedRange:&#40;NSRangePointer&#41;proposedSelRangePtr originalString:&#40;NSString *&#41;origString originalSelectedRange:&#40;NSRange&#41;origSelRange errorDescription:&#40;NSString **&#41;error &#123; int size = &#91;*partialStringPtr length&#93;; if &#40; size &#62; maxLength &#41; &#123; if &#40;origSelRange.location == &#91;origString length&#93;&#41; &#123; // 如果修改的位置在原来字符串的最后，则不做修改，只是拒绝内容修改 &#125; else &#123; // 如果修改的位置在原来字符串的中间，就根据剩余的可用的长度把新增加的字符串进行截取 int preLen = origSelRange.location + &#40;maxLength - &#91;origString <a href="http://www.xujiwei.com/blog/2010/05/25/limit-text-length-of-nstextfield/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<h4>需求</h4>
<p>NSTextField 作为一个常用的输入控件，有些在使用时需要去限制其中可以输入文本的长度，而 NSTextField 本身并没有提供这个功能，这就需要我们自己去想办法来实现了。</p>
<h4>方法</h4>
<p>在网上找了一下，发现可以通过继承 NSFormatter 实现一个子类来实现这个功能，参考了一下找到的代码<sup><a href="#ref-1">[1]</a></sup>，再将主要的 isPartialStringValid 方法根据自己的需要改了一下。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;">&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>isPartialStringValid<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">**</span><span style="color: #002200;">&#41;</span>partialStringPtr
       proposedSelectedRange<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>NSRangePointer<span style="color: #002200;">&#41;</span>proposedSelRangePtr
              originalString<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>origString
       originalSelectedRange<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">NSRange</span><span style="color: #002200;">&#41;</span>origSelRange
            errorDescription<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">**</span><span style="color: #002200;">&#41;</span>error 
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">int</span> size <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">*</span>partialStringPtr length<span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span> size &gt; maxLength <span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>origSelRange.location <span style="color: #002200;">==</span> <span style="color: #002200;">&#91;</span>origString length<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
            <span style="color: #11740a; font-style: italic;">// 如果修改的位置在原来字符串的最后，则不做修改，只是拒绝内容修改</span>
        <span style="color: #002200;">&#125;</span> <span style="color: #a61390;">else</span> <span style="color: #002200;">&#123;</span>
            <span style="color: #11740a; font-style: italic;">// 如果修改的位置在原来字符串的中间，就根据剩余的可用的长度把新增加的字符串进行截取</span>
            <span style="color: #a61390;">int</span> preLen <span style="color: #002200;">=</span> origSelRange.location <span style="color: #002200;">+</span> <span style="color: #002200;">&#40;</span>maxLength <span style="color: #002200;">-</span> <span style="color: #002200;">&#91;</span>origString length<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">+</span> origSelRange.length;
            <span style="color: #002200;">*</span>partialStringPtr <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> stringWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@%@&quot;</span>,
                                 <span style="color: #002200;">&#91;</span><span style="color: #002200;">*</span>partialStringPtr substringToIndex<span style="color: #002200;">:</span>preLen<span style="color: #002200;">&#93;</span>,
                                 <span style="color: #002200;">&#91;</span>origString substringFromIndex<span style="color: #002200;">:</span>origSelRange.location<span style="color: #002200;">+</span>origSelRange.length<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
            <span style="color: #002200;">&#40;</span><span style="color: #002200;">*</span>proposedSelRangePtr<span style="color: #002200;">&#41;</span>.location <span style="color: #002200;">=</span> preLen;
        <span style="color: #002200;">&#125;</span>
&nbsp;
        <span style="color: #a61390;">return</span> <span style="color: #a61390;">NO</span>;
    <span style="color: #002200;">&#125;</span>
    <span style="color: #a61390;">return</span> <span style="color: #a61390;">YES</span>;
<span style="color: #002200;">&#125;</span></pre></div></div>

<h4>参考资料</h4>
<ul>
<li id="ref-1"><a href="http://stackoverflow.com/questions/827014/how-to-limit-nstextfield-text-length-and-keep-it-always-upper-case">How to limit NSTextField text length and keep it always upper case?</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.xujiwei.com/blog/2010/05/25/limit-text-length-of-nstextfield/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在 REALbasic 中注册 AppleEvent</title>
		<link>http://www.xujiwei.com/blog/2010/01/31/register-appleevent-in-realbasic/</link>
		<comments>http://www.xujiwei.com/blog/2010/01/31/register-appleevent-in-realbasic/#comments</comments>
		<pubDate>Sun, 31 Jan 2010 06:37:19 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[AppleEvent]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[REALbasic]]></category>

		<guid isPermaLink="false">http://www.xujiwei.com/blog/?p=228</guid>
		<description><![CDATA[之前为了注册一个自定义协议，需要通过注册 AppleEvent 来实现，在 Objective-C 中，可以很方便的使用 NSAppleEventManager 来注册 AppleEvent 句柄，但是在 REALbaisc 中，是没有办法直接去调用 NSAppleEventManager 的，所以需要通过声明然后调用 C API 来实现相应的功能。 与 NSAppleEventManager 中功能相对应的 C API 有 AEInstallEventHandler, NewAEEventHandlerUPP 等，通过这些 API 我们也可以在 REALbasic 中来注册 AppleEvent 了，再配合 Info.plist 中的 URLScheme 声明，即可实现 URL 自定义协议处理句柄。 #if TargetCarbon soft declare function AEInstallEventHandler Lib CarbonLib ( _ theAEEventClass as Integer, _ theAEEventID as Integer, _ <a href="http://www.xujiwei.com/blog/2010/01/31/register-appleevent-in-realbasic/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>之前为了注册一个自定义协议，需要通过注册 AppleEvent 来实现，在 Objective-C 中，可以很方便的使用 NSAppleEventManager 来注册 AppleEvent 句柄，但是在 REALbaisc 中，是没有办法直接去调用 NSAppleEventManager 的，所以需要通过声明然后调用 C API 来实现相应的功能。</p>
<p>与 NSAppleEventManager 中功能相对应的 C API 有 AEInstallEventHandler, NewAEEventHandlerUPP 等，通过这些 API 我们也可以在 REALbasic 中来注册 AppleEvent 了，再配合 Info.plist 中的 URLScheme 声明，即可实现 URL 自定义协议处理句柄。</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">#if TargetCarbon
    soft <span style="color: #000080;">declare</span> <span style="color: #000080;">function</span> AEInstallEventHandler <span style="color: #000080;">Lib</span> CarbonLib ( _
    theAEEventClass <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span>, _
    theAEEventID <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span>, _
    handler <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span>, _
    handlerRefcon <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span>, _
    isSysHandler <span style="color: #000080;">as</span> <span style="color: #000080;">Boolean</span>) <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span>
&nbsp;
    Soft <span style="color: #000080;">Declare</span> <span style="color: #000080;">Function</span> NewAEEventHandlerUPP <span style="color: #000080;">Lib</span> CarbonLib (userRoutine <span style="color: #000080;">as</span> Ptr) <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span>
&nbsp;
    <span style="color: #000080;">Static</span> CallbackUPP <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span> = 0
    <span style="color: #000080;">If</span> CallbackUPP = 0 <span style="color: #000080;">then</span>
      <span style="color: #000080;">dim</span> m <span style="color: #000080;">as</span> MemoryBlock =  <span style="color: #000080;">AddressOf</span> ForwardCarbonAEEventToObject
      <span style="color: #000080;">If</span> m <span style="color: #000080;">is</span> nil <span style="color: #000080;">then</span>
        Return
      <span style="color: #000080;">End</span> <span style="color: #000080;">if</span>
      CallbackUPP = NewAEEventHandlerUPP(m)
    <span style="color: #000080;">End</span> <span style="color: #000080;">if</span>
&nbsp;
    <span style="color: #000080;">dim</span> v <span style="color: #000080;">as</span> <span style="color: #000080;">Variant</span> = me
&nbsp;
    <span style="color: #000080;">dim</span> OSError <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span> = AEInstallEventHandler( _
    OSTypeToUInt(kInternetEventClass), _
    OSTypeToUInt(kAEGetURL), _
    CallbackUPP, _
    v.Hash, <span style="color: #000080;">false</span>)
&nbsp;
    msgbox str(OSError)
#endif</pre></div></div>

<p>先使用 NewAEEventHandlerUPP 来生成一个 AppleEvent 回调函数的句柄，然后调用 AEInstallEventHandler 来注册一个共享函数 ForwardCarbonAEEventToObject 为 AppleEvent 事件处理句柄。</p>
<p>AEInstallEventHandler 所需的 AEEventClass 和 AEEventID 都是一个 4 字节的整型，但是通常我们在调用的时候，是用的一个 4 字符的字符串，因此需要一个函数来将 4 字符转换为 4 字节的整形。</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">// code from ToolbarSearchField by The ZAZ Studios
// http://www.thezaz.com/opensource/realbasic/macosx/searchfield/
<span style="color: #000080;">static</span> m <span style="color: #000080;">as</span> <span style="color: #000080;">new</span> MemoryBlock(4)
m.LittleEndian = <span style="color: #000080;">false</span>
m.StringValue(0, 4) = s
return m.UInt32Value(0)</pre></div></div>

<p>在 ForwardCartonAEEventToObject 里，参数 theEvent 和 replyEvent 都量个整形，为了从这两个参数里拿到数据，还需要使用 AEGetParamPtr 来从 AppleEvent 中拿到数据。</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">soft <span style="color: #000080;">declare</span> <span style="color: #000080;">function</span> AEGetParamPtr <span style="color: #000080;">lib</span> CarbonLib ( _
    theAppleEvent <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span>, theAEKeyword <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span>, _
    desiredType <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span>, <span style="color: #000080;">byref</span> actualType <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span>, _
    dataPtr <span style="color: #000080;">as</span> Ptr, maximumSize <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span>, _
    <span style="color: #000080;">byref</span> actualSize <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span>) <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span></pre></div></div>

<p>当然还有一系列的 AEGetDataDesc、AEGetDescSize 等函数可以，具体可以查 Xocde 随带的库文档。</p>
<p>关于注册自定义协议，可以参考<a href="http://stackoverflow.com/questions/49510/how-do-you-set-your-cocoa-application-as-the-default-web-browser">这篇文章</a>。</p>
<p>通过 Core Foundation 中的一些 C API，在 REALbasic 也可以完成一些平台相关的工作，虽然麻烦了些：）</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xujiwei.com/blog/2010/01/31/register-appleevent-in-realbasic/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>慎用 script 节点的 src 属性来传递参数</title>
		<link>http://www.xujiwei.com/blog/2009/11/13/avoid-pass-parameters-through-src/</link>
		<comments>http://www.xujiwei.com/blog/2009/11/13/avoid-pass-parameters-through-src/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 14:49:45 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=63</guid>
		<description><![CDATA[在有些使用 javascript 来渲染数据的时候，为了能动态获取不同的数据，并且保持 javascript 代码的可扩展性，会将 javascript 代码中获取数据的部分需要的参数提取出来，做为参数放在 script 节点的外部。 一般来说，传递参数到 javascript 文件内部的方法有两种，一种是将参数写在一个 script 节点中，写成全局变量的方式的传递给紧接着这个 script 节点的外部 javascript 中，Google Analytics 就是使用这样的方式： &#60;script type=&#34;text/javascript&#34;&#62; var p1 = &#34;v1&#34;, p2 = &#34;v2&#34;; &#60;/script&#62; &#60;script type=&#34;text/javascript&#34; src=&#34;foo.js&#34;&#62;&#60;/script&#62; 另外一种是将参数直接写在 script 节点的 src 属性中，相当于一个页面的查询字符串一样： &#60;script type=&#34;text/javascript&#34; src=&#34;foo.js?p1=v1&#38;p2=v2&#34;&#62;&#60;/script&#62; 不过，使用 script 节点的 src 属性来传递参数需要注意一个很重要的问题，那就是动态变化的 src 属性会导致缓存失效。 现在，为了网站性能的需要，一般都会将 javascript 文件放在独立的服务器上，并设置一个较长的过期时间，这样客户端只会在第一次访问网站时需要去下载这个 javascript 文件。但是，如果使用 src 来传递参数，就可能会使这种缓存策略失效。特别是 src 中存在动态参数的情况，例如统计脚本中如果有一个 ip 参数，那么访客每次连上线时，可能 ip 都会不同，就会导致 javascript 缓存失效了。 解决这个问题的方法也很简单，简单地的将 src 属性中的参数放到 script 节点的一个自定义属性中就可以了，例如 data-args，而 src 属性只需要保留一个时间戳就可以了。因为使用 src 属性来传递参数本来就需要定位 script 节点，所以改由 data-args 自定义属性来传递参数并不会增加额外的代码。只不过页面会通不过 w3c 的验证罢了 :) &#38;lt;script type=&#34;text/javascript&#34; src=&#34;foo.js&#34; data-args=&#34;p1=v1&#38;amp;p2=v2&#34;&#38;gt;&#38;lt;/script&#38;gt; 再次提醒，慎用 script 节点的 src 属性来传递参数 :)]]></description>
			<content:encoded><![CDATA[<p>在有些使用 javascript 来渲染数据的时候，为了能动态获取不同的数据，并且保持 javascript 代码的可扩展性，会将 javascript 代码中获取数据的部分需要的参数提取出来，做为参数放在 script 节点的外部。</p>
<p>一般来说，传递参数到 javascript 文件内部的方法有两种，一种是将参数写在一个 script 节点中，写成全局变量的方式的传递给紧接着这个 script 节点的外部 javascript 中，Google Analytics 就是使用这样的方式：</p>

<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;script <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text/javascript&quot;</span>&gt;</span>
var p1 = &quot;v1&quot;, p2 = &quot;v2&quot;;
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;</span>
<span style="color: #009900;">&lt;script <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;foo.js&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;</span></pre></div></div>

<p>另外一种是将参数直接写在 script 节点的 src 属性中，相当于一个页面的查询字符串一样：</p>

<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;script <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;foo.js?p1=v1&amp;p2=v2&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;</span></pre></div></div>

<p>不过，使用 script 节点的 src 属性来传递参数需要注意一个很重要的问题，那就是<strong>动态变化的 src 属性会导致缓存失效</strong>。</p>
<p>现在，为了网站性能的需要，一般都会将 javascript 文件放在独立的服务器上，并设置一个较长的过期时间，这样客户端只会在第一次访问网站时需要去下载这个 javascript 文件。但是，如果使用 src 来传递参数，就可能会使这种缓存策略失效。特别是 src 中存在动态参数的情况，例如统计脚本中如果有一个 ip 参数，那么访客每次连上线时，可能 ip 都会不同，就会导致 javascript 缓存失效了。</p>
<p>解决这个问题的方法也很简单，简单地的将 src 属性中的参数放到 script 节点的一个自定义属性中就可以了，例如 data-args，而 src 属性只需要保留一个时间戳就可以了。因为使用 src 属性来传递参数本来就需要定位 script 节点，所以改由 data-args 自定义属性来传递参数并不会增加额外的代码。只不过页面会通不过 w3c 的验证罢了 :)</p>

<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #ddbb00;">&amp;lt;</span>script type=&quot;text/javascript&quot; src=&quot;foo.js&quot; data-args=&quot;p1=v1<span style="color: #ddbb00;">&amp;amp;</span>p2=v2&quot;<span style="color: #ddbb00;">&amp;gt;&amp;lt;</span>/script<span style="color: #ddbb00;">&amp;gt;</span></pre></div></div>

<p>再次提醒，<strong>慎用</strong> script 节点的 src 属性来传递参数 :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xujiwei.com/blog/2009/11/13/avoid-pass-parameters-through-src/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>REALbasic 中使用结构体作为 Win32 API 的参数及使用 Win32 API 停止服务</title>
		<link>http://www.xujiwei.com/blog/2009/11/10/using-win32-api-in-realbasic/</link>
		<comments>http://www.xujiwei.com/blog/2009/11/10/using-win32-api-in-realbasic/#comments</comments>
		<pubDate>Tue, 10 Nov 2009 15:47:42 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[REALbasic]]></category>
		<category><![CDATA[Win32]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=65</guid>
		<description><![CDATA[在之前，我使用 ShellExecute 这个 API 来执行命令（《REALbasic 中使用 ShellExecute 执行命令》），然后通过这个方法来停止某个服务，但是今天想加服务运行状态检测，这样就可以在服务没有运行的情况下不再询问用户是否需要停止某个服务。 为了省事，我一开始决定同样使用 cmd 去执行一个命令，将服务状态输出到一个临时文件中，再通过读取这个临时文件，查找特征字符串来判断服务是否运行： // 伪代码 ShellExecute(&#34;cmd.exe /c sc query service_name &#38;gt; tmpfile&#34;) dim serviceStatus as string serviceStatus = TextInputStream.Open(tmpfile).ReadAll() if instr(serviceStatus, &#34;STOPPED&#34;) &#38;lt; 1 then // 提示用户是否停止服务 end if 但是这样做不太靠谱，因为 sc 这个命令执行是要时间的，而 ShellExecute 是异步的，这就导致了在调用 ShellExecute 执行完 sc query 之后，临时文件 tmpfile 里并不是马上就有服务状态的内容了。 为了防止这个情况，我再加了一个临时文件内容的检测，如果为空的话，sleep 100ms，再继续读取，如果超过 10 次仍没有内容，直接当作服务正在运行来对待。 // 伪代码 <a href="http://www.xujiwei.com/blog/2009/11/10/using-win32-api-in-realbasic/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>在之前，我使用 ShellExecute 这个 API 来执行命令（《REALbasic 中使用 ShellExecute 执行命令》），然后通过这个方法来停止某个服务，但是今天想加服务运行状态检测，这样就可以在服务没有运行的情况下不再询问用户是否需要停止某个服务。</p>
<p>为了省事，我一开始决定同样使用 cmd 去执行一个命令，将服务状态输出到一个临时文件中，再通过读取这个临时文件，查找特征字符串来判断服务是否运行：</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">// 伪代码
ShellExecute(<span style="color: #800000;">&quot;cmd.exe /c sc query service_name &amp;gt; tmpfile&quot;</span>)
<span style="color: #000080;">dim</span> serviceStatus <span style="color: #000080;">as</span> <span style="color: #000080;">string</span>
serviceStatus = TextInputStream.<span style="color: #000080;">Open</span>(tmpfile).ReadAll()
<span style="color: #000080;">if</span> instr(serviceStatus, <span style="color: #800000;">&quot;STOPPED&quot;</span>) &amp;lt; 1 <span style="color: #000080;">then</span>
  // 提示用户是否停止服务
<span style="color: #000080;">end</span> <span style="color: #000080;">if</span></pre></div></div>

<p>但是这样做不太靠谱，因为 sc 这个命令执行是要时间的，而 ShellExecute 是异步的，这就导致了在调用 ShellExecute 执行完 sc query 之后，临时文件 tmpfile 里并不是马上就有服务状态的内容了。</p>
<p>为了防止这个情况，我再加了一个临时文件内容的检测，如果为空的话，sleep 100ms，再继续读取，如果超过 10 次仍没有内容，直接当作服务正在运行来对待。</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">// 伪代码
ShellExecute(<span style="color: #800000;">&quot;cmd.exe /c sc query service_name &amp;gt; tmpfile&quot;</span>)
<span style="color: #000080;">dim</span> serviceStatus <span style="color: #000080;">as</span> <span style="color: #000080;">string</span>
<span style="color: #000080;">dim</span> tryCount <span style="color: #000080;">as</span> <span style="color: #000080;">integer</span>
<span style="color: #000080;">while</span> tryCount &amp;lt; 10 <span style="color: #000080;">and</span> serviceStatus = <span style="color: #800000;">&quot;&quot;</span>
  tryCount = tryCount + 1
  App.SleepCurrentThread(100)
  serviceStatus = TextInputStream.<span style="color: #000080;">Open</span>(tmpfile).ReadAll()
&nbsp;
wend
<span style="color: #000080;">if</span> instr(serviceStatus, <span style="color: #800000;">&quot;STOPPED&quot;</span>) &amp;lt; 1 <span style="color: #000080;">then</span>
  // 提示用户是否停止服务
<span style="color: #000080;">end</span> <span style="color: #000080;">if</span></pre></div></div>

<p>但是这样仍然不能百分百保证正确，于是想到可不可以继续用 win32 api 来做这些，Google 了一下，找到一篇博客[1]，看了之后发现如果只需要停止服务的话，还是蛮简单的，决定使用 win32 api 来实现我想要的功能了。</p>
<p>在停止服务这个过程中需要用到的 win32 api 有：OpenSCManagerW、OpenServiceW、QueryServiceStatus、ControlService，还有一个结构体：SERVICE_STATUS。</p>
<p>win32 api 的参数都很好对应，数值、句柄类型的参数直接使用 Integer 即可，字符串类型使用 CString，而 SERVICE_STATUS 这个结构体也可以直接通过工程菜单添加。</p>
<p>在传参的时候需要注意两点：</p>
<ol>
<li><strong>如果是字符串类型的参数并且调用的接口是 Unicode 类型的，那么需要在传入参数之前，将参数值转换为 Unicode 编码。可以通过 ConvertEncoding(text, Encodings.UTF16) 来转换。</strong></li>
<li><strong>如果参数是结构体，那么参数前的传参方式就要写 ByRef，也就是按引用传值，字符串和数值类型的参数可以不写或者写 ByVal。</strong></li>
</ol>
<p>以下是 4 个 win32 api 的 REALbasic 定义：</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">soft <span style="color: #000080;">declare</span> <span style="color: #000080;">function</span> OpenSCManagerW <span style="color: #000080;">Lib</span> <span style="color: #800000;">&quot;advapi32.dll&quot;</span> _
(<span style="color: #000080;">ByVal</span> lpMachineName <span style="color: #000080;">As</span> CString, <span style="color: #000080;">ByVal</span> lpDatabaseName <span style="color: #000080;">As</span> CString, _
<span style="color: #000080;">ByVal</span> dwDesiredAccess <span style="color: #000080;">As</span> <span style="color: #000080;">Integer</span>) <span style="color: #000080;">As</span> <span style="color: #000080;">Integer</span>
&nbsp;
soft <span style="color: #000080;">declare</span> <span style="color: #000080;">function</span> OpenServiceW <span style="color: #000080;">lib</span> <span style="color: #800000;">&quot;advapi32.dll&quot;</span> _
(<span style="color: #000080;">ByVal</span> hSCManager <span style="color: #000080;">As</span> <span style="color: #000080;">Integer</span>, <span style="color: #000080;">ByVal</span> lpServiceName <span style="color: #000080;">As</span> CString, _
<span style="color: #000080;">ByVal</span> dwDesiredAccess <span style="color: #000080;">As</span> <span style="color: #000080;">Integer</span>) <span style="color: #000080;">As</span> <span style="color: #000080;">Integer</span>
&nbsp;
soft <span style="color: #000080;">declare</span> <span style="color: #000080;">function</span> QueryServiceStatus <span style="color: #000080;">lib</span> <span style="color: #800000;">&quot;advapi32.dll&quot;</span> _
(<span style="color: #000080;">byval</span> hService <span style="color: #000080;">as</span> <span style="color: #000080;">integer</span>, <span style="color: #000080;">byref</span> lpServiceStatus <span style="color: #000080;">as</span> SERVICE_STATUS) _
<span style="color: #000080;">as</span> <span style="color: #000080;">boolean</span>
&nbsp;
soft <span style="color: #000080;">declare</span> <span style="color: #000080;">function</span> ControlService <span style="color: #000080;">lib</span> <span style="color: #800000;">&quot;advapi32.dll&quot;</span> _
(<span style="color: #000080;">byval</span> hService <span style="color: #000080;">as</span> <span style="color: #000080;">integer</span>, <span style="color: #000080;">byval</span> dwControl <span style="color: #000080;">as</span> <span style="color: #000080;">integer</span>, _
<span style="color: #000080;">byref</span> lpServiceStatus <span style="color: #000080;">as</span> SERVICE_STATUS) <span style="color: #000080;">as</span> <span style="color: #000080;">boolean</span></pre></div></div>

<p>有了 api 定义之后，就可以直接根据上面提到的 vc++ 流程来停止某个服务了。</p>
<p>完整的服务操作 api 可以参阅微软的 MSDN。</p>
<p>这样看来，REALbasic 要写出支持 Windows 7 特性的应用程序也不是难事：）</p>
<p><strong>参数资料</strong></p>
<ol>
<li><a rel="external" href="http://blog.csdn.net/huangchonghai/archive/2007/04/25/1583602.aspx">VC++启动和停止服务</a>, huangchonghai</li>
<li><a rel="external" href="http://msdn.microsoft.com/en-us/library/ms684939(VS.85).aspx">QueryServiceStatus</a>, MSDN</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.xujiwei.com/blog/2009/11/10/using-win32-api-in-realbasic/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于 REALbasic 中使用 AutoDiscovery 时发生错误 40 的问题</title>
		<link>http://www.xujiwei.com/blog/2009/11/02/%e5%85%b3%e4%ba%8e-realbasic-%e4%b8%ad%e4%bd%bf%e7%94%a8-autodiscovery-%e6%97%b6%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af-40-%e7%9a%84%e9%97%ae%e9%a2%98/</link>
		<comments>http://www.xujiwei.com/blog/2009/11/02/%e5%85%b3%e4%ba%8e-realbasic-%e4%b8%ad%e4%bd%bf%e7%94%a8-autodiscovery-%e6%97%b6%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af-40-%e7%9a%84%e9%97%ae%e9%a2%98/#comments</comments>
		<pubDate>Sun, 01 Nov 2009 16:12:14 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[AutoDiscovery]]></category>
		<category><![CDATA[REALbasic]]></category>
		<category><![CDATA[UDP]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=70</guid>
		<description><![CDATA[今天在使用 AutoDiscovery 发送数据时，发生了错误码为 40 的错误，直接在 UDPSocket 的属性列表里找了一下，没有找到对应的错误码。 在网上搜了一下，找到这篇帖子，里面提到在发送大量数据时，UDPSocket 就会报错误，并且这个错误没有在文档中提到，因此这应该是一个系统级别的错误。 MonkeybreadSoftware 提到了 unix 的错误码定义： #define    EMSGSIZE    40     /* Message too long */ 联想到在程序中是在今天开始有问题的，而且今天添加了一大堆数据，看来的确是同于 UDP 消息过大造成的错误 40。 在网上找了找，使用 UDP 发送消息时，报文的大小最好不要超过 MTU，否则会就容易丢包。我在测试时是使用的 127.0.0.1，包大小为 12.5K，照理说应该是直接走 loopback 而不需要走路由的，就算超过 MTU 也应该能发送，不清楚是不是因为 OS 内部实现机制的问题。 为了彻底解决这个问题，最后还是采用了 TCP 来传递大量数据，只使用 UDP 来传递一些控制信息。]]></description>
			<content:encoded><![CDATA[<p>今天在使用 AutoDiscovery 发送数据时，发生了错误码为 40 的错误，直接在 UDPSocket 的属性列表里找了一下，没有找到对应的错误码。</p>
<p>在网上搜了一下，找到<a rel="external" href="http://forums.realsoftware.com/viewtopic.php?f=2&amp;t=25418">这篇帖子</a>，里面提到在发送大量数据时，UDPSocket 就会报错误，并且这个错误没有在文档中提到，因此这应该是一个系统级别的错误。</p>
<p>MonkeybreadSoftware 提到了 unix 的错误码定义：</p>
<blockquote><p>#define    EMSGSIZE    40     /* Message too long */</p></blockquote>
<p>联想到在程序中是在今天开始有问题的，而且今天添加了一大堆数据，看来的确是同于 UDP 消息过大造成的错误 40。</p>
<p>在网上找了找，使用 UDP 发送消息时，报文的大小最好不要超过 <a rel="external" href="http://en.wikipedia.org/wiki/Maximum_transmission_unit">MTU</a>，否则会就容易丢包。我在测试时是使用的 127.0.0.1，包大小为 12.5K，照理说应该是直接走 loopback 而不需要走路由的，就算超过 MTU 也应该能发送，不清楚是不是因为 OS 内部实现机制的问题。</p>
<p>为了彻底解决这个问题，最后还是采用了 TCP 来传递大量数据，只使用 UDP 来传递一些控制信息。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xujiwei.com/blog/2009/11/02/%e5%85%b3%e4%ba%8e-realbasic-%e4%b8%ad%e4%bd%bf%e7%94%a8-autodiscovery-%e6%97%b6%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af-40-%e7%9a%84%e9%97%ae%e9%a2%98/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在 AIR 中突破同源策略访问 iframe 中的内容</title>
		<link>http://www.xujiwei.com/blog/2009/10/26/access-iframe-in-air/</link>
		<comments>http://www.xujiwei.com/blog/2009/10/26/access-iframe-in-air/#comments</comments>
		<pubDate>Mon, 26 Oct 2009 12:20:15 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[AIR]]></category>
		<category><![CDATA[iframe]]></category>
		<category><![CDATA[Sandbox]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=139</guid>
		<description><![CDATA[本篇所讲关于 AIR 的内容是基本 HTML+JS，而不是 Flex 或其他。 在 AIR 中，如果当前页面有一个 iframe，并且我们需要获取这个 iframe 的内容，但是如果 iframe 里包含的是远程页面，在默认情况下，浏览器策略并不允许这种情况，这就是同源策略的限制。 在 Titanium 这个类似于 AIR 的平台中，默认情况下是可以直接从应用的页面中去读取 iframe 中的内容而没有任何限制，但是在 AIR 中不可以。在网上搜索了一番，再看了好几遍 AIR 的文档之后，终于找到解决问题的方法了。 在 AIR 中，iframe 标签拥有额外的几个属性：sandboxRoot、documentRoot、allowCrossDomainXHR 及 ondominitialize。这里为了解决读取 iframe 内容所用到的属性就是 sandboxRoot 及 documentRoot。 通过 sandboxRoot 及 documentRoot，可以将本地的页面映射为远程页面，并在沙盒中运行，另外，在沙盒中运行的页面就会拥有映射域名的域。例如，我们可以将本地的 proxy.html 映射为 http://example.com/local/proxy.html，这样，在实际运行时，proxy.html 中如果用 document.domain 获取页面所在的域，就会得到 example.com，这个时候如果在 proxy.html 中添加一个 iframe，这个 iframe 指向我们实际需要获取内容的地址，因为域相同，就可以直接获取 iframe 的内容了。 例如，我们要在 AIR 中获取 http://example.com/member/login.html 的内容，或者操作这个页面的元素，就可以先用一个 proxy.html，用来实现将本地文件运行在沙盒中，再用一个 login.html 来对实际网页进行操作。 &#60;!&#8211; proxy.html &#8211;&#62; &#60;iframe src=&#8221;http://example.com/local/login.html&#8221; id=&#8221;frame&#8221; width=&#8221;100%&#8221; sandboxRoot=&#8221;http://example.com/local/&#8221; documentRoot=&#8221;app:/&#8221; name=&#8221;frame&#8221; height=&#8221;100%&#8221;&#62;&#60;/iframe&#62; &#60;!&#8211; login.html &#8211;&#62; &#60;iframe id=&#8217;f' frameborder=&#8221;0&#8243; scrolling=&#8221;no&#8221; src=&#8221;http://example.com/member/login.html&#8221; width=&#8221;100%&#8221; height=&#8221;100%&#8221;&#62;&#60;/iframe&#62; &#60;script type=&#8221;text/javascript&#8221;&#62; alert(document.domain); var f = document.getElementById(&#8216;f&#8217;); f.onload = function() { alert(f.contentWindow.document.documentElement.innerHTML); }; &#60;/script&#62; 在 proxy.html 中，虽然 iframe 的 src 属性是 http://example.com/locale/login.html，但是由于这个 iframe 具有 sandboxRoot 属性，所以实际请求会被重定向到相对于 sandboxRoot，并且使用 documentRoot 进行定位的实际地址 app://login.html，但是这个时候 login.html 中具有  document.domain=&#8221;example.com&#8221; 这个属性，所有可以直接使用 iframe.contentWindow 来访问 iframe 中的内容。 虽然解决方法有些麻烦，但终归可以实现突破同源策略的限制来读取 iframe 的内容了。 当然，如果你有更好的方法，请不吝赐教：）]]></description>
			<content:encoded><![CDATA[<div class="post-content">
<p>本篇所讲关于 AIR 的内容是基本 HTML+JS，而不是 Flex 或其他。</p>
<p>在 <a rel="external" href="get.adobe.com/air/">AIR</a> 中，如果当前页面有一个 iframe，并且我们需要获取这个 iframe 的内容，但是如果 iframe 里包含的是远程页面，在默认情况下，浏览器策略并不允许这种情况，这就是同源策略的限制。</p>
<p>在 <a rel="external" href="http://www.appcelerator.com">Titanium</a> 这个类似于 AIR 的平台中，默认情况下是可以直接从应用的页面中去读取 iframe 中的内容而没有任何限制，但是在 AIR 中不可以。在网上搜索了一番，再看了好几遍 AIR 的文档之后，终于找到解决问题的方法了。</p>
<p>在 AIR 中，<a rel="external" href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7eb2.html#WS5b3ccc516d4fbf351e63e3d118666ade46-7edb">iframe 标签拥有额外的几个属性</a>：sandboxRoot、documentRoot、allowCrossDomainXHR 及 ondominitialize。这里为了解决读取 iframe 内容所用到的属性就是 sandboxRoot 及 documentRoot。</p>
<p>通过 sandboxRoot 及 documentRoot，可以将本地的页面映射为远程页面，并在沙盒中运行，另外，在沙盒中运行的页面就会拥有映射域名的域。例如，我们可以将本地的 proxy.html 映射为 http://example.com/local/proxy.html，这样，在实际运行时，proxy.html 中如果用 document.domain 获取页面所在的域，就会得到 example.com，这个时候如果在 proxy.html 中添加一个 iframe，这个 iframe 指向我们实际需要获取内容的地址，因为域相同，就可以直接获取 iframe 的内容了。</p>
<p>例如，我们要在 AIR 中获取 http://example.com/member/login.html 的内容，或者操作这个页面的元素，就可以先用一个 proxy.html，用来实现将本地文件运行在沙盒中，再用一个 login.html 来对实际网页进行操作。</p>
<blockquote>
<div id="CODE_6635" class="codeMain"><span style="font-style: normal;">&lt;!&#8211; proxy.html &#8211;&gt;<br />
&lt;iframe src=&#8221;http://example.com/local/login.html&#8221; id=&#8221;frame&#8221; width=&#8221;100%&#8221;<br />
sandboxRoot=&#8221;http://example.com/local/&#8221;<br />
documentRoot=&#8221;app:/&#8221; name=&#8221;frame&#8221; height=&#8221;100%&#8221;&gt;&lt;/iframe&gt;</span></div>
</blockquote>
<blockquote>
<div id="CODE_4316" class="codeMain">
<ul></ul>
<p><em><span style="font-style: normal;">&lt;!&#8211; login.html &#8211;&gt;</span></em><span style="font-style: normal;"><br />
</span><em><span style="font-style: normal;">&lt;iframe id=&#8217;f' frameborder=&#8221;0&#8243; scrolling=&#8221;no&#8221;</span></em><span style="font-style: normal;"><br />
</span><em><span style="font-style: normal;"> src=&#8221;http://example.com/member/login.html&#8221; </span></em><span style="font-style: normal;"><br />
</span><em><span style="font-style: normal;"> width=&#8221;100%&#8221; height=&#8221;100%&#8221;&gt;&lt;/iframe&gt;</span></em><span style="font-style: normal;"><br />
</span><em><span style="font-style: normal;">&lt;script type=&#8221;text/javascript&#8221;&gt;</span></em><span style="font-style: normal;"><br />
</span><em><span style="font-style: normal;">alert(document.domain);</span></em><span style="font-style: normal;"><br />
</span><em><span style="font-style: normal;">var f = document.getElementById(&#8216;f&#8217;);</span></em><span style="font-style: normal;"><br />
</span><em><span style="font-style: normal;">f.onload = function() {</span></em><span style="font-style: normal;"><br />
</span><em><span style="font-style: normal;"> alert(f.contentWindow.document.documentElement.innerHTML);</span></em><span style="font-style: normal;"><br />
</span><em><span style="font-style: normal;">};</span></em><span style="font-style: normal;"><br />
</span><em><span style="font-style: normal;">&lt;/script&gt;</span></em></div>
</blockquote>
<p>在 proxy.html 中，虽然 iframe 的 src 属性是 http://example.com/locale/login.html，但是由于这个 iframe 具有 sandboxRoot 属性，所以实际请求会被重定向到相对于 sandboxRoot，并且使用 documentRoot 进行定位的实际地址 app://login.html，但是这个时候 login.html 中具有  document.domain=&#8221;example.com&#8221; 这个属性，所有可以直接使用 iframe.contentWindow 来访问 iframe 中的内容。</p>
<p>虽然解决方法有些麻烦，但终归可以实现突破同源策略的限制来读取 iframe 的内容了。</p>
<p>当然，如果你有更好的方法，请不吝赐教：）</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.xujiwei.com/blog/2009/10/26/access-iframe-in-air/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用 arguments.caller 实现自动回调</title>
		<link>http://www.xujiwei.com/blog/2009/10/25/autocallback-by-arguments-caller/</link>
		<comments>http://www.xujiwei.com/blog/2009/10/25/autocallback-by-arguments-caller/#comments</comments>
		<pubDate>Sun, 25 Oct 2009 01:36:31 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[Arguments]]></category>
		<category><![CDATA[Callback]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=141</guid>
		<description><![CDATA[这是一篇介绍类似于 js hack 的文章，只是说明了一种可行的途径，并且可能会增加代码复杂程度，具体项目中是否可以使用还请自辨：） 在前端开发过程中，有许多业务流程可能是需要用户进行登录的，并且登录过程是放在弹出层中，这样就可以不用刷新页面，增强用户体验。在登录时，用户的操作就会被打断，为了进一步增强用户体验，我们可能需要在登录完成后自动继续进行用户在登录前想进行的操作。 假设有这样一个场景，用户需要发表一个留言，但是发表留言是需要登录的，而发表留言的输入框是一直显示的，这也就要求在用户点击了发表按钮时对用户登录状态进行验证，传统的做法是将在用户登录状态检查封装在一个函数之中，这个函数接收一个回调参数，如果登录验证通过，则执行回调函数。这样的逻辑可以用以下代码表示： 程序代码：[ 复制代码到剪贴板 ] function doAction() { checkLogin(function() { // 处理业务逻辑 }); } function checkLogin(callback) { if (isLogin) { callback(); } else { showLogin(callback); } } function showLogin(callback) { document.getElementById(&#8220;login-btn&#8221;).onclick = function() { isLogin = true; callback(); }; } 总觉得这样的方式会将业务逻辑放到一个匿名函数中，而不是放在了按钮的事件响应函数中，感觉上不是那么好。这对整个事件响应函数的改动比较大，主要的业务逻辑都放在了登录验证函数的回调中。而希望可以是下面这样： 程序代码：[ 复制代码到剪贴板 ] function doAction() { // 直接在函数开始进行登录验证，将业务逻辑独立出来 if (!doLogin()) { return; } // 处理业务逻辑 } function doLogin() { if (isLogin) { return true; } else { var callback = function() {}; // 自动组装 callback showLogin(callback); return false; } } function showLogin(callback) { document.getElementById(&#8220;login-btn&#8221;).onclick = function() { isLogin = true; callback(); }; } 这里的关键在于怎么“自动组装 callback”，很幸运的是，JavaScript 的 Function 提供了一个属性 caller 可以用来获取调用当前函数的函数是什么。并且还可以用 caller 的 arguments 属性来获取 caller 执行时的参数是什么，这也就使我们自动组装 callback 并恢复 caller 的原参数成为可能。 &#60;div id=&#8221;result&#8221;&#62;&#60;/div&#62; &#60;input type=&#8221;button&#8221; <a href="http://www.xujiwei.com/blog/2009/10/25/autocallback-by-arguments-caller/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<div class="post-content">
<p>这是一篇介绍类似于 js hack 的文章，只是说明了一种可行的途径，并且可能会增加代码复杂程度，具体项目中是否可以使用还请自辨：）</p>
<p>在前端开发过程中，有许多业务流程可能是需要用户进行登录的，并且登录过程是放在弹出层中，这样就可以不用刷新页面，增强用户体验。在登录时，用户的操作就会被打断，为了进一步增强用户体验，我们可能需要在登录完成后自动继续进行用户在登录前想进行的操作。</p>
<p>假设有这样一个场景，用户需要发表一个留言，但是发表留言是需要登录的，而发表留言的输入框是一直显示的，这也就要求在用户点击了发表按钮时对用户登录状态进行验证，传统的做法是将在用户登录状态检查封装在一个函数之中，这个函数接收一个回调参数，如果登录验证通过，则执行回调函数。这样的逻辑可以用以下代码表示：</p>
<div class="codeHead">程序代码：<a href="javascript:CopyText($('CODE_4316'));">[ 复制代码到剪贴板 ]</a></div>
<blockquote>
<div id="CODE_4316" class="codeMain"><span style="font-style: normal;">function doAction() {<br />
checkLogin(function() {<br />
// 处理业务逻辑<br />
});<br />
}<br />
function checkLogin(callback) {<br />
if (isLogin) {<br />
callback();<br />
} else {<br />
showLogin(callback);<br />
}<br />
}<br />
function showLogin(callback) {<br />
document.getElementById(&#8220;login-btn&#8221;).onclick = function() {<br />
isLogin = true;<br />
callback();<br />
};<br />
}</span></p>
<ul></ul>
</div>
</blockquote>
<p>总觉得这样的方式会将业务逻辑放到一个匿名函数中，而不是放在了按钮的事件响应函数中，感觉上不是那么好。这对整个事件响应函数的改动比较大，主要的业务逻辑都放在了登录验证函数的回调中。而希望可以是下面这样：</p>
<div class="codeHead">程序代码：<a href="javascript:CopyText($('CODE_4415'));">[ 复制代码到剪贴板 ]</a></div>
<blockquote>
<div id="CODE_4415" class="codeMain"><span style="font-style: normal;">function doAction() {<br />
// 直接在函数开始进行登录验证，将业务逻辑独立出来<br />
if (!doLogin()) {<br />
return;<br />
}<br />
// 处理业务逻辑<br />
}<br />
function doLogin() {<br />
if (isLogin) {<br />
return true;<br />
} else {<br />
var callback = function() {}; // 自动组装 callback<br />
showLogin(callback);<br />
return false;<br />
}<br />
}<br />
function showLogin(callback) {<br />
document.getElementById(&#8220;login-btn&#8221;).onclick = function() {<br />
isLogin = true;<br />
callback();<br />
};<br />
}</span></p>
<ul></ul>
</div>
</blockquote>
<p>这里的关键在于怎么“自动组装 callback”，很幸运的是，JavaScript 的 Function 提供了一个属性 caller 可以用来获取调用当前函数的函数是什么。并且还可以用 caller 的 arguments 属性来获取 caller 执行时的参数是什么，这也就使我们自动组装 callback 并恢复 caller 的原参数成为可能。</p>
<blockquote>
<p style="text-align: auto;">
<p><span style="font-family: 'Lucida Grande', 'Lucida Sans Unicode', Arial, Helvetica, Sans, FreeSans, Jamrul, Garuda, Kalimati; color: #000000;"></p>
<div id="_mcePaste">
<div id="_mcePaste"><span style="font-style: normal;">&lt;div id=&#8221;result&#8221;&gt;&lt;/div&gt;</span></div>
<div id="_mcePaste"><span style="font-style: normal;">&lt;input type=&#8221;button&#8221; value=&#8221;Sumit&#8221; onclick=&#8221;sendPost()&#8221; id=&#8221;post&#8221; /&gt;</span></div>
<div id="_mcePaste"><span style="font-style: normal;">&lt;input type=&#8221;button&#8221; value=&#8221;Clear login&#8221; onclick=&#8221;isLogin=false&#8221; id=&#8221;reset&#8221; /&gt;</span></div>
<div id="_mcePaste"><span style="font-style: normal;">&lt;div id=&#8217;login&#8217; style=&#8221;border:1px solid #000;padding:10px;margin:10px;display:none&#8221;&gt;</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> &lt;strong&gt;Login&lt;/strong&gt;&lt;br /&gt;</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> &lt;input type=&#8221;button&#8221; id=&#8217;loginbtn&#8217; value=&#8221;Login&#8221; /&gt;</span></div>
<div id="_mcePaste"><span style="font-style: normal;">&lt;/div&gt;</span></div>
<div id="_mcePaste"><span style="font-style: normal;">&lt;script type=&#8221;text/javascript&#8221;&gt;</span></div>
<div id="_mcePaste"><span style="font-style: normal;">// 是否登录</span></div>
<div id="_mcePaste"><span style="font-style: normal;">var isLogin = false;</span></div>
<div id="_mcePaste"><span style="font-style: normal;">// 检查登录状态</span></div>
<div id="_mcePaste"><span style="font-style: normal;">var checkLogin = function(cfg) {</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> if (isLogin) {</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> return true;</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> }</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> cfg = cfg || {};</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> var callback = null;</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> // 自动执行回调</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> if (cfg.autoCallback &amp;&amp; arguments.callee.caller) {</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> try {</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> var caller  = arguments.callee.caller,</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> args    = caller.arguments || [],</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> scope   = cfg.callbackScope || {},</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> newArgs = [];</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> for (var i = 0; i &lt; args.length; ++i) {</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> newArgs.push(args[i]);</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> }</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> callback = caller ? function() {</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> try {</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> caller &amp;&amp; caller.apply(scope, newArgs);</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> } catch (e) {</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> //alert(e.message);</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> }</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> } : null;</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> } catch (e) {</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> callback = null;</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> }</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> }</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> </span></div>
<div id="_mcePaste"><span style="font-style: normal;"> showLogin(callback);</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> </span></div>
<div id="_mcePaste"><span style="font-style: normal;"> return false;</span></div>
<div id="_mcePaste"><span style="font-style: normal;">};</span></div>
<div id="_mcePaste"><span style="font-style: normal;">function sendPost() {</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> if (!checkLogin({autoCallback:true})) {</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> return;</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> }</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> </span></div>
<div id="_mcePaste"><span style="font-style: normal;"> document.getElementById(&#8216;result&#8217;).innerHTML += &#8216;Hello&lt;br /&gt;&#8217;;</span></div>
<div id="_mcePaste"><span style="font-style: normal;">}</span></div>
<div id="_mcePaste"><span style="font-style: normal;">function showLogin(callback) {</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> document.getElementById(&#8216;login&#8217;).style.display = &#8216;;</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> document.getElementById(&#8216;loginbtn&#8217;).onclick = function() {</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> document.getElementById(&#8216;login&#8217;).style.display = &#8216;none&#8217;;</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> isLogin = true;</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> callback &amp;&amp; callback();</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> }</span></div>
<div id="_mcePaste"><span style="font-style: normal;">}</span></div>
<div id="_mcePaste"><span style="font-style: normal;">&lt;/script&gt;</span></div>
</div>
<p></span></p></blockquote>
<p>其实弄出这么个方法来实现登录自动回调也是为了方便写代码，不用每次去将一堆业务逻辑放到 callback 中，直接在函数开始回一个 if (!checkLogin({autoCallback:true})) 就行。</p>
<p>caller 属性在 MDC 中被标记为“非标准”的，但是在主流浏览器中，都是支持这个属性的，也就是说，在浏览器兼容性上使用 caller 是没有问题的。</p>
<p>不过，使用奇技淫巧容易伤身体，慎用：）</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.xujiwei.com/blog/2009/10/25/autocallback-by-arguments-caller/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>REALbasic 中使用 ShellExecute 执行命令</title>
		<link>http://www.xujiwei.com/blog/2009/10/16/using-shellexecute-in-realbasic/</link>
		<comments>http://www.xujiwei.com/blog/2009/10/16/using-shellexecute-in-realbasic/#comments</comments>
		<pubDate>Fri, 16 Oct 2009 13:50:40 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[REALbasic]]></category>
		<category><![CDATA[ShellExecute]]></category>
		<category><![CDATA[Win32]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=72</guid>
		<description><![CDATA[在 REALbasic 中，如果需要执行 cmd 命令，可以直接使用 Shell 类，但是这样的话，编译成 Windows 程序时会额外需要一个 Shell.dll 的动态链接库，这对于我这样的 1exe 爱好者是不能忍受的。但是对于 Mac OS X 和 Linux 的生成目标来说，是不存在这个问题的，因为 Mac OS X 的应用程序本身就是一个文件夹，而 Linux 的目标不会生成额外的链接库。因此，需要针对 Windows 进行特殊处理。于是在网上搜索解决方案，找到了 VB 中执行程序的几种方法： 1. 使用 CreateProcess 通过 CreateProcess 以及使用管道，可以执行外部程序并获取输出，但是这个方法过于烦琐，并且我也不需要外部进程执行完毕后的输出结果，因此不采用。 2. 使用 Shell 方法 VB 里有一个 Shell 方法，但是在 RB 中并没有，所以此路不通。 3. 使用 ShellExecute 这个方法同样是一个系统 API，可以直接通过 RB 的 declare 声明并调用它，在测试之后，使用 declare 来使用系统 API 不会生成额外的 dll，正是我需要的。 首先在 RB 的某个模块中添加一个方法 ShellExecute，用来封装对系统 API 的请求： function ShellExecute(hWnd as Integer, lpOperation as String, _ lpFile as String, lpParameters as String, lpDirectory as String, nShowCmd as Integer) 注意，在 RB 中添加方法时，参数列表中的 _ 需要去掉，这里是为了排版的需要而加上的。 这个 API 是定义在 shell32.dll 中的，在 ShellExecute 方法中先需要声明： soft declare function ShellExecuteA Lib &#8221;shell32.dll&#8221; _ (ByVal hWnd As Integer, ByVal lpOperation As CString, _ ByVal lpFile As CString, ByVal lpParameters As CString, _ ByVal lpDirectory As CString, ByVal nShowCmd As Integer) As Integer soft declare function ShellExecuteW Lib &#8221;shell32.dll&#8221; _ (ByVal hWnd As Integer, ByVal lpOperation As CString, _ ByVal lpFile As CString, ByVal lpParameters As CString, _ ByVal lpDirectory As CString, ByVal nShowCmd As Integer) As Integer 然后来调用这个 API： dim ret as Integer Try ret = ShellExecuteW(hWnd, ConvertEncoding(lpOperation, Encodings.UTF16), _ ConvertEncoding(lpFile, Encodings.UTF16), _ ConvertEncoding(lpParameters, Encodings.UTF16), _ ConvertEncoding(lpDirectory, Encodings.UTF16), nShowCmd) Catch ret = ShellExecuteA(hWnd, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd) End return ret 把 <a href="http://www.xujiwei.com/blog/2009/10/16/using-shellexecute-in-realbasic/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>在 REALbasic 中，如果需要执行 cmd 命令，可以直接使用 Shell 类，但是这样的话，编译成 Windows 程序时会额外需要一个 Shell.dll 的动态链接库，这对于我这样的 1exe 爱好者是不能忍受的。但是对于 Mac OS X 和 Linux 的生成目标来说，是不存在这个问题的，因为 Mac OS X 的应用程序本身就是一个文件夹，而 Linux 的目标不会生成额外的链接库。因此，需要针对 Windows 进行特殊处理。于是在网上搜索解决方案，找到了 VB 中执行程序的几种方法：</p>
<p><strong>1. 使用 CreateProcess</strong></p>
<p>通过 CreateProcess 以及使用管道，可以执行外部程序并获取输出，但是这个方法过于烦琐，并且我也不需要外部进程执行完毕后的输出结果，因此不采用。</p>
<p><strong>2. 使用 Shell 方法</strong></p>
<p>VB 里有一个 Shell 方法，但是在 RB 中并没有，所以此路不通。</p>
<p><strong>3. 使用 ShellExecute</strong></p>
<p>这个方法同样是一个系统 API，可以直接通过 RB 的 declare 声明并调用它，在测试之后，使用 declare 来使用系统 API 不会生成额外的 dll，正是我需要的。</p>
<p>首先在 RB 的某个模块中添加一个方法 ShellExecute，用来封装对系统 API 的请求：</p>
<blockquote><p>function ShellExecute(hWnd as Integer, lpOperation as String, _<br />
lpFile as String, lpParameters as String, lpDirectory as String, nShowCmd as Integer)</p></blockquote>
<p>注意，在 RB 中添加方法时，参数列表中的 _ 需要去掉，这里是为了排版的需要而加上的。</p>
<p>这个 API 是定义在 shell32.dll 中的，在 ShellExecute 方法中先需要声明：</p>
<blockquote><p>soft declare function ShellExecuteA Lib &#8221;shell32.dll&#8221; _<br />
(ByVal hWnd As Integer, ByVal lpOperation As CString, _<br />
ByVal lpFile As CString, ByVal lpParameters As CString, _<br />
ByVal lpDirectory As CString, ByVal nShowCmd As Integer) As Integer</p>
<p>soft declare function ShellExecuteW Lib &#8221;shell32.dll&#8221; _<br />
(ByVal hWnd As Integer, ByVal lpOperation As CString, _<br />
ByVal lpFile As CString, ByVal lpParameters As CString, _<br />
ByVal lpDirectory As CString, ByVal nShowCmd As Integer) As Integer</p></blockquote>
<p>然后来调用这个 API：</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">  <span style="color: #000080;">dim</span> ret <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span>
    Try
      ret = ShellExecuteW(hWnd, ConvertEncoding(lpOperation, Encodings.UTF16), _
      ConvertEncoding(lpFile, Encodings.UTF16), _
      ConvertEncoding(lpParameters, Encodings.UTF16), _
      ConvertEncoding(lpDirectory, Encodings.UTF16), nShowCmd)
    Catch
      ret = ShellExecuteA(hWnd, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd)
    <span style="color: #000080;">End</span>
    return ret</pre></div></div>

<p>把 ShellExecuteW 放在 Try &#8230; Catch 中是为了兼容的需要，因为像 Windows 98 这样比较老的系统中，系统内部编码还不是 Unicode，还没有 ShellExecuteW 这样结尾是 W 的 API。</p>
<p>另外，因为 RB 内部是使用的 UTF-8 编码，而系统 API ShellExecuteW 使用的编码是 Unicode，所以参数在传递前需要进行转码，将字符串参数值转换为 Unicode 编码，否则在执行一个明明正确的命令时，会出现“找不到文件”的错误。</p>
<p>好了，这样就可以使用 ShellExecute 方法来执行外部程序了，例如：</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">  #if TargetWin32
    <span style="color: #000080;">dim</span> ret <span style="color: #000080;">as</span> <span style="color: #000080;">Integer</span>
    ret = Win32Helper.ShellExecute(hWnd, <span style="color: #800000;">&quot;open&quot;</span>, <span style="color: #800000;">&quot;cmd.exe&quot;</span>, _
    <span style="color: #800000;">&quot;/c shutdown -t 10&quot;</span>, <span style="color: #800000;">&quot;&quot;</span>, 0)
  #endif</pre></div></div>

<p>上面的代码就调用 cmd.exe 执行了命令 shutdown -s -t 10，也就是 10 秒后关机。</p>
<p>其实这个方法也可以用来打开文档或者网址，具体的用法可以去 MSDN 找一找。</p>
<p>当然，如果不在乎生成的 Windows 目标还有额外的 dll 的话，完全可以使用 RB 自带的 Shell 类，功能也强上不少。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xujiwei.com/blog/2009/10/16/using-shellexecute-in-realbasic/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
