RSS 2.0 Feed
技术类
摘要:理解 ActiveObject ActiveObject 在symbian里是一个很重要的概念应该说所有的Symbian程序都是运行在一个或多个ActiveObject里面。 大多数Symbian的程序的入口几乎都是这样的,除了少数Console程序以外GLDEF_C TInt E32Main(){ return EikStart::RunApplication( NewApplication );} 如果你有机会调试并跟踪到Symbian的源代码里面,你会发现EikStart::RunApplication会调用CActiveScheduler::Start() 这个调用意味着启动了一个 Scheduler 也就意味着进入了 ActiveScheduler的循环。 程序运行进入CActiveScheduler::Start()之后就不会出来了,直到程序结束。 这似乎很象什么?对了,象windows的消息循环! while(getmessage(...)){ TranslateMessage(...); DispatchMessage(...);} 除非程序退出,否则会一直运行在这样的死循环里面。 Scheduler::Start里面也是类似的代码,做着类似的事情1。等待事件2。找一个合适的对象来处理事件3。然后继续等待事件,直到得到一个退出的事件。 但是和windows的消息循环不一样的地方在于,Scheduler 里面调度的不是窗口而是一个个ActiveObject,Scheduler获得了一个事件后,就会找一个合适的ActiveObject去处理事件 所有的ActiveObject在创建后会通过CActiveScheduler::Add 把自己加入到Scheduler里面。 这套模式又使我想起了什么,对了,是ACE--那个网络程序的framework,ACE中也是类似的模式不过Scheduler叫做Reactor。不过ActiveObject叫做Task。 本质上讲,这就是一套用单线程通过事件驱动,来模拟多任务的设计模式。每个ActiveObject是独立的,多个ActiveOject看似是并行的,实际上却是运行在一个线程里。 不同的是ACE里面的 Reactor 是可以多线程的,可以用一个线程池来同时执行多个 Task。 在symbian的世界里,设备的资源都很有限,内存小,CPU也慢,所以开一个线程开销比较大,ActiveObject有效的代替了部分多线程的功能。 编写ActiveObject还是比较简单的,所有的ActiveObject都是从CActive派生的。其中RunL、DoCancel 是必须重载的虚函数,每次有事件发生Scheduler就会调用RunL那么如果有多个ActiveObject存在,那么事件发生了Scheduler怎么才能知道该调用哪个ActiveObject呢? 很简单,每个ActiveObject都有一个iStatus成员,每个事件发生器都会指定一个iStatus,Scheduler会调用iStatus对应的那个ActiveObject。 比如最简单事件发生器,RTimer,他的作用是在指定的时间后产生一个事件,起到定时器的作用用法如下RTimer t;t.After(iStatus, 1000000); 上面的语句表示在1秒钟后 产生事件,这个事件将由iStatus对应的ActiveObject来响应。(Symbian系统下 时间单位是 1/1000000 秒,而不是1/1000秒)  ...[阅读全文]

posted @ | Feedback (2) |

