[转载]jquery 神一样的插件制作 10几种常用网页特效

mikel阅读(824)

[转载]jquery 神一样的插件制作 10几种常用网页特效 只有4.5K大小 – jsfoot.com 网页特效 – 博客园.

JQuery.Switchable是一款整合了Tabs、Slide、Scrollable等常见UI组件的JQuery插件。它有简单易用的API、可灵活配置的Configuration,支持自定义Effect,支持自主开发Plugin。

选项卡

手风琴

焦点图片滚动

图片滚动

图片滚动

 

下面是jQuery.Switchable的演示下载地址http://www.jsfoot.com/jquery/demo/2012-04-07/534.html

 

 

下面是jQuery.Switchable的几个亮点:

 

  1. 在当前 trigger 中 mouseenter/mouseleave, click 不触发
  2. 鼠标快速滑过非当前 trigger, 不触发
  3. mouseenter 到非当前 trigger, 停留时间到达延迟时,触发
  4. click trigger/panel, 立即触发
  5. beforeSwitch/onSwitch 事件的触发
  6. panel 内的锚链触发
  7. 无法获取 trigger 时,自动创建 trigger

下面是jQuery.Switchable的调用参数:

property default description
triggers “a” 触点,默认是<a>标签
currentCls “current” 当前触点的className
initIndex 0 默认激活项
triggerType “mouse” 触发类型,还可以是”click”
delay .1 触发延迟,单位是秒。默认值即100毫秒
effect “default” 切换效果。内置效果有:
“default”:最简单的显/隐效果
“ajax”:AJAX动态加载 Panel 的内容
你还可以自己动手制作 Effect
steps 1 每次切换的 Panel 数量
visible 1 可见区域的 Panel 数量
speed .7 动画步时,单位是秒。默认值即700毫秒
easing “swing” 动画效果
circular false 循环
vertical false 纵向切换
panelSwitch false 点击 Panels 触发
beforeSwitch null 触发前的 Callback
onSwitch null 触发时的 Callback
api false jQuery.Switchable默认返回的是jQuery对象。当该属性设置为 true 时,将返回 JavaScript API

[转载]C# #if, #else和#endif预处理指令

mikel阅读(962)

[转载]C# #if, #else和#endif预处理指令 – Peter Luo – 博客园.

    #if 使您可以开始条件指令,测试一个或多个符号以查看它们是否计算为 true。如果它们的计算结果确实为true,则编译器将计算位于 #if 与最近的 #endif 指令之间的所有代码。例如,

1 #if DEBUG  
2             string file = root + "/conf_debug.xml";  
3 #else  
4             string file = root + "/conf.xml";  
5 #endif

    这段代码会像往常那样编译,但读取Debug配置文件包含在#if子句内。这行代码只有在前面的#define命令定义了符号Debug后才执行。当编译器遇到#if语句后,将先检查相关的符号是否存在,如果符号存在,就只编译#if块中的代码。否则,编译器会忽略所有的代码,直到遇到匹配的#endif指令为止。一般是在调试时定义符号DEBUG,把不同的调试相关代码放在#if句中。在完成了调试后,就把#define语句注释掉,所有的调试代码会奇迹般地消失,可执行文件也会变小,最终用户不会被这些调试信息弄糊涂(显然,要做更多的测试,确保代码在没有定义DEBUG的情况下也能工作)。这项技术在CC++编程中非常普通,称为条件编译(conditional compilation)


参考msdn实例:

// preprocessor_if.cs
 #define DEBUG
 #define VC_V7
 using System;
 public class MyClass 
 {
     static void Main() 
     {
 #if (DEBUG && !VC_V7)
         Console.WriteLine("DEBUG is defined");
 #elif (!DEBUG && VC_V7)
         Console.WriteLine("VC_V7 is defined");
 #elif (DEBUG && VC_V7)
         Console.WriteLine("DEBUG and VC_V7 are defined");
 #else
         Console.WriteLine("DEBUG and VC_V7 are not defined");
 #endif
     }
 }

[转载]新浪微博刷粉丝小号被秒-揭秘隐式收集用户信息方式

mikel阅读(1207)

[转载]新浪微博刷粉丝小号被秒-揭秘隐式收集用户信息方式 – 路过秋天 – 博客园.

记得好久好久前发布了:刷微博粉丝工具发布及原理解说,好像是去年中秋的时候了,现在微博粉丝精灵发布到V3.75版本了,同时也相关的微博人气精灵也发布了V1.8版本,对于玩微博的人来说,粉丝是入门必备的过程,不管是个人还是企业,在微博的初始阶段,都会为追求粉丝数的上升而寻找不同的途径去努力。

 

新浪微博怎么刷粉丝?为了快速突破粉丝数的上升,除了花钱,就是花时间手工互粉,或者就是使用各种收费的软件,直到微博粉丝精灵出现,基本使得大多数用户让增加粉丝变成一种免费的状态,不过在长期的发展历程中,小号被新浪秒杀的事时而不断。

 

根据个人经验,新浪封杀账号有三种形式:

1:被举报,直接封号,或删除账号,这一类基本就没了。

2:被封号,但没删除,可以通过投诉找回,但是投诉基本是没有用的,像粉丝精灵的官方微博,就被封过好几个,也是投诉不回来的。

3:提示账常,要用手机号发短信解封,通常这一类是系统自动检测的,理论上只要不引发新浪的纠察系统,应该就是安全的。

 

对于第三种,出现还是经常性的,比例占的有点大,目前微博粉丝精灵占的比例为5%以下,其它软件被秒率高达60%以上。

 

关于纠察系统的设想:

无论是淘宝还是新浪,在纠察系统出来之前,总会想方设法的收集客户端的信息,用于集中分析。

 

对于淘宝,有很多收集客户端信息的地方,预计包括:

1:登陆的安全插件。

2:淘宝旺旺。

3:安装淘宝旺旺时,还会默认安装一个系统服务(目前没人知道这个系统服务是干什么用的,进程名称为:wwCtrlSrv.exe )。

4:其它未知方式。

 

对于新浪微博,又是怎样收集信息来进行自纠察的呢?

 

曾经以为:一直以为新浪应该是在提交登陆的时候,来分析客户端的情况,从而判断用户登陆信息,因此一直没有细想。

如果细想:对于大多数的新浪微博刷粉丝软件而言,多数是会自行修改请求头进而提交的,也会调整Cookie信息进行提交,因此,新浪对这类仅能提取很少的信息,是不能很好的判断如何精准定位检测的。

那么新浪仅靠用户的IP+小号自身的微博粉丝、关注数、发微博的时间,就能直接秒杀小号?这个应该难度是大的,除非连续关注的请求时间实在太过异常。
如果没有更详细的信息,新浪估计是不会太轻易秒杀的,毕竟也要考虑到用户体验。

 

不经意的发现:

 

在前几天,截包中,发现了一条以前都忽略的请求链接:

http://beacon.sina.com.cn/a.gif?V=2& amp;CI=sz:1280×800|dp:32|ac:Mozilla|an:MSIE|cpu:x86|pf:Win32|jv:1.3|ct:lan|lg:zh- cn|tz:-8|fv:10|ja:1&PI=pid:0-9999-0-0-1|st:0|et:2|ref:|hp:N|PGLS:|ZT:|MT:|keys:|dom:1529|ifr:0|nld:3187|drd:3187|bp:0|url:& amp;UI=vid:1411785839295.4668.1333768962718|sid:1411785839295.4668.1333768962718|lv:1333724174953:5:5:5|un:4: 邮箱%40126.com:微博ID::|uo:|ae:&EX=ex1:|ex2:&gUid_1333771202187

 

截图如下:

这里我是把该主机解析到本机,所以出现404。

说明:

把用户多数的客户端信息,伪装成图片,实际是在私底下收集信息。

该图片链接会在新浪微博登陆时产生,登陆进微博主页时也有概率产生,该条记录提交了不少用户的客户端信息,估计就是为了进行小号秒杀而收集的信息。

目前来说,多数基于WebBrowser而应用的新浪微博刷粉丝软件,目前好像还没有能屏蔽图片下载的,而通过IE设置或临时操作注册表(会被杀毒软件秒报毒),这个对不明真相的用户伤害极大,因此也不好实行。

 

 

防止被收集:如果想避免被新浪通过这种隐匿方式收集信息,可以添加一条host解析,屏蔽这个域名:

