一片枫叶's profile追梦的人BlogLists Tools Help

枫叶

Occupation
Interests
人要倒退,可以有一千个理由,而要前进,只需要一个信念
No list items have been added yet.

追梦的人

March 22

类似boost库function的免delete委托实现

困难不因你害怕而不出现,只因你勇敢面对迎刃而解
                     ------ 鼓励已成大龄程序员的自己
                    
近来试验着重写一个C++的委托功能,就是.net里的delegate关键字描述的东东,似乎C++里喜欢说是成员函数closure,记不太清楚了。
原来的实现跟loki库里的思路差不多,就是利用虚函数描述委托函数的原型,这个原型与具体实现类无关,子类实现函数的功能,实现
里可以记住具体实现函数的类实例,现在看来没有什么很巧妙的东东了:
1、接口层,纯虚接口,与实现对象无关。
class IEvent
{
public:
virtual ~IEvent(){}
public:
virtual bool operator () (const EventArg& arg)=0;
};
2、实现层,利用模板参数化实现对象类型。
template<typename Obj>
class Event : public IEvent
{
 typedef bool (Obj::*Fptr)(const EventArg&);
public:
 Event(Obj* pObj,Fptr fptr)
 {
  mObj=pObj;
  mFunc=fptr;
 }
 bool operator () (const EventArg& arg)
 {
  return (mObj->*mFunc)(arg);
 }
private:
 Obj* mObj;
 Fptr mFunc;
};
3、创建函数,利用模板推导自动提供对象类型。
template<typename Obj>
IEvent* create(Obj* pObj,bool (Obj::*fptr)(const EventArg&)
{
 return new Event<Obj>(pObj,fptr);
}
boost库里的function不使用虚函数机制,而是使用安全的强制转换实现了这种委托功能,它的核心技术在于对成员函数closure
的对象封装(对象指针可以与普通指针互相强制转型)以及模板类的静态成员函数指针(函数原型可以不依赖模板类的模板参数
,而函数实现可以使用模板类的模板参数,从而实现虚函数接口与实现动态绑定的类似效果)。
委托的实质其实是用一个普通函数原型(实现类无关的)关联一个函数closure对象(绑定到具体实现类的),一个是接口层的,
一个是实现层的。
不管是虚函数的实现还是基于强制转型的实现,closure对象的数据部分主要包含一个对象指针与一个函数指针,这两个指针在委
托的生命周期内是必须有效的,委托无需关心它们指向对象的释放,委托需要关心的是closure对象实例的释放,因为closure对象
有实现类的信息,不能直接作为委托的数据成员(否则委托方就被绑定到一个具体实现类了,而委托的涵义是可以有任意类型的实
现类),所以基于虚函数的实现与boost库的实现均使用了堆内存分配closure对象,从而强加给委托方一个释放的职责。
closure对象因为只是两个指针,占用的空间很小,如果不倒致类型依赖的话,作为委托方的数据成员是完全合适的,由此我们可
以看到一个底层的实现,假设委托方类为Delegation,closure对象类为Closure:
class Delegation
{
public:
 ...
 接口层的东西
 ...
private:
 char space[sizeof(Closure)];
};
Delegation d;
Closure c;
*(Closure*)&(d.space)=c;//直接浅拷贝
经过这样的处理,Delegation的成员space的空间里就会保存一个Closure实例的数据,在实现代码里再将此数据强制转成Closure
对象也就没问题了(boost的实现里的模板类静态成员函数invoke里正适合做此工作),这里还有一个问题,就是sizeof(Closure)
,其中出现了Closure,会倒致Delegation对Closure的依赖,不过我们只是想知道Closure实例的大小,这个依赖似乎是可以消除的
,前面说过,Closure里主要是保存一个对象指针与一个成员函数指针,我们只需要伪造一个类似的虚拟类,用这个虚拟类来获取
实例大小即可(也就是Delegation依赖一个虚拟类获取大小,这个大小却适用于任何Closure对象),因为涉及成员函数指针,C++对
有多重继承的类与无多重继承的类的成员函数指针大小是不一样的,我们这里需要取尺寸的最大值,也就是使用一个多重继承的虚
拟类。
上面的方法是利用对象实例浅拷贝来存储实例数据的,与此类似,还有一个办法是像内存池的实现一样重载new操作,采用带placement
参数的new重载,明确的将空间指定,下面我们给出基于重载new的实现,对我而言,用重载new感觉上比对象实例浅拷贝更优雅一些。
//提供Closure存储空间的虚拟类
struct ObjectPlaceHolder
{
 //用来模拟实际情况类的虚拟类,成员函数指针在有继承与无继承下大小不一样,
 //ObjectPlaceHolder需要提供足够的空间供MemFuncInvoker...实例存储,所以需
 //要按多继承情形模拟成员函数指针。
 class DummyBaseA
 {};
 class DummyBaseB
 {};
 class DummyClass : public DummyBaseA,
  public DummyBaseB
 {};
public:
 ObjectPlaceHolder()
 {
  clear();
 }
 ObjectPlaceHolder(const ObjectPlaceHolder& other)
 {
  obj=other.obj;
  fptr=other.fptr;
 }
 inline bool isNull(void) const
 {
  return obj==NULL || fptr==NULL;
 }
 inline void clear(void)
 {
  obj=NULL;
  fptr=NULL;
 }
private:
 DummyClass* obj;
 void (DummyClass::*fptr)(void);
};
//Closure对象实现,同时实现了静态成员函数接口invoke,这是实现虚函数相似功能的关键
//重载的new方法使用指定的空间作为对象实例化的空间,因为我们实际上是用的委托方的空
//间,并不需要释放,所以delete方法什么也不做
template<typename Delegation,typename T,typename R>
struct MemFuncInvoker0
{
private:
 friend typename Delegation;
 typedef MemFuncInvoker0<Delegation,T,R> ThisType;
 typedef R (T::*Fptr)(void);
 MemFuncInvoker0(T* obj,Fptr func)
 {
  mObj=obj;
  mFunc=func;
 }
 static inline R invoke(const ObjectPlaceHolder* address)
 {
  const ThisType* pThis=reinterpret_cast<const ThisType*>(address);
  T* pObj=pThis->mObj;
  Fptr pFunc=pThis->mFunc;
  return (pObj->*pFunc)();
 }
 static inline void* operator new (size_t size,const ObjectPlaceHolder* address,size_t space)
 {
  _ASSERT(size<=space);
  return (void*)address;
 }
 static inline void operator delete(void*,const ObjectPlaceHolder* address,size_t space)
 {}
private:
 T* mObj;
 Fptr mFunc;
};
//委托的实现
template<typename R>
struct Delegation0
{
public:
 typedef Delegation0<R> ThisType;
 typedef R (*InvokerType)(const ObjectPlaceHolder*);
public:
 Delegation0()
 {
  detach();
 }
 Delegation0(const Delegation0& other)
 {
  mObj=other.mObj;
  invoker=other.invoker;
 }
 template<typename T>
 Delegation0(T* obj,R (T::*fptr)(void))
 {
  attach(obj,fptr);
 }
 template<typename T>
 inline void attach(T* obj,R (T::*fptr)(void))
 {
  invoker=MemFuncInvoker0<ThisType,T,R>::invoke;
  new(&mObj,sizeof(ObjectPlaceHolder)) MemFuncInvoker0<ThisType,T,R>(obj,fptr);
 }
 inline void detach(void)
 {
  mObj.clear();
  invoker=NULL;
 }
 inline bool isNull(void) const
 {
  return mObj.isNull() || invoker==NULL;
 }
 inline R operator () (void)
 {
  return invoker(&mObj);
 }
private:
 ObjectPlaceHolder mObj;//用来保存MemFuncInvoker实例的空间
 InvokerType invoker;
};
上面的实现是对有一个返回类型(含void)无参数的函数样式的委托,一个典型用法如下:
class A
{
public:
 char* run(void)
 {
  if(!onRun.isNull())
   return onRun();
 }
public:
 Delegation0<char*> onRun;
};
class B
{
public:
 char* test(void)
 {
  return "B::test called !";
 }
};
int main(void)
{
 A a;
 B b;
 a.onRun.attach(&b,&B::test);
 std::cout<<a.run()<<std::endl;
 ::_getch();
 return 0;
}
可以看到动态的将A::run委托到B::test的实现了。
November 20

笔记:DataGridView用对象做数据源时可能存在一个BUG

做了一个小的试验,一个DataGridView,一个BindingSource,然后用List<T>作实际的数据源。
当T为struct时,编辑功能失效,修改完按enter,cell里的内容立即恢复为初始值。
大致看了一下DataGridView的操作过程,
1、DataGridView用户操作的事件处理,比如按键、鼠标等;
2、DataGridView.CommitEdit方法;
3、DataGridViewCell.SetValue方法;
5、PropertyDescriptor.SetValue方法。
以前在用PropertyGrid时曾经研究过像PropertyDescriptor这一类.net设计时架构的关键元素,依稀记得对于struct与对object的处理有很大
的不同,于是试了试将T由struct改为class,再试,编辑功能正常。
没有时间研究具体原因了,以后有兴趣时再说吧,先记下。
 
从MS的几个大部头控件可以看到这向个控件背后有一个庞大的架构支撑,不过MS在介绍它们时就像介绍别的普通控件一样一寥寥数笔,实在是
令人费解,而且这个几个大部头控件的实现类相当多,不过大多为internal不为用户所见,如果不使用reflector这样的反编译工具,使用这些控件时出问题基本上是一头雾水的。
另外一点,MS的reflection API对.net framework的几个架构的支持非常重要,而reflection API基本上是目前.net程序安全的一个大问题,不知道以后MS如何处理这个矛盾(当然,从open source的角度看,这里本没有矛盾,呵呵)。
November 08

笔记:为ntdll.dll创建移入库ntdll.lib

本来以为很简单的,结果费了一番周折,为了防止下次重蹈覆辙,记个笔记。
一开始的想法:
1、用impdef或dumpbin生成一个ntdll.dll的模块定义文件ntdll.def;
2、用lib /def:ntdll.def生成ntdll.lib;
3、按网上hacker给出的函数原形写个头文件ntdll.h.
结果编译时说无法链接_LdrLoadDll@16,看起来是__stdcall调用约定修饰名的原因,但是找不到办法将链接时的_LdrLoadDll@16转换到DLL实际输出的名称LdrLoadDll,查def文件格式时有EXPORTS部分的写法:
entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA]
以为可以用这种方法换名,于是改def文件:
重新生成ntdll.lib后程序编译通过,但是运行提示找不到_LdrLoadDll@16入口点,看来这次反过来了,移入库里我名称对了,但还是没对应到DLL实际输出的名称。
 