摘要:理解 NewL ConstructL NewLC ELeave 初学Symbian开发,第一件感觉迷惑的事情是CleanupStack 第二件肯定是随处可见的NewL,NewLC,ConstructL。这些函数的出现依然和内存泄漏有关,这是一种被称为两步构造的机制,英文叫Two-phase Construction。我知道C++里面的 new 操作符实际上完成2件事,第一根据对象类的大小在堆上分配一块内存并获得指向内存的指针,第二利用指针调用类的构造函数,最后把指针返回。 在Symbian上这样做是有隐患的,就是当你分配好了内存,但是调用构造函数的时候程序意外退出了,这样会造成刚才分配的内存产生泄漏。只有那些放入CleanupStack的内存,在程序意外结束后会被释放,new 分配的内存在调用构造函数之前还没有被放入CleanupStack呢。 Symbian的设计师为了解决这个问题,给所有开发者设计了一个编写程序的定式,这就是Two-phase Construction。 具体是这样的: 把普通的new 操作分为2个步骤来进行,第一步只分配内存,当分配的内存被放入cleanupstack后,第二步进行构造。但是在C++里 如何阻止编译器的new操作不调用构造函数呢?这个貌似不可以。。。于是Symbian的设计者作了个规定,类在构造函数里不要做任何可能产生异常的操作,只能做那些绝对安全的事情,比如简单的变量赋值,然后提供一个名字叫 ConstructL的函数,在这个函数里做所有类的初始化工作,当然包括那些危险的可能导致异常的操作。 那么 Symbian的 类构造就变成了这样比如 有一个叫 CFoo 的类,我想声明一个指针 p,创建一个CFoo的对象赋给 pCFoo *p = new(ELeave) CFoo();CleanupStack::PushL(p);p->ConstructL();CleanupStack::Pop(); 这样写是不是有点太罗嗦?每个对象都要用4条语句创建,如果是频繁使用实在是太麻烦了。于是Symbian的设计者又作了一个规定,每个类要实现一个NewL的static函数来完成上面的4条语句的工作class CFoo{public: static CFoo *NewL() {  CFoo *self = new(ELeave) CFoo();  CleanupStack::PushL(self);  self->ConstructL();  CleanupStack::Pop();  return self; }} 有了NewL以后,调用CFoo的类的程序简化了CFoo *p = CFoo::NewL(); 那么NewLC又是什么呢?和NewL有什么不同?有些类是这样的,他们提供一些方法,需要在对象创建完成后执行,但是这些方法也是会产生异常的比如CFoo 如果有一个方法叫 DoSomethingL() 那么程序可以这样写吗?CFoo *p = CFoo::NewL();p->DoSomethingL(); 显然这样写是有问题的正确的写法是CFoo *p = CFoo::NewL();CleanupStack::PushL(p);p->DoSomethingL();CleanupStack::Pop(); 天啊,又是4条语句,太麻烦了。要知道在NewL结尾我们刚刚把CFoo的指针从CleanupStack里拿出来,马上就又放了进去。是不是可以简化呢,那好我们再节约2条语句NewL去掉结尾的CleanupStack::Pop(); static CFoo *NewL() {  CFoo *self = new(ELeave) CFoo();  CleanupStack::PushL(self);  self->ConstructL();  return self; }调用去掉CleanupStack::PushLCFoo *p = CFoo::NewL();p->DoSomethingL();CleanupStack::Pop(); Symbian的设计者又规定了,具有以上行为的NewL 应该叫NewLC。表示指针返回后,没有从CleanupStack里取出,你可以继续调用一个危险的操作,在最后调用CleanupStack::Pop(); 我发现 NewL 可以通过调用NewLC实现。那么一个符合Symbian设计师的N条规定的类应该这样写 class CFoo{public: static CFoo *NewLC() {  CFoo *self = new(ELeave) CFoo();  CleanupStack::PushL(self);  self->ConstructL();  return self; }  static CFoo *NewL() {  CFoo *self = NewLC();  CleanupStack::Pop();  return self; }  virtual ~CFoo() { } protected: CFoo() { }  void ConstructL() { // .... }} 这里注意 CFoo的构造函数不能是Public的,为了防止使用者用new 或者在栈上创建对象。析构函数要写成虚函数,这是纯C++问题,不明白的去看 More Effective C++ 要说明一下,以上的写法是Symbian极力推荐的,但是不是硬性规定的,你只要保证没有内存泄漏可以不这么写。我个人还是推荐这样,这样的代码写Symbian程序的人都可以很好地理解。 最后说一下 new 之后为什么要有一个 (ELeave)。new操作符是被Symbian重载过了,ELeave是给new的一个参数,他的意思是告诉new当无法分配内存时程序就退出。比如内存不足的时候。 所以我们用了ELeave的话 就不用检查new 返回的指针了,能返回就一定是对的如果出了错程序就结束掉了,new根本就不会返回。 NewL NewLC 是Symbian程序标志性的函数,所以有个Symbian开发的资源站点就叫 www.newlc.com...[阅读全文]

posted @ | Feedback (9) |

摘要:关于定时器 定时器是个很有意思的东西,它很有用,但我认为这不是现代计算机的结构所擅长的事情。计算机适合做那些很大量的简单重复工作,或者根据请求做出回应。 DOS时代是没有进程线程等概念的,那时候要想做到定时真是有些麻烦通常的做法是死循环不断监测时间,发现时间到了就做特定的事情当然你可以用delay,来指定等待多长时间,但是如果你一边要响应用户的操作,比如输入,一边要定时做些事情就是一件麻烦的事了 当然有些人可以这样做,截取系统的时钟中断(我忘了中断号是多少了),每秒钟有18.2次当这些做法都不是很优雅。但DOS时代只能这样凑合着了 Windows是个伟大的进步,系统提供了Timer支持,但是问题是这个定时器并不准时而且有时候根本不能用。 Win32 API中有个SetTimer函数,可以为一个窗口创建一个定时器,这个定时器会定时产生消息WM_TIMER也可以调用指定的回调函数,其实这都是一样的,因为都是单线程的。 单线程的定时器会有很多问题,首先是不准时,定时器只是定时把消息WM_TIMER访到线程的消息队列里,但是并不保证消息会立刻被响应,如果碰巧系统比较忙,那么消息可能会在队列里放一端时间才被响应,还会造成本来应该间隔一段时间发生的消息响应连续发生了 解决方法通常是 OnTimer(...){ //Timer process.....  MSG msg; While(PeekMessage(&msg, m_hWnd, WM_TIMER, WM_TIMER, PM_REMOVE));}在当前Timer处理中,把消息队列里的WM_TIMER消息,清除掉。 更糟的是如果你不去调用GetMessage,那么就不会有Timer发生了。这个问题直到win xp都没什么改变,似乎微软并不打算在Win32 API中解决这个问题了。 .NET Framework为我们带来了新的解决方案 .NET Framework提供三种Timer Server Timers        System.Timers.TimerThread Timers       System.Threading.Timer Windows Timers   System.Windows.Forms.Timer 其中Windows Timers只是提供了和WinAPI 一样的Timer,仍然是基于消息,仍然是单线程 其它两个就不同了,他们是基于线程池的Thread Pool,这样最大的好处在于,产生的时间间隔准确均匀。Server Timers  和 Thread Timers 的不同在于ServerTimers 是基于事件的,Thread Timers是基于回调函数 我更喜欢Thread Timer,比较轻量级方便易用。 但是这样的Timer也有问题,就是由于时多线程定时器,就会出现如果一个Timer处理没有完成,到了时间下一个照样会发生,这就会导致重入问题 对付重入问题通常的办法是加锁,但是对于 Timer却不能简单的这样做,你需要评估一下 首先Timer处理里本来就不应该做太需要时间的事情,或者花费时间无法估计的事情,比同远方的服务器建立一个网络连接,这样的做法尽量避免 如果实在无法避免,那么要评估Timer处理超时是否经常发生,如果是很少出现,那么可以用lock(Object)的方法来防止重入如果这种情况经常出现呢?那就要用另外的方法来防止重入了 我们可以设置一个标志,表示一个Timer处理正在执行,下一个Timer发生的时候发现上一个没有执行完就放弃执行 static  int inTimer = 0;public static void threadTimerCallback(Object obj){     if ( inTiemr == 0 )    {         inTimer = 1;                   Console.WriteLine("Time:{0}, \tThread ID:{1}", DateTime.Now, Thread.CurrentThread.GetHashCode());         Thread.Sleep(2000);          inTimer = 0;      }} 但是在多线程下给inTimer赋值不够安全,还好Interlocked.Exchange提供了一种轻量级的线程安全的给对象赋值的方法  static int inTimer = 0; public static void threadTimerCallback(Object obj) {       if ( Interlocked.Exchange(ref inTimer, 1) == 0 )      {           Console.WriteLine("Time:{0}, \tThread ID:{1}", DateTime.Now, Thread.CurrentThread.GetHashCode());           Thread.Sleep(250);            Interlocked.Exchange(ref inTimer, 0);      } }  ...[阅读全文]

posted @ | Feedback (8) |

摘要:web.config文件自定义配置节的使用方法的一个简单例子 用来演示的程序名为MyApp,Namespace也是MyApp 1。编辑web.config文件 添加以下内容,声明一个Section <configSections>    <section name="AppConfig" type="MyApp.AppConfig, MyApp" /> </configSections>   声明了一个叫AppConfig的Section 2。编辑web.config文件 添加以下内容,加入一个Section <AppConfig>  <add key="ConnectionString" value="this is a ConnectionString" />   <add key="UserCount" value="199" /></AppConfig> 这个Section包括两个 Key 3。从IConfigurationSectionHandler派生一个类,AppConfig 实现Create方法,代码如下 public class AppConfig : IConfigurationSectionHandler{  static String m_connectionString = String.Empty;  static Int32 m_userCount = 0;  public static String ConnectionString  {   get   {    return m_connectionString;   }  }  public static Int32 UserCount  {   get   {    return m_userCount;   }  }   static String ReadSetting(NameValueCollection nvc, String key, String defaultValue)  {   String theValue = nvc[key];   if(theValue == String.Empty)    return defaultValue;    return theValue;  }   public object Create(object parent, object configContext, XmlNode section)  {   NameValueCollection settings;      try    {     NameValueSectionHandler baseHandler = new NameValueSectionHandler();     settings = (NameValueCollection)baseHandler.Create(parent, configContext, section);    }    catch    {     settings = null;    }       if......[阅读全文]

posted @ | Feedback (19) |

摘要:这篇文章最早是发在北极星论坛的一系列帖子,那时候闻怡洋(好像他也是MVP)也在那里混 原始的帖子我已经没有了,但不知道是谁帮我收集整理了下来(非常感谢),我用google找到了 ? 这是我进金山之前写的,应该不算泄露公司技术秘密吧 而且这些现在看来似乎已经有些过时了 ? 那时讨论的只是Win31和Win9x下的取词实现 ? 我到了金山之后不是负责取词模块,而是做UI,因为有个家伙比我更擅长做这种东西 他用SoftIce调试汇编代码非常熟练,做逆向工程方面有过人的天分。 ? ? “亦东” 是我那时的笔名 ? ? “金山词霸”屏幕取词技术揭密(讨论稿) ? 主题  屏幕取词技术系列讲座(一) 作者   亦东 很多人对这个问题感兴趣。 原因是这项技术让人感觉很神奇,也很有商业价值。 现在词典市场金山词霸占了绝对优势,所以再做字典也没什么前途了。我就是这么认为的,所以我虽然掌握了这项技术,却没去做字典软件。只做了一个和词霸相似的软件自己用,本来想拿出来做共享软件,但我的词库是“偷”来的,而且词汇不多,所以也就算了,词库太小,只能取词有什么用呢?而且词霸有共享版的。 但既然很多人想了解这项技术,我也不会保留。我准备分多次讲述这项技术的所有细节。 大约每周一两次。想知道的人就常常来看看吧! 一.基础知识 首先想编这种程序需要一些基础知识。 会用Vc++,包括16/32位。 精通Windows API特别是GDI,KERNEL部分。 懂汇编语言,会用softice调试程序,因为这种程序最好用softice调试。 二.基本原理 在Window 3.x时代,windows系统提供的字符输出函数只有很少的几个。 TextOut ExtTextOut DrawText ...... 其中DrawText最终是用ExtTextOut实现的。 所以Windows的所有字符输出都是由调用TextOut和ExtTextOut实现的。因此,如果你可以修改这两个函数的入口,让程序先调用你自己的一个函数再调用系统的字符输出,你就可以得到Windows所有输出的字符了。 到了Windows95时代,原理基本没变,但是95比3.x要复杂。开始的时候,一些在windows3.x下编写的取词软件仍然可以是使用。但是后来出了个IE4,结果很多词典软件就因为不支持IE4而被淘汰了,但同时也给一些软件创造了机会,如金山词霸。其实IE4的问题并不复杂,只不过它的输出的是unicode字符,是用TextOutW和ExtTextOutW输出的。知道了这一点,只要也截取就可以了。不过实现方法复杂一点,以后会有详细讲解。现在又出了个IE5,结果词霸也不好用了,微软真是#^@#$%$*&^&#@#@.......... 我研究后找到了一种解决办法,但还有些问题,有时会取错,正在继续研究,希望大家共同探讨。 另外还有WindowsNT,原理也是一样,只是实现方法和95下完全不同。 三.技术要点 要实现取词,主要要解决以下技术问题。 1.截取API入口,获得API的参数。 2.安全地潜入Windows内部,良好地兼容Windows的各个版本 3.计算鼠标所在的单词和字母。 4.如果你在Window95下,做32位程序,还涉及Windows32/16混合编程的技术。 今天先到这里吧!最好准备一份softice for 95/98和金山词霸,让我们先来分析一下别人是怎么做的。 欢迎与我联系 E-Mail:yeedong@163.net 主题  屏幕取词技术系列讲座(二) 作者   亦东 很抱歉让大家久等了! 我看了一些人的回帖,发现很多人对取词的原理还是不太清楚。 首先我来解释一下hook问题。词霸中的确用到了hook,而且他用了两种hook其中一种是Windows标准hook,通过SetWindowHook安装一个回调函数,它安装了一个鼠标hook,是为了可以及时响应鼠标的消息用的和取词没太大关系。 另一种钩子是API钩子,这才是取词的核心技术所在。他在TextOut等函数的开头写了一个jmp语句,跳转到自己的代码里。 你用softice看不到这个跳转语句是因为它只在取词的一瞬间才存在,平时是没有的。 你可以在TextOut开头设一个读写断点 bpm textout 再取词,就会找到词霸用来写钩子的代码了。 /********************************** 所以我在次强调,想学这种技术一定要懂汇编语言和熟练使用softice. **********************************/ 至于从cjktl95中dump出来的未公开函数是和Windows32/16混合编程有关的,以后我会提到他们。 我先来讲述取词的过程, 0 判断鼠标是否在一个地方停留了一段时间 1 取得鼠标当前位置 2 以鼠标位置为中心生成一个矩形 3 挂上API钩子 4 让这个矩形产生重画消息 5 在钩子里等输出字符 6 计算鼠标在哪个单词上面,把这个单词保存下来 7 如果得到单词则摘掉API钩子,在一段时间后,无论是否得到单词都摘掉API钩子 8 用单词查词库,显示解释框。 很多步骤实现起来都有一些难度,所以在中国可以做一个完善的取词词典的人屈指可数。 其中0,1,2,7,8比较简单就不提了。 先说如何挂钩子: 所谓钩子其实就是在WindowsAPI入口写一个JMP XXXX:XXXX语句,跳转到自己的代码里。 步骤如下: 1.取得Windows API入口,用GetProcAddress实现 2.保存API入口的前五个字节,因为JMP是0xEA,地址是4个字节 3.写入跳转语句 这步最复杂 Windows的代码段本来是不可以写的,但是Microsoft给自己留了个后门。 有一个未公开函数是AllocCsToDsAlias, UINT WINAPI ALLOCCSTODSALIAS(UINT); 你可以取到这个函数的入口,把API的代码段的选择符(要是不知道什么是选择符,就先去学学保护模式编程吧)传给他,他会返回一个可写的数据段选择符。这个选择符用完要释放的。用新选择符和API入口的偏移量合成一个指针就可以写windows的代码段了。 这就是取词技术的最核心的东东,不止取词,连外挂中文平台全屏汉化都是使用的这种技术。现在知道为什么这么简单的几句话却很少知道了吧?因为太多的产品使用他,太多的公司靠他赚钱了。 这些公司和产品有:中文之星,四通利方,南极星,金山词霸,实达铭泰的东方快车,roboword,译典通,即时汉化专家等等等等。。。。还有至少20多家小公司。他们的具体实现虽然不同,但大致原理是相同的。 我这些都是随手写的,也没有提纲之类的东西,以后如果有机会我会整理一下,大家先凑合着看吧!xixi... ? 主题......[阅读全文]

posted @ | Feedback (102) |