127.0.0.1 beacon.sina.com.cn

 

下面再补充一下微博粉丝精灵+微博人气精灵的图片介绍:

微博粉丝精灵

 

微博人气精灵

 

微博人气精灵:大号关注(互粉)平台

 

官方博客地址:http://www.cyqdata.com/fensi

[转载]浅谈.NET反射机制的性能优化

mikel阅读(1320)

[转载]浅谈.NET反射机制的性能优化 – 陈彦铭 – 博客园.

在进入解释型模版引擎的探讨之前,我决定先分享一下这篇博客。因为在解释型引擎里将会引入反射的概念来实现更多、更复杂的功能。可能大家谈到反射面部肌肉都开始抽搐了吧!因为在托管语言里面,最臭名昭著的就是反射!它的性能实在是太低了,甚至在很多时候让我们无法忍受。不过不用那么纠结了,老陈今天就来分享一下如何来优化反射!

概述

本文涉及到的反射优化的途径有如下两种:

  1. 通过Delegate.CreateDelegate()创建委托进行优化
  2. 通过.NET4的动态运行时进行优化

如果您还知道其他更加有效的优化途径,请不吝赐教!

准备工作

今天我们总计要对比五种不同的调用对象成员的方式,也算是一种性能测评。

在开始之前,我们首先定义一个简单的对象和一个方法,以供测试之用:

namespace ReflectionOptimization
{
public sealed class TestObject
{
public int Add(int a, int b)
{
// 简单演示
return a + b;
}
}
}

这个类非常简单,只提供了一个方法,这个方法返回两个整形的和。接下来我们看看执行时间测量的代码,很简单,想必您已经驾轻就熟了:

private static double _Run(string description, Action action, int a, int b)
{
if (action == null) throw new ArgumentNullException("action");

// 启动计时器
var stopwatch = Stopwatch.StartNew();

// 运行要测量的代码
action(a, b);

// 终止计时
stopwatch.Stop();

// 输出结果
Console.WriteLine("{0}: {1}", description, stopwatch.Elapsed.TotalMilliseconds.ToString(CultureInfo.InvariantCulture));

// 返回执行时间
return stopwatch.Elapsed.TotalMilliseconds;
}

以上测量时间的方法返回了执行时间,因为我们要在后面用到这个值,在执行多次之后取个平均值,以求测试的公平性、权威性。
编码实现

首先我们来看看原生反射的实现:

var obj = new TestObject();
var add = obj.GetType().GetMethod("Add");

for (var i = 0; i &lt; _TIMES; i++) add.Invoke(obj, new object[] {a, b});

然后我们看看.NET4动态编程的实现:

dynamic obj = new TestObject();

// 有木有发现这个代码超级简单?
for (var i = 0; i &lt; _TIMES; i++) obj.Add(a, b);

最后我们看看如何使用委托来优化反射:

// 委托
public delegate int AddMethod(int a, int b);

// 实现
var obj = new TestObject();
var objType = obj.GetType();
var add = objType.GetMethod("Add");
var d = (AddMethod)Delegate.CreateDelegate(typeof(AddMethod), obj, add);

for (var i = 0; i &lt; _TIMES; i++) d(a, b);

上面的代码看起来多了几行,而且还需要自定义一个委托,写起来挺麻烦的。因此我们的测试代码里面还实现了另外一种形式,其实它也是委托:

var d = (Func)Delegate.CreateDelegate(typeof(Func), add);

测试总结

我们首先在Debug模式下将整个测试代码运行5遍,然后分别记录平均值,然后再到Release模式下重复该测试。

测试的过程不再阐述,测试结果整理如下:

Debug模式:

调用方式 第一次 第二次 第三次 第四次 第五次
Generic Call 1.022425 1.012885 0.990775 1.020950 1.046880
Reflection 147.489220 146.012010 142.690080 139.189335 141.663475
dynamic 9.645850 9.979965 9.307235 9.532665 9.730030
Func 1.201860 1.214800 1.170215 1.189280 1.239485
Delegate 1.062215 1.061635 1.067510 1.047180 1.075190

Release模式:

调用方式 第一次 第二次 第三次 第四次 第五次
Generic Call 0.745600 0.741365 0.722145 0.732630 0.725645
Reflection 141.778260 142.855410 142.346095 139.649990 138.541285
dynamic 9.631460 10.341850 9.284230 9.457580 9.060470
Func 0.882100 0.852680 0.875695 0.854655 0.831670
Delegate 0.710280 0.722465 0.723355 0.727175 0.693320

点评&结论:

  • 使用委托优化反射之后,其性能与直接调用相差无几,保持在同一个数量级之内,对性能要求极度苛刻时推荐此方案;
  • 显式委托(Delegate)和匿名委托(Func)性能差异非常不明显,但显式委托的性能还是好一点;
  • 原生委托比直接调用慢出了两个数量级,性能差异达到了200倍之多!
  • .NET 4的动态编程语法相当简洁,其性能只比直接调用高出一个数量级,由于其语法相当简洁,我们推荐这种做法!
  • 原生反射技术在Debug模式和Release模式下没有太大差异,但其他方式有较为明显的优化效果(请思考为什么);
  • 虽然我们今天的测试不能完全意味着反射优化之后可以和直接调用相媲美,但至少可以从某种程度上击败那些个谣言——谁说反射就一定会慢(嘻嘻)!

代码下载:浅谈反射优化.zip

 

[转载]6步确保 windbg 成功调试 .net

mikel阅读(1120)

[转载]6步确保 windbg 成功调试 .net – 孤剑 – 博客园.

原文地址:http://blogs.msdn.com/b/dougste/archive/2011/10/31/tips-for-successful-net-debugging-with-windbg.aspx

1、windbg 的版本一致。

   分析时、dump内存时的 windbg 版本一致,且保证是完整的内存文件。使用 .dump /ma c:\dump.dmp 执行