想不出办法了,所以到网上搜了一下,发觉原MS在DDK提供了一个ntdll.lib,汗!
 
最后不知道从哪看到一个说自己建一个dll工程ntdll,然后生成移入库,于是试了试,自己建一个纯win32 dll项目,加一个模块定义文件:
EXPORTS
LdrLoadDll
再在程序里写一个与ntdll.dll里LdrLoadDll原型一样的空函数,编译一下,得到一个ntdll.lib,用这个编译原来的程序,编译通过,运行,
也OK了,用dumpbin看一下生成的ntdll.lib,呵呵,居然它就是用的_LdrLoadDll@16这个名字,但它却能正确的定位ntdll.dll里的LdrLoadDll,搞不明白了,为什么,lib /def:ntdll.def生成的库就不行:(
 
这方法麻烦点,不过可行,就这样吧,MS的东西,搞不明白的太多了!
 
August 16

.NET里的优化太差了!

一般来说编译型,甚至许多解释型的语言教程里会说:请不要自己优化代码,语言编译器是足够聪明的。不过今天我却发现.NET 2.0的优化实在是太。。。。。。了!
我测试了一下foreach与for循环的代码(为了防止误解编译器的优化能力,我加了一个多线程锁,.NET工程没有单线程与多线程的属性,所以我猜测编译器不敢做优化是害怕多线程并发修改变量,于是特地告诉它这块不会有并发修改的情况):
        private void TestColl()
        {
            List<int> intList=new List<int>();
            for(int i=0;i<10;i++)
            {
                intList.Add(i);
            }
            lock (intList)
            {
                for (int i = 0; i < intList.Count; i++)
                {
                    intList[i].CompareTo(1);
                    intList[i].Equals(1);
                    intList[i].GetHashCode();
                    intList[i].GetTypeCode();
                    intList[i].ToString();
                }
            }
            foreach(int i in intList)
            {
                i.CompareTo(1);
                i.Equals(1);
                i.GetHashCode();
                i.GetTypeCode();
                i.ToString();
            }
        }
我知道foreach是利用IEnumerable接口实现的,也就是它会在每次循环调用get_Current与MoveNext来得到集合中的下一个元素,而for语句是直白的,它按我们所写的那样去做,现在我假想一下一般编译器应该会做的优化(第二个循环),在循环开始调get_Item(i)来得到集合中元素的值,然后用这个值依次执行后续的方法调用,因为在这段代码里我们并没有改变集合中的元素,而且这段代码加锁了,确保集合在这期间不会被别的线程改变,所以先取出集合中的元素,再访问它的若干方法是最常见的提取公共表达式相似的优化。那么.NET是这么做的吗?我们来看一下对应的IL:
.method private hidebysig instance void TestColl() cil managed
{
      .maxstack 2
      .locals init (
            [0] [mscorlib]System.Collections.Generic.List`1<int32> list1,
            [1] int32 num1,
            [2] int32 num2,
            [3] int32 num3,
            [4] [mscorlib]System.Collections.Generic.List`1<int32> list2,
            [5] int32 num4,
            [6] int32 num5,
            [7] int32 num6,
            [8] int32 num7,
            [9] int32 num8,
            [10] [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> enumerator1)
      L_0000: newobj instance void [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
      L_0005: stloc.0
      L_0006: ldc.i4.0
      L_0007: stloc.1
      L_0008: br.s L_0015
      L_000a: ldloc.0
      L_000b: ldloc.1
      L_000c: callvirt instance void [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
      L_0011: ldloc.1
      L_0012: ldc.i4.1
      L_0013: add
      L_0014: stloc.1
      L_0015: ldloc.1
      L_0016: ldc.i4.s 10
      L_0018: blt.s L_000a
      L_001a: ldloc.0
      L_001b: dup
      L_001c: stloc.s list2
      L_001e: call void [mscorlib]System.Threading.Monitor::Enter(object)
      L_0023: ldc.i4.0
      L_0024: stloc.2
      L_0025: br.s L_0082
      L_0027: ldloc.0
      L_0028: ldloc.2
      L_0029: callvirt instance !0 [mscorlib]System.Collections.Generic.List`1<int32>::get_Item(int32)
      L_002e: stloc.s num4
      L_0030: ldloca.s num4
      L_0032: ldc.i4.1
      L_0033: call instance int32 int32::CompareTo(int32)
      L_0038: pop
      L_0039: ldloc.0
      L_003a: ldloc.2
      L_003b: callvirt instance !0 [mscorlib]System.Collections.Generic.List`1<int32>::get_Item(int32)
      L_0040: stloc.s num5
      L_0042: ldloca.s num5
      L_0044: ldc.i4.1
      L_0045: call instance bool int32::Equals(int32)
      L_004a: pop
      L_004b: ldloc.0
      L_004c: ldloc.2
      L_004d: callvirt instance !0 [mscorlib]System.Collections.Generic.List`1<int32>::get_Item(int32)
      L_0052: stloc.s num6
      L_0054: ldloca.s num6
      L_0056: call instance int32 int32::GetHashCode()
      L_005b: pop
      L_005c: ldloc.0
      L_005d: ldloc.2
      L_005e: callvirt instance !0 [mscorlib]System.Collections.Generic.List`1<int32>::get_Item(int32)
      L_0063: stloc.s num7
      L_0065: ldloca.s num7
      L_0067: call instance [mscorlib]System.TypeCode int32::GetTypeCode()
      L_006c: pop
      L_006d: ldloc.0
      L_006e: ldloc.2
      L_006f: callvirt instance !0 [mscorlib]System.Collections.Generic.List`1<int32>::get_Item(int32)
      L_0074: stloc.s num8
      L_0076: ldloca.s num8
      L_0078: call instance string int32::ToString()
      L_007d: pop
      L_007e: ldloc.2
      L_007f: ldc.i4.1
      L_0080: add
      L_0081: stloc.2
      L_0082: ldloc.2
      L_0083: ldloc.0
      L_0084: callvirt instance int32 [mscorlib]System.Collections.Generic.List`1<int32>::get_Count()
      L_0089: blt.s L_0027
      L_008b: leave.s L_0095
      L_008d: ldloc.s list2
      L_008f: call void [mscorlib]System.Threading.Monitor::Exit(object)
      L_0094: endfinally
      L_0095: ldloc.0
      L_0096: callvirt instance [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
      L_009b: stloc.s enumerator1
      L_009d: br.s L_00d1
      L_009f: ldloca.s enumerator1
      L_00a1: call instance !0 [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
      L_00a6: stloc.3
      L_00a7: ldloca.s num3
      L_00a9: ldc.i4.1
      L_00aa: call instance int32 int32::CompareTo(int32)
      L_00af: pop
      L_00b0: ldloca.s num3
      L_00b2: ldc.i4.1
      L_00b3: call instance bool int32::Equals(int32)
      L_00b8: pop
      L_00b9: ldloca.s num3
      L_00bb: call instance int32 int32::GetHashCode()
      L_00c0: pop
      L_00c1: ldloca.s num3
      L_00c3: call instance [mscorlib]System.TypeCode int32::GetTypeCode()
      L_00c8: pop
      L_00c9: ldloca.s num3
      L_00cb: call instance string int32::ToString()
      L_00d0: pop
      L_00d1: ldloca.s enumerator1
      L_00d3: call instance bool [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
      L_00d8: brtrue.s L_009f
      L_00da: leave.s L_00ea
      L_00dc: ldloca.s enumerator1
      L_00de: constrained [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
      L_00e4: callvirt instance void [mscorlib]System.IDisposable::Dispose()
      L_00e9: endfinally
      L_00ea: ret
      .try L_0023 to L_008d finally handler L_008d to L_0095
      .try L_009d to L_00dc finally handler L_00dc to L_00ea
}
代码挺长的,不过没必要仔细看,数一下get_Item的个数就知道它有没有提取这个公共调用语句了,它的确没有做这种优化,为什么呢?难道是留给JIT编译器来做?不明白了,看来以后遇到这种有公共调用语句的情形,需要自己搞一个临时变量暂存一下结果,如果是集合的话,则优先使用foreach,这样的语句正好帮我们提取了这个公共调用。
 
VS.NET 里面即使是Release状态也是可以调试的,这有点出人意料,在这个函数里断下来,打开反汇编,可以看到如下显示:
        private void TestColl()
        {
            List<int> intList=new List<int>();
00000000  push        ebp 
00000001  mov         ebp,esp
00000003  push        edi 
00000004  push        esi 
00000005  push        ebx 
00000006  sub         esp,60h
00000009  mov         esi,ecx
0000000b  lea         edi,[ebp-6Ch]
0000000e  mov         ecx,10h
00000013  xor         eax,eax
00000015  rep stos    dword ptr es:[edi]
00000017  mov         ecx,esi
00000019  xor         eax,eax
0000001b  mov         dword ptr [ebp-18h],eax
0000001e  mov         dword ptr [ebp-24h],ecx
00000021  cmp         dword ptr ds:[00A79BC0h],0
00000028  je          0000002F
0000002a  call        752AEFF6
0000002f  xor         edx,edx
00000031  mov         dword ptr [ebp-68h],edx
00000034  xor         edx,edx
00000036  mov         dword ptr [ebp-28h],edx
00000039  xor         edx,edx
0000003b  mov         dword ptr [ebp-2Ch],edx
0000003e  xor         edx,edx
00000040  mov         dword ptr [ebp-6Ch],edx
00000043  mov         ecx,7919F9FCh
00000048  call        FBC7ED14
0000004d  mov         esi,eax
0000004f  mov         ecx,esi
00000051  call        74790818
00000056  mov         dword ptr [ebp-68h],esi
            for(int i=0;i<10;i++)
00000059  xor         edx,edx
0000005b  mov         dword ptr [ebp-28h],edx
0000005e  nop             
0000005f  jmp         00000071
            {
                intList.Add(i);
00000061  mov         edx,dword ptr [ebp-28h]
00000064  mov         ecx,dword ptr [ebp-68h]
00000067  cmp         dword ptr [ecx],ecx
00000069  call        74791BA8
            for(int i=0;i<10;i++)
0000006e  inc         dword ptr [ebp-28h]
00000071  cmp         dword ptr [ebp-28h],0Ah
00000075  jl          00000061
            }
            lock (intList)
00000077  mov         eax,dword ptr [ebp-68h]
0000007a  mov         dword ptr [ebp-6Ch],eax
0000007d  mov         ecx,dword ptr [ebp-6Ch]
00000080  call        75090841
            {
                for (int i = 0; i < intList.Count; i++)
00000085  xor         edx,edx
00000087  mov         dword ptr [ebp-2Ch],edx
0000008a  nop             
0000008b  jmp         00000124
                {
                    intList[i].CompareTo(1);
00000090  mov         edx,dword ptr [ebp-2Ch]
00000093  mov         ecx,dword ptr [ebp-68h]
00000096  cmp         dword ptr [ecx],ecx
00000098  call        74791278
0000009d  mov         esi,eax
0000009f  mov         dword ptr [ebp-34h],esi
000000a2  lea         ecx,[ebp-34h]
000000a5  mov         edx,1
000000aa  call        7459E490
000000af  nop             
                    intList[i].Equals(1);
000000b0  mov         edx,dword ptr [ebp-2Ch]
000000b3  mov         ecx,dword ptr [ebp-68h]
000000b6  cmp         dword ptr [ecx],ecx
000000b8  call        74791278
000000bd  mov         esi,eax
000000bf  mov         dword ptr [ebp-38h],esi
000000c2  lea         ecx,[ebp-38h]
000000c5  mov         edx,1
000000ca  call        7457AD14
000000cf  nop             
                    intList[i].GetHashCode();
000000d0  mov         edx,dword ptr [ebp-2Ch]
000000d3  mov         ecx,dword ptr [ebp-68h]
000000d6  cmp         dword ptr [ecx],ecx
000000d8  call        74791278
000000dd  mov         esi,eax
000000df  mov         dword ptr [ebp-3Ch],esi
000000e2  lea         ecx,[ebp-3Ch]
000000e5  call        7456B10C
000000ea  nop             
                    intList[i].GetTypeCode();
000000eb  mov         edx,dword ptr [ebp-2Ch]
000000ee  mov         ecx,dword ptr [ebp-68h]
000000f1  cmp         dword ptr [ecx],ecx
000000f3  call        74791278
000000f8  mov         esi,eax
000000fa  mov         dword ptr [ebp-40h],esi
000000fd  lea         ecx,[ebp-40h]
00000100  call        7456B398
00000105  nop             
                    intList[i].ToString();
00000106  mov         edx,dword ptr [ebp-2Ch]
00000109  mov         ecx,dword ptr [ebp-68h]
0000010c  cmp         dword ptr [ecx],ecx
0000010e  call        74791278
00000113  mov         esi,eax
00000115  mov         dword ptr [ebp-44h],esi
00000118  lea         ecx,[ebp-44h]
0000011b  call        7456B400
00000120  nop             
                for (int i = 0; i < intList.Count; i++)
00000121  inc         dword ptr [ebp-2Ch]
00000124  mov         edi,dword ptr [ebp-2Ch]
00000127  mov         ecx,dword ptr [ebp-68h]
0000012a  cmp         dword ptr [ecx],ecx
0000012c  call        74790EDC
00000131  mov         esi,eax
00000133  cmp         edi,esi
00000135  jl          00000090
0000013b  nop             
0000013c  mov         dword ptr [ebp-1Ch],0
00000143  mov         dword ptr [ebp-18h],0FCh
0000014a  push        4DE3503h
0000014f  jmp         00000151
00000151  mov         ecx,dword ptr [ebp-6Ch]
00000154  call        75090ABB
00000159  pop         eax 
0000015a  jmp         eax 
            foreach(int i in intList)
0000015c  lea         edx,[ebp-64h]
0000015f  mov         ecx,dword ptr [ebp-68h]
00000162  cmp         dword ptr [ecx],ecx
00000164  call        747971F8
00000169  lea         edi,[ebp-54h]
0000016c  lea         esi,[ebp-64h]
0000016f  movs        dword ptr es:[edi],dword ptr [esi]
00000170  movs        dword ptr es:[edi],dword ptr [esi]
00000171  movs        dword ptr es:[edi],dword ptr [esi]
00000172  movs        dword ptr es:[edi],dword ptr [esi]
00000173  nop             
00000174  jmp         000001BA
00000176  lea         ecx,[ebp-54h]
00000179  call        747972B8
0000017e  mov         esi,eax
00000180  mov         dword ptr [ebp-30h],esi
            {
                i.CompareTo(1);
00000183  lea         ecx,[ebp-30h]
00000186  mov         edx,1
0000018b  call        7459E490
00000190  nop             
                i.Equals(1);
00000191  lea         ecx,[ebp-30h]
00000194  mov         edx,1
00000199  call        7457AD14
0000019e  nop             
                i.GetHashCode();
0000019f  lea         ecx,[ebp-30h]
000001a2  call        7456B10C
000001a7  nop             
                i.GetTypeCode();
000001a8  lea         ecx,[ebp-30h]
000001ab  call        7456B398
000001b0  nop             
                i.ToString();
000001b1  lea         ecx,[ebp-30h]
000001b4  call        7456B400
000001b9  nop             
            foreach(int i in intList)
000001ba  lea         ecx,[ebp-54h]
000001bd  call        7479725C
000001c2  mov         esi,eax
000001c4  test        esi,esi
000001c6  jne         00000176
000001c8  nop             
000001c9  mov         dword ptr [ebp-1Ch],0
000001d0  mov         dword ptr [ebp-18h],0FCh
000001d7  push        4DE34FAh
000001dc  jmp         000001DE
000001de  lea         ecx,[ebp-54h]
000001e1  call        74797250
000001e6  pop         eax 
000001e7  jmp         eax 
            }
        }
000001e9  nop             
000001ea  lea         esp,[ebp-0Ch]
000001ed  pop         ebx 
000001ee  pop         esi 
000001ef  pop         edi 
000001f0  pop         ebp 
000001f1  ret             
000001f2  mov         dword ptr [ebp-18h],0
000001f9  jmp         000001E9
000001fb  mov         dword ptr [ebp-18h],0
00000202  jmp         0000015C
 
这些应该便是JIT编译后的最终代码了,不过在VS.NET中调试运行程序时JIT是按调试状态处理的代码,所以这里没办法确认JIT在实际运行时是否会做优化,反正上面的代码是没有优化的了。
 
注:
上面我说.NET编译器没做优化的原因欠妥,真实的原因可能是.NET语言中方法没有const修饰这个设计缺陷倒致编译器不能确认何时能提取公共调用语句,我没想到的那种情形牛顿顿说的挺明白的(呵呵,他总是想得比较全面):
这个,这个似乎不应该优化吧。
foreach 是不是只针对一个特定的可枚举的接口工作?(这和C++的原生数组不同--原生数组是编译器完全理解和控制的,反而和重载的[]很像)
那么实际上编译器不知道各个GetItem(我不了解具体的名字是什么)是否有副作用。
比如说我实现的GetItem 不恰当的在内部统计 本方法的调用次数。如果按照你说的思路自动优化,那么该计数必然失败。
也就是说,该优化是需要了解实现的,编译器很难基于接口外的具体实现去进行优化。
August 03

在.NET里使用脚本语言jscript

.NET框架库里包含了对MS推出的几个语言的完整编译支持,所以这些语言理论上都可以用来作脚本,不过脚本是随手写的,还是动态语言作为脚本比较合适,我指的这个动态语言就是jscript,在.NET库里对编译的支持集中在一个抽象类System.CodeDom.Compiler.CodeDomProvider,编译与装入一个脚本的写法如下:
CodeDomProvider cdp=new JScriptCodeProvider();
CompilerParameters args = new CompilerParameters();
args.GenerateExecutable = false;
args.GenerateInMemory = true;
args.ReferencedAssemblies.Add("System.dll");
args.ReferencedAssemblies.Add("System.Data.dll");
args.ReferencedAssemblies.Add("System.Web.dll");
args.ReferencedAssemblies.Add("System.Windows.Forms.dll");
//执行编译,字符串参数scriptCode为脚本内容
CompilerResults res = cdp.CompileAssemblyFromSource(args, scriptCode);
if (res.Output.Count > 0)
            return null;//编译失败
//执行装入实例的功能,指定全限定名,设为MyLib.MyType
MyType obj=res.CompiledAssembly.CreateInstance("MyLib.MyType") as MyType;
之后就可以调用obj的方法了,上面的MyType是一个定义在宿主程序里的抽象类,脚本中继承这个类以提供具体的功能实现,使用宿主定义抽象类的好处在于宿主程序里可以像常规库一样的使用脚本提供的功能,而不需要使用Type.InvokeMember的怪异句法调用脚本,此外,通过抽象类宿主还可以向脚本展示宿主对象模型。
一个典型的抽象类如下:
public abstract class MyType
{
         public MyDOM Dom
         {
                  get{return dom;}
                  set{dom=value;}
         }
         public abstract void Run();
}
在脚本里的作法:
public class JSObj extends MyType
{
          public override function Run()
          {
                   //脚本功能实现代码
          }
}
在宿主程序中将入脚本后,如前述我们得到了MyType实例obj,则调用脚本的过程为:
obj.Dom=innerDom;//向脚本暴露内部对象模型,虽然也可以直接在Run的参数里传递,不过用参数传递的对象数量不能 
                               //过多,如果不封装成一个根对象的DOM,则可以用多个特性提供。
obj.Run();//执行脚本提供的功能
上面这个过程脚本修改过便需要重新编译再装入,编译会消耗一些时间,我们可以利用JScript语言的特性来提供一个解释式的脚本,那就是使用eval函数。只需要改变一个JSObj类就可以了:
public class JSObj extends MyType
{
             public override function Run()
             {
                           //假设我们的脚本代码由一个控件提供,这个控件实例通过抽象类的特性Dom.ScriptEdit提供.
                           eval(Dom.ScriptEdit.Text,"unsafe");//unsafe参数比较关键,不然脚本会有诸多限制
             }
}
现在只需要编译装入一次,之后每次修改Dom.ScriptEdit.Text之后,只要调用obj.Run执行就可以了。
解释执行虽然没有编译的时间消耗,但是执行效率会远低于编译执行,所以我的想法是解释与编译同时提供,解释用于执行短小的脚本,一般这类用于试验或测试,编译用于正式的功能脚本,性能较高。
解释与编译的另一个差别是JScript的eval里的代码不能识别Array,不过可以识别IList,做法很简单,将Array型的对象强制转为IList即可:
             var listObj=IList(arrayObj);
.net 2.0开始支持泛型,不过JScript不能访问使用非封闭的泛型参数的方法(参照一下C++的函数模板,这种调用基于模板参数推导,作为动态语言可能不能提供足够的类型信息吧,这是我的猜测:) ),所以如果宿主的DOM里有这样的方法,需要在宿主提供这些方法的非泛型版本(其实就是对每个封闭的泛型参数写一个方法,方法实现就是调相应的泛型方法)。
 
在实际使用中,我对脚本的编译进行了封装,然后脚本代码主要基于模板实现,因为脚本通常是随手写的,通常不需要定义类与方法,往往就是一个代码片断而已,但是如前所述脚本代码需要实现抽象类,这些框架性的东西用一个模板来提供就可以了。
封装类代码如下:
using System;
using System.Collections.Generic;
using System.CodeDom.Compiler;
using System.IO;
namespace MeshLib
{
    public class ScriptInterpreter<T> where T : CodeDomProvider,new()
    {
        public ScriptInterpreter()
        {}
        /// <summary>
        /// 借用一个模板文件来构造一个含有一个装配与一个类的script源代码,模板文件中必须有二个可替换变量:#ASSEMBLYNAME#,#CLASSNAME#,分别对应装配名、类名。
        /// </summary>
        public static string ReadTemplate(string templateFile, string assemblyName, string className)
        {
            try
            {
                StreamReader sr = new StreamReader(templateFile);
                string templateCode = sr.ReadToEnd();
                sr.Close();
                return templateCode.Replace("#ASSEMBLYNAME#", assemblyName).Replace("#CLASSNAME#", className);
            }
            catch(Exception)
            {
                return "";
            }
        }
        public List<string> ReferencedAssemblies
        {
            get
            {
                return referencedAssemblies;
            }
        }
        public string CompilerOptions
        {
            get
            {
                return compilerOptions;
            }
            set
            {
                compilerOptions = value;
            }
        }
        public List<string> Results
        {
            get
            {
                return compilerResults;
            }
        }
        public R LoadCode<R>(string scriptCode, string assemblyName, string className) where R : class
        {
            try
            {
                T cdp = new T();
                CompilerParameters args = new CompilerParameters();
                args.GenerateExecutable = false;
                args.GenerateInMemory = true;
                foreach (string s in ReferencedAssemblies)
                {
                    args.ReferencedAssemblies.Add(s);
                }
                args.CompilerOptions = CompilerOptions;
                CompilerResults res = cdp.CompileAssemblyFromSource(args, scriptCode);
                Results.Clear();
                foreach (string s in res.Output)
                {
                    Results.Add(s);
                }
                if (res.Output.Count > 0)
                    return null;
                return res.CompiledAssembly.CreateInstance(assemblyName + "." + className) as R;
            }
            catch(Exception eee)
            {
                Results.Add(eee.Message);
                return null;
            }
        }
        public R LoadFile<R>(string file, string assemblyName, string className) where R : class
        {
            string content = ReadTemplate(file, assemblyName, className);
            if (content.Length <= 0)
                return null;
            return LoadCode<R>(content, assemblyName, className);
        }
        private List<string> referencedAssemblies = new List<string>();
        private string compilerOptions = null;
        private List<string> compilerResults = new List<string>();
    }
}
脚本模板(一个编译型的模板,一个解释型的模板)
编译型:
import System;
import System.Collections;
import System.Collections.Generic;
import System.Data;
import System.Data.OleDb;
import System.IO;
import System.Net;
import System.Net.Sockets;
import System.Diagnostics;
import System.Drawing;
import System.Web;
import System.Web.SessionState;
import System.Web.UI;
import System.Web.UI.WebControls;
import System.Web.UI.HtmlControls;
import System.Text;
import System.Text.RegularExpressions;
import System.Windows.Forms;
import System.Threading;
import System.Xml;
import MeshLib.ShapeFile;
import MeshLib;
import MeshUI;
package #ASSEMBLYNAME#
{
 public class #CLASSNAME# extends ScriptCode
 {
  public override function Run()
  {
   //此处开始写您的脚本代码
  }
 }
}
解释型:
import System;
import System.Collections;
import System.Collections.Generic;
import System.Data;
import System.Data.OleDb;
import System.IO;
import System.Net;
import System.Net.Sockets;
import System.Diagnostics;
import System.Drawing;
import System.Web;
import System.Web.SessionState;
import System.Web.UI;
import System.Web.UI.WebControls;
import System.Web.UI.HtmlControls;
import System.Text;
import System.Text.RegularExpressions;
import System.Windows.Forms;
import System.Threading;
import System.Xml;
import MeshLib.ShapeFile;
import MeshLib;
import MeshUI;
package #ASSEMBLYNAME#
{
 public class #CLASSNAME# extends ScriptCode
 {
  public override function Run()
  {
   eval(script.Text,"unsafe");
  }
 }
}
抽象类ScriptCode:

    public abstract class ScriptCode
    {
        public ShapeFile.ShapeFile shapeFile;
        public MeshPanel meshPanel;
        public Control script;
        public Control output;
        public Mesh<SharedData,NodeData, SideData, CellData> mesh;
        public List<Mesh<GisSharedData, GisNodeData, GisSideData, GisCellData>> gisMeshes;
        public abstract void Run();
    }
针对编译型与解释型脚本的编译运行与编译+多次运行的方法
编译运行是将模板文件装入供用户编辑,然后直接编译运行最终编辑过的完整代码:
        private void CheckCScript()
        {
            if (cscriptEdit.Text.Trim().Length <= 0)
            {
                string path = Application.ExecutablePath;
                path = Path.GetDirectoryName(path);
                string tempFile = Path.Combine(path, "CompileScript.js");
                cscriptEdit.Text = ScriptInterpreter<JScriptCodeProvider>.ReadTemplate(tempFile, "CompiledMeshScript", "CompiledJScript");
            }
        }
       
        private void CompileAndRunScript()
        {
            try
            {
                string path = Application.ExecutablePath;
                path = Path.GetDirectoryName(path);
                scriptResult.Text = "";
                ScriptInterpreter<JScriptCodeProvider> si = new ScriptInterpreter<JScriptCodeProvider>();
                si.ReferencedAssemblies.Add("System.dll");
                si.ReferencedAssemblies.Add("System.Data.dll");
                si.ReferencedAssemblies.Add("System.Drawing.dll");
                si.ReferencedAssemblies.Add("System.Web.dll");
                si.ReferencedAssemblies.Add("Microsoft.JScript.dll");
                si.ReferencedAssemblies.Add("System.Windows.Forms.dll");
                si.ReferencedAssemblies.Add(Path.Combine(path, "MeshLib.dll"));
                si.ReferencedAssemblies.Add(Path.Combine(path, "MeshUI.exe"));
                ScriptCode compiledScriptCode = si.LoadCode<ScriptCode>(cscriptEdit.Text, "CompiledMeshScript", "CompiledJScript");
                if (compiledScriptCode != null)
                {
                    compiledScriptCode.shapeFile = mainForm.shapeFile;
                    compiledScriptCode.meshPanel = mainForm.meshPanel;
                    compiledScriptCode.script = cscriptEdit;
                    compiledScriptCode.output = scriptResult;
                    compiledScriptCode.mesh = mainForm.mesh;
                    compiledScriptCode.gisMeshes = mainForm.gisMeshes;
                    compiledScriptCode.Run();
                }
                else
                {
                    string ss = "编译错误:";
                    foreach (string s in si.Results)
                    {
                        ss += "\r\n" + s;
                    }
                    scriptResult.Text = ss;
                }
            }
            catch (Exception eee)
            {
                scriptResult.Text = "产生异常:" + eee.Message;
            }
        }
解释型脚本检查是否更新,如有更新则编译:       
private void CheckScript()
        {
            try
            {
                string path = Application.ExecutablePath;
                path = Path.GetDirectoryName(path);
                string tempFile = Path.Combine(path, "EvalScript.js");
                DateTime dt = File.GetLastWriteTime(tempFile);
                if (scriptTime != dt)
                {
                    scriptTime = dt;
                }
                else
                {
                    return;
                }
                ScriptInterpreter<JScriptCodeProvider> si = new ScriptInterpreter<JScriptCodeProvider>();
                si.ReferencedAssemblies.Add("System.dll");
                si.ReferencedAssemblies.Add("System.Data.dll");
                si.ReferencedAssemblies.Add("System.Drawing.dll");
                si.ReferencedAssemblies.Add("System.Web.dll");
                si.ReferencedAssemblies.Add("Microsoft.JScript.dll");
                si.ReferencedAssemblies.Add("System.Windows.Forms.dll");
                si.ReferencedAssemblies.Add(Path.Combine(path, "MeshLib.dll"));
                si.ReferencedAssemblies.Add(Path.Combine(path, "MeshUI.exe"));
                scriptCode = si.LoadFile<ScriptCode>(tempFile, "MeshScript", "JScript");
                if (scriptCode == null)
                {
                    string ss = "编译脚本文件" + tempFile + "出现了错误:";
                    foreach (string s in si.Results)
                    {
                        ss += "\r\n" + s;
                    }
                    scriptResult.Text = ss;
                }
            }
            catch (Exception eee)
            {
                scriptResult.Text = "产生异常:" + eee.Message;
            }
        }
        private void RunScript()
        {
            if (scriptCode != null)
            {
                try
                {
                    scriptResult.Text = "";
                    scriptCode.shapeFile = mainForm.shapeFile;
                    scriptCode.meshPanel = mainForm.meshPanel;
                    scriptCode.script = iscriptEdit;
                    scriptCode.output = scriptResult;
                    scriptCode.mesh = mainForm.mesh;
                    scriptCode.gisMeshes = mainForm.gisMeshes;
                    scriptCode.Run();
                }
                catch (Exception eee)
                {
                    scriptResult.Text = "产生异常:" + eee.Message;
                }
            }
        }

使用PropertyGrid来为应用提供兼容.NET设计时架构的特性编辑功能

只要在应用中使用PropertyGrid控件来提供对应用中的对象模型实例的特性编辑,这便已经是兼容了.NET设计时架构了,不过我发现一个问题,
当我们需要一次性编辑许多对象的时候,量变引起质变,此时严重的性能问题会让我们怀疑是不是不该使用PropertyGrid了(这种量变引起质变的现象在使用第三方库的时候好象经常碰到,大概原因在于库的设计者当初定位的使用环境是常规的,而量变到一个程度时,问题已经不再是常规的了,这好象与库的设计是否可伸缩无关。另一个例子,一般情况动态数组可以容下足够多的东东,我们无需关心它的存储问题,但如果元素数目非常非常多,比如100G的数目,这时就必须要自己考虑了[呵呵,这个例子有点夸张了]。),然而介于.NET设计时架构的良好设计的吸引,实在不愿意就此放弃,所以我想看看如何改造一下PropertyGrid来适应这种新情况新问题。
前面提到的性能问题主要是PropertyGrid在编辑一组对象时是在循环中依次修改各个对象,数目大的时候,这个循环需要很长的时间(这个没办法改变,时间不大可能变少),此时应用界面会失去响应,这在WIN32 GUI里的解决办法是在循环中插入消息处理,顺便加上一个进度条。我们在.net程序里当然也是这个解决思路,不过PropertyGrid在设计时并没有为这个留下接口(附带说一下,PropertyGrid的设计复杂的很,它的代码主要集中在System.Windows.Forms.PropertyGridInternal名空间下,不过很可惜,主要类都是internal的),经过阅读PropertyGrid的代码(用reflector看的,这个不太好玩,关系实在太复杂,只能了解大概),发现直接使用PropertyGrid来编辑一组大数目的对象不失去响应不大可能,所以考虑变通的办法。
虽然PropertyGrid的实现非常复杂,但是在.net框架库里只暴露了很少的几个类:GridItem,PropertyGrid,PropertiesTab等,PropertiesTab类主要用于实现自定义特性(或动态特性)类的编辑,没有逮到什么机会。GridItem代表了特性编辑器里的一行,也就是说它代表对一个特性的编辑(因为特性编辑器的行是可以树状展开的,GridItem类也是组织成树状的,GridItem可以有若干个子GridItem),它有三个属性与我们的目标相关,一个Value代表当前编辑器里的值,一个PropertyDescriptor用来实现它对应的特性的修改,一个Parent用来获取父项目。PropertyGrid的成员N多,不过对我们有用的是一个事件:PropertyValueChanged ,在特性值改变之后,它会触发这个事件,不过在触发这个事件时,与PropertyGrid关联的那组对象的特性已经被修改了。
我们没办法让PropertyGrid直接修改全部需要编辑的对象,现在有一个可能的办法是,提取这组对象中的一部分与PropertyGrid关联,并在PropertyValueChanged事件里对剩下的对象进行更改。(当然也可以只与PropertyGrid控件关联一个对象,不过这样有一个问题是PropertyGrid会显示那个对象的所有特性值,当你的应用展示给最终用户时,用户选择了许多对象,结果展示的是其中一个对象的值,很容易让用户误解所有这些对象的特性值相同,而让PropertyGrid关联多个对象时,它会检查这组对象的特性值是否相同,不同的则设为空[对引用对象]或默认值[对值对象],显然我们可以挑出一些有代表性的对象关联[也就是如果有不同的对象,就用这几个不同的]从而利用PropertyGrid的这一特性)。
现在来看看PropertyValueChanged事件给了我们哪些信息:OldValue 该项目更改前的值,ChangedItem 发生更改的项目(一个GridItem), 也就是我们可以知道新值、旧值、以及一个用于修改对象特性的PropertyDescriptor,看起来好象够了:
                PropertyDescriptor.SetValue(obj,ChangedItem.Value);
试验了一下,惨败!!!原因:
一、前面提到过GridItem是组织成树状的,也就是说当一个对象的特性又是一个对象,而我们编辑的是这个特性对象的某个特性时,ChangedItem.PropertyDescriptor是针对那个特性对象的那个特性的,我们调用PropertyDescriptor.SetValue时,第一个参数必须是那个特性对象,然而我们现在并不知道它;
二、如果PropertyGrid关联的是一组对象,那么ChangedItem.PropertyDescriptor不是一个单一对象的特性编辑器,PropertyDescriptor.SetValue的第一个参数是对象数组,并且,数组元素个数必须是PropertyGrid关联的那组对象的个数(我们显然不能假设我们要编辑的对象总是可以分解为PropertyGrid关联的对象个数的整数倍的,特别的,对象总数还可能是质数)。
对问题一,我们可以利用GridItem.Parent来向上回溯到顶级对象,再利用各级GridItem.PropertyGrid.GetValue来得到特性对象的值,直到更改的那个GridItem的上一级,然后,在我们修改了发生更改的那个特性对象的特性后,我们还必须再次回溯一次,因为特性对象有可能是一个值对象的特性,而值对象特性的修改必须通过赋值才能影响到它所属的对象(引用便无此要求)。
对问题二,我们需要的是一个单一对象的特性编辑器,看一下源代码(当然还是用reflector)
internal class MergePropertyDescriptor : PropertyDescriptor
{
...
      public PropertyDescriptor this[int index] { get; }
...
}
这个MergePropertyDescriptor就是编辑一组对象特性的PropertyDescriptor,它有一个索引化的属性可以得到它用来修改每个对象的PropertyDescriptor,现在剩下最后一个问题,便是MergePropertyDescriptor类是internal的,我们不能直接访问,怎么办?呵呵,利用
反射机制:Type.InvokeMember ,这个是通杀的!
基本实现机制差不多就是这样了,剩下的便是在对每个对象修改的空隙里调用Application.DoEvents(),然后更新一下进度条了。
 
前面说的有点太轻松了,实际做起来还是比较费劲的,好在reflector给了不少参考源代码,下面是对上述一、二的实现:
 public static class PropertyAccess
    {
        public static void UpdateNodeValue<SharedDataT, NodeDataT, SideDataT, CellDataT>(PropertyValueChangedEventArgs e, Mesh<SharedDataT, NodeDataT, SideDataT, CellDataT> mesh, int startIndex)
            where SharedDataT : ISharedData<SharedDataT, NodeDataT, SideDataT, CellDataT>, new()
            where NodeDataT : INodeData<SharedDataT, NodeDataT, SideDataT, CellDataT>, new()
            where SideDataT : ISideData<SharedDataT, NodeDataT, SideDataT, CellDataT>, new()
            where CellDataT : ICellData<SharedDataT, NodeDataT, SideDataT, CellDataT>, new()
        {
            LinkedList<AccessInfo> list = BuildPropertyHiberarchy(e);
            mesh.OnProgressTip("开始更新选中的结点数据......");
            mesh.OnProgress(0);
            for (int i = startIndex; i < mesh.SelectedNodes.Count; i++)
            {
                mesh.OnProgress(100 * i / mesh.SelectedNodes.Count);
                object obj = mesh.SelectedNodes[i];
                UpdatePropertyValue(e, obj, list);
            }
            mesh.OnProgress(0);
            mesh.OnProgressTip("结点数据更新完成.");
        }
        public static void UpdateSideValue<SharedDataT, NodeDataT, SideDataT, CellDataT>(PropertyValueChangedEventArgs e, Mesh<SharedDataT, NodeDataT, SideDataT, CellDataT> mesh, int startIndex)
            where SharedDataT : ISharedData<SharedDataT, NodeDataT, SideDataT, CellDataT>, new()
            where NodeDataT : INodeData<SharedDataT, NodeDataT, SideDataT, CellDataT>, new()
            where SideDataT : ISideData<SharedDataT, NodeDataT, SideDataT, CellDataT>, new()
            where CellDataT : ICellData<SharedDataT, NodeDataT, SideDataT, CellDataT>, new()
        {
            LinkedList<AccessInfo> list = BuildPropertyHiberarchy(e);
            mesh.OnProgressTip("开始更新选中的边数据......");
            mesh.OnProgress(0);
            for (int i = startIndex; i < mesh.SelectedSides.Count; i++)
            {
                mesh.OnProgress(100 * i / mesh.SelectedSides.Count);
                object obj = mesh.SelectedSides[i];
                UpdatePropertyValue(e, obj, list);
            }
            mesh.OnProgress(0);
            mesh.OnProgressTip("边数据更新完成.");
        }
        public static void UpdateCellValue<SharedDataT, NodeDataT, SideDataT, CellDataT>(PropertyValueChangedEventArgs e, Mesh<SharedDataT, NodeDataT, SideDataT, CellDataT> mesh, int startIndex)
            where SharedDataT : ISharedData<SharedDataT, NodeDataT, SideDataT, CellDataT>, new()
            where NodeDataT : INodeData<SharedDataT, NodeDataT, SideDataT, CellDataT>, new()
            where SideDataT : ISideData<SharedDataT, NodeDataT, SideDataT, CellDataT>, new()
            where CellDataT : ICellData<SharedDataT, NodeDataT, SideDataT, CellDataT>, new()
        {
            LinkedList<AccessInfo> list = BuildPropertyHiberarchy(e);
            mesh.OnProgressTip("开始更新选中的多边形区域数据");
            mesh.OnProgress(0);
            for (int i = startIndex; i < mesh.SelectedCells.Count; i++)
            {
                mesh.OnProgress(100 * i / mesh.SelectedCells.Count);
                object obj = mesh.SelectedCells[i];
                UpdatePropertyValue(e, obj, list);
            }
            mesh.OnProgress(0);
            mesh.OnProgressTip("多边形区域数据更新完成.");
        }
        private static LinkedList<AccessInfo> BuildPropertyHiberarchy(PropertyValueChangedEventArgs e)
        {
            GridItem gridItem = e.ChangedItem;
            LinkedList<AccessInfo> list = new LinkedList<AccessInfo>();
            GridItem gi = gridItem.Parent;
            while (gi != null && (gi.GridItemType == GridItemType.Category || gi.GridItemType == GridItemType.Root))
                gi = gi.Parent;
            while (gi != null)
            {
                AccessInfo ai = new AccessInfo(GetMergePropertyDescriptorItem0(gi.PropertyDescriptor));
                if (list.Count <= 0)
                {
                    list.AddLast(ai);
                }
                else
                {
                    list.AddFirst(ai);
                }
                gi = gi.Parent;
                while (gi != null && (gi.GridItemType == GridItemType.Category || gi.GridItemType == GridItemType.Root))
                    gi = gi.Parent;
            }
            return list;
        }
        private static void UpdatePropertyValue(PropertyValueChangedEventArgs e, object target, LinkedList<AccessInfo> list)
        {
            GridItem gridItem = e.ChangedItem;
            object obj = target;
            foreach (AccessInfo ai in list)
            {
                obj = GetPropertyValueCore(obj, ai.PropertyDescriptor);
                ai.Value = obj;
            }
            SetPropertyValueCore(obj, CopyValue(gridItem.Value), GetMergePropertyDescriptorItem0(gridItem.PropertyDescriptor));
            LinkedListNode<AccessInfo> infoNode = list.Last;
            if (infoNode != null)
            {
                infoNode.Value.Value = obj;
            }
            while (infoNode != null)
            {
                obj = infoNode.Value.Value;
                if (obj.GetType().IsValueType || obj.GetType().IsArray)
                {
                    if (infoNode.Previous != null)
                    {
                        SetPropertyValueCore(infoNode.Previous.Value.Value, obj, infoNode.Value.PropertyDescriptor);
                    }
                    else
                    {
                        SetPropertyValueCore(target, obj, infoNode.Value.PropertyDescriptor);
                    }
                }
                infoNode = infoNode.Previous;
            }
        }
        /// <summary>
        /// 利用Type的动态成员访问方法获取MergePropertyDescriptor.Item[0],MergePropertyDescriptor类是System.Windows.Forms.PropertyGridInternal下的internal类,不能直接访问。
        /// </summary>
        /// <param name="pd"></param>
        /// <returns></returns>
        /// <remarks>
        /// 另一种访问不可访问成员的办法是用TypeDescriptor.CreateProperty创建一个PropertyDescriptor,然后用PropertyDescriptor.GetValue得到特性值,不过这种方法无法访问对象索
        /// 引化属性Item,不适于这里的需求。
        /// </remarks>
        private static PropertyDescriptor GetMergePropertyDescriptorItem0(PropertyDescriptor pd)
        {
            Type t = pd.GetType();
            PropertyDescriptor _pd = null;
            PropertyInfo pi=t.GetProperty("Item");
            if(pi!=null)
            {
                object o = t.InvokeMember("Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.IgnoreCase, null,
                                          pd, new object[] { 0 });
                _pd = o as PropertyDescriptor;
            }
            if(_pd!=null)
            {
                return _pd;
            }
            return pd;
        }
        private static object GetPropertyValueCore(object target, PropertyDescriptor pd)
        {
            if (pd == null)
            {
                return null;
            }
            if (target is ICustomTypeDescriptor)
            {
                target = ((ICustomTypeDescriptor)target).GetPropertyOwner(pd);
            }
            object obj = pd.GetValue(target);
            return obj;
        }
        private static void SetPropertyValueCore(object target, object value, PropertyDescriptor pd)
        {
            if (pd != null)
            {
                object obj = target;
                if (obj is ICustomTypeDescriptor)
                {
                    obj = ((ICustomTypeDescriptor)obj).GetPropertyOwner(pd);
                }
                if (obj != null)
                {
                    pd.SetValue(obj, value);
                }
            }
        }
        private static object CopyValue(object value)
        {
            if (value != null)
            {
                Type type = value.GetType();
                if (type.IsValueType)
                {
                    return value;
                }
                object obj = null;
                ICloneable cloneable = value as ICloneable;
                if (cloneable != null)
                {
                    obj = cloneable.Clone();
                }
                if (obj == null)
                {
                    TypeConverter converter = TypeDescriptor.GetConverter(value);
                    if (converter.CanConvertTo(typeof(InstanceDescriptor)))
                    {
                        InstanceDescriptor descriptor = (InstanceDescriptor)converter.ConvertTo(null, CultureInfo.InvariantCulture, value, typeof(InstanceDescriptor));
                        if ((descriptor != null) && descriptor.IsComplete)
                        {
                            obj = descriptor.Invoke();
                        }
                    }
                    if (((obj == null) && converter.CanConvertTo(typeof(string))) && converter.CanConvertFrom(typeof(string)))
                    {
                        object _obj = converter.ConvertToInvariantString(value);
                        obj = converter.ConvertFromInvariantString((string)_obj);
                    }
                }
                if ((obj == null) && type.IsSerializable)
                {
                    BinaryFormatter formatter = new BinaryFormatter();
                    MemoryStream stream = new MemoryStream();
                    formatter.Serialize(stream, value);
                    stream.Position = 0;
                    obj = formatter.Deserialize(stream);
                }
                if (obj != null)
                {
                    return obj;
                }
            }
            return value;
        }
        class AccessInfo
        {
            public PropertyDescriptor PropertyDescriptor
            {
                get
                {
                    return propertyDescriptor;
                }
                set
                {
                    propertyDescriptor = value;
                }
            }
            public object Value
            {
                get
                {
                    return val;
                }
                set
                {
                    val = value;
                }
            }
            public AccessInfo()
            { }
            public AccessInfo(PropertyDescriptor pd)
            {
                propertyDescriptor = pd;
            }
            private PropertyDescriptor propertyDescriptor = null;
            private object val = null;
        }
    }
 
最后说点别的,与前面提到的值类型与引用类型处理的差异相关,当我们实现一个自定义的UITypeEditor的时候,因为我们是脱离了PropertyGrid控件来操作对象属性,对对象属性的直接更改将不能引起PropertyGrid的GridItem树的逐级更新,PropertyGrid在调用UITypeEditor.EditValue后,它会比较传给EditValue的obj以及由EditValue返回的obj,仅在二者不同时才触发更新,因为EditValue接受的参数是object的,即使是一个值类型的值,也会被装箱成引用对象,因此EditValue中一定不能直接在传入参数上进行in-place修改,而必须要COPY一份对象实例,然而如何才能COPY任意的对象实例呢,事实上不可能,上面的代码中有一个CopyValue,这是来自.net 2.0的实现代码的,可以看到有三种方法让一个对象支持COPY(在上面讲的UITypeEditor.EditValue实现中,值类型也需要这些条件),即:
1、实现ICloneable;
2、与对象类型关联一个TypeConverter并且它可以将特性实例转为InstanceDescriptor,或者,可以将特性实例转为字符串并能由字符串转为特性实例;
3、对象类型指明了[Serializable]属性。
注:这里所说的UITypeEditor.EditValue的要求是考虑一个通用的UITypeEditor时的,如果是一个特定对象,因为我们十分了解那个特定的对象,所以完全可以构造一份实例并逐个特性的赋值,或者,那个对象本来有一个Copy构造。
 
呵呵,这篇的技巧可是费了我相当多的时间与脑力呢。

使用Lambda表达式为jscript脚本提供一个快速搜索功能

这几天为Ollydbg的插件OllyHtml加了一个快速搜索反汇编代码的API,起因是因为在jscript脚本里逐语句的查找太慢了,然而搜索条件又不方便简单的利用函数参数表示,最后我想到了Lambda表达式,感觉在为脚本提供的库中使用Lambda表达式来提高某些操作的效率与灵活性还是比较有用的。(算了,今天写的太多了,手酸了,直接贴代码了)
LAMBDA表达式实现,主要用于构造逻辑表达式,表达式中的基本数据来自ollydbg插件SDK的结构t_disasm:
#pragma once
#include "stdafx.h"
#include "resource.h"
#include "Plugin.h"
#include <vector>
#include <map>
class ConditionExpression
{
public:
 virtual bool operator () (t_disasm* p)=0;
public:
 ConditionExpression()
 {
  TotalObjectsRef()++;
  refCount=1;
 }
 virtual ~ConditionExpression(void)
 {}
public:
 virtual void AddRef(void)
 {
  refCount++;
 }
 virtual void Release(void)
 {
  refCount--;
  if(refCount==0)
  {
   TotalObjectsRef()--;
   /*
   CString temp;
   temp.Format("release one , left : %u",TotalObjectsRef());
   ::MessageBox(NULL,temp,"TotalCount",MB_OK);
   */
   delete this;
  }
 }
public:
 static inline int TotalObjects(void)
 {
  return TotalObjectsRef();
 }
private:
 static inline int& TotalObjectsRef(void)
 {
  static int totalCount=0;
  return totalCount;
 }
private:
    int refCount;
};
class AndCondition : public ConditionExpression
{
public:
 virtual bool operator () (t_disasm* p)
 {
  if(!exp1 || !exp2)
   return false;
  if((*exp1)(p) && (*exp2)(p))
   return true;
  else
   return false;
 }
 virtual ~AndCondition()
 {
  if(exp1)
   exp1->Release();
  if(exp2)
   exp2->Release();
 }
public:
 AndCondition(ConditionExpression* p1,ConditionExpression* p2)
 {
  exp1=p1;
  exp2=p2;
  if(p1)
   p1->AddRef();
  if(p2)
   p2->AddRef();
 }
private:
 ConditionExpression* exp1;
 ConditionExpression* exp2;
};
class OrCondition : public ConditionExpression
{
public:
 virtual bool operator () (t_disasm* p)
 {
  if(!exp1 || !exp2)
   return false;
  if((*exp1)(p) || (*exp2)(p))
   return true;
  else
   return false;
 }
 virtual ~OrCondition()
 {
  if(exp1)
   exp1->Release();
  if(exp2)
   exp2->Release();
 }
public:
 OrCondition(ConditionExpression* p1,ConditionExpression* p2)
 {
  exp1=p1;
  exp2=p2;
  if(p1)
   p1->AddRef();
  if(p2)
   p2->AddRef();
 }
private:
 ConditionExpression* exp1;
 ConditionExpression* exp2;
};
class NotCondition : public ConditionExpression
{
public:
 virtual bool operator () (t_disasm* p)
 {
  if(!exp)
   return false;
  if(!(*exp)(p))
   return true;
  else
   return false;
 }
 virtual ~NotCondition()
 {
  if(exp)
   exp->Release();
 }
public:
 NotCondition(ConditionExpression* p)
 {
  exp=p;
  if(p)
   p->AddRef();
 }
private:
 ConditionExpression* exp;
};
typedef int (*IntValuePtr)(t_disasm* p);
typedef char* (*StrValuePtr)(t_disasm* p);
//--------------------------------------------------------
/*
 *CompareType : 0 = EQ , 1 = GE , -1 = LE
 */
//--------------------------------------------------------
template<int CompareType>
 class CompareCondition : public ConditionExpression
{
public:
 virtual bool operator () (t_disasm* p)
 {
  if(!p || !fptr)
   return false;
  return Compare<CompareType>::Do(p,fptr,value);
 }
 virtual ~CompareCondition()
 {}
public:
 CompareCondition(IntValuePtr _fptr,int val)
 {
  fptr=_fptr;
  value=val;
 } 
private:
 IntValuePtr fptr;
 int value; 
private:
 template<int CT=0>
  class Compare
 {
 public:
  static inline bool Do(t_disasm* p,IntValuePtr fptr,int val)
  {
   return (*fptr)(p)==val;
  }
 };
 template<>
  class Compare<1>
 {
 public:
  static inline bool Do(t_disasm* p,IntValuePtr fptr,int val)
  {
   return (*fptr)(p)>=val;
  }
 };
 template<>
  class Compare<-1>
 {
 public:
  static inline bool Do(t_disasm* p,IntValuePtr fptr,int val)
  {
   return (*fptr)(p)<=val;
  }
 };
};
class StringLikeCondition : public ConditionExpression
{
 typedef std::vector<CString> Strings;
public:
 virtual bool operator () (t_disasm* p)
 {
  if(!p || !fptr)
   return false;
  CString src=fptr(p);
  Strings::iterator it=strs.begin();
  while(it!=strs.end())
  {
   if(src.Find(*it)>=0)
    return true;
   it++;
  }
  return false;
 }
 virtual ~StringLikeCondition()
 {}
public:
 StringLikeCondition(StrValuePtr _fptr,const char* s)
 {
  fptr=_fptr;
  char *buf=new char[::strlen(s)+1];
  ::strcpy(buf,s);
  char* token = strtok(buf, "%");
  while( token != NULL )
  {
            strs.push_back(CString(token));   
   token = strtok(NULL, "%");
  }
 } 
private:
 StrValuePtr fptr;
 Strings strs;
};
//下面是为表达式提供基本值的若干个类,一个类对应t_disasm结构的一个成员,它们实际上被用作函数指针。
#define FieldValueClass(NAME) NAME##FieldValue
#define DefFieldValueClass(NAME,FN) \
 class FieldValueClass(NAME)\
 {\
 public:\
  static inline int Value(t_disasm* p)\
  {\
   return (int)p->##FN;\
  }\
 };
#define DefStrFieldValueClass(NAME,FN) \
 class FieldValueClass(NAME)\
 {\
 public:\
  static inline char* Value(t_disasm* p)\
  {\
   return (char*)p->##FN;\
  }\
 };
DefFieldValueClass(IP,ip)
DefFieldValueClass(CmdType,cmdtype)
DefFieldValueClass(MemType,memtype)
DefFieldValueClass(PrefixNum,nprefix)
DefFieldValueClass(Indexed,indexed)
DefFieldValueClass(JumpConst,jmpconst)
DefFieldValueClass(JumpTable,jmptable)
DefFieldValueClass(AddrConst,adrconst)
DefFieldValueClass(ImmConst,immconst)
DefFieldValueClass(ZeroImm,zeroconst)
DefFieldValueClass(FixupOffset,fixupoffset)
DefFieldValueClass(FixupSize,fixupsize)
DefFieldValueClass(JumpAddr,jmpaddr)
DefFieldValueClass(Error,error)
DefFieldValueClass(Warnings,warnings)
DefFieldValueClass(OPType1,op[0].optype)
DefFieldValueClass(OPType2,op[1].optype)
DefFieldValueClass(OPType3,op[2].optype)
DefFieldValueClass(OPSize1,op[0].opsize)
DefFieldValueClass(OPSize2,op[1].opsize)
DefFieldValueClass(OPSize3,op[2].opsize)
DefFieldValueClass(OPSeg1,op[0].seg)
DefFieldValueClass(OPSeg2,op[1].seg)
DefFieldValueClass(OPSeg3,op[2].seg)
DefFieldValueClass(OPConst1,op[0].opconst)
DefFieldValueClass(OPConst2,op[1].opconst)
DefFieldValueClass(OPConst3,op[2].opconst)
DefFieldValueClass(OPEaxScale1,op[0].regscale[REG_EAX])
DefFieldValueClass(OPEcxScale1,op[0].regscale[REG_ECX])
DefFieldValueClass(OPEdxScale1,op[0].regscale[REG_EDX])
DefFieldValueClass(OPEbxScale1,op[0].regscale[REG_EBX])
DefFieldValueClass(OPEspScale1,op[0].regscale[REG_ESP])
DefFieldValueClass(OPEbpScale1,op[0].regscale[REG_EBP])
DefFieldValueClass(OPEsiScale1,op[0].regscale[REG_ESI])
DefFieldValueClass(OPEdiScale1,op[0].regscale[REG_EDI])
DefFieldValueClass(OPEaxScale2,op[1].regscale[REG_EAX])
DefFieldValueClass(OPEcxScale2,op[1].regscale[REG_ECX])
DefFieldValueClass(OPEdxScale2,op[1].regscale[REG_EDX])
DefFieldValueClass(OPEbxScale2,op[1].regscale[REG_EBX])
DefFieldValueClass(OPEspScale2,op[1].regscale[REG_ESP])
DefFieldValueClass(OPEbpScale2,op[1].regscale[REG_EBP])
DefFieldValueClass(OPEsiScale2,op[1].regscale[REG_ESI])
DefFieldValueClass(OPEdiScale2,op[1].regscale[REG_EDI])
DefFieldValueClass(OPEaxScale3,op[2].regscale[REG_EAX])
DefFieldValueClass(OPEcxScale3,op[2].regscale[REG_ECX])
DefFieldValueClass(OPEdxScale3,op[2].regscale[REG_EDX])
DefFieldValueClass(OPEbxScale3,op[2].regscale[REG_EBX])
DefFieldValueClass(OPEspScale3,op[2].regscale[REG_ESP])
DefFieldValueClass(OPEbpScale3,op[2].regscale[REG_EBP])
DefFieldValueClass(OPEsiScale3,op[2].regscale[REG_ESI])
DefFieldValueClass(OPEdiScale3,op[2].regscale[REG_EDI])
DefStrFieldValueClass(Dump,dump)
DefStrFieldValueClass(Disasm,result)
DefStrFieldValueClass(Comment,comment)
DefStrFieldValueClass(OPComment1,opinfo[0])
DefStrFieldValueClass(OPComment2,opinfo[1])
DefStrFieldValueClass(OPComment3,opinfo[2])
下面是对这些表达式的IDispatch封装,从而可用于jscript:
//逻辑条件类,支持AND,OR,NOT逻辑操作
class Condition : public IDispatch
{
public:
 virtual BOOL __stdcall get_IsCondition(void)
 {
  return TRUE;
 }
 virtual IDispatch* __stdcall And(IDispatch* v)
 {
  BOOL r=DispatchDriver::GetProperty(v,L"IsCondition",Type2Type<BOOL>());
  if(r && pCondition)
  {
   Condition* pv=static_cast<Condition*>(v);
   AndCondition* p=new AndCondition(pCondition,pv->GetCondition());
   Condition* ptr=Condition::CreateDispatch();
   ptr->Init(p);
   p->Release();
   return ptr;
  }
  return NULL;
 }
 virtual IDispatch* __stdcall Or(IDispatch* v)
 {
  BOOL r=DispatchDriver::GetProperty(v,L"IsCondition",Type2Type<BOOL>());
  if(r && pCondition)
  {
   Condition* pv=static_cast<Condition*>(v);
   OrCondition* p=new OrCondition(pCondition,pv->GetCondition());
   Condition* ptr=Condition::CreateDispatch();
   ptr->Init(p);
   p->Release();
   return ptr;
  }
  return NULL;
 }
 virtual IDispatch* __stdcall Not(void)
 {
  if(pCondition)
  {
   NotCondition* p=new NotCondition(pCondition);
   Condition* ptr=Condition::CreateDispatch();
   ptr->Init(p);
   p->Release();
   return ptr;
  }
  return NULL;
 }
public:
 BEGIN_INTF(Condition)
  PROPERTYGET(IsCondition,true)
  METHOD(And)
  METHOD(Or)
  METHOD(Not)
 END_INTF()
public:
 Condition()
 {
  pCondition=NULL;
 }
 ~Condition()
 {
  if(pCondition)
   pCondition->Release();
 }
 void Init(ConditionExpression* p)
 {
  pCondition=p;
  if(p)
   p->AddRef();
 }
 ConditionExpression* GetCondition(void)
 {
  return pCondition;
 }
private:
 ConditionExpression* pCondition;
};
#define DefFieldMember(NAME) \
 virtual IDispatch* __stdcall get_##NAME(void)\
 {\
  IntegerFields* p=IntegerFields::CreateDispatch();\
  p->Init(FieldValueClass(NAME)::Value);\
  return p;\
 }
#define DefStrFieldMember(NAME) \
 virtual IDispatch* __stdcall get_##NAME(void)\
 {\
  StringFields* p=StringFields::CreateDispatch();\
  p->Init(FieldValueClass(NAME)::Value);\
  return p;\
 }
//t_disasm结构中整型成员的封装,这个类提供基本值,以及由基本值参与比较运算EQ(等于),GE(大于等于),LE(小于等于)
//而得到的条件表达式,这样得到的条件表达式可以直接传给FindDisasm2方法用作条件,也可以经由前一个类的AND,OR,NOT操作
//合成新的条件表达式后再用于FindDisasm2方法。
class IntegerFields : public IDispatch
{
public:
 virtual IDispatch* __stdcall EQ(int v)
 {
  if(!fptr)
   return NULL;
  ConditionExpression* p=new CompareCondition<0>(fptr,v); 
  Condition* ptr=Condition::CreateDispatch();
  ptr->Init(p);
  p->Release();
  return ptr;
 }
 virtual IDispatch* __stdcall GE(int v)
 {
  if(!fptr)
   return NULL;
  ConditionExpression* p=new CompareCondition<1>(fptr,v); 
  Condition* ptr=Condition::CreateDispatch();
  ptr->Init(p);
  p->Release();
  return ptr;
 }
 virtual IDispatch* __stdcall LE(int v)
 {
  if(!fptr)
   return NULL;
  ConditionExpression* p=new CompareCondition<-1>(fptr,v); 
  Condition* ptr=Condition::CreateDispatch();
  ptr->Init(p);
  p->Release();
  return ptr;
 }
 virtual IDispatch* __stdcall get_IP(void)
 {
  IntegerFields* p=IntegerFields::CreateDispatch();
  p->Init(FieldValueClass(IP)::Value);
  return p;
 }
DefFieldMember(CmdType)
DefFieldMember(MemType)
DefFieldMember(PrefixNum)
DefFieldMember(Indexed)
DefFieldMember(JumpConst)
DefFieldMember(JumpTable)
DefFieldMember(AddrConst)
DefFieldMember(ImmConst)
DefFieldMember(ZeroImm)
DefFieldMember(FixupOffset)
DefFieldMember(FixupSize)
DefFieldMember(JumpAddr)
DefFieldMember(Error)
DefFieldMember(Warnings)
DefFieldMember(OPType1)
DefFieldMember(OPType2)
DefFieldMember(OPType3)
DefFieldMember(OPSize1)
DefFieldMember(OPSize2)
DefFieldMember(OPSize3)
DefFieldMember(OPSeg1)
DefFieldMember(OPSeg2)
DefFieldMember(OPSeg3)
DefFieldMember(OPConst1)
DefFieldMember(OPConst2)
DefFieldMember(OPConst3)
DefFieldMember(OPEaxScale1)
DefFieldMember(OPEcxScale1)
DefFieldMember(OPEdxScale1)
DefFieldMember(OPEbxScale1)
DefFieldMember(OPEspScale1)
DefFieldMember(OPEbpScale1)
DefFieldMember(OPEsiScale1)
DefFieldMember(OPEdiScale1)
DefFieldMember(OPEaxScale2)
DefFieldMember(OPEcxScale2)
DefFieldMember(OPEdxScale2)
DefFieldMember(OPEbxScale2)
DefFieldMember(OPEspScale2)
DefFieldMember(OPEbpScale2)
DefFieldMember(OPEsiScale2)
DefFieldMember(OPEdiScale2)
DefFieldMember(OPEaxScale3)
DefFieldMember(OPEcxScale3)
DefFieldMember(OPEdxScale3)
DefFieldMember(OPEbxScale3)
DefFieldMember(OPEspScale3)
DefFieldMember(OPEbpScale3)
DefFieldMember(OPEsiScale3)
DefFieldMember(OPEdiScale3)
public:
 BEGIN_INTF(IntegerFields)
  METHOD(EQ)
  METHOD(GE)
  METHOD(LE)
  PROPERTYGET(IP,true)
  PROPERTYGET(CmdType,true)
  PROPERTYGET(MemType,true)
  PROPERTYGET(PrefixNum,true)
  PROPERTYGET(Indexed,true)
  PROPERTYGET(JumpConst,true)
  PROPERTYGET(JumpTable,true)
  PROPERTYGET(AddrConst,true)
  PROPERTYGET(ImmConst,true)
  PROPERTYGET(ZeroImm,true)
  PROPERTYGET(FixupOffset,true)
  PROPERTYGET(FixupSize,true)
  PROPERTYGET(JumpAddr,true)
  PROPERTYGET(Error,true)
  PROPERTYGET(Warnings,true)
  PROPERTYGET(OPType1,true)
  PROPERTYGET(OPType2,true)
  PROPERTYGET(OPType3,true)
  PROPERTYGET(OPSize1,true)
  PROPERTYGET(OPSize2,true)
  PROPERTYGET(OPSize3,true)
  PROPERTYGET(OPSeg1,true)
  PROPERTYGET(OPSeg2,true)
  PROPERTYGET(OPSeg3,true)
  PROPERTYGET(OPConst1,true)
  PROPERTYGET(OPConst2,true)
  PROPERTYGET(OPConst3,true)
  PROPERTYGET(OPEaxScale1,true)
  PROPERTYGET(OPEcxScale1,true)
  PROPERTYGET(OPEdxScale1,true)
  PROPERTYGET(OPEbxScale1,true)
  PROPERTYGET(OPEspScale1,true)
  PROPERTYGET(OPEbpScale1,true)
  PROPERTYGET(OPEsiScale1,true)
  PROPERTYGET(OPEdiScale1,true)
  PROPERTYGET(OPEaxScale2,true)
  PROPERTYGET(OPEcxScale2,true)
  PROPERTYGET(OPEdxScale2,true)
  PROPERTYGET(OPEbxScale2,true)
  PROPERTYGET(OPEspScale2,true)
  PROPERTYGET(OPEbpScale2,true)
  PROPERTYGET(OPEsiScale2,true)
  PROPERTYGET(OPEdiScale2,true)
  PROPERTYGET(OPEaxScale3,true)
  PROPERTYGET(OPEcxScale3,true)
  PROPERTYGET(OPEdxScale3,true)
  PROPERTYGET(OPEbxScale3,true)
  PROPERTYGET(OPEspScale3,true)
  PROPERTYGET(OPEbpScale3,true)
  PROPERTYGET(OPEsiScale3,true)
  PROPERTYGET(OPEdiScale3,true)
 END_INTF()
public:
 IntegerFields()
 {
  fptr=NULL;
 }
 void Init(IntValuePtr _fptr)
 {
  fptr=_fptr;
 }
private:
 IntValuePtr fptr;
};
//t_disasm结构中字符串成员的封装,这个类提供基本值,以及由基本值参与字符串搜索Like
//而得到的条件表达式,这样得到的条件表达式可以直接传给FindDisasm2方法用作条件,也可以经由前一个类的AND,OR,NOT操作
//合成新的条件表达式后再用于FindDisasm2方法。
class StringFields : public IDispatch
{
public:
 virtual IDispatch* __stdcall Like(BSTR str)
 {
  if(!fptr)
   return NULL;
  StringLikeCondition* p=new StringLikeCondition(fptr,CString(str)); 
  Condition* ptr=Condition::CreateDispatch();
  ptr->Init(p);
  p->Release();
  return ptr;
 }
DefStrFieldMember(Dump)
DefStrFieldMember(Disasm)
DefStrFieldMember(Comment)
DefStrFieldMember(OPComment1)
DefStrFieldMember(OPComment2)
DefStrFieldMember(OPComment3)
public:
 BEGIN_INTF(StringFields)
  METHOD(Like)
  PROPERTYGET(Dump,true)
  PROPERTYGET(Disasm,true)
  PROPERTYGET(Comment,true)
  PROPERTYGET(OPComment1,true)
  PROPERTYGET(OPComment2,true)
  PROPERTYGET(OPComment3,true)
 END_INTF()
public:
 StringFields()
 {
  fptr=NULL;
 }
 void Init(StrValuePtr _fptr)
 {
  fptr=_fptr;
 }
private:
 StrValuePtr fptr;
};
反汇编代码搜索方法的实现:
virtual IDispatch* __stdcall FindDisasm2(DWORD addr,IDispatch* condition)
 {
//判断参数是否条件表达式,因为没有定义新接口,所以不能用QueryInterface来确定。
  BOOL r=DispatchDriver::GetProperty(condition,L"IsCondition",Type2Type<BOOL>());
  if(!r)
   return NULL;
  Condition* pv=static_cast<Condition*>(condition);
  ConditionExpression* pCE=pv->GetCondition();
  pCE->AddRef();//引用计数加1
  DWORD endaddr;
  int ct=0;
  int size = 0;
  t_memory* tmem = Findmemory(addr);
  char cmd[MAXCMDSIZE]={0};
  do
  {
   addr = Disassembleforward(0, tmem->base, tmem->size, addr, 1, 1);
   endaddr = Disassembleforward(0, tmem->base, tmem->size, addr, 1, 1);
   size = Readcommand(addr, cmd);
   if(addr == tmem->base + tmem->size)
    size = 0;
   if(size)
   {
    t_disasm dasm;
    ::memset(&dasm,0,sizeof(t_disasm));
    DWORD dsize=0;
    unsigned char* bytes=Finddecode(addr,&dsize);
    ::Disasm((uchar*)cmd,size,addr,bytes,&dasm,DISASM_CODE,NULL);
//应用LAMBDA表达式执行计算来得到判断
    if((*pCE)(&dasm))
    {
     pCE->Release();//引用计数减1
     DisasmInfo* p=DisasmInfo::CreateDispatch();
     p->Init(&dasm);
     return p;
    }
   }
   if(ct % EXTERN_EVENT_INTERVAL == 0)
   {
    dlg.DoMessageLoopOnce();
   }
   ct++;
  } while(size != 0);
  pCE->Release();//引用计数减1
  return NULL;
 }