| 本帖最后由 十二 于 2011-4-21 10:48 编辑 
 FXTZ的控制流程被包含在DirectInput中。虽然IAT中没有DirectInputCreate这样类似的助手函数(大部分程序IAT中都会导入d3d9.dll、dinput.dll其中会导入DirectInputCreate、Direct3DCreate9之类的助手函数。)方便返回接口的指针来方便调用。
 
 以前一直以为所有的windows程序都是用windows消息循环来执行call back function来实现自定义的逻辑,直到主席提到dxinput,才改变了我的看法。
 
 windows是以API为基础用消息来驱动的。但是消息并不只是WM_规范的这些,消息很广义可以为一个信号,也可以是一个值,这对程序流程而言都可以看做一个消息。并非只指WIN规范WM_消息。
 
 从消息队列取走消息然后处理,效率是相当低下的所以DXinput出现了。
 
 以上全是废话,下面进入正题。
 
 FXTZ的IAT中并没有导入dinput.dll和其助手函数DirectInputCreate来得到IDirectInput接口的指针,(吐槽那你怎么知道用了dxinput)。
 
 dx组件的调用并非必须用助手函数来得到接口指针,dx组件是基于COM的详见,http://bbs.nyasama.com/forum.php?mod=viewthread&tid=1887&extra=page%3D1
 
 如果拥有组件的CLSID和IID可以通过CoCreateInstance函数来得到IDirectInput接口,很巧FXTZ就用的这种方法。
 
 F3载入th123.exe
 
 bp  CoCreateInstance
 
 栈信息如下:
 
 
  
 0012FB30处是CLSID可在注册表中找到。
 
 0012FB3C处是IID可在 http://bbs.nyasama.com/forum.php?mod=viewthread&tid=1887&extra=page%3D1 此贴10L中的附件中找到
 
 0012FB40处记录的指针0088D17C中就是IDirectInput8W接口的指针了。
 
 Alt+F9返回。
 
 
 复制代码0040D20B  |.  85C0          TEST EAX,EAX
