月度归档:2013年06月

前面也聊过,python最大的优势,就是能找到自己,并且修改自己的源代码,实现自我升级!

原帖:http://zhuoqiang.me/how-program-find-self.html

程序如何找自己
自我定位很重要,不但是对人,对程序来说也一样。如果能知道自己的路径位置,程序就可以通过相对定位找到身边的资源文件,这对于制作无需安装的绿色软件和各类插件很关键。下面列出几种程序的自我定位方法。

Windows API
Unix 平台
Python
Mac & iOS
Mozilla Gecko
Windows API

可利用 Win32 API GetModuleHandleEx 来取得内存地址所在的程序路径。如果传入可执行文件自身的某个函数地址,那就能获得自己的路径。该方法如下,默认是取自身的路径:

std::wstring get_module_path(void* address=NULL)
{
if (! address) {
address = (void*)(&get_module_path);
}

HMODULE handle = NULL;
BOOL const ret = ::GetModuleHandleExW(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
//|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
static_cast<wchar_t*>(address),
&handle);

if (ret != 0 && handle != NULL) {
wchar_t path_buffer[MAX_PATH] = {L’’};
DWORD const ret = ::GetModuleFileNameW(handle, path_buffer, MAX_PATH);
// We have to free it
::FreeLibrary(handle);
if (0 != ret) {
return path_buffer;
}
}

return L””; // not found
}
这个方法也能在 DLL 中使用,让动态库也能获取自身的位置,方便插件的编写。

Unix 平台

与 Win32 类似,在 POSIX 中 dladdr 函数也可以获取某个地址所在可执行文件的路径:

std::string get_module_path(void* address=NULL)
{
if (! address) {
address = (void*)(&get_module_path);
}

::Dl_info dl_info;
dl_info.dli_fname = 0;
int const ret = ::dladdr(address, &dl_info);
if (0 != ret && dl_info.dli_fname != NULL) {
return dl_info.dli_fname;
}
return “”;
}
该方法同样能让 so 动态库找到自身的位置,方便插件的编写。

Python

Python 内置变量 __file__ 的值就是脚本文件位置,很方便。不过一旦脚本被 py2exe 这类程序打包后,“ __file__“ 就不准确了。这时就需要用 sys.argv[0] 甚至 sys.executable 变量来取得打包后的程序文件的位置

import imp
import os
import sys
import os.path

def is_frozen():
return (hasattr(sys, “frozen”) or # new py2exe
hasattr(sys, “importers”) # old py2exe
or imp.is_frozen(“__main__”)) # tools/freeze

def get_self_path():
if is_frozen():
return os.path.abspath(sys.executable)
return os.path.abspath(sys.argv[0])
Mac & iOS

Mac 和 iOS 平台上标准的 App 结构都是把可执行文件和资源文件打包在程序束 (bundle) 中,苹果还提供专门的 API 来取得 bundle 的路径,从这点上来说,苹果上的软件都是绿色的。不过如果需要,你还是可以取得自身的路径,

char path[1024];
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) == 0) {
printf(“executable path is %sn”, path);
}
else {
printf(“buffer too small; need size %un”, size);
}
这种方法不管是对传统的 Unix 可执行文件或是 Apple 自己标准的 App 都适用。

Mozilla Gecko

Firefox 的扩展都基于 Gecko 架构提供的插件机制。要得到扩展自身的路径应该很方便才是,但实际上并非如此:

Components.utils.import(“resource://gre/modules/AddonManager.jsm”);
AddonManager.getAddonByID(“your@addon.name”, function(addon)
{
var uri = addon.getResourceURI(“relative/path/to/file”);
if (uri instanceof Components.interfaces.nsIFileURL)
{
// get the absolute path to the file inside Your@Addon.name
var absolute_file_path = uri.file.path;
}
});
这里,需要按扩展的名字去 AddonManager 中找出扩展对象,再通过扩展对象取得扩展包内相对位置的文件路径,使用起来不太方便。

其实,Gecko 中有更直接的方法。你可以在 manifest 文件里把需要引用的文件都声明成 resource,所有的 resource 都可以在扩展里通过 URI 名字直接获得路径

resource YOUR-ADDON-LIB path/to/libaddon.so ABI=Linux_x86-gcc3
resource YOUR-ADDON-LIB path/to/addon.dll ABI=WINNT_x86-msvc
const ioService = Cc[“@mozilla.org/network/io-service;1″].getService(Ci.nsIIOService);
var uri = ioService.newURI(‘resource://YOUR-ADDON-LIB’, null, null);
if (uri instanceof Components.interfaces.nsIFileURL) {
var lib = ctypes.open(uri.file.path);
/// …
}
在不同平台上,同一名字还能对应不同的资源文件,方便跨平台扩展的开发。在上面例子中,Win32 平台 js-ctypes 会使用 addon.dll 而 Linux 上则会使用 libaddon.so,这一切都由 gecko 帮着选择定位。我在 chmfox 里正是使用了这个手法。

人工智能,不光无法达到成年人的智能,即使是小孩子(婴幼儿)的智能,在某些方面,也是非常神奇并且难以达到的。

 

比如我们知道小孩子喜欢跟小孩子玩,确切点说,是喜欢跟同龄人以及比自己大的人(孩子)玩。我的女儿11个月大,明显的喜欢跟自己年龄相当,或者比自己大的孩子玩。但是,她是怎么能够判断出那个小孩比她大还是比她小呢? 我对此感到很惊奇,因为6-12个月大的小孩,我都很难快速的分辨出他们的月龄,并因此判断女儿是该喊他们哥哥姐姐还是弟弟妹妹,而女儿总是很快就能判断出来,至少从行为上,看不出有丝毫的犹豫时间。

这就是婴幼儿神奇的能力。我以成年人的思维方式,认为这种判断的程序为:

根据对方与自己的相似性,来判断是否跟他玩,而不是用成年人的思维:先估算年龄,再跟自己的年龄进行比较(婴幼儿本身就没有自己年龄的概念),根据比较结果判断是否跟他玩。

相似性的判断为:

1 外观相似性。如果对方跟自己体型差不多,就可以认为对方跟自己“合适”,当然体型大于自己的,也“合适”。 这是视觉

2 行为相似性。比如11个月的女儿,只会发出简单的“爸爸” “妈妈”等声音,只会做一些简单的动作,如果对方的行为跟自己相似或者还有比自己“复杂”的行为,那么就认为“合适” 这是。视觉和听觉

3 对11个月的女儿来说,她较少能够用触觉和味觉去感觉其它小朋友,顶多就是让她去跟对方握握手。但我观察到他们是有触碰的意愿的。

4 是否闻气味,这个不太确定,据说婴儿的嗅觉也是很灵敏的,只是慢慢长大反而不太敏感了。

可以看到,根据设想,婴幼儿采用的是模糊的匹配方式进行判断。而我,作为一个成年人,是先用精确的判断年龄大小,然后再跟女儿的年纪进行比较运算,这样两步来进行判断的。