在 REALbasic 中注册 AppleEvent

之前为了注册一个自定义协议,需要通过注册 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, 


阅读全文 »

博客迁移到 WordPress 平台

花了两天人肉把老博客的大部分技术文章迁移到 WordPress,评论数据不迁了,工作难度太大……

如果您是从外部链接进来的,例如 www.xujiwei.com/blog/?id=123 这样的形式,那就会找不到页面,可以使用右上角的搜索来搜索相关的文章。

以后会陆续把剩下的文章迁移过来:)

一个自动还原短网址的 Chrome 插件 AutoExpander

上 twitter 时,为了节省消息内容的长度,通常都会把网址用一些网址缩短服务进行简化,例如 bit.ly、is.gd 等,但是在有些时 候可能会碰到打不开缩短后网址的情况,例如连接 bit.ly 失败等,这个时候可以通过第三方的服务来将地址还原,但是这样会比较麻烦,要五个步骤才能 看到原来的地址,现在使用 AutoExpander 插件后,只需要直接输入短地址,插件会自动调用第三方的服务来进行短地址的还原,将“复制短地址、 粘贴到还原短地址的服务网站的输入框、点击还原、拷贝原地址到 Chrome 地址栏、回车”这样五个步骤直接缩短为“粘贴短地址到 Chrome 地址 栏、回车”这样两个步骤。当然,如果你的默认浏览器就是 Chrome,那么可以更方便地,直接点击短地址就行了,连“回车”这一步都省了。

插 件项目地址:

http://autoexpander.googlecode.com/

直接安装:

http://autoexpander.googlecode.com/files/autoexpander-0.3.crx

请 使用 Chrome 4.0 测试版安装:)

慎用 script 节点的 src 属性来传递参数

在有些使用 javascript 来渲染数据的时候,为了能动态获取不同的数据,并且保持 javascript 代码的可扩展性,会将 javascript 代码中获取数据的部分需要的参数提取出来,做为参数放在 script 节点的外部。

一般来说,传递参数到 javascript 文件内部的方法有两种,一种是将参数写在一个 script 节点中,写成全局变量的方式的传递给紧接着这个 script 节点的外部 javascript 中,Google Analytics 就是使用这样的方式:

<script type="text/javascript">
var p1 = "v1", p2 = "v2";
</script>
<script type="text/javascript" src="foo.js"></script>

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

<script type="text/javascript" src="foo.js?p1=v1&p2=v2"></script>

不过,使用 script 节点的 src 属性来传递参数需要注意一个很重要的问题,那就是动态变化的 src 属性会导致缓存失效。…

阅读全文 »

REALbasic 中使用结构体作为 Win32 API 的参数及使用 Win32 API 停止服务

在之前,我使用 ShellExecute 这个 API 来执行命令(《REALbasic 中使用 ShellExecute 执行命令》),然后通过这个方法来停止某个服务,但是今天想加服务运行状态检测,这样就可以在服务没有运行的情况下不再询问用户是否需要停止某个服务。

为了省事,我一开始决定同样使用 cmd 去执行一个命令,将服务状态输出到一个临时文件中,再通过读取这个临时文件,查找特征字符串来判断服务是否运行:

// 伪代码
ShellExecute("cmd.exe /c sc query service_name > tmpfile")
dim serviceStatus as string
serviceStatus = TextInputStream.Open(tmpfile).ReadAll()
if instr(serviceStatus, "STOPPED") < 1 then
  // 提示用户是否停止服务
end if

但是这样做不太靠谱,因为 sc 这个命令执行是要时间的,而 ShellExecute 是异步的,这就导致了在调用 ShellExecute 执行完 sc query 之后,临时文件 tmpfile 里并不是马上就有服务状态的内容了。

为了防止这个情况,我再加了一个临时文件内容的检测,如果为空的话,sleep …

阅读全文 »

Chromium Updater for Mac

图片附件为了随时更新到 Chromium 的最新 nightly build,又不想每次去 Chromium 的网站下,还有解压,移动,麻烦……为了省事,直接用 REALbasic 写了一个 Chromium Updater,专门用来更新 Chromium。目前只支持 Mac :)

详细说明

下载(使用右键下载):ChromiumUpdater (3.5M)

图片附件

关于 REALbasic 中使用 AutoDiscovery 时发生错误 40 的问题

今天在使用 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 来传递一些控制信息。

在 AIR 中突破同源策略访问 iframe 中的内容

本篇所讲关于 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 



阅读全文 »

使用 arguments.caller 实现自动回调

这是一篇介绍类似于 js hack 的文章,只是说明了一种可行的途径,并且可能会增加代码复杂程度,具体项目中是否可以使用还请自辨:)

在前端开发过程中,有许多业务流程可能是需要用户进行登录的,并且登录过程是放在弹出层中,这样就可以不用刷新页面,增强用户体验。在登录时,用户的操作就会被打断,为了进一步增强用户体验,我们可能需要在登录完成后自动继续进行用户在登录前想进行的操作。

假设有这样一个场景,用户需要发表一个留言,但是发表留言是需要登录的,而发表留言的输入框是一直显示的,这也就要求在用户点击了发表按钮时对用户登录状态进行验证,传统的做法是将在用户登录状态检查封装在一个函数之中,这个函数接收一个回调参数,如果登录验证通过,则执行回调函数。这样的逻辑可以用以下代码表示:

function doAction() {
checkLogin(function() {
// 处理业务逻辑
});
}
function checkLogin(callback) {
if (isLogin) {
callback();
} else {
showLogin(callback);
}
}
function showLogin(callback) {
document.getElementById("login-btn").onclick = function() {
isLogin = true;
callback();
};
}

    总觉得这样的方式会将业务逻辑放到一个匿名函数中,而不是放在了按钮的事件响应函数中,感觉上不是那么好。这对整个事件响应函数的改动比较大,主要的业务逻辑都放在了登录验证函数的回调中。而希望可以是下面这样:



    阅读全文 »

    REALbasic 中使用 ShellExecute 执行命令

    在 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,可以直接通过 …

    阅读全文 »