0040D20D  |.  7D 1E         JGE SHORT th123_汉.0040D22D
0040D20F  |.  8B0D 78D18800 MOV ECX,DWORD PTR DS:[88D178]
0040D215  |.  6A 00         PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
0040D217  |.  68 D0E38500   PUSH th123_汉.0085E3D0                    ; |Title = "DInput-Error"
0040D21C  |.  68 80E38500   PUSH th123_汉.0085E380                    ; |Text = "DirectInput对象创建失败#0"
0040D221  |.  51            PUSH ECX                                 ; |hOwner = 002EAA64
0040D222  |.  FF15 4C628400 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA
0040D228  |.  32C0          XOR AL,AL
0040D22A  |.  C2 0800       RETN 8
0040D22D  |>  A1 7CD18800   MOV EAX,DWORD PTR DS:[88D17C]
0040D232  |.  8B4C24 08     MOV ECX,DWORD PTR SS:[ESP+8]             ;  th123_汉.00400000
0040D236  |.  8B10          MOV EDX,DWORD PTR DS:[EAX]
0040D238  |.  8B52 1C       MOV EDX,DWORD PTR DS:[EDX+1C]
0040D23B  |.  68 00080000   PUSH 800
0040D240  |.  51            PUSH ECX
0040D241  |.  50            PUSH EAX
0040D242  |.  FFD2          CALL EDX
0040D244  |.  85C0          TEST EAX,EAX
0040D246  |.  7D 1D         JGE SHORT th123_汉.0040D265
0040D248  |.  A1 78D18800   MOV EAX,DWORD PTR DS:[88D178]
0040D24D  |.  6A 00         PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
0040D24F  |.  68 D0E38500   PUSH th123_汉.0085E3D0                    ; |Title = "DInput-Error"
0040D254  |.  68 A8E38500   PUSH th123_汉.0085E3A8                    ; |Text = "DirectInput对象创建失败#1"
0040D259  |.  50            PUSH EAX                                 ; |hOwner = NULL
0040D25A  |.  FF15 4C628400 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA
0040D260  |.  32C0          XOR AL,AL
0040D262  |.  C2 0800       RETN 8
0040D265  |>  B0 01         MOV AL,1
0040D267  \.  C2 0800       RETN 8
 
 可以看到会出现判断EAX的值来确定是否获得IDirectInput8接口指针。
 
 0088D17C 中也返回了 IDirectInput8 的接口指针,右键数据跟随00126AA1C。
 
 
  
 来到这里
 
 
  
 再跟随一次。
 
 
  
 这里就是 IDirectInput8接口下的方法了对照http://bbs.nyasama.com/forum.php?mod=viewthread&tid=1887&extra=page%3D1此贴10L中的附件
 
 DECLARE_INTERFACE_(IDirectInput8W, IUnknown)
 {
 /*** IUnknown methods ***/
 STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE;
 STDMETHOD_(ULONG,AddRef)(THIS) PURE;
 STDMETHOD_(ULONG,Release)(THIS) PURE;
 
 /*** IDirectInput8W methods ***/
 STDMETHOD(CreateDevice)(THIS_ REFGUID,LPDIRECTINPUTDEVICE8W *,LPUNKNOWN) PURE;
 STDMETHOD(EnumDevices)(THIS_ DWORD,LPDIENUMDEVICESCALLBACKW,LPVOID,DWORD) PURE;
 STDMETHOD(GetDeviceStatus)(THIS_ REFGUID) PURE;
 STDMETHOD(RunControlPanel)(THIS_ HWND,DWORD) PURE;
 STDMETHOD(Initialize)(THIS_ HINSTANCE,DWORD) PURE;
 STDMETHOD(FindDevice)(THIS_ REFGUID,LPCWSTR,LPGUID) PURE;
 STDMETHOD(EnumDevicesBySemantics)(THIS_ LPCWSTR,LPDIACTIONFORMATW,LPDIENUMDEVICESBYSEMANTICSCBW,LPVOID,DWORD) PURE;
 STDMETHOD(ConfigureDevices)(THIS_ LPDICONFIGUREDEVICESCALLBACK,LPDICONFIGUREDEVICESPARAMSW,DWORD,LPVOID) PURE;
 };
 
 和上面的地址指针的顺序是一样的。
 
 判断得到IDirectInput8后会调用Initialize进行初始化。然后会调用一个重要的方法。CreateDevice来得到LPDIRECTINPUTDEVICE8的接口指针。调试的时候别数错了同上一样跟踪。
 
 顺道就全部贴出来了。
 
 DECLARE_INTERFACE_(IDirectInputDevice8W, IUnknown)
 {
 /*** IUnknown methods ***/
 STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE;
 STDMETHOD_(ULONG,AddRef)(THIS) PURE;
 STDMETHOD_(ULONG,Release)(THIS) PURE;
 
 /*** IDirectInputDevice8W methods ***/
 STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS) PURE;
 STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW,LPVOID,DWORD) PURE;
 STDMETHOD(GetProperty)(THIS_ REFGUID,LPDIPROPHEADER) PURE;
 STDMETHOD(SetProperty)(THIS_ REFGUID,LPCDIPROPHEADER) PURE;
 STDMETHOD(Acquire)(THIS) PURE;
 STDMETHOD(Unacquire)(THIS) PURE;
 STDMETHOD(GetDeviceState)(THIS_ DWORD,LPVOID) PURE;
 STDMETHOD(GetDeviceData)(THIS_ DWORD,LPDIDEVICEOBJECTDATA,LPDWORD,DWORD) PURE;
 STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT) PURE;
 STDMETHOD(SetEventNotification)(THIS_ HANDLE) PURE;
 STDMETHOD(SetCooperativeLevel)(THIS_ HWND,DWORD) PURE;
 STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW,DWORD,DWORD) PURE;
 STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW) PURE;
 STDMETHOD(RunControlPanel)(THIS_ HWND,DWORD) PURE;
 STDMETHOD(Initialize)(THIS_ HINSTANCE,DWORD,REFGUID) PURE;
 STDMETHOD(CreateEffect)(THIS_ REFGUID,LPCDIEFFECT,LPDIRECTINPUTEFFECT *,LPUNKNOWN) PURE;
 STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKW,LPVOID,DWORD) PURE;
 STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOW,REFGUID) PURE;
 STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD) PURE;
 STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD) PURE;
 STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK,LPVOID,DWORD) PURE;
 STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE) PURE;
 STDMETHOD(Poll)(THIS) PURE;
 STDMETHOD(SendDeviceData)(THIS_ DWORD,LPCDIDEVICEOBJECTDATA,LPDWORD,DWORD) PURE;
 STDMETHOD(EnumEffectsInFile)(THIS_ LPCWSTR,LPDIENUMEFFECTSINFILECALLBACK,LPVOID,DWORD) PURE;
 STDMETHOD(WriteEffectToFile)(THIS_ LPCWSTR,DWORD,LPDIFILEEFFECT,DWORD) PURE;
 STDMETHOD(BuildActionMap)(THIS_ LPDIACTIONFORMATW,LPCWSTR,DWORD) PURE;
 STDMETHOD(SetActionMap)(THIS_ LPDIACTIONFORMATW,LPCWSTR,DWORD) PURE;
 STDMETHOD(GetImageInfo)(THIS_ LPDIDEVICEIMAGEINFOHEADERW) PURE;
 };
 
 可以看到这下面有很多方法,想折腾的人可以去MSDN找原型,或者去百度找找DXinput的具体流程,这里不熬述。
 
 这里有两个重要的方法GetDeviceState,GetDeviceData。这两个函数是把键盘数据送给缓冲区然后做为消息让FXTZ实现键盘按键后的游戏逻辑。
 
 FXTZ没有用GetDeviceData,因为格斗游戏要求即使操作,所以用GetDeviceState来得到即时缓冲。
 
 断到GetDeviceState方法内部。
 
 
 |