2、检查 CLR的版本要一致。
   检查 mscorwks.dll (#2.0) 或 clr.dll (#4.0) 版本正确。使用 lm vm mscorwks 或 lm vm clr 检查,看输出内容中是否有 # M C 之类的,存在则表示文件不匹配

3、加载了正确的扩展命令。
   检查加载的扩展是否为: psscor2.dll (#2.0)      psscor4.dll (#4.0) 。使用命令 !threads 检查扩展是否正常工作。
   psscor2 下载地址: http://www.microsoft.com/download/en/details.aspx?id=1073
psscor4 下载地址: http://www.microsoft.com/download/en/details.aspx?id=21255

4、如果步骤3 执行失败,则检查 和CLR版本相同的DAC(Data Access Component)是否正确。
   将dump机器上(或其他机器上同版本的 mscordacwks.dll)拷贝到windbg.exe 同目录,并命名为:mscordacwks_xPP_xPP_2.0.50727.vvvv.dll,

5、确认 CLR  版本。
   使用 lm vm mscorwks (#2.0) 或 lm vm clr (#4.0) 来确认 CLR 版本。

6、顺带说一个非常强大的调试托管代码的扩展命令。
   SOSEX     : http://www.stevestechspot.com/
========================================================================
总结:
1、上述 6步 是”确保windb成功调试.net“的前提,每一步都非常重要。切记,切记!
2、关于CLR的版本列表,外国大牛就是总结的好,方便查找,应该为.net调试常备之利器。
3、除了 sos.dll 进行托管调试外,还有2款瑞士军刀可用: psscor2 / sosex

[转载]SQL Server 2008中增强的汇总技巧

mikel阅读(988)

[转载]SQL Server 2008中增强的汇总技巧 – 邀月 – 博客园.
SQL Server 2008中对汇总有明显的增强,有点像Oracle的语法了。请看下面四个例子:

假定场景如下:某几位员工在不同时间参加了不同的项目,获取了相应的收入,现在需要按各种分类进行统计。

基本表如下:

USE testDb2
GO

IF NOT OBJECT_ID('tb_Income') IS NULL
DROP TABLE [tb_Income]

/****** Object: Table [dbo].[tb_Income] Script Date: 2012/4/5 8:19:21 ******/

CREATE TABLE [dbo].[tb_Income](
[TeamID] int not null,
[PName] [Nvarchar](20) NOT NULL,
[CYear] Smallint NOT NULL,
[CMonth] TinyInt NOT NULL,
[CMoney] Decimal (10,2) Not Null

)

GO
INSERT [dbo].[tb_Income]
SELECT 1,'胡一刀',2011,2,5600
union ALL SELECT 1,'胡一刀',2011,1,5678
union ALL SELECT 1,'胡一刀',2011,3,6798
union ALL SELECT 2,'胡一刀',2011,4,7800
union ALL SELECT 2,'胡一刀',2011,5,8899
union ALL SELECT 3,'胡一刀',2012,8,8877

union ALL SELECT 1,'苗人凤',2011,1,3455
union ALL SELECT 1,'苗人凤',2011,2,4567
union ALL SELECT 2,'苗人凤',2011,3,5676
union ALL SELECT 3,'苗人凤',2011,4,5600
union ALL SELECT 2,'苗人凤',2011,5,6788
union ALL SELECT 2,'苗人凤',2012,6,5679
union ALL SELECT 2,'苗人凤',2012,7,6785

union ALL SELECT 2,'张无忌',2011,2,5600
union ALL SELECT 2,'张无忌',2011,3,2345
union ALL SELECT 2,'张无忌',2011,5,12000
union ALL SELECT 3,'张无忌',2011,4,23456
union ALL SELECT 3,'张无忌',2011,6,4567
union ALL SELECT 1,'张无忌',2012,7,6789
union ALL SELECT 1,'张无忌',2012,8,9998

union ALL SELECT 3,'赵半山',2011,7,6798
union ALL SELECT 3,'赵半山',2011,10,10000
union ALL SELECT 3,'赵半山',2011,9,12021
union ALL SELECT 2,'赵半山',2012,11,8799
union ALL SELECT 1,'赵半山',2012,12,10002

union ALL SELECT 3,'令狐冲',2011,8,7896
union ALL SELECT 3,'令狐冲',2011,9,7890
union ALL SELECT 2,'令狐冲',2011,10,7799
union ALL SELECT 2,'令狐冲',2011,11,9988
union ALL SELECT 2,'令狐冲',2012,9,34567
union ALL SELECT 3,'令狐冲',2012,12,5609

GO

数据如下:

SELECT * FROM tb_Income

/*

TeamID PName CYear CMonth CMoney
胡一刀 2011 2 5600.00
胡一刀 2011 1 5678.00
胡一刀 2011 3 6798.00
胡一刀 2011 4 7800.00
胡一刀 2011 5 8899.00
胡一刀 2012 8 8877.00
苗人凤 2011 1 3455.00
苗人凤 2011 2 4567.00
苗人凤 2011 3 5676.00
苗人凤 2011 4 5600.00
苗人凤 2011 5 6788.00
苗人凤 2012 6 5679.00
苗人凤 2012 7 6785.00
张无忌 2011 2 5600.00
张无忌 2011 3 2345.00
张无忌 2011 5 12000.00
张无忌 2011 4 23456.00
张无忌 2011 6 4567.00
张无忌 2012 7 6789.00
张无忌 2012 8 9998.00
赵半山 2011 7 6798.00
赵半山 2011 10 10000.00
赵半山 2011 9 12021.00
赵半山 2012 11 8799.00
赵半山 2012 12 10002.00
令狐冲 2011 8 7896.00
令狐冲 2011 9 7890.00
令狐冲 2011 10 7799.00
令狐冲 2011 11 9988.00
令狐冲 2012 9 34567.00
令狐冲 2012 12 5609.00
*/

一、使用CUBE汇总数据(http://msdn.microsoft.com/en-us/library/bb522495%28v=sql.105%29.aspx

小试牛刀,

/*********使用CUBE汇总数据***************/

/********* 3w@live.cn 邀月***************/
SELECT TeamID as 小组ID,
SUM(CMoney) 总收入
FROM tb_Income
GROUP BY CUBE (TeamID)
----ORDER BY TeamID desc

 

邀月工作室

改进查询:

SELECT TeamID as 小组ID,PName as 姓名,
SUM(CMoney) 总收入
FROM tb_Income
GROUP BY CUBE (TeamID,PName)

 

邀月工作室

 

二、使用ROLLUP汇总数据(http://msdn.microsoft.com/en-us/library/bb522495%28v=sql.105%29.aspx

/*********使用ROLLUP汇总数据***************/

/********* 3w@live.cn 邀月***************/

SELECT TeamID as 小组ID,PName as 姓名,
SUM(CMoney) 总收入
FROM tb_Income
GROUP BY ROLLUP (TeamID,PName)

 

邀月工作室

注意:使用Rollup与指定的聚合列的顺序有关。

 

 

三、使用Grouping Sets创建自定义汇总数据(http://msdn.microsoft.com/en-us/library/bb522495%28v=sql.105%29.aspx

除了Cube和Rollup,还有更加灵活强大的自定义集合汇总--Grouping Sets

/*********使用Grouping Sets创建自定义汇总数据***************/

/********* 3w@live.cn 邀月***************/

SELECT TeamID as 小组ID,PName as 姓名,CYear as 年份,----min(CMonth) as 月份,
SUM(CMoney) 总收入
FROM tb_Income
Where CMonth=2
GROUP BY grouping SETS ((TeamID),(TeamID,PName),(CYear,PName))

 

邀月工作室

四、使用Grouping标识汇总行(http://technet.microsoft.com/zh-cn/library/ms178544.aspx

细心的朋友可能会注意到,如果Cube后有两个以上的汇总列时,可能会有一些列是Null,那么这些Null值究竟本身就是Null,还是由于聚合产生的Null呢,此时,GroupingID函数大显身手的机会来了。

/*********使用Grouping标识汇总行***************/

/********* 3w@live.cn 邀月***************/
SELECT TeamID as 小组ID,CYear as 年份,
CASE WHEN grouping(TeamID)=0 AND grouping(CYear)=1 THEN '小组汇总'
WHEN grouping(TeamID)=1 AND grouping(CYear)=0 THEN '年份汇总'
WHEN grouping(TeamID)=1 AND grouping(CYear)=1 THEN '所有汇总'
else '正常行' END as 行类别,
SUM(CMoney) 总收入
FROM tb_Income
GROUP BY CUBE (TeamID,CYear)

结果:

邀月工作室

其实,还有更复杂的Grouping_ID,不过,一般情况下用不到,需要的同学,请看MSDN:

http://technet.microsoft.com/zh-cn/library/bb510624.aspx

 

小结:带有Cube,Rollup,grouping Sets的Group By函数在统计与分析中有着广泛的应用,相信它的高效简捷,在特定的场合会令人你爱不释手!

邀月注:本文版权由邀月和博客园共同所有,转载请注明出处。
助人等于自助!  3w@live.cn

[转载]andorid里的手势电话学习(上)

mikel阅读(894)

[转载]andorid里的手势电话学习(上) – 落尘祥 – 博客园.

自己在学习手势Gesture绘制的时候突然想画一个爱心实现一键拨号给honey的应用,先在安卓巴士找了个手势电话案例结合Android samples里的Gesture Builder改写了个画爱心拨通号码的应用,先把我在安卓巴士上看到的案例复制过来:

 

学习一下Android中的手势文件。手势相关的类有
1.GestureOverlayView,这个是手势绘制区,既布局中的一个控件,用于接收用户绘制的手势、监听绘制区的改变、清除当前手势等等。
2.GestureLibrary 这个算是手势文件的一个库,里面存放着当前保存过的手势资源,可以用这个类进行手势资源的存储和读取。
3.Gesture,手势实例,无论是读取手势,还是要保存当前的手势,都是Gesture对象。
4.Prediction 识别率。主要用于在根据当前手势查询手势库中是否有匹配手势时需要用到。
下面根据程序来详细讲解一下如何应用这几个类。

 

本主要功能是根据手势判别来拨打电话。可以保存手势,查看现在保存的手势,如果程序第一次运行,便在指定路径下建立手势文件。

 

因为要保存手势文件和打电话,所以首先在程序清单中添加权限
AndroidManifest.xml代码片段:

 

1 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2         <uses-permission android:name="android.permission.CALL_PHONE"/>

 

程序用到的布局文件有4个,一个是主Activity用到的xml布局。就是第一张图的布局文件:
main.xml代码:

 

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3  android:layout_width="fill_parent"
 4  android:layout_height="fill_parent"
 5  android:orientation="vertical" >
 6 
 7     <TextView
 8 android:layout_width="fill_parent"
 9  android:layout_height="wrap_content"
10  android:text="@string/hello" />
11 
12     <android.gesture.GestureOverlayView
13 android:id="@+id/gestures"
14  android:layout_width="fill_parent"
15  android:layout_height="fill_parent"
16  android:layout_weight="1"
17  android:gestureStrokeType="multiple" >
18     </android.gesture.GestureOverlayView>
19 
20 <LinearLayout android:layout_width="fill_parent"
21  android:layout_height="wrap_content"
22  android:gravity="center_horizontal">
23         <Button
24 android:id="@+id/btnAdd"
25  android:layout_width="wrap_content"
26  android:layout_height="wrap_content"
27  android:text=" 添加手势 " />
28           <Button
29 android:id="@+id/btnSelect"
30  android:layout_width="wrap_content"
31  android:layout_height="wrap_content"
32  android:text="查看已有手势" />
33 </LinearLayout>
34 
35 </LinearLayout>

 

以及添加手势资源时用的布局文件:
addgesture.xml

 

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3  android:layout_width="fill_parent"
 4  android:layout_height="fill_parent"
 5  android:orientation="vertical" 
 6  android:gravity="center_horizontal">
 7 
 8     <LinearLayout
 9 android:layout_width="fill_parent"
10  android:layout_height="wrap_content" >
11 
12         <TextView
13 android:layout_width="wrap_content"
14  android:layout_height="wrap_content"
15  android:text="手机号码:" 
16  android:inputType="number"/>
17 
18         <EditText
19 android:id="@+id/txtNum"
20  android:layout_width="match_parent"
21  android:layout_height="wrap_content" />
22     </LinearLayout>
23 
24     <android.gesture.GestureOverlayView
25 android:id="@+id/gestureAdd"
26  android:layout_width="fill_parent"
27  android:layout_height="fill_parent"
28  android:layout_weight="1"
29  android:gestureStrokeType="multiple" >
30     </android.gesture.GestureOverlayView>
31 
32     <Button
33 android:id="@+id/btnOK"
34  android:layout_width="wrap_content"
35  android:layout_height="wrap_content"
36  android:text=" 确定 " />
37 
38 </LinearLayout>

 

剩下2个是gridView的布局文件和点击查看所有手势的布局文件:

 

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="wrap_content"
 4     android:layout_height="wrap_content"
 5     android:orientation="vertical"  android:gravity="center">
 6     <ImageView android:id="@+id/itemIcon"    android:layout_width="wrap_content"
 7         android:layout_height="wrap_content"        />
 8     <TextView android:id="@+id/itemText" android:layout_width="wrap_content"
 9         android:layout_height="wrap_content"     android:textColor="#fff"/>
10 
11 </LinearLayout>

 

 

 

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3  android:layout_width="match_parent"
 4  android:layout_height="match_parent"
 5  android:orientation="vertical" >
 6 
 7     <GridView
 8 android:id="@+id/gvTop"
 9  android:layout_width="fill_parent"
10  android:layout_height="fill_parent"
11  android:gravity="center"
12  android:numColumns="auto_fit" 
13  android:scrollbars="none">
14     </GridView>
15 
16 </LinearLayout>

 

在主activity GestureLearnActivity中,要判断第一次加载时是否有手势文件,如果没有则创建一个手势文件,并监听手势绘制区的改变,当绘制完成时与手势库中的手势进行比较。
GestureLearnActivity代码片段

 

 1 /**
 2  * 初始化
 3 */
 4         public void init() {
 5                 // 获得布局中的组件
 6                 btnAdd = (Button) findViewById(R.id.btnAdd);
 7                 btnAdd.setOnClickListener(this);
 8                 btnSelect = (Button) findViewById(R.id.btnSelect);
 9                 btnSelect.setOnClickListener(this);
10                 gesture = (GestureOverlayView) findViewById(R.id.gestures);
11                 // 手势文件的加载路径
12                 String path = "/sdcard/gestures";
13                 // 加载手势文件
14                 library = GestureLibraries.fromFile(path);
15                 if (library.load()) {
16                         
17                         gesture.addOnGesturePerformedListener(this);
18                 } else {
19                         Toast.makeText(GestureLearnActivity.this, "无手势文件",
20                                         Toast.LENGTH_LONG).show();
21                         
22                         File file = new File(path);
23                         try {
24                                 //创建手势文件
25                                 file.createNewFile();
26                         } catch (Exception e) {
27                                 e.printStackTrace();
28                         }
29                 }
30         }
31 // 这个接口里处理匹配的手势
32 public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
33         ArrayList<Prediction> predictions = library.recognize(gesture);
34         if (predictions.size() > 0) {
35                 // 获得识别率
36                 Prediction predict = predictions.get(0);
37                 // 如果识别率大于1,则说明找到匹配手势
38                 if (predict.score > 1.0) {
39                         //调用打电话activity
40                         Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"
41                                         + predict.name));
42                         //不打电话,只进入打电话界面
43 //Intent phone=new Intent("com.android.phone.action.TOUCH_DIALER");
44                         startActivity(intent);
45                         }
46                 }
47 
48         }

 

剩下的就是查看手势文件了,这里我用到的是GridView控件来布局,将手势库中的文件都读取出来,由于是练习程序,所以没做复杂的操作,只是显示已经保存的手势文件。这里用到Gesture 的实例对象,通过这个对象将手势文件转换成位图来显示。
ListGestures.java代码片段

 

 1 public void load() {
 2                 String path = "/sdcard/gestures";
 3                 // 加载手势文件
 4                 library = GestureLibraries.fromFile(path);
 5 
 6                 if (library.load()) {
 7                         int index = library.getGestureEntries().size();
 8                         pics = new Bitmap[index];
 9                         gesName=new String[index];
10                         int i = 0;
11                         //获得所有手势文件,返回的是存储key的set集合
12                         for (String name : library.getGestureEntries()) {
13                                 // 因为在手势仓库中,支持一个name对应多个手势文件,
14 // 所以会返回一个list,在这里我们取list里的第一个
15                                 ArrayList<Gesture> geess = library.getGestures(name);
16                                 Gesture gg = geess.get(0);
17                                 //将手势文件转成位图
18                                 Bitmap bmp = gg.toBitmap(100, 100, 12, Color.BLUE);
19                                 pics[i] = bmp;//保存位图
20                                 gesName[i]=name;//保存当前的手势名称。
21                                 i++;
22                         }
23                 }
24         }

 

最后的gridView的适配器代码就不多说了。直接上源码

 

 1 public class GridAdapter extends BaseAdapter {
 2         // 每个gridItem显示的值
 3         private Context mContext;
 4         private LayoutInflater mInflater;
 5 
 6         public GridAdapter(Context context) {
 7                 mContext = context;
 8                 mInflater = (LayoutInflater) context
 9                                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
10 
11         }
12 
13         public int getCount() {
14                 // 返回适配器中数据的数量
15                 return ListGestures.pics.length;
16         }
17 
18         public Object getItem(int position) {
19                 // 用不到
20                 return null;
21         }
22 
23         public long getItemId(int position) {
24                 // 用不到
25                 return 0;
26         }
27 
28         // 此方法的convertView是在grid_item里定义的组件。这里是一个ImageView和TextView
29         public View getView(int position, View convertView, ViewGroup parent) {
30                 if (convertView == null) {
31                         convertView = mInflater.inflate(R.layout.grid_item, null);
32                 }
33                 ImageView icon = (ImageView) convertView.findViewById(R.id.itemIcon);
34                 TextView text = (TextView) convertView.findViewById(R.id.itemText);
35                 icon.setImageBitmap(ListGestures.pics[position]);
36                 text.setText(ListGestures.gesName[position]);
37                 return convertView;// 返回已经改变过的convertView,节省系统资源
38         }
39 
40 }

 

OK,这些就是实现这个程序的主要代码,程序在运行后,会根据当前的绘制手势匹配库中的手势,如果匹配成功,就会调用打电话的activity。后 面附上源代码,感兴趣的可以下载了以后去运行并查看完整的代码,记得是在真机上运行哦。因为我直接访问的SD卡,模拟器上运行可能会出错。下一得晚上将自 己的再挂出来。

完整代码我已放网盘:http://dl.dbank.com/c000mayxox

[转载]eXeScope无法导入比原来图标大的文件

mikel阅读(1317)

部分软件确实有着强大的功能,但是图标设计的实在太XX了,俺就来说一下怎么去更换软件的图标(EXE文件)。

  首先要准备几个软件:
  eXeScope---用于更换图标(百度之)
  ToYcon---用于生成图标,简单快捷的工具(百度之)

更换图标前先要确认你的EXE文件有没有被加壳,用EXESCOPE打开一下,提示加壳就基本没戏了,如果没有加壳的话。可以用EXESCope确认你的EXE文件包含的ICO规格,如图,我用UCWEB做例子,可以看到其包含的两个ICO文件分别是32*32
256色和16*16 256色的,替换这两个文件就可以了,替换的方法是,点击图标选项中你要替换的文件,然后点击菜单栏的 文件---导入
就成功了,注意的是,导入的文件分辨率要一样,颜色位数可以小于但不能大于原文件的规格。

如果你没有相应的图标就要自制图标了,ToYcon就能方便的生成图标文件。图标资源可到http://www.icosea.com/下载,选择有包含 PNG(通常是PNG)格式的才下,俺折腾一下午也没找到有效改变ICO分辨率的方法。启动ToYcon显示的是一个箱子,只要将相应格式的文件拖放到箱子里面就会产生ICO文件,ToYcon的设置很简单,对着那个箱子右键,选择类型可以设置输入的格式,选择输出格式要注意的是一次只能选择一种格式,如图,256色就选择8bit的。

  但是如果eXeScope出现警告的话,就选择色深较小的,如4bit的。

  接着输出成功生成了ICO文件。

然后就可以按照上面的eXeScope使用方法替换图标了,提示是否改变文件大小,按确认就可以。

  替换过后,右面会显示图换好的图标。

  完成后就可以看到替换后的结果:

最后,替换好后就不一定能用,因为修改后的软件需

[转载]Android学习系列(28)--App集成支付宝

mikel阅读(872)

[转载]Android学习系列(28)–App集成支付宝 – 谦虚的天下 – 博客园.

手机的在线支付,被认为是2012年最看好的功能,我个人认为这也是移动互联网较传统互联网将会大放光彩的一个功能。
人人有手机,人人携带手机,花钱买东西,不再需要取钱付现,不再需要回家上网银,想买什么,扫描一下,或者搜索一下,然后下单,不找零,直接送到你家,这将是手机支付给我们带来的全新交易体验。
谷歌刚推出了谷歌钱包,这必是我们后面要使用的主要手段,但是鉴于当前国情,我觉得有必要介绍一下Android手机集成支付宝功能。

1.下载官方架包和说明文档
其实官方已经提供了安装指南,下载地址:
https://mobiless.alipay.com/product/product_down_load.htm?code=SECURITY_PAY
里面有有个pdf,详细说明了说用指南,写的比较详细,可以重点参考。


下载下来,我们主要是用到Android(20120104)目录下的alipay_plugin.jar和AppDemo/assets下的alipay_plugin223_0309.apk,这两个文件是我们不能修改的支付宝api和安装包。

2. 商户签约
现在的安全机制,都是这样,客户端需要先和服务端请求验证后才能进行进一步操作,oauth也是如此。
打开https://ms.alipay.com/,登陆支付宝,点击签约入口,选择”应用类产品”,填写并等待审核,获取商户ID和账户ID。
签约的时候还要向需要提供实名认证和上传应用,所以我建议先把应用做好了,最后再集成支付宝。


我大概等了1-2天审核,审核是失败的,回复是应用类型啥的应该是”虚拟货币”,我改成那个马上自动就审核通过了。

3.密钥配置
解压openssl-0.9.8k_WIN32(RSA密钥生成工具).zip,打开cmd,命令行进入openssl-0.9.8k_WIN32(RSA密钥生成工具)\bin目录下,
(1).执行

1
openssl genrsa  -out rsa_private_key.pem 1024

生成rsa_private_key.pem文件。
(2).再执行

1
openssl rsa  -in rsa_private_key.pem  -pubout -out rsa_public_key.pem

生成rsa_public_key.pem 文件。
(3).在执行

1
openssl pkcs8  -topk8  -inform PEM  -in rsa_private_key.pem  -outform PEM  -nocrypt

将RSA私钥转换成 PKCS8 格式,去掉begin和end那两行,把里面的内容拷贝出来,保存到某个txt中,如rsa_private_pkcs8_key.txt中(我好像没用到这个)。
打 开rsa_public_key.pem,即商户的公钥,复制到一个新的TXT中,删除文件头”—–BEGIN PUBLIC KEY—–“与文件尾”—–END PUBLIC KEY—–“还有空格、换行,变成一行字符串并保存该 TXT 文件,然后在网站的“我的商家服务”切换卡下的右边点击“密钥管理”,然后有个”上传商户公钥(RSA)”项,选择上传刚才的TXT文件.
好了,服务器配置OK,因为这一段之前没有截图,现在弄好了又不好截图,如果有不明白的地方请大家参考官方文档。

4.引用jar和包含安装包
(1).新建Android工程;
(2).copy上面说的alipay_plugin.jar到工程的libs目录下,并在java build path中通过Add External JARs找到并引用该jar;
(3).copy上面说的alipay_plugin223_0309.apk安装包到assets目录下,后面配置路径用到。

如果libs和assets目录没有,手动建立者两个目录。

5.调用代码整理
这里我们要严重的参考文档中AppDemo,我们建一个包 com.tianxia.lib.baseworld.alipay,把AppDemo的com.alipay.android.appDemo4包下的 源码全部copy到刚才我们自己的包下,还有res目录下的资源文件也合并到我们工程res下。
其中AlixDemo.java,ProductListAdapter.java,Products.java是示例类,我们借鉴完后可以删除。
PartnerConfig.java是配置类,配置商户的一些配置参数。
其他的类是严重参考类,直接留下使用。
PartnerConfig.java代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public class PartnerConfig {
    //合作商户ID。用签约支付宝账号登录ms.alipay.com后,在账户信息页面获取。
    public static final String PARTNER = "xxx";
    //账户ID。用签约支付宝账号登录ms.alipay.com后,在账户信息页面获取。
    public static final String SELLER = "xxx";
    //商户(RSA)私钥 ,即rsa_private_key.pem中去掉首行,最后一行,空格和换行最后拼成一行的字符串
    public static final String RSA_PRIVATE = "xxx";
    //支付宝(RSA)公钥  用签约支付宝账号登录ms.alipay.com后,在密钥管理页面获取。
    public static final String RSA_ALIPAY_PUBLIC = "xxx";
    //下面的配置告诉应用去assets目录下找安装包
    public static final String ALIPAY_PLUGIN_NAME ="alipay_plugin223_0309.apk";
}

AlixDemo中代码是最终的调用代码在onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {}中,下面我们提取其中的核心代码。

6.提取核心调用代码
在AlixDemo.java同目录下新建AlixPay.java,来提取AlixDemo.java的核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package com.tianxia.lib.baseworld.alipay;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.tianxia.lib.baseworld.R;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;
import android.view.KeyEvent;
import android.widget.Toast;
public class AlixPay {
    static String TAG = "AlixPay";
    private Activity mActivity;
    public AlixPay(Activity activity) {
        mActivity = activity;
    }
    private ProgressDialog mProgress = null;
    // the handler use to receive the pay result.
    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            try {
                String strRet = (String) msg.obj;
                switch (msg.what) {
                case AlixId.RQF_PAY: {
                    closeProgress();
                    BaseHelper.log(TAG, strRet);
                    try {
                        String memo = "memo=";
                        int imemoStart = strRet.indexOf("memo=");
                        imemoStart += memo.length();
                        int imemoEnd = strRet.indexOf(";result=");
                        memo = strRet.substring(imemoStart, imemoEnd);
                        ResultChecker resultChecker = new ResultChecker(strRet);
                        int retVal = resultChecker.checkSign();
                        if (retVal == ResultChecker.RESULT_CHECK_SIGN_FAILED) {
                            BaseHelper.showDialog(
                                    mActivity,
                                    "提示",
                                    mActivity.getResources().getString(
                                            R.string.check_sign_failed),
                                    android.R.drawable.ic_dialog_alert);
                        } else {
                            BaseHelper.showDialog(mActivity, "提示", memo,
                                    R.drawable.infoicon);
                        }
                        
                    } catch (Exception e) {
                        e.printStackTrace();
                        BaseHelper.showDialog(mActivity, "提示", strRet,
                                R.drawable.infoicon);
                    }
                }
                    break;
                }
                super.handleMessage(msg);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };
    // close the progress bar
    void closeProgress() {
        try {
            if (mProgress != null) {
                mProgress.dismiss();
                mProgress = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void pay() {
        MobileSecurePayHelper mspHelper = new MobileSecurePayHelper(mActivity);
        boolean isMobile_spExist = mspHelper.detectMobile_sp();
        if (!isMobile_spExist)
            return;
        if (!checkInfo()) {
            BaseHelper.showDialog(mActivity, "提示",
                    "缺少partner或者seller,", R.drawable.infoicon);
            return;
        }
        try {
            // prepare the order info.
            String orderInfo = getOrderInfo();
            String signType = getSignType();
            String strsign = sign(signType, orderInfo);
            strsign = URLEncoder.encode(strsign);
            String info = orderInfo + "&sign=" + "\"" + strsign + "\"" + "&"
                    + getSignType();
            
            // start the pay.
            MobileSecurePayer msp = new MobileSecurePayer();
            boolean bRet = msp.pay(info, mHandler, AlixId.RQF_PAY, mActivity);
            
            if (bRet) {
                // show the progress bar to indicate that we have started paying.
                closeProgress();
                mProgress = BaseHelper.showProgress(mActivity, null, "正在支付", false,
                        true);
            } else
                ;
        } catch (Exception ex) {
            Toast.makeText(mActivity, R.string.remote_call_failed,
                    Toast.LENGTH_SHORT).show();
        }
        
    }
    private boolean checkInfo() {
        String partner = PartnerConfig.PARTNER;
        String seller = PartnerConfig.SELLER;
        if (partner == null || partner.length() <= 0 || seller == null
                || seller.length() <= 0)
            return false;
        return true;
    }
    // get the selected order info for pay.
    String getOrderInfo() {
        String strOrderInfo = "partner=" + "\"" + PartnerConfig.PARTNER + "\"";
        strOrderInfo += "&";
        strOrderInfo += "seller=" + "\"" + PartnerConfig.SELLER + "\"";
        strOrderInfo += "&";
        strOrderInfo += "out_trade_no=" + "\"" + getOutTradeNo() + "\"";
        strOrderInfo += "&";
        //这笔交易价钱
        strOrderInfo += "subject=" + "\"" + mActivity.getString(R.string.donate_subject) + "\"";
        strOrderInfo += "&";
        //这笔交易内容
        strOrderInfo += "body=" + "\"" + mActivity.getString(R.string.donate_body) + "\"";
        strOrderInfo += "&";
        //这笔交易价钱
        strOrderInfo += "total_fee=" + "\"" + "10.00" + "\"";
        strOrderInfo += "&";
        strOrderInfo += "notify_url=" + "\""
                + "http://notify.java.jpxx.org/index.jsp" + "\"";
        return strOrderInfo;
    }
    // get the out_trade_no for an order.
    String getOutTradeNo() {
        SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss");
        Date date = new Date();
        String strKey = format.format(date);
        java.util.Random r = new java.util.Random();
        strKey = strKey + r.nextInt();
        strKey = strKey.substring(0, 15);
        return strKey;
    }
    // get the sign type we use.
    String getSignType() {
        String getSignType = "sign_type=" + "\"" + "RSA" + "\"";
        return getSignType;
    }
    // sign the order info.
    String sign(String signType, String content) {
        return Rsa.sign(content, PartnerConfig.RSA_PRIVATE);
    }
    // the OnCancelListener for lephone platform.
    static class AlixOnCancelListener implements
            DialogInterface.OnCancelListener {
        Activity mcontext;
        AlixOnCancelListener(Activity context) {
            mcontext = context;
        }
        public void onCancel(DialogInterface dialog) {
            mcontext.onKeyDown(KeyEvent.KEYCODE_BACK, null);
        }
    }
}

这个类的pay方法就是支付的方法,最简单的不设置的话,调用方法如下:

1
2
AlixPay alixPay = new AlixPay(SettingTabActivity.this);
alixPay.pay();

如果没有安装支付宝,它会提示你安装,如果已经安装,它直接让你选择付款:

这说明已经配置成功了。
然后可以删掉那些示例java文件了: AlixDemo.java,ProductListAdapter.java,Products.java。
你也可以通过调整参数来修改订单信息,如主题,价格等。
另外在BaseHelper的94行:

1
dialog.setOnCancelListener( new AlixDemo.AlixOnCancelListener( (Activity)context ) );

需要修改为:

1
dialog.setOnCancelListener( new AlixPay.AlixOnCancelListener( (Activity)context ) );

7.注意
我在测试的时候,调用的activity是框在一个ActivityGroup里的(与tabhost类似,据说tabhost也有这个问题),导致MobileSecurePayer.java的pay方法中调用服务的两行代码:

mActivity.bindService(new Intent(IAlixPay.class.getName()), mAlixPayConnection, Context.BIND_AUTO_CREATE);
mActivity.unbindService(mAlixPayConnection);

需要修改为:

1
2
mActivity.getApplicationContext().bindService(new Intent(IAlixPay.class.getName()), mAlixPayConnection, Context.BIND_AUTO_CREATE);
mActivity.getApplicationContext().unbindService(mAlixPayConnection);

不然会报错java.lang.ClassCastException: android.os.BinderProxy cannot be cast to com.android.server.am.ActivityRecord$Token…

8.小结
支付宝的集成比我想象的要复杂一些,比较麻烦,首先需要审核,然后代码需要提取,所以写出来与大家分享。
在做集成配置的时候,一定要仔细认真,一个地方出错,可能要导致后面查错查很长时间。
因为本人是先集成成功后才写的这篇文章,难免会漏掉一些重要的细节或者步骤,如有不对,请留言指正。

[转载]软件汉化自己做

mikel阅读(1120)

[转载]软件汉化,自己做! – 韦敏宗 – 博客园.

第一篇:大话软件汉化

“汉化”,港台地区叫“中文化”,它源自英文“Localize” 或“Localization”,意即“本地化”。简单地说,将一个外文版(绝大部分是英文版)软件改写成中文版,就叫做“软件汉化”。说得“专业”一 点,它是指通过一系列本地化的技术处理,对软件的某一部分(主要针对界面语言)进行某种程度的加工,使其操作界面(如菜单、对话框、提示、帮助等)变成中 文(程序内核和功能保持不变),从而满足特定市场上的用户对语言和功能的特殊要求。它涉及语言文字的翻译及相应的用户界面布局调整、本地特性开发、联机文 档的制作,以及保证程序的本地化版本能正常工作的软件质量保证活动等方面。

目前在浩瀚的软件海洋中,英文软件数量绝对居冠,而真正发布中文版的软件几乎寥若晨星。作为一个中国人,每天面对那来自另一个国度的洋文,无论您的外语水 平有多高,总不如自己的母语来得亲切吧!因此,软件汉化的意义不言自明。这里要说明一下软件汉化牵涉的版权问题。任何软件程序的版权归原创作者所有,汉化 的目的应该是用于学习、研究和方便自己使用,或对软件作无商业意图的推广。如果您要用于任何商业目的,肯定会带来法律纠纷。看看软件《许可协议》中的条款 “该计算机程序受版权法和国际条约保护。如未经授权而……将受到严厉的刑事及民事制裁,并将在法律许可范围内受到最大可能的起诉。”呵呵,严重吧。不过, 只要在版权的约束之下,是没有任何问题的。相反,软件汉化可以促进我国计算机用户对国外优秀软件的了解和认识,既提高了我们的工作效率,又对全世界的优秀 软件进行了免费推广,应该大力提倡才是!

怎么样?跃跃欲试了吧!在“砍柴”之前,当然先要好好磨磨刀啦——我们该有哪些准备工作呢?笔者认为,首先,必须对我们的本地语言有着深厚的感情(废话, 这还要说!),最好有较好的文字基础和一定的英文水平(呵呵,英文不要好过头呵,否则的话就不会需要汉化啦!);其次,熟悉电脑操作,但并不需要高深的编 程基础(利用编程手段对软件进行过度的反编译,反而会有侵权之嫌)。多看看网上汉化前辈们写的心得文章,留心研究一下同行们的汉化作品,最主要的是自己行 动起来,选定一两个软件目标,实实在在地开始自己的汉化之旅。闲话少说,跟我来,动手吧!

第二篇:软件汉化基础

一、软件资源结构

就象外科大夫首先要了解人体结构一样,在进行实际汉化工作之前,我们首先要弄清楚一个软件程序的基本结构。为了解剖结构的需要,首先让我们来熟悉一下第一把“手术刀”——eXeScope。

eXeScope 目前最新版为 v6.32,有汉化版本。

eXeScope具备界面语言即时修改、对话框手动调整、资源导入导出(图标、位图、字串、菜单项等)、宏定义等等的强大功能,堪称当前资源修改的首席工 具。目前市场上的软件主要用VC、BC及VB、Delphi等工具编写,从汉化的角度出发,按照资源数据的分布特点,大致可分为“资源分离型”及“资源混 杂型”(注:此分类纯属个人观点,仅为方便讨论汉化),下面我们简单介绍一下这两种类型的资源特征:

1、“资源分离型”软件。以C类语言VC++、BC++等编译,其资源(Resource)一般包含“位图(Bitmap)”、“菜单(Menu)”、 “对话框(Dialog)”、“字串(String)”以及小部分“RC数据(RCData)”等,而且几类资源间相对独立。一般地,其界面表现的语言资 源大部分包含在主执行文件“*.exe”或链接库文件“*.dll”的“菜单”、“对话框”和“字串”三部分中,汉化时,我们只要将其中可修改的其他语种 翻译修改成中文即可。这一类型软件的汉化技术目前已比较成熟,其修改过程一般能实现“所见即所得”。其代表软件有 Winamp、ACDSee、WinZip等。

2、“资源混杂型”软件。多以Delphi编译,通常将窗体、菜单包括界面语言等可修改的资源未作分离而全部混杂在主执行文件“*.exe”或链接库文件 “*.dll”的“RC数据(RCData)”项中,这样就对程序的本地化工作带来了极大的不便,汉化难度相对较大。目前,此类软件的本地化技术还不够成 熟(当然,也不是完全没办法),尚未能实现“所见即所得”的工作环境。

另外还有相当部分的软件(包括以VB编译的程序),其资源数据形态的信息分配相对无序,或将部分资源转移附加在其它数据文件中,甚至一些程序还进行了加壳 或压缩处理,使我们用一般工具很难看到资源所在,为以修改资源为手段的本地化工作带来了种种困难,这些软件程序一般要根据其个别特点进行特别的技术处理, 或采用十分繁杂的方式,才能进行资源修改工作,我们在这里暂且不作深入讨论。

就常规的软件程序说来,软件的资源(界面语言等)部分与内核部分相对独立。为了最大程度地保持软件原貌,同时也是为了尊重软件原作者的劳动和程序版权,我们在汉化过程中不应(也不必要)对软件的内核作修改。

二、常见汉化手段

1、即时界面汉化。如果您根本不想亲自操刀修改程序,仅只是为了能够使用到中文界面的软件,那么其实您并不需要了解本文所介绍的一些知识。您可以用如下两 种方式获得英文软件的中文界面:第一种方式是采用“东方快车”、“金山快译”等即时翻译软件将英文界面转换成中文界面。这种方式不会对软件作任何修改,而 且可以随时转换回原来的英文界面。当然,由于智能翻译的准确性限制,其翻译的效果只能说差强人意,有时甚至出现啼笑皆非的译文,如一般会将“Auto” (软件程序中一般为“自动”之意)翻译成“汽车”等等。其使用简单,也不是本文的目的,在这里就不展开说明;第二种方式是安装现成的汉化包进行汉化。您只 要到汉化或软件网站以及杂志光盘中找到汉化人士早已为您准备的与外文软件所对应的汉化包即可。汉化包的使用方法很简单,它一般是一个可执行文件。在安装了 软件的英文(或其它语种)版后,先确认在系统中完全退出该应用程序,然后执行汉化文件,完成后再启动应用程序时,出现的就是亲切的中文界面了。不过某些汉 化包在安装过程中有一些特殊的要求,您只要阅读一下汉化包附带的说明文本,并按照其提示操作即可。

2、资源永久汉化。这是本文要着重介绍的内容,也就是广大汉化人士所说的“汉化”了。对软件程序的界面语言作适度修改后,就可使软件程序成为永久的“中文版”软件。其一般步骤如下:

第一步、判断类型。先了解将要进行工作的对象,做到有的放矢,心中有数。方法:首先用eXeScope打开看看就略知一二。详细地,我们可以利用 FileInfo 等软件更准确地判断软件的类型。FileInfo的使用相当简单,就笔者经验,用拖曳方式最为快捷。先在Windows中启动MS-DOS方式,然后将 FileInfo的主执行文件拖到MS-DOS界面,键入空格,再将要检测的文件也拖到MS-DOS界面,回车即OK!FileInfo 立即报告出该文件的类型,甚至还能指出所采用的编译工具及加壳类型等信息。

第二步、选定工具。根据上面的判断结果,选用合适的资源修改工具(工具介绍请看本文下一篇)。由于不同程序与不同的汉化工具之间可能存在适应性与兼容性方面的问题,有时可能需要多试几个工具。

第三步、修改资源。选定汉化工具后,就要开始对我们的汉化对象进行“换肤手术”了。这一步是整个汉化过程中最重要、工作量最大的一部分工作,也就是汉化工 作的“重头戏” 了。其主要任务就是将“菜单”、“对话框”、“字串”中的英文翻译成中文。根据翻译任务工作量的的大小,一般以如下方式进行处理:

1、纯手工作业。即找到语言资源后,进行逐字逐句人工翻译。该方式适合翻译量不大的小型软件使用。其优点是出错可能性较小,翻译准确(准确程度在于您自己 的翻译水平呵);缺点嘛,呵呵,劳动强度较大。不过您要知道,大凡精品,均出自handiwork(手工工艺)呵!在工具使用方面,大部分工作用 eXeScope即可完成。另外,VC++ 6.0、BC++ 5.02(这两个有简化的汉化版本可用)以及Resource Hacker(资源黑客)、Resource Workshop(资源工厂),还有较早一点的Pebble 3.10均可考虑使用。而直接修改ASCII字符,则推荐使用UltraEdit 5.0及Hex Workshop。

2、机器翻译。采用“东方快车”之“永久汉化”、“中文工具箱”等带资源写入功能的智能翻译工具。其优点是快捷,点击几下鼠标即完成过程;不过其缺点也是 致命的:质量差,又容易出错(有时修改了不该动的字符,可能导致软件不能正常运行,使您前功尽弃!)。关于质量问题,“东方快车”暂无解决方案,而“中文 工具箱”有“翻译对照档”及“外挂字典”功能,可通过加强前期准备工作的办法在这方面进行较大程度的弥补。另外,“资源混杂型”软件,采用 Language Localizator 的字典功能亦可减轻我们的部分劳动强度。

3、先机器,后人工。对于大多数软件,这就是我们的汉化翻译自然而然要采取的工作程序了。在经机器翻译并确认软件运行正常后,再对其中的译文进行修缮,最后全面完成界面语言翻译工作。

注意事项:

a、不要“过度翻译”。如 List1、$68、Progress、$0A、s%、n、r 等或一些莫名其妙的字符,您千万不要一相情愿地去修改它,否则的话……

b、注意“过程测试”。即每完成一小段工作后,要测试一下程序是否还保持正常运行。否则辛苦几小时后却发现程序根本已经不能运行了,而且连问题出在哪个步骤都搞不清;同时还要时刻注意备份已经完成的有效成果。总之,一旦弄成“白辛苦”,确实是件很痛苦的事呵!

第四步、调整界面。在语言翻译工作完成之后(或在同时),我们需要对软件界面中的字体及各部分的长短高矮等作适当的调整,以适应中文系统的显示特点。英文 软件的界面字体大部分为“MS Sans Serif”,字号为“8号”,而中文系统最佳显示字体(默认字体)为“宋体”,字号为“9号”(即“小五”号),我们可在修改对话框资源时将它改过来。 不过在这一点上,工具软件一般已作了自动设定,如在eXeScope中,您只要点按字号旁边的“改变” 按钮,在出现的字体选择窗口点按“确定”按钮即可

另外,由于即使对于同一个词条,译文与原文的长短一般是不同的,可能需要据此对它们在界面中所占的位置作些许调整。这些调整幅度不宜过大,以界面美观、方 便使用为原则。调整方法(eXeScope中):使用“视图”菜单下的“对话框编辑器”,用鼠标实行“铆定拖曳”或“边界拖曳”即可;也可在点选修改对象 后,改变编辑区最上方的“X”坐标(自左至右横向起点)、“Y” 坐标(自上而下纵向起点)及“宽度”、“高度”编辑框中的数值。

第五步、后期测试。在所有可能的资源修改工作完成之后,我们要对软件的整体作全面的运行测试。虽然在修改的过程中我们也进行了“过程测试”,但最后的测试 是必须要进行的。有时候我们修改的文件不只一个,而是几个或更多时,最后的协同测试就变得尤其重要!事实上,当前个别汉化包使软件的部分功能丧失的现象也 时有出现。我们要使自己的作品尽量保持原有功能,这是一个成功的汉化作品要具备的基本条件和起码品质。

在后期测试过程中,我们通常会发现还有个别顽固的英文词条还是未修改过来,更奇怪的是,查遍全部的菜单、对话框及字串都发现不了,这是怎么回事?不用急, 这一定是作者将这部分资源转移附加在其它代码段或其它数据文件中了。这时候,让我们请出杰出的“16进制编辑器”工具 UltraEdit 5.0(或Hex Workshop等)。呵呵,说UltraEdit是当前汉化人的最后一张“王牌”工具可一点也不过份,因为它的功能实在是太强大了。这里的基本用法是: 启动UltraEdit,在其中打开修改对象文件,使用其“搜索”功能将我们要寻找的英文词条查出,在其右边的编辑区直接将之修改成中文即可!(当然这里 面还有些“道道”,您可自己去慢慢体会,详细使用方法及注意事项在本文第四篇将结合实例介绍)。什么,还搜索不出来?那这个词条可能根本就不在这个文件 中,快看看安装目录中是否有其它可能包含资源的文件!

第六步、打包发布。好啦,全部的资源修改工作全部完成了,辛苦吧?如果只是为了自己即时使用,到这里也就可以收工了。不过,辛苦这么久,您就不想把自己的 成果拿出来与朋友们分享分享?再则,您用了那么多的汉化软件,也不回报一下?好吧,一鼓作气,马上行动。记得首先为您的汉化作品写一个说明文本,向将要使 用您的大作的朋友们交代一下使用方法和其它需要交代的事项。简单一点的,用WinZip、WinRAR打个压缩包;酷一点的,使用WinPatch、 Patch Maker等补丁工具把它做成补丁文件;或者干脆一酷到底,加上专业的安装程序,直接将软件做成百分之百的中文版!打包的具体方法各不相同,请参看关于所 使用打包软件的说明文件或教学文章。

至此,一件完整的汉化作品就诞生了!如何发布出去呢?有条件的,建立自己的主页,将自己的作品放在自己的“网上家园”,时髦而又专业;不过,大多数初学汉 化的朋友可没有这个条件呵,没关系,上传到汉化网站就行。目前,发布汉化作品最方便,坚持得最好的汉化综合网站首推“汉化新世纪”。

第三篇:常用汉化工具简介

“工欲善其事,必先利其器。”现在让我们来看看当前进行汉化作业的“十八般兵器”(各兵器的用法请阅读各汉化站点的汉化教学文章):

兵器库一:程序分析类。所谓“知己知彼,百战不殆”,先搞清下手对象并对其制定作战方案,是取得战斗胜利的重要基础。除了下面列出的两员大将外,象Aspack及UnAspack、UPX等可执行文件压缩/解压工具,也经常成为汉化人的常规武器。

1、FileInfo

最新版本:2.49a
运行平台:Win9X/WinNT/Win2K/WinME/WinXP
软件大小:140KB
下载网址:http://www.hanzify.org/ 之“汉化工具 -相关工具”页面
授权形式:免费

软件功能简介:能检测出软件所使用的编译工具及加壳类型。汉化作业必备工具之一。

2、ProcDump32

最新版本:1.62
运行平台:Win9X/WinNT/Win2K/WinME/WinXP
软件大小:270KB
下载网址:http://www.gb-2312.com/list.asp?id=825
授权形式:免费

软件功能简介:功能强悍的脱壳工具,支持多达由28类、几十种加壳工具生成的压缩加密文件,是修改文件资源前进行脱壳处理的不可多得的利器!

兵器库二:资源修改类。这是汉化的主战场,要使的武器较多,为什么?因为软件程序五花八门,对付起来不容易啊,呵呵。

1、eXeScope

最新版本:6.32
运行平台:Win9X/WinNT/Win2K/WinME/WinXP
软件大小:0.54MB
下载网址:http://www.gb-2312.com/list.asp?id=1222
授权形式:共享

软件功能简介:直接修改语言资源,导出导入图形资源,汉化作业首席工具。

2、中文工具箱

最新版本:1.9 Beta1
运行平台:Win9X/WinNT/Win2K/WinME/WinXP
软件大小:297KB
下载网址:http://www.hanzify.org/ 之“汉化工具 -界面汉化”页面
授权形式:免费

软件功能简介:台湾朋友编写的一个可自动将软件中的英文字挑出、翻译,然后改写成中文界面的工具。自带翻译字典,并有“翻译对照档”及“外挂字典”功能,现已改写成简体中文版。

3、Pebble

最新版本:3.10
运行平台:Win9X/WinNT/Win2K/WinME/WinXP
软件大小:780KB
下载网址:http://www.hanzify.org/ 之“汉化工具 -界面汉化”页面
授权形式:共享

软件功能简介:类似eXeScope,但不可处理图形等资源。用 Pebble 打开可执行文件编辑后可直接在 Win9X/NT下保存。让人称奇的是,其整个程序仅只一个文件。

4、Resource Hacker

最新版本:3.4.0.79
运行平台:Win9X/WinNT/Win2K/WinME/WinXP
软件大小:546KB
下载网址:http://www.hanzify.org/ 之“汉化工具 -界面汉化”页面
授权形式:共享

软件功能简介:用于查看、修改、添加和删除 Win32 可执行文件的资源。内置了一个内部资源编译器和反编译器。

5、VC++ 6.0简化版

最新版本:6.0.8168.2
运行平台:WinNT/Win2K/WinXP
软件大小:3600KB
下载网址:http://www.hanzify.org/ 之“汉化工具 -界面汉化”页面
授权形式:共享

软件功能简介:VC++汉化专用简化版本。能够打开EXE和DLL等文件,查找修改界面语言、图形、甚至改变语系等,但在Win9X下不能存盘。是实现软件完美汉化的必备工具。

6、BC++5.02汉化专用简化版

最新版本:5.02
运行平台:Win9X/WinNT/Win2K/WinME/WinXP
软件大小:4000KB
下载网址:http://www.hanzify.org/ 之“汉化工具 -界面汉化”页面
授权形式:共享

软件功能简介:汉化功能类似VC++6.0,但可在Win9X下存盘。

7、Language Localizator

最新版本:5.04.02.048
运行平台:Win9X/WinNT/Win2K/WinME/WinXP
软件大小:1474KB
下载网址:http://www.hanzify.org/ 之“汉化工具 -界面汉化”页面
授权形式:共享

软件功能简介:针对Delphi格式进行汉化的强力工具,有字典功能。

8、点睛字串替换器

最新版本:1.02
运行平台:Win9X/WinNT/Win2K/WinME/WinXP
软件大小:139KB
下载网址:http://www.hanzify.org/ 之“汉化工具 -汉化辅助”页面
授权形式:共享

软件功能简介:点睛工作室作品。字串替换工具,可以查找和替换 VB 程序或其它程序的字串。能解决汉化超长截断问题,支持普通 UniCode 码及 ASCII码。

兵器库三:文本编辑类。在处理ASCII码或其它非资源性界面语言时,以上武器肯定会力不从心。这时候,我们就要请16进制编辑工具出马了!

1、UltraEdit

最新版本:9.00b
运行平台:Win9X/WinNT/Win2K/WinME/WinXP
软件大小:1600KB
下载网址:http://www.hanzify.org/ 之“实用工具 -文本编辑”页面
授权形式:共享

软件功能简介:功能强大的文本及 16 进制编辑工具。可同时打开多个文件并可在之间快速切换;支持多文件查找、替换;支持自定义宏命令,多语言突出显示。汉化人的终极王牌工具!

2、Hex Workshop

最新版本:3.11
运行平台:Win9X/WinME
软件大小:原版1793KB,汉化581KB
下载网址:http://chinease.myetang.com/local.htm
授权形式:共享