Browse Source

【模块名称】
gm辅助模块
【问题原因】
首次添加,未解决bug。
【修改描述】

【测试结果】

sat23 3 years ago
parent
commit
fe63e9fa94
78 changed files with 15928 additions and 0 deletions
  1. 1073 0
      gm/3rd_party/include/METHODSTABLE.txt
  2. 186 0
      gm/3rd_party/include/MinHook.h
  3. 78 0
      gm/3rd_party/include/kiero.h
  4. BIN
      gm/3rd_party/lib/x64/minhook.lib
  5. BIN
      gm/3rd_party/lib/x86/ScintillaEdit4.lib
  6. BIN
      gm/3rd_party/lib/x86/minhook.lib
  7. 750 0
      gm/3rd_party/src/kiero.cpp
  8. 31 0
      gm/gm.sln
  9. 16 0
      gm/gm/Resource.h
  10. 159 0
      gm/gm/algorithm/AStar.hpp
  11. 647 0
      gm/gm/background/Hook/DisplayHook.cpp
  12. 30 0
      gm/gm/background/Hook/DisplayHook.h
  13. 65 0
      gm/gm/background/Hook/HookExport.cpp
  14. 18 0
      gm/gm/background/Hook/HookExport.h
  15. 263 0
      gm/gm/background/Hook/InputHook.cpp
  16. 33 0
      gm/gm/background/Hook/InputHook.h
  17. 55 0
      gm/gm/background/Hook/dinput.md
  18. 13 0
      gm/gm/background/Hook/opMessage.h
  19. 94 0
      gm/gm/background/display/IDisplay.cpp
  20. 68 0
      gm/gm/background/display/IDisplay.h
  21. 17 0
      gm/gm/background/display/frameInfo.h
  22. 307 0
      gm/gm/background/display/opDxGL.cpp
  23. 31 0
      gm/gm/background/display/opDxGL.h
  24. 252 0
      gm/gm/background/display/opGDI.cpp
  25. 43 0
      gm/gm/background/display/opGDI.h
  26. 210 0
      gm/gm/background/keypad/Bkkeypad.cpp
  27. 32 0
      gm/gm/background/keypad/Bkkeypad.h
  28. 206 0
      gm/gm/background/keypad/winkeypad.cpp
  29. 30 0
      gm/gm/background/keypad/winkeypad.h
  30. 311 0
      gm/gm/background/mouse/opMouseDx.cpp
  31. 51 0
      gm/gm/background/mouse/opMouseDx.h
  32. 390 0
      gm/gm/background/mouse/opMouseWin.cpp
  33. 51 0
      gm/gm/background/mouse/opMouseWin.h
  34. 486 0
      gm/gm/background/opBackground.cpp
  35. 64 0
      gm/gm/background/opBackground.h
  36. 23 0
      gm/gm/core/Cmder.h
  37. 112 0
      gm/gm/core/Pipe.cpp
  38. 28 0
      gm/gm/core/Pipe.h
  39. 13 0
      gm/gm/core/globalVar.cpp
  40. 96 0
      gm/gm/core/globalVar.h
  41. 221 0
      gm/gm/core/helpfunc.cpp
  42. 91 0
      gm/gm/core/helpfunc.h
  43. 31 0
      gm/gm/core/opEnv.cpp
  44. 18 0
      gm/gm/core/opEnv.h
  45. 95 0
      gm/gm/core/optype.h
  46. 24 0
      gm/gm/framework.h
  47. 47 0
      gm/gm/gm.cpp
  48. 22 0
      gm/gm/gm.h
  49. BIN
      gm/gm/gm.rc
  50. 292 0
      gm/gm/gm.vcxproj
  51. 243 0
      gm/gm/gm.vcxproj.filters
  52. 1400 0
      gm/gm/imageProc/ImageLoc.cpp
  53. 184 0
      gm/gm/imageProc/ImageLoc.h
  54. 524 0
      gm/gm/imageProc/ImageProc.cpp
  55. 95 0
      gm/gm/imageProc/ImageProc.h
  56. 13 0
      gm/gm/imageProc/compute/ThreadPool.cpp
  57. 100 0
      gm/gm/imageProc/compute/ThreadPool.h
  58. 24 0
      gm/gm/imageProc/imageView.hpp
  59. 380 0
      gm/gm/include/Dict.h
  60. 319 0
      gm/gm/include/Image.hpp
  61. 22 0
      gm/gm/include/bitfunc.h
  62. 75 0
      gm/gm/include/color.h
  63. 298 0
      gm/gm/include/libop.h
  64. 57 0
      gm/gm/include/promutex.h
  65. 77 0
      gm/gm/include/sharedmem.h
  66. 1261 0
      gm/gm/libop.cpp
  67. 298 0
      gm/gm/libop.h
  68. 5 0
      gm/gm/pch.cpp
  69. 13 0
      gm/gm/pch.h
  70. 6 0
      gm/gm/targetver.h
  71. 98 0
      gm/gm/winapi/Injecter.cpp
  72. 12 0
      gm/gm/winapi/Injecter.h
  73. 259 0
      gm/gm/winapi/MemoryEx.cpp
  74. 25 0
      gm/gm/winapi/MemoryEx.h
  75. 2882 0
      gm/gm/winapi/WinApi.cpp
  76. 58 0
      gm/gm/winapi/WinApi.h
  77. 22 0
      gm/gm/winapi/query_api.cpp
  78. 5 0
      gm/gm/winapi/query_api.h

+ 1073 - 0
gm/3rd_party/include/METHODSTABLE.txt

@@ -0,0 +1,1073 @@
+D3D9 Methods Table:
+[0]   QueryInterface
+[1]   AddRef
+[2]   Release
+[3]   TestCooperativeLevel
+[4]   GetAvailableTextureMem
+[5]   EvictManagedResources
+[6]   GetDirect3D
+[7]   GetDeviceCaps
+[8]   GetDisplayMode
+[9]   GetCreationParameters
+[10]  SetCursorProperties
+[11]  SetCursorPosition
+[12]  ShowCursor
+[13]  CreateAdditionalSwapChain
+[14]  GetSwapChain
+[15]  GetNumberOfSwapChains
+[16]  Reset
+[17]  Present
+[18]  GetBackBuffer
+[19]  GetRasterStatus
+[20]  SetDialogBoxMode
+[21]  SetGammaRamp
+[22]  GetGammaRamp
+[23]  CreateTexture
+[24]  CreateVolumeTexture
+[25]  CreateCubeTexture
+[26]  CreateVertexBuffer
+[27]  CreateIndexBuffer
+[28]  CreateRenderTarget
+[29]  CreateDepthStencilSurface
+[30]  UpdateSurface
+[31]  UpdateTexture
+[32]  GetRenderTargetData
+[33]  GetFrontBufferData
+[34]  StretchRect
+[35]  ColorFill
+[36]  CreateOffscreenPlainSurface
+[37]  SetRenderTarget
+[38]  GetRenderTarget
+[39]  SetDepthStencilSurface
+[40]  GetDepthStencilSurface
+[41]  BeginScene
+[42]  EndScene
+[43]  Clear
+[44]  SetTransform
+[45]  GetTransform
+[46]  MultiplyTransform
+[47]  SetViewport
+[48]  GetViewport
+[49]  SetMaterial
+[50]  GetMaterial
+[51]  SetLight
+[52]  GetLight
+[53]  LightEnable
+[54]  GetLightEnable
+[55]  SetClipPlane
+[56]  GetClipPlane
+[57]  SetRenderState
+[58]  GetRenderState
+[59]  CreateStateBlock
+[60]  BeginStateBlock
+[61]  EndStateBlock
+[62]  SetClipStatus
+[63]  GetClipStatus
+[64]  GetTexture
+[65]  SetTexture
+[66]  GetTextureStageState
+[67]  SetTextureStageState
+[68]  GetSamplerState
+[69]  SetSamplerState
+[70]  ValidateDevice
+[71]  SetPaletteEntries
+[72]  GetPaletteEntries
+[73]  SetCurrentTexturePalette
+[74]  GetCurrentTexturePalette
+[75]  SetScissorRect
+[76]  GetScissorRect
+[77]  SetSoftwareVertexProcessing
+[78]  GetSoftwareVertexProcessing
+[79]  SetNPatchMode
+[80]  GetNPatchMode
+[81]  DrawPrimitive
+[82]  DrawIndexedPrimitive
+[83]  DrawPrimitiveUP
+[84]  DrawIndexedPrimitiveUP
+[85]  ProcessVertices
+[86]  CreateVertexDeclaration
+[87]  SetVertexDeclaration
+[88]  GetVertexDeclaration
+[89]  SetFVF
+[90]  GetFVF
+[91]  CreateVertexShader
+[92]  SetVertexShader
+[93]  GetVertexShader
+[94]  SetVertexShaderConstantF
+[95]  GetVertexShaderConstantF
+[96]  SetVertexShaderConstantI
+[97]  GetVertexShaderConstantI
+[98]  SetVertexShaderConstantB
+[99]  GetVertexShaderConstantB
+[100] SetStreamSource
+[101] GetStreamSource
+[102] SetStreamSourceFreq
+[103] GetStreamSourceFreq
+[104] SetIndices
+[105] GetIndices
+[106] CreatePixelShader
+[107] SetPixelShader
+[108] GetPixelShader
+[109] SetPixelShaderConstantF
+[110] GetPixelShaderConstantF
+[111] SetPixelShaderConstantI
+[112] GetPixelShaderConstantI
+[113] SetPixelShaderConstantB
+[114] GetPixelShaderConstantB
+[115] DrawRectPatch
+[116] DrawTriPatch
+[117] DeletePatch
+[118] CreateQuery
+
+D3D10 Methods Table:
+[0]   QueryInterface
+[1]   AddRef
+[2]   Release
+[3]   SetPrivateData
+[4]   SetPrivateDataInterface
+[5]   GetPrivateData
+[6]   GetParent
+[7]   GetDevice
+[8]   Present
+[9]   GetBuffer
+[10]  SetFullscreenState
+[11]  GetFullscreenState
+[12]  GetDesc
+[13]  ResizeBuffers
+[14]  ResizeTarget
+[15]  GetContainingOutput
+[16]  GetFrameStatistics
+[17]  GetLastPresentCount
+[18]  QueryInterface
+[19]  AddRef
+[20]  Release
+[21]  VSSetConstantBuffers
+[22]  PSSetShaderResources
+[23]  PSSetShader
+[24]  PSSetSamplers
+[25]  VSSetShader
+[26]  DrawIndexed
+[27]  Draw
+[28]  PSSetConstantBuffers
+[29]  IASetInputLayout
+[30]  IASetVertexBuffers
+[31]  IASetIndexBuffer
+[32]  DrawIndexedInstanced
+[33]  DrawInstanced
+[34]  GSSetConstantBuffers
+[35]  GSSetShader
+[36]  IASetPrimitiveTopology
+[37]  VSSetShaderResources
+[38]  VSSetSamplers
+[39]  SetPredication
+[40]  GSSetShaderResources
+[41]  GSSetSamplers
+[42]  OMSetRenderTargets
+[43]  OMSetBlendState
+[44]  OMSetDepthStencilState
+[45]  SOSetTargets
+[46]  DrawAuto
+[47]  RSSetState
+[48]  RSSetViewports
+[49]  RSSetScissorRects
+[50]  CopySubresourceRegion
+[51]  CopyResource
+[52]  UpdateSubresource
+[53]  ClearRenderTargetView
+[54]  ClearDepthStencilView
+[55]  GenerateMips
+[56]  ResolveSubresource
+[57]  VSGetConstantBuffers
+[58]  PSGetShaderResources
+[59]  PSGetShader
+[60]  PSGetSamplers
+[61]  VSGetShader
+[62]  PSGetConstantBuffers
+[63]  IAGetInputLayout
+[64]  IAGetVertexBuffers
+[65]  IAGetIndexBuffer
+[66]  GSGetConstantBuffers
+[67]  GSGetShader
+[68]  IAGetPrimitiveTopology
+[69]  VSGetShaderResources
+[70]  VSGetSamplers
+[71]  GetPredication
+[72]  GSGetShaderResources
+[73]  GSGetSamplers
+[74]  OMGetRenderTargets
+[75]  OMGetBlendState
+[76]  OMGetDepthStencilState
+[77]  SOGetTargets
+[78]  RSGetState
+[79]  RSGetViewports
+[80]  RSGetScissorRects
+[81]  GetDeviceRemovedReason
+[82]  SetExceptionMode
+[83]  GetExceptionMode
+[84]  GetPrivateData
+[85]  SetPrivateData
+[86]  SetPrivateDataInterface
+[87]  ClearState
+[88]  Flush
+[89]  CreateBuffer
+[90]  CreateTexture1D
+[91]  CreateTexture2D
+[92]  CreateTexture3D
+[93]  CreateShaderResourceView
+[94]  CreateRenderTargetView
+[95]  CreateDepthStencilView
+[96]  CreateInputLayout
+[97]  CreateVertexShader
+[98]  CreateGeometryShader
+[99]  CreateGemoetryShaderWithStreamOutput
+[100] CreatePixelShader
+[101] CreateBlendState
+[102] CreateDepthStencilState
+[103] CreateRasterizerState
+[104] CreateSamplerState
+[105] CreateQuery
+[106] CreatePredicate
+[107] CreateCounter
+[108] CheckFormatSupport
+[109] CheckMultisampleQualityLevels
+[110] CheckCounterInfo
+[111] CheckCounter
+[112] GetCreationFlags
+[113] OpenSharedResource
+[114] SetTextFilterSize
+[115] GetTextFilterSize
+
+D3D11 Methods Table:
+[0]   QueryInterface
+[1]   AddRef
+[2]   Release
+[3]   SetPrivateData
+[4]   SetPrivateDataInterface
+[5]   GetPrivateData
+[6]   GetParent
+[7]   GetDevice
+[8]   Present
+[9]   GetBuffer
+[10]  SetFullscreenState
+[11]  GetFullscreenState
+[12]  GetDesc
+[13]  ResizeBuffers
+[14]  ResizeTarget
+[15]  GetContainingOutput
+[16]  GetFrameStatistics
+[17]  GetLastPresentCount
+[18]  QueryInterface
+[19]  AddRef
+[20]  Release
+[21]  CreateBuffer
+[22]  CreateTexture1D
+[23]  CreateTexture2D
+[24]  CreateTexture3D
+[25]  CreateShaderResourceView
+[26]  CreateUnorderedAccessView
+[27]  CreateRenderTargetView
+[28]  CreateDepthStencilView
+[29]  CreateInputLayout
+[30]  CreateVertexShader
+[31]  CreateGeometryShader
+[32]  CreateGeometryShaderWithStreamOutput
+[33]  CreatePixelShader
+[34]  CreateHullShader
+[35]  CreateDomainShader
+[36]  CreateComputeShader
+[37]  CreateClassLinkage
+[38]  CreateBlendState
+[39]  CreateDepthStencilState
+[40]  CreateRasterizerState
+[41]  CreateSamplerState
+[42]  CreateQuery
+[43]  CreatePredicate
+[44]  CreateCounter
+[45]  CreateDeferredContext
+[46]  OpenSharedResource
+[47]  CheckFormatSupport
+[48]  CheckMultisampleQualityLevels
+[49]  CheckCounterInfo
+[50]  CheckCounter
+[51]  CheckFeatureSupport
+[52]  GetPrivateData
+[53]  SetPrivateData
+[54]  SetPrivateDataInterface
+[55]  GetFeatureLevel
+[56]  GetCreationFlags
+[57]  GetDeviceRemovedReason
+[58]  GetImmediateContext
+[59]  SetExceptionMode
+[60]  GetExceptionMode
+[61]  QueryInterface
+[62]  AddRef
+[63]  Release
+[64]  GetDevice
+[65]  GetPrivateData
+[66]  SetPrivateData
+[67]  SetPrivateDataInterface
+[68]  SetConstantBuffers
+[69]  SetShaderResources
+[70]  SetShader
+[71]  SetSamplers
+[72]  SetShader
+[73]  DrawIndexed
+[74]  Draw
+[75]  Map
+[76]  Unmap
+[77]  SetConstantBuffers
+[78]  IASetInputLayout
+[79]  IASetVertexBuffers
+[80]  IASetIndexBuffer
+[81]  DrawIndexedInstanced
+[82]  DrawInstanced
+[83]  SetConstantBuffers
+[84]  SetShader
+[85]  IASetPrimitiveTopology
+[86]  SetShaderResources
+[87]  SetSamplers
+[88]  Begin
+[89]  End
+[90]  GetData
+[91]  SetPredication
+[92]  SetShaderResources
+[93]  SetSamplers
+[94]  OMSetRenderTargets
+[95]  OMSetRenderTargetsAndUnorderedAccessViews
+[96]  OMSetBlendState
+[97]  OMSetDepthStencilState
+[98]  SOSetTargets
+[99]  DrawAuto
+[100] DrawIndexedInstancedIndirect
+[101] DrawInstancedIndirect
+[102] Dispatch
+[103] DispatchIndirect
+[104] RSSetState
+[105] RSSetViewports
+[106] RSSetScissorRects
+[107] CopySubresourceRegion
+[108] CopyResource
+[109] UpdateSubresource
+[110] CopyStructureCount
+[111] ClearRenderTargetView
+[112] ClearUnorderedAccessViewUint
+[113] ClearUnorderedAccessViewFloat
+[114] ClearDepthStencilView
+[115] GenerateMips
+[116] SetResourceMinLOD
+[117] GetResourceMinLOD
+[118] ResolveSubresource
+[119] ExecuteCommandList
+[120] SetShaderResources
+[121] SetShader
+[122] SetSamplers
+[123] SetConstantBuffers
+[124] SetShaderResources
+[125] SetShader
+[126] SetSamplers
+[127] SetConstantBuffers
+[128] SetShaderResources
+[129] CSSetUnorderedAccessViews
+[130] SetShader
+[131] SetSamplers
+[132] SetConstantBuffers
+[133] VSGetConstantBuffers
+[134] PSGetShaderResources
+[135] PSGetShader
+[136] PSGetSamplers
+[137] VSGetShader
+[138] PSGetConstantBuffers
+[139] IAGetInputLayout
+[140] IAGetVertexBuffers
+[141] IAGetIndexBuffer
+[142] GSGetConstantBuffers
+[143] GSGetShader
+[144] IAGetPrimitiveTopology
+[145] VSGetShaderResources
+[146] VSGetSamplers
+[147] GetPredication
+[148] GSGetShaderResources
+[149] GSGetSamplers
+[150] OMGetRenderTargets
+[151] OMGetRenderTargetsAndUnorderedAccessViews
+[152] OMGetBlendState
+[153] OMGetDepthStencilState
+[154] SOGetTargets
+[155] RSGetState
+[156] RSGetViewports
+[157] RSGetScissorRects
+[158] HSGetShaderResources
+[159] HSGetShader
+[160] HSGetSamplers
+[161] HSGetConstantBuffers
+[162] DSGetShaderResources
+[163] DSGetShader
+[164] DSGetSamplers
+[165] DSGetConstantBuffers
+[166] CSGetShaderResources
+[167] CSGetUnorderedAccessViews
+[168] CSGetShader
+[169] CSGetSamplers
+[170] CSGetConstantBuffers
+[171] ClearState
+[172] Flush
+[173] GetType
+[174] GetContextFlags
+[175] FinishCommandList
+[176] CopySubresourceRegion1
+[177] UpdateSubresource1
+[178] DiscardResource
+[179] DiscardView
+[180] SetConstantBuffers1
+[181] SetConstantBuffers1
+[182] SetConstantBuffers1
+[183] SetConstantBuffers1
+[184] SetConstantBuffers1
+[185] SetConstantBuffers1
+[186] VSGetConstantBuffers1
+[187] HSGetConstantBuffers1
+[188] DSGetConstantBuffers1
+[189] GSGetConstantBuffers1
+[190] PSGetConstantBuffers1
+[191] CSGetConstantBuffers1
+[192] SwapDeviceContextState
+[193] ClearView
+[194] DiscardView1
+[195] UpdateTileMappings
+[196] CopyTileMappings
+[197] CopyTiles
+[198] UpdateTiles
+[199] ResizeTilePool
+[200] TiledResourceBarrier
+[201] IsAnnotationEnabled
+[202] SetMarkerInt
+[203] BeginEventInt
+[204] EndEvent
+
+D3D12 Methods Table:
+[0]   QueryInterface
+[1]   AddRef
+[2]   Release
+[3]   GetPrivateData
+[4]   SetPrivateData
+[5]   SetPrivateDataInterface
+[6]   SetName
+[7]   GetNodeCount
+[8]   CreateCommandQueue
+[9]   CreateCommandAllocator
+[10]  CreateGraphicsPipelineState
+[11]  CreateComputePipelineState
+[12]  CreateCommandList
+[13]  CheckFeatureSupport
+[14]  CreateDescriptorHeap
+[15]  GetDescriptorHandleIncrementSize
+[16]  CreateRootSignature
+[17]  CreateConstantBufferView
+[18]  CreateShaderResourceView
+[19]  CreateUnorderedAccessView
+[20]  CreateRenderTargetView
+[21]  CreateDepthStencilView
+[22]  CreateSampler
+[23]  CopyDescriptors
+[24]  CopyDescriptorsSimple
+[25]  GetResourceAllocationInfo
+[26]  GetCustomHeapProperties
+[27]  CreateCommittedResource
+[28]  CreateHeap
+[29]  CreatePlacedResource
+[30]  CreateReservedResource
+[31]  CreateSharedHandle
+[32]  OpenSharedHandle
+[33]  OpenSharedHandleByName
+[34]  MakeResident
+[35]  Evict
+[36]  CreateFence
+[37]  GetDeviceRemovedReason
+[38]  GetCopyableFootprints
+[39]  CreateQueryHeap
+[40]  SetStablePowerState
+[41]  CreateCommandSignature
+[42]  GetResourceTiling
+[43]  GetAdapterLuid
+[44]  QueryInterface
+[45]  AddRef
+[46]  Release
+[47]  GetPrivateData
+[48]  SetPrivateData
+[49]  SetPrivateDataInterface
+[50]  SetName
+[51]  GetDevice
+[52]  UpdateTileMappings
+[53]  CopyTileMappings
+[54]  ExecuteCommandLists
+[55]  SetMarker
+[56]  BeginEvent
+[57]  EndEvent
+[58]  Signal
+[59]  Wait
+[60]  GetTimestampFrequency
+[61]  GetClockCalibration
+[62]  GetDesc
+[63]  QueryInterface
+[64]  AddRef
+[65]  Release
+[66]  GetPrivateData
+[67]  SetPrivateData
+[68]  SetPrivateDataInterface
+[69]  SetName
+[70]  GetDevice
+[71]  Reset
+[72]  QueryInterface
+[73]  AddRef
+[74]  Release
+[75]  GetPrivateData
+[76]  SetPrivateData
+[77]  SetPrivateDataInterface
+[78]  SetName
+[79]  GetDevice
+[80]  GetType
+[81]  Close
+[82]  Reset
+[83]  ClearState
+[84]  DrawInstanced
+[85]  DrawIndexedInstanced
+[86]  Dispatch
+[87]  CopyBufferRegion
+[88]  CopyTextureRegion
+[89]  CopyResource
+[90]  CopyTiles
+[91]  ResolveSubresource
+[92]  IASetPrimitiveTopology
+[93]  RSSetViewports
+[94]  RSSetScissorRects
+[95]  OMSetBlendFactor
+[96]  OMSetStencilRef
+[97]  SetPipelineState
+[98]  ResourceBarrier
+[99]  ExecuteBundle
+[100] SetDescriptorHeaps
+[101] SetComputeRootSignature
+[102] SetGraphicsRootSignature
+[103] SetComputeRootDescriptorTable
+[104] SetGraphicsRootDescriptorTable
+[105] SetComputeRoot32BitConstant
+[106] SetGraphicsRoot32BitConstant
+[107] SetComputeRoot32BitConstants
+[108] SetGraphicsRoot32BitConstants
+[109] SetComputeRootConstantBufferView
+[110] SetGraphicsRootConstantBufferView
+[111] SetComputeRootShaderResourceView
+[112] SetGraphicsRootShaderResourceView
+[113] SetComputeRootUnorderedAccessView
+[114] SetGraphicsRootUnorderedAccessView
+[115] IASetIndexBuffer
+[116] IASetVertexBuffers
+[117] SOSetTargets
+[118] OMSetRenderTargets
+[119] ClearDepthStencilView
+[120] ClearRenderTargetView
+[121] ClearUnorderedAccessViewUint
+[122] ClearUnorderedAccessViewFloat
+[123] DiscardResource
+[124] BeginQuery
+[125] EndQuery
+[126] ResolveQueryData
+[127] SetPredication
+[128] SetMarker
+[129] BeginEvent
+[130] EndEvent
+[131] ExecuteIndirect
+[132] QueryInterface
+[133] AddRef
+[134] Release
+[135] SetPrivateData
+[136] SetPrivateDataInterface
+[137] GetPrivateData
+[138] GetParent
+[139] GetDevice
+[140] Present
+[141] GetBuffer
+[142] SetFullscreenState
+[143] GetFullscreenState
+[144] GetDesc
+[145] ResizeBuffers
+[146] ResizeTarget
+[147] GetContainingOutput
+[148] GetFrameStatistics
+[149] GetLastPresentCount
+
+OpenGL Methods Table:
+[0]   glAccum
+[1]   glAlphaFunc
+[2]   glAreTexturesResident
+[3]   glArrayElement
+[4]   glBegin
+[5]   glBindTexture
+[6]   glBitmap
+[7]   glBlendFunc
+[8]   glCallList
+[9]   glCallLists
+[10]  glClear
+[11]  glClearAccum
+[12]  glClearColor
+[13]  glClearDepth
+[14]  glClearIndex
+[15]  glClearStencil
+[16]  glClipPlane
+[17]  glColor3b
+[18]  glColor3bv
+[19]  glColor3d
+[20]  glColor3dv
+[21]  glColor3f
+[22]  glColor3fv
+[23]  glColor3i
+[24]  glColor3iv
+[25]  glColor3s
+[26]  glColor3sv
+[27]  glColor3ub
+[28]  glColor3ubv
+[29]  glColor3ui
+[30]  glColor3uiv
+[31]  glColor3us
+[32]  glColor3usv
+[33]  glColor4b
+[34]  glColor4bv
+[35]  glColor4d
+[36]  glColor4dv
+[37]  glColor4f
+[38]  glColor4fv
+[39]  glColor4i
+[40]  glColor4iv
+[41]  glColor4s
+[42]  glColor4sv
+[43]  glColor4ub
+[44]  glColor4ubv
+[45]  glColor4ui
+[46]  glColor4uiv
+[47]  glColor4us
+[48]  glColor4usv
+[49]  glColorMask
+[50]  glColorMaterial
+[51]  glColorPointer
+[52]  glCopyPixels
+[53]  glCopyTexImage1D
+[54]  glCopyTexImage2D
+[55]  glCopyTexSubImage1D
+[56]  glCopyTexSubImage2D
+[57]  glCullFaceglCullFace
+[58]  glDeleteLists
+[59]  glDeleteTextures
+[60]  glDepthFunc
+[61]  glDepthMask
+[62]  glDepthRange
+[63]  glDisable
+[64]  glDisableClientState
+[65]  glDrawArrays
+[66]  glDrawBuffer
+[67]  glDrawElements
+[68]  glDrawPixels
+[69]  glEdgeFlag
+[70]  glEdgeFlagPointer
+[71]  glEdgeFlagv
+[72]  glEnable
+[73]  glEnableClientState
+[74]  glEnd
+[75]  glEndList
+[76]  glEvalCoord1d
+[77]  glEvalCoord1dv
+[78]  glEvalCoord1f
+[79]  glEvalCoord1fv
+[80]  glEvalCoord2d
+[81]  glEvalCoord2dv
+[82]  glEvalCoord2f
+[83]  glEvalCoord2fv
+[84]  glEvalMesh1
+[85]  glEvalMesh2
+[86]  glEvalPoint1
+[87]  glEvalPoint2
+[88]  glFeedbackBuffer
+[89]  glFinish
+[90]  glFlush
+[91]  glFogf
+[92]  glFogfv
+[93]  glFogi
+[94]  glFogiv
+[95]  glFrontFace
+[96]  glFrustum
+[97]  glGenLists
+[98]  glGenTextures
+[99]  glGetBooleanv
+[100] glGetClipPlane
+[101] glGetDoublev
+[102] glGetError
+[103] glGetFloatv
+[104] glGetIntegerv
+[105] glGetLightfv
+[106] glGetLightiv
+[107] glGetMapdv
+[108] glGetMapfv
+[109] glGetMapiv
+[110] glGetMaterialfv
+[111] glGetMaterialiv
+[112] glGetPixelMapfv
+[113] glGetPixelMapuiv
+[114] glGetPixelMapusv
+[115] glGetPointerv
+[116] glGetPolygonStipple
+[117] glGetString
+[118] glGetTexEnvfv
+[119] glGetTexEnviv
+[120] glGetTexGendv
+[121] glGetTexGenfv
+[122] glGetTexGeniv
+[123] glGetTexImage
+[124] glGetTexLevelParameterfv
+[125] glGetTexLevelParameteriv
+[126] glGetTexParameterfv
+[127] glGetTexParameteriv
+[128] glHint
+[129] glIndexMask
+[130] glIndexPointer
+[131] glIndexd
+[132] glIndexdv
+[133] glIndexf
+[134] glIndexfv
+[135] glIndexi
+[136] glIndexiv
+[137] glIndexs
+[138] glIndexsv
+[139] glIndexub
+[140] glIndexubv
+[141] glInitNames
+[142] glInterleavedArrays
+[143] glIsEnabled
+[144] glIsList
+[145] glIsTexture
+[146] glLightModelf
+[147] glLightModelfv
+[148] glLightModeli
+[149] glLightModeliv
+[150] glLightf
+[151] glLightfv
+[152] glLighti
+[153] glLightiv
+[154] glLineStipple
+[155] glLineWidth
+[156] glListBase
+[157] glLoadIdentity
+[158] glLoadMatrixd
+[159] glLoadMatrixf
+[160] glLoadName
+[161] glLogicOp
+[162] glMap1d
+[163] glMap1f
+[164] glMap2d
+[165] glMap2f
+[166] glMapGrid1d
+[167] glMapGrid1f
+[168] glMapGrid2d
+[169] glMapGrid2f
+[170] glMaterialf
+[171] glMaterialfv
+[172] glMateriali
+[173] glMaterialiv
+[174] glMatrixMode
+[175] glMultMatrixd
+[176] glMultMatrixf
+[177] glNewList
+[178] glNormal3b
+[179] glNormal3bv
+[180] glNormal3d
+[181] glNormal3dv
+[182] glNormal3f
+[183] glNormal3fv
+[184] glNormal3i
+[185] glNormal3iv
+[186] glNormal3s
+[187] glNormal3sv
+[188] glNormalPointer
+[189] glOrtho
+[190] glPassThrough
+[191] glPixelMapfv
+[192] glPixelMapuiv
+[193] glPixelMapusv
+[194] glPixelStoref
+[195] glPixelStorei
+[196] glPixelTransferf
+[197] glPixelTransferi
+[198] glPixelZoom
+[199] glPointSize
+[200] glPolygonMode
+[201] glPolygonOffset
+[202] glPolygonStipple
+[203] glPopAttrib
+[204] glPopClientAttrib
+[205] glPopMatrix
+[206] glPopName
+[207] glPrioritizeTextures
+[208] glPushAttrib
+[209] glPushClientAttrib
+[210] glPushMatrix
+[211] glPushName
+[212] glRasterPos2d
+[213] glRasterPos2dv
+[214] glRasterPos2f
+[215] glRasterPos2fv
+[216] glRasterPos2i
+[217] glRasterPos2iv
+[218] glRasterPos2s
+[219] glRasterPos2sv
+[220] glRasterPos3d
+[221] glRasterPos3dv
+[222] glRasterPos3f
+[223] glRasterPos3fv
+[224] glRasterPos3i
+[225] glRasterPos3iv
+[226] glRasterPos3s
+[227] glRasterPos3sv
+[228] glRasterPos4d
+[229] glRasterPos4dv
+[230] glRasterPos4f
+[231] glRasterPos4fv
+[232] glRasterPos4i
+[233] glRasterPos4iv
+[234] glRasterPos4s
+[235] glRasterPos4sv
+[236] glReadBuffer
+[237] glReadPixels
+[238] glRectd
+[239] glRectdv
+[240] glRectf
+[241] glRectfv
+[242] glRecti
+[243] glRectiv
+[244] glRects
+[245] glRectsv
+[246] glRenderMode
+[247] glRotated
+[248] glRotatef
+[249] glScaled
+[250] glScalef
+[251] glScissor
+[252] glSelectBuffer
+[253] glShadeModel
+[254] glStencilFunc
+[255] glStencilMask
+[256] glStencilOp
+[257] glTexCoord1d
+[258] glTexCoord1dv
+[259] glTexCoord1f
+[260] glTexCoord1fv
+[261] glTexCoord1i
+[262] glTexCoord1iv
+[263] glTexCoord1s
+[264] glTexCoord1sv
+[265] glTexCoord2d
+[266] glTexCoord2dv
+[267] glTexCoord2f
+[268] glTexCoord2fv
+[269] glTexCoord2i
+[270] glTexCoord2iv
+[271] glTexCoord2s
+[272] glTexCoord2sv
+[273] glTexCoord3d
+[274] glTexCoord3dv
+[275] glTexCoord3f
+[276] glTexCoord3fv
+[277] glTexCoord3i
+[278] glTexCoord3iv
+[279] glTexCoord3s
+[280] glTexCoord3sv
+[281] glTexCoord4d
+[282] glTexCoord4dv
+[283] glTexCoord4f
+[284] glTexCoord4fv
+[285] glTexCoord4i
+[286] glTexCoord4iv
+[287] glTexCoord4s
+[288] glTexCoord4sv
+[289] glTexCoordPointer
+[290] glTexEnvf
+[291] glTexEnvfv
+[292] glTexEnvi
+[293] glTexEnviv
+[294] glTexGend
+[295] glTexGendv
+[296] glTexGenf
+[297] glTexGenfv
+[298] glTexGeni
+[299] glTexGeniv
+[300] glTexImage1D
+[301] glTexImage2D
+[302] glTexParameterf
+[303] glTexParameterfv
+[304] glTexParameteri
+[305] glTexParameteriv
+[306] glTexSubImage1D
+[307] glTexSubImage2D
+[308] glTranslated
+[309] glTranslatef
+[310] glVertex2d
+[311] glVertex2dv
+[312] glVertex2f
+[313] glVertex2fv
+[314] glVertex2i
+[315] glVertex2iv
+[316] glVertex2s
+[317] glVertex2sv
+[318] glVertex3d
+[319] glVertex3dv
+[320] glVertex3f
+[321] glVertex3fv
+[322] glVertex3i
+[323] glVertex3iv
+[324] glVertex3s
+[325] glVertex3sv
+[326] glVertex4d
+[327] glVertex4dv
+[328] glVertex4f
+[329] glVertex4fv
+[330] glVertex4i
+[331] glVertex4iv
+[332] glVertex4s
+[333] glVertex4sv
+[334] glVertexPointer
+[335] glViewport
+
+Vulkan Methods Table:
+[0]   vkCreateInstance
+[1]   vkDestroyInstance
+[2]   vkEnumeratePhysicalDevices
+[3]   vkGetPhysicalDeviceFeatures
+[4]   vkGetPhysicalDeviceFormatProperties
+[5]   vkGetPhysicalDeviceImageFormatProperties
+[6]   vkGetPhysicalDeviceProperties
+[7]   vkGetPhysicalDeviceQueueFamilyProperties
+[8]   vkGetPhysicalDeviceMemoryProperties
+[9]   vkGetInstanceProcAddr
+[10]  vkGetDeviceProcAddr
+[11]  vkCreateDevice
+[12]  vkDestroyDevice
+[13]  vkEnumerateInstanceExtensionProperties
+[14]  vkEnumerateDeviceExtensionProperties
+[15]  vkEnumerateDeviceLayerProperties
+[16]  vkGetDeviceQueue
+[17]  vkQueueSubmit
+[18]  vkQueueWaitIdle
+[19]  vkDeviceWaitIdle
+[20]  vkAllocateMemory
+[21]  vkFreeMemory
+[22]  vkMapMemory
+[23]  vkUnmapMemory
+[24]  vkFlushMappedMemoryRanges
+[25]  vkInvalidateMappedMemoryRanges
+[26]  vkGetDeviceMemoryCommitment
+[27]  vkBindBufferMemory
+[28]  vkBindImageMemory
+[29]  vkGetBufferMemoryRequirements
+[30]  vkGetImageMemoryRequirements
+[31]  vkGetImageSparseMemoryRequirements
+[32]  vkGetPhysicalDeviceSparseImageFormatProperties
+[33]  vkQueueBindSparse
+[34]  vkCreateFence
+[35]  vkDestroyFence
+[36]  vkResetFences
+[37]  vkGetFenceStatus
+[38]  vkWaitForFences
+[39]  vkCreateSemaphore
+[40]  vkDestroySemaphore
+[41]  vkCreateEvent
+[42]  vkDestroyEvent
+[43]  vkGetEventStatus
+[44]  vkSetEvent
+[45]  vkResetEvent
+[46]  vkCreateQueryPool
+[47]  vkDestroyQueryPool
+[48]  vkGetQueryPoolResults
+[49]  vkCreateBuffer
+[50]  vkDestroyBuffer
+[51]  vkCreateBufferView
+[52]  vkDestroyBufferView
+[53]  vkCreateImage
+[54]  vkDestroyImage
+[55]  vkGetImageSubresourceLayout
+[56]  vkCreateImageView
+[57]  vkDestroyImageView
+[58]  vkCreateShaderModule
+[59]  vkDestroyShaderModule
+[60]  vkCreatePipelineCache
+[61]  vkDestroyPipelineCache
+[62]  vkGetPipelineCacheData
+[63]  vkMergePipelineCaches
+[64]  vkCreateGraphicsPipelines
+[65]  vkCreateComputePipelines
+[66]  vkDestroyPipeline
+[67]  vkCreatePipelineLayout
+[68]  vkDestroyPipelineLayout
+[69]  vkCreateSampler
+[70]  vkDestroySampler
+[71]  vkCreateDescriptorSetLayout
+[72]  vkDestroyDescriptorSetLayout
+[73]  vkCreateDescriptorPool
+[74]  vkDestroyDescriptorPool
+[75]  vkResetDescriptorPool
+[76]  vkAllocateDescriptorSets
+[77]  vkFreeDescriptorSets
+[78]  vkUpdateDescriptorSets
+[79]  vkCreateFramebuffer
+[80]  vkDestroyFramebuffer
+[81]  vkCreateRenderPass
+[82]  vkDestroyRenderPass
+[83]  vkGetRenderAreaGranularity
+[84]  vkCreateCommandPool
+[85]  vkDestroyCommandPool
+[86]  vkResetCommandPool
+[87]  vkAllocateCommandBuffers
+[88]  vkFreeCommandBuffers
+[89]  vkBeginCommandBuffer
+[90]  vkEndCommandBuffer
+[91]  vkResetCommandBuffer
+[92]  vkCmdBindPipeline
+[93]  vkCmdSetViewport
+[94]  vkCmdSetScissor
+[95]  vkCmdSetLineWidth
+[96]  vkCmdSetDepthBias
+[97]  vkCmdSetBlendConstants
+[98]  vkCmdSetDepthBounds
+[99]  vkCmdSetStencilCompareMask
+[100] vkCmdSetStencilWriteMask
+[101] vkCmdSetStencilReference
+[102] vkCmdBindDescriptorSets
+[103] vkCmdBindIndexBuffer
+[104] vkCmdBindVertexBuffers
+[105] vkCmdDraw
+[106] vkCmdDrawIndexed
+[107] vkCmdDrawIndirect
+[108] vkCmdDrawIndexedIndirect
+[109] vkCmdDispatch
+[110] vkCmdDispatchIndirect
+[111] vkCmdCopyBuffer
+[112] vkCmdCopyImage
+[113] vkCmdBlitImage
+[114] vkCmdCopyBufferToImage
+[115] vkCmdCopyImageToBuffer
+[116] vkCmdUpdateBuffer
+[117] vkCmdFillBuffer
+[118] vkCmdClearColorImage
+[119] vkCmdClearDepthStencilImage
+[120] vkCmdClearAttachments
+[121] vkCmdResolveImage
+[122] vkCmdSetEvent
+[123] vkCmdResetEvent
+[124] vkCmdWaitEvents
+[125] vkCmdPipelineBarrier
+[126] vkCmdBeginQuery
+[127] vkCmdEndQuery
+[128] vkCmdResetQueryPool
+[129] vkCmdWriteTimestamp
+[130] vkCmdCopyQueryPoolResults
+[131] vkCmdPushConstants
+[132] vkCmdBeginRenderPass
+[133] vkCmdNextSubpass
+[134] vkCmdEndRenderPass
+[135] vkCmdExecuteCommands

+ 186 - 0
gm/3rd_party/include/MinHook.h

@@ -0,0 +1,186 @@
+/*
+ *  MinHook - The Minimalistic API Hooking Library for x64/x86
+ *  Copyright (C) 2009-2017 Tsuda Kageyu.
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
+ *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
+    #error MinHook supports only x86 and x64 systems.
+#endif
+
+#include <windows.h>
+
+// MinHook Error Codes.
+typedef enum MH_STATUS
+{
+    // Unknown error. Should not be returned.
+    MH_UNKNOWN = -1,
+
+    // Successful.
+    MH_OK = 0,
+
+    // MinHook is already initialized.
+    MH_ERROR_ALREADY_INITIALIZED,
+
+    // MinHook is not initialized yet, or already uninitialized.
+    MH_ERROR_NOT_INITIALIZED,
+
+    // The hook for the specified target function is already created.
+    MH_ERROR_ALREADY_CREATED,
+
+    // The hook for the specified target function is not created yet.
+    MH_ERROR_NOT_CREATED,
+
+    // The hook for the specified target function is already enabled.
+    MH_ERROR_ENABLED,
+
+    // The hook for the specified target function is not enabled yet, or already
+    // disabled.
+    MH_ERROR_DISABLED,
+
+    // The specified pointer is invalid. It points the address of non-allocated
+    // and/or non-executable region.
+    MH_ERROR_NOT_EXECUTABLE,
+
+    // The specified target function cannot be hooked.
+    MH_ERROR_UNSUPPORTED_FUNCTION,
+
+    // Failed to allocate memory.
+    MH_ERROR_MEMORY_ALLOC,
+
+    // Failed to change the memory protection.
+    MH_ERROR_MEMORY_PROTECT,
+
+    // The specified module is not loaded.
+    MH_ERROR_MODULE_NOT_FOUND,
+
+    // The specified function is not found.
+    MH_ERROR_FUNCTION_NOT_FOUND
+}
+MH_STATUS;
+
+// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
+// MH_QueueEnableHook or MH_QueueDisableHook.
+#define MH_ALL_HOOKS NULL
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    // Initialize the MinHook library. You must call this function EXACTLY ONCE
+    // at the beginning of your program.
+    MH_STATUS WINAPI MH_Initialize(VOID);
+
+    // Uninitialize the MinHook library. You must call this function EXACTLY
+    // ONCE at the end of your program.
+    MH_STATUS WINAPI MH_Uninitialize(VOID);
+
+    // Creates a Hook for the specified target function, in disabled state.
+    // Parameters:
+    //   pTarget    [in]  A pointer to the target function, which will be
+    //                    overridden by the detour function.
+    //   pDetour    [in]  A pointer to the detour function, which will override
+    //                    the target function.
+    //   ppOriginal [out] A pointer to the trampoline function, which will be
+    //                    used to call the original target function.
+    //                    This parameter can be NULL.
+    MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
+
+    // Creates a Hook for the specified API function, in disabled state.
+    // Parameters:
+    //   pszModule  [in]  A pointer to the loaded module name which contains the
+    //                    target function.
+    //   pszTarget  [in]  A pointer to the target function name, which will be
+    //                    overridden by the detour function.
+    //   pDetour    [in]  A pointer to the detour function, which will override
+    //                    the target function.
+    //   ppOriginal [out] A pointer to the trampoline function, which will be
+    //                    used to call the original target function.
+    //                    This parameter can be NULL.
+    MH_STATUS WINAPI MH_CreateHookApi(
+        LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
+
+    // Creates a Hook for the specified API function, in disabled state.
+    // Parameters:
+    //   pszModule  [in]  A pointer to the loaded module name which contains the
+    //                    target function.
+    //   pszTarget  [in]  A pointer to the target function name, which will be
+    //                    overridden by the detour function.
+    //   pDetour    [in]  A pointer to the detour function, which will override
+    //                    the target function.
+    //   ppOriginal [out] A pointer to the trampoline function, which will be
+    //                    used to call the original target function.
+    //                    This parameter can be NULL.
+    //   ppTarget   [out] A pointer to the target function, which will be used
+    //                    with other functions.
+    //                    This parameter can be NULL.
+    MH_STATUS WINAPI MH_CreateHookApiEx(
+        LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
+
+    // Removes an already created hook.
+    // Parameters:
+    //   pTarget [in] A pointer to the target function.
+    MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
+
+    // Enables an already created hook.
+    // Parameters:
+    //   pTarget [in] A pointer to the target function.
+    //                If this parameter is MH_ALL_HOOKS, all created hooks are
+    //                enabled in one go.
+    MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
+
+    // Disables an already created hook.
+    // Parameters:
+    //   pTarget [in] A pointer to the target function.
+    //                If this parameter is MH_ALL_HOOKS, all created hooks are
+    //                disabled in one go.
+    MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
+
+    // Queues to enable an already created hook.
+    // Parameters:
+    //   pTarget [in] A pointer to the target function.
+    //                If this parameter is MH_ALL_HOOKS, all created hooks are
+    //                queued to be enabled.
+    MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
+
+    // Queues to disable an already created hook.
+    // Parameters:
+    //   pTarget [in] A pointer to the target function.
+    //                If this parameter is MH_ALL_HOOKS, all created hooks are
+    //                queued to be disabled.
+    MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
+
+    // Applies all queued changes in one go.
+    MH_STATUS WINAPI MH_ApplyQueued(VOID);
+
+    // Translates the MH_STATUS to its name as a string.
+    const char * WINAPI MH_StatusToString(MH_STATUS status);
+
+#ifdef __cplusplus
+}
+#endif
+

+ 78 - 0
gm/3rd_party/include/kiero.h

@@ -0,0 +1,78 @@
+#ifndef __KIERO_H__
+#define __KIERO_H__
+
+#include <stdint.h>
+#include <string.h>
+
+#define KIERO_VERSION "1.1.8"
+
+#define KIERO_USE_MINHOOK
+
+#define KIERO_ARCH_X64 0
+#define KIERO_ARCH_X86 0
+
+#if defined(_M_X64)	
+# undef  KIERO_ARCH_X64
+# define KIERO_ARCH_X64 1
+#else
+# undef  KIERO_ARCH_X86
+# define KIERO_ARCH_X86 1
+#endif
+
+#ifdef _UNICODE
+# define KIERO_TEXT(text) L##text
+#else
+# define KIERO_TEXT(text) text
+#endif
+
+#define KIERO_ARRAY_SIZE(arr) ((size_t)(sizeof(arr)/sizeof(arr[0])))
+
+namespace kiero
+{
+	struct Status
+	{
+		enum Enum
+		{
+			UnknownError = -1,
+			NotSupportedError = -2,
+			ModuleNotFoundError = -3,
+
+			Success = 0,
+		};
+	};
+
+	struct RenderType
+	{
+		enum Enum
+		{
+			None,
+
+			D3D9,   // Implemented
+			D3D10,  // Implemented
+			D3D11,  // Implemented
+			D3D12,  // Implemented
+
+			OpenGL, // Implemented
+			OpenglES,
+			Vulkan  // Implemented
+		};
+	};
+
+	Status::Enum init(int renderType);
+
+	void shutdown();
+
+	RenderType::Enum getRenderType();
+
+#if KIERO_ARCH_X64
+	uint64_t* getMethodsTable();
+#else
+	uint32_t* getMethodsTable();
+#endif
+
+	int bind(uint16_t index, void** original, void* function);
+
+	int unbind();
+}
+
+#endif // __KIERO_H__

BIN
gm/3rd_party/lib/x64/minhook.lib


BIN
gm/3rd_party/lib/x86/ScintillaEdit4.lib


BIN
gm/3rd_party/lib/x86/minhook.lib


+ 750 - 0
gm/3rd_party/src/kiero.cpp

@@ -0,0 +1,750 @@
+
+#include "../include/kiero.h"
+#include <Windows.h>
+
+#ifdef KIERO_USE_MINHOOK
+#include "../include/minhook.h"
+#endif
+//#include <MinHook.h>
+// Uncomment a needed graphical library (you can include all)
+#include <d3d9.h>          // D3D9
+#include <dxgi.h>          // D3D10/D3D11/D3D12 (must be included for d3d12 hook)
+#include <d3d10_1.h>       // D3D10
+#include <d3d10.h>         // D3D10
+#define KIERO_D3D10_USAGE  // This need because d3d11.h includes d3d10.h
+#include <d3d11.h>         // D3D11
+//#include <d3d12.h>         // D3D12
+//#include <gl/GL.h>         // OpenGL
+//#include <vulkan/vulkan.h> // Vulkan
+#include <string>
+#if defined(KIERO_D3D10_USAGE) && !defined(__d3d10_h__)
+# error KIERO_D3D10_USAGE defined, but d3d10.h not included
+#endif
+
+#if defined(__d3d12_h__) && !defined(__dxgi_h__)
+# error d3d12.h included, but dxgi.h not included
+#endif
+
+static kiero::RenderType::Enum g_renderType = kiero::RenderType::None;
+
+// See METHODSTABLE.txt for more information
+#if KIERO_ARCH_X64
+static uint64_t* g_methodsTable = NULL;
+#else
+static uint32_t* g_methodsTable = NULL;
+#endif
+
+HMODULE GetSystemModule(const char* module) {
+	static std::string systemPath;
+	if (systemPath.empty()) {
+		systemPath.resize(2048);
+		uint32_t res = GetSystemDirectoryA(&systemPath[0], systemPath.size());
+		systemPath.resize(res);
+	}
+
+	std::string basePath = systemPath + "\\" + module;
+	//MessageBoxA(NULL, basePath.data(), "", 0);
+	return GetModuleHandleA(basePath.c_str());
+}
+
+kiero::Status::Enum kiero::init(int _renderType)
+{
+	if (_renderType != RenderType::None)
+	{
+		if (_renderType >= RenderType::D3D9 && _renderType <= RenderType::D3D12)
+		{
+			WNDCLASSEX windowClass;
+			windowClass.cbSize = sizeof(WNDCLASSEX);
+			windowClass.style = CS_HREDRAW | CS_VREDRAW;
+			windowClass.lpfnWndProc = DefWindowProc;
+			windowClass.cbClsExtra = 0;
+			windowClass.cbWndExtra = 0;
+			windowClass.hInstance = GetModuleHandle(NULL);
+			windowClass.hIcon = NULL;
+			windowClass.hCursor = NULL;
+			windowClass.hbrBackground = NULL;
+			windowClass.lpszMenuName = NULL;
+			windowClass.lpszClassName = KIERO_TEXT("Kiero");
+			windowClass.hIconSm = NULL;
+
+			::RegisterClassEx(&windowClass);
+
+			HWND window = ::CreateWindow(windowClass.lpszClassName, KIERO_TEXT("Kiero DirectX Window"), WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, NULL, NULL, windowClass.hInstance, NULL);
+
+			if (_renderType == RenderType::D3D9)
+			{
+#ifdef _D3D9_H_
+				HMODULE libD3D9;
+				if ((libD3D9 = ::GetModuleHandle(KIERO_TEXT("d3d9.dll"))) == NULL)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::ModuleNotFoundError;
+				}
+
+				void* Direct3DCreate9;
+				if ((Direct3DCreate9 = ::GetProcAddress(libD3D9, "Direct3DCreate9")) == NULL)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				LPDIRECT3D9 direct3D9;
+				if ((direct3D9 = ((LPDIRECT3D9(__stdcall*)(uint32_t))(Direct3DCreate9))(D3D_SDK_VERSION)) == NULL)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				D3DDISPLAYMODE displayMode;
+				if (direct3D9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode) < 0)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				D3DPRESENT_PARAMETERS params;
+				params.BackBufferWidth = 0;
+				params.BackBufferHeight = 0;
+				params.BackBufferFormat = displayMode.Format;
+				params.BackBufferCount = 0;
+				params.MultiSampleType = D3DMULTISAMPLE_NONE;
+				params.MultiSampleQuality = NULL;
+				params.SwapEffect = D3DSWAPEFFECT_DISCARD;
+				params.hDeviceWindow = window;
+				params.Windowed = 1;
+				params.EnableAutoDepthStencil = 0;
+				params.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
+				params.Flags = NULL;
+				params.FullScreen_RefreshRateInHz = 0;
+				params.PresentationInterval = 0;
+
+				LPDIRECT3DDEVICE9 device;
+				if (direct3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_DISABLE_DRIVER_MANAGEMENT, &params, &device) < 0)
+				{
+					direct3D9->Release();
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+#if KIERO_ARCH_X64
+				g_methodsTable = (uint64_t*)::calloc(119, sizeof(uint64_t));
+				::memcpy(g_methodsTable, *(uint64_t**)device, 119 * sizeof(uint64_t));
+#else
+				g_methodsTable = (uint32_t*)::calloc(119, sizeof(uint32_t));
+				::memcpy(g_methodsTable, *(uint32_t**)device, 119 * sizeof(uint32_t));
+#endif
+
+#ifdef KIERO_USE_MINHOOK
+				MH_Initialize();
+#endif
+
+				direct3D9->Release();
+				direct3D9 = NULL;
+
+				device->Release();
+				device = NULL;
+
+				g_renderType = RenderType::D3D9;
+
+				::DestroyWindow(window);
+				::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+
+				return Status::Success;
+#endif // _D3D9_H_
+			}
+			else if (_renderType == RenderType::D3D10)
+			{
+#if defined(__d3d10_h__) && defined(KIERO_D3D10_USAGE)
+				HMODULE libDXGI;
+				HMODULE libD3D10;
+				if ((libDXGI = ::GetModuleHandle(KIERO_TEXT("dxgi.dll"))) == NULL || (libD3D10 = ::GetModuleHandle(KIERO_TEXT("d3d10.dll"))) == NULL)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::ModuleNotFoundError;
+				}
+
+				void* CreateDXGIFactory;
+				if ((CreateDXGIFactory = ::GetProcAddress(libDXGI, "CreateDXGIFactory")) == NULL)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				IDXGIFactory* factory;
+				if (((long(__stdcall*)(const IID&, void**))(CreateDXGIFactory))(__uuidof(IDXGIFactory), (void**)&factory) < 0)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				IDXGIAdapter* adapter;
+				if (factory->EnumAdapters(0, &adapter) == DXGI_ERROR_NOT_FOUND)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				void* D3D10CreateDeviceAndSwapChain;
+				if ((D3D10CreateDeviceAndSwapChain = ::GetProcAddress(libD3D10, "D3D10CreateDeviceAndSwapChain")) == NULL)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				DXGI_RATIONAL refreshRate;
+				refreshRate.Numerator = 60;
+				refreshRate.Denominator = 1;
+
+				DXGI_MODE_DESC bufferDesc;
+				bufferDesc.Width = 100;
+				bufferDesc.Height = 100;
+				bufferDesc.RefreshRate = refreshRate;
+				bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+				bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
+				bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
+
+				DXGI_SAMPLE_DESC sampleDesc;
+				sampleDesc.Count = 1;
+				sampleDesc.Quality = 0;
+
+				DXGI_SWAP_CHAIN_DESC swapChainDesc;
+				swapChainDesc.BufferDesc = bufferDesc;
+				swapChainDesc.SampleDesc = sampleDesc;
+				swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+				swapChainDesc.BufferCount = 1;
+				swapChainDesc.OutputWindow = window;
+				swapChainDesc.Windowed = 1;
+				swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
+				swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
+
+				IDXGISwapChain* swapChain;
+				ID3D10Device* device;
+
+				if (((long(__stdcall*)(
+					IDXGIAdapter*,
+					D3D10_DRIVER_TYPE,
+					HMODULE,
+					UINT,
+					UINT,
+					DXGI_SWAP_CHAIN_DESC*,
+					IDXGISwapChain**,
+					ID3D10Device**))(D3D10CreateDeviceAndSwapChain))(adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &swapChainDesc, &swapChain, &device) < 0)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+#if KIERO_ARCH_X64
+				g_methodsTable = (uint64_t*)::calloc(116, sizeof(uint64_t));
+				::memcpy(g_methodsTable, *(uint64_t**)swapChain, 18 * sizeof(uint64_t));
+				::memcpy(g_methodsTable + 18, *(uint64_t**)device, 98 * sizeof(uint64_t));
+#else
+
+				g_methodsTable = (uint32_t*)::calloc(116, sizeof(uint32_t));
+				::memcpy(g_methodsTable, *(uint32_t**)swapChain, 18 * sizeof(uint32_t));
+				::memcpy(g_methodsTable + 18, *(uint32_t**)device, 98 * sizeof(uint32_t));
+#endif
+
+#ifdef KIERO_USE_MINHOOK
+				MH_Initialize();
+#endif
+
+				swapChain->Release();
+				swapChain = NULL;
+
+				device->Release();
+				device = NULL;
+
+				::DestroyWindow(window);
+				::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+
+				g_renderType = RenderType::D3D10;
+
+				return Status::Success;
+#endif // __d3d10_h__
+			}
+			else if (_renderType == RenderType::D3D11)
+			{
+#ifdef __d3d11_h__
+				HMODULE libD3D11;
+				if ((libD3D11 = ::GetModuleHandle(KIERO_TEXT("d3d11.dll"))) == NULL)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::ModuleNotFoundError;
+				}
+
+				void* D3D11CreateDeviceAndSwapChain;
+				if ((D3D11CreateDeviceAndSwapChain = ::GetProcAddress(libD3D11, "D3D11CreateDeviceAndSwapChain")) == NULL)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				D3D_FEATURE_LEVEL featureLevel;
+				const D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_11_0 };
+
+				DXGI_RATIONAL refreshRate;
+				refreshRate.Numerator = 60;
+				refreshRate.Denominator = 1;
+
+				DXGI_MODE_DESC bufferDesc;
+				bufferDesc.Width = 100;
+				bufferDesc.Height = 100;
+				bufferDesc.RefreshRate = refreshRate;
+				bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+				bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
+				bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
+
+				DXGI_SAMPLE_DESC sampleDesc;
+				sampleDesc.Count = 1;
+				sampleDesc.Quality = 0;
+
+				DXGI_SWAP_CHAIN_DESC swapChainDesc;
+				swapChainDesc.BufferDesc = bufferDesc;
+				swapChainDesc.SampleDesc = sampleDesc;
+				swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+				swapChainDesc.BufferCount = 1;
+				swapChainDesc.OutputWindow = window;
+				swapChainDesc.Windowed = 1;
+				swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
+				swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
+
+				IDXGISwapChain* swapChain;
+				ID3D11Device* device;
+				ID3D11DeviceContext* context;
+
+				if (((long(__stdcall*)(
+					IDXGIAdapter*,
+					D3D_DRIVER_TYPE,
+					HMODULE,
+					UINT,
+					const D3D_FEATURE_LEVEL*,
+					UINT,
+					UINT,
+					const DXGI_SWAP_CHAIN_DESC*,
+					IDXGISwapChain**,
+					ID3D11Device**,
+					D3D_FEATURE_LEVEL*,
+					ID3D11DeviceContext**))(D3D11CreateDeviceAndSwapChain))(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, featureLevels, 1, D3D11_SDK_VERSION, &swapChainDesc, &swapChain, &device, &featureLevel, &context) < 0)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+#if KIERO_ARCH_X64
+				g_methodsTable = (uint64_t*)::calloc(205, sizeof(uint64_t));
+				::memcpy(g_methodsTable, *(uint64_t**)swapChain, 18 * sizeof(uint64_t));
+				::memcpy(g_methodsTable + 18, *(uint64_t**)device, 43 * sizeof(uint64_t));
+				::memcpy(g_methodsTable + 18 + 43, *(uint64_t**)context, 144 * sizeof(uint64_t));
+#else
+				g_methodsTable = (uint32_t*)::calloc(205, sizeof(uint32_t));
+				::memcpy(g_methodsTable, *(uint32_t**)swapChain, 18 * sizeof(uint32_t));
+				::memcpy(g_methodsTable + 18, *(uint32_t**)device, 43 * sizeof(uint32_t));
+				::memcpy(g_methodsTable + 18 + 43, *(uint32_t**)context, 144 * sizeof(uint32_t));
+#endif
+
+#ifdef KIERO_USE_MINHOOK
+				MH_Initialize();
+#endif
+
+				swapChain->Release();
+				swapChain = NULL;
+
+				device->Release();
+				device = NULL;
+
+				context->Release();
+				context = NULL;
+
+				::DestroyWindow(window);
+				::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+
+				g_renderType = RenderType::D3D11;
+
+				return Status::Success;
+#endif // __d3d11_h__
+			}
+			else if (_renderType == RenderType::D3D12)
+			{
+#if defined(__d3d12_h__) && defined(__dxgi_h__)
+				HMODULE libDXGI;
+				HMODULE libD3D12;
+				if ((libDXGI = ::GetModuleHandle(KIERO_TEXT("dxgi.dll"))) == NULL || (libD3D12 = ::GetModuleHandle(KIERO_TEXT("d3d12.dll"))) == NULL)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::ModuleNotFoundError;
+				}
+
+				void* CreateDXGIFactory;
+				if ((CreateDXGIFactory = ::GetProcAddress(libDXGI, "CreateDXGIFactory")) == NULL)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				IDXGIFactory* factory;
+				if (((long(__stdcall*)(const IID&, void**))(CreateDXGIFactory))(__uuidof(IDXGIFactory), (void**)&factory) < 0)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				IDXGIAdapter* adapter;
+				if (factory->EnumAdapters(0, &adapter) == DXGI_ERROR_NOT_FOUND)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				void* D3D12CreateDevice;
+				if ((D3D12CreateDevice = ::GetProcAddress(libD3D12, "D3D12CreateDevice")) == NULL)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				ID3D12Device* device;
+				if (((long(__stdcall*)(IUnknown*, D3D_FEATURE_LEVEL, const IID&, void**))(D3D12CreateDevice))(adapter, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), (void**)&device) < 0)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				D3D12_COMMAND_QUEUE_DESC queueDesc;
+				queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
+				queueDesc.Priority = 0;
+				queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
+				queueDesc.NodeMask = 0;
+
+				ID3D12CommandQueue* commandQueue;
+				if (device->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue), (void**)&commandQueue) < 0)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				ID3D12CommandAllocator* commandAllocator;
+				if (device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator), (void**)&commandAllocator) < 0)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				ID3D12GraphicsCommandList* commandList;
+				if (device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator, NULL, __uuidof(ID3D12GraphicsCommandList), (void**)&commandList) < 0)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+				DXGI_RATIONAL refreshRate;
+				refreshRate.Numerator = 60;
+				refreshRate.Denominator = 1;
+
+				DXGI_MODE_DESC bufferDesc;
+				bufferDesc.Width = 100;
+				bufferDesc.Height = 100;
+				bufferDesc.RefreshRate = refreshRate;
+				bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+				bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
+				bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
+
+				DXGI_SAMPLE_DESC sampleDesc;
+				sampleDesc.Count = 1;
+				sampleDesc.Quality = 0;
+
+				DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
+				swapChainDesc.BufferDesc = bufferDesc;
+				swapChainDesc.SampleDesc = sampleDesc;
+				swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+				swapChainDesc.BufferCount = 2;
+				swapChainDesc.OutputWindow = window;
+				swapChainDesc.Windowed = 1;
+				swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
+				swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
+
+				IDXGISwapChain* swapChain;
+				if (factory->CreateSwapChain(commandQueue, &swapChainDesc, &swapChain) < 0)
+				{
+					::DestroyWindow(window);
+					::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+					return Status::UnknownError;
+				}
+
+#if KIERO_ARCH_X64
+				g_methodsTable = (uint64_t*)::calloc(150, sizeof(uint64_t));
+				memcpy(g_methodsTable, *(uint64_t**)device, 44 * sizeof(uint64_t));
+				memcpy(g_methodsTable + 44, *(uint64_t**)commandQueue, 19 * sizeof(uint64_t));
+				memcpy(g_methodsTable + 44 + 19, *(uint64_t**)commandAllocator, 9 * sizeof(uint64_t));
+				memcpy(g_methodsTable + 44 + 19 + 9, *(uint64_t**)commandList, 60 * sizeof(uint64_t));
+				memcpy(g_methodsTable + 44 + 19 + 9 + 60, *(uint64_t**)swapChain, 18 * sizeof(uint64_t));
+#else
+				g_methodsTable = (uint32_t*)::calloc(150, sizeof(uint32_t));
+				memcpy(g_methodsTable, *(uint32_t**)device, 44 * sizeof(uint32_t));
+				memcpy(g_methodsTable + 44, *(uint32_t**)commandQueue, 19 * sizeof(uint32_t));
+				memcpy(g_methodsTable + 44 + 19, *(uint32_t**)commandAllocator, 9 * sizeof(uint32_t));
+				memcpy(g_methodsTable + 44 + 19 + 9, *(uint32_t**)commandList, 60 * sizeof(uint32_t));
+				memcpy(g_methodsTable + 44 + 19 + 9 + 60, *(uint32_t**)swapChain, 18 * sizeof(uint32_t));
+#endif
+
+#ifdef KIERO_USE_MINHOOK
+				MH_Initialize();
+#endif
+
+				device->Release();
+				device = NULL;
+
+				commandQueue->Release();
+				commandQueue = NULL;
+
+				commandAllocator->Release();
+				commandAllocator = NULL;
+
+				commandList->Release();
+				commandList = NULL;
+
+				swapChain->Release();
+				swapChain = NULL;
+
+				::DestroyWindow(window);
+				::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+
+				g_renderType = RenderType::D3D12;
+
+				return Status::Success;
+#endif // __d3d12_h__
+			}
+
+			return Status::NotSupportedError;
+		}
+		else if (_renderType == RenderType::OpenGL)
+		{
+
+			HMODULE libOpenGL32 = GetSystemModule("opengl32.dll");
+			if (libOpenGL32 == NULL)
+			{
+				return Status::ModuleNotFoundError;
+			}
+
+			const char* const methodsNames[] = {
+				"glBegin","glEnd","wglSwapBuffers","glFinish"
+			};
+
+			const size_t size = KIERO_ARRAY_SIZE(methodsNames);
+
+#if KIERO_ARCH_X64
+			g_methodsTable = (uint64_t*)::calloc(size, sizeof(uint64_t));
+
+			for (int i = 0; i < size; i++)
+			{
+				g_methodsTable[i] = (uint64_t)::GetProcAddress(libOpenGL32, methodsNames[i]);
+			}
+#else
+			g_methodsTable = (uint32_t*)::calloc(size, sizeof(uint32_t));
+
+			for (int i = 0; i < size; i++)
+			{
+				g_methodsTable[i] = (uint32_t)::GetProcAddress(libOpenGL32, methodsNames[i]);
+			}
+#endif
+
+#ifdef KIERO_USE_MINHOOK
+			MH_Initialize();
+#endif
+
+			g_renderType = RenderType::OpenGL;
+
+			return Status::Success;
+			//#endif // __gl_h_
+		}
+		else if (_renderType == RenderType::OpenglES) {
+			HMODULE libegl = GetModuleHandleW(L"libEGL.dll");
+			if (libegl == NULL)
+			{
+				return Status::ModuleNotFoundError;
+			}
+
+			const char* const methodsNames[] = {
+				"eglSwapBuffers"
+			};
+
+			const size_t size = KIERO_ARRAY_SIZE(methodsNames);
+
+#if KIERO_ARCH_X64
+			g_methodsTable = (uint64_t*)::calloc(size, sizeof(uint64_t));
+
+			for (int i = 0; i < size; i++)
+			{
+				g_methodsTable[i] = (uint64_t)::GetProcAddress(libegl, methodsNames[i]);
+			}
+#else
+			g_methodsTable = (uint32_t*)::calloc(size, sizeof(uint32_t));
+
+			for (int i = 0; i < size; i++)
+			{
+				g_methodsTable[i] = (uint32_t)::GetProcAddress(libegl, methodsNames[i]);
+			}
+#endif
+
+#ifdef KIERO_USE_MINHOOK
+			MH_Initialize();
+#endif
+
+			g_renderType = RenderType::OpenglES;
+
+			return Status::Success;
+		}
+		else if (_renderType == RenderType::Vulkan)
+		{
+#ifdef VULKAN_H_
+			HMODULE libVulkan;
+			if ((libVulkan = GetModuleHandle(KIERO_TEXT("vulcan-1.dll"))) == NULL)
+			{
+				return Status::ModuleNotFoundError;
+			}
+
+			const char* const methodsNames[] = {
+				"vkCreateInstance", "vkDestroyInstance", "vkEnumeratePhysicalDevices", "vkGetPhysicalDeviceFeatures", "vkGetPhysicalDeviceFormatProperties", "vkGetPhysicalDeviceImageFormatProperties",
+				"vkGetPhysicalDeviceProperties", "vkGetPhysicalDeviceQueueFamilyProperties", "vkGetPhysicalDeviceMemoryProperties", "vkGetInstanceProcAddr", "vkGetDeviceProcAddr", "vkCreateDevice",
+				"vkDestroyDevice", "vkEnumerateInstanceExtensionProperties", "vkEnumerateDeviceExtensionProperties", "vkEnumerateDeviceLayerProperties", "vkGetDeviceQueue", "vkQueueSubmit", "vkQueueWaitIdle",
+				"vkDeviceWaitIdle", "vkAllocateMemory", "vkFreeMemory", "vkMapMemory", "vkUnmapMemory", "vkFlushMappedMemoryRanges", "vkInvalidateMappedMemoryRanges", "vkGetDeviceMemoryCommitment",
+				"vkBindBufferMemory", "vkBindImageMemory", "vkGetBufferMemoryRequirements", "vkGetImageMemoryRequirements", "vkGetImageSparseMemoryRequirements", "vkGetPhysicalDeviceSparseImageFormatProperties",
+				"vkQueueBindSparse", "vkCreateFence", "vkDestroyFence", "vkResetFences", "vkGetFenceStatus", "vkWaitForFences", "vkCreateSemaphore", "vkDestroySemaphore", "vkCreateEvent", "vkDestroyEvent",
+				"vkGetEventStatus", "vkSetEvent", "vkResetEvent", "vkCreateQueryPool", "vkDestroyQueryPool", "vkGetQueryPoolResults", "vkCreateBuffer", "vkDestroyBuffer", "vkCreateBufferView", "vkDestroyBufferView",
+				"vkCreateImage", "vkDestroyImage", "vkGetImageSubresourceLayout", "vkCreateImageView", "vkDestroyImageView", "vkCreateShaderModule", "vkDestroyShaderModule", "vkCreatePipelineCache",
+				"vkDestroyPipelineCache", "vkGetPipelineCacheData", "vkMergePipelineCaches", "vkCreateGraphicsPipelines", "vkCreateComputePipelines", "vkDestroyPipeline", "vkCreatePipelineLayout",
+				"vkDestroyPipelineLayout", "vkCreateSampler", "vkDestroySampler", "vkCreateDescriptorSetLayout", "vkDestroyDescriptorSetLayout", "vkCreateDescriptorPool", "vkDestroyDescriptorPool",
+				"vkResetDescriptorPool", "vkAllocateDescriptorSets", "vkFreeDescriptorSets", "vkUpdateDescriptorSets", "vkCreateFramebuffer", "vkDestroyFramebuffer", "vkCreateRenderPass", "vkDestroyRenderPass",
+				"vkGetRenderAreaGranularity", "vkCreateCommandPool", "vkDestroyCommandPool", "vkResetCommandPool", "vkAllocateCommandBuffers", "vkFreeCommandBuffers", "vkBeginCommandBuffer", "vkEndCommandBuffer",
+				"vkResetCommandBuffer", "vkCmdBindPipeline", "vkCmdSetViewport", "vkCmdSetScissor", "vkCmdSetLineWidth", "vkCmdSetDepthBias", "vkCmdSetBlendConstants", "vkCmdSetDepthBounds",
+				"vkCmdSetStencilCompareMask", "vkCmdSetStencilWriteMask", "vkCmdSetStencilReference", "vkCmdBindDescriptorSets", "vkCmdBindIndexBuffer", "vkCmdBindVertexBuffers", "vkCmdDraw", "vkCmdDrawIndexed",
+				"vkCmdDrawIndirect", "vkCmdDrawIndexedIndirect", "vkCmdDispatch", "vkCmdDispatchIndirect", "vkCmdCopyBuffer", "vkCmdCopyImage", "vkCmdBlitImage", "vkCmdCopyBufferToImage", "vkCmdCopyImageToBuffer",
+				"vkCmdUpdateBuffer", "vkCmdFillBuffer", "vkCmdClearColorImage", "vkCmdClearDepthStencilImage", "vkCmdClearAttachments", "vkCmdResolveImage", "vkCmdSetEvent", "vkCmdResetEvent", "vkCmdWaitEvents",
+				"vkCmdPipelineBarrier", "vkCmdBeginQuery", "vkCmdEndQuery", "vkCmdResetQueryPool", "vkCmdWriteTimestamp", "vkCmdCopyQueryPoolResults", "vkCmdPushConstants", "vkCmdBeginRenderPass", "vkCmdNextSubpass",
+				"vkCmdEndRenderPass", "vkCmdExecuteCommands"
+			};
+
+			size_t size = KIERO_ARRAY_SIZE(methodsNames);
+
+#if KIERO_ARCH_X64
+			g_methodsTable = (uint64_t*)::calloc(size, sizeof(uint64_t));
+
+			for (int i = 0; i < size; i++)
+			{
+				g_methodsTable[i] = (uint64_t)::GetProcAddress(libVulkan, methodsNames[i]);
+			}
+#else
+			g_methodsTable = (uint32_t*)::calloc(size, sizeof(uint32_t));
+
+			for (int i = 0; i < size; i++)
+			{
+				g_methodsTable[i] = (uint32_t)::GetProcAddress(libVulkan, methodsNames[i]);
+			}
+#endif
+
+#ifdef KIERO_USE_MINHOOK
+			MH_Initialize();
+#endif
+
+			g_renderType = RenderType::Vulkan;
+
+			return Status::Success;
+#endif // VULKAN_H_
+		}
+
+		return Status::NotSupportedError;
+	}
+
+	return Status::Success;
+}
+
+void kiero::shutdown()
+{
+	if (g_renderType > 0)
+	{
+#ifdef KIERO_USE_MINHOOK
+		MH_Uninitialize();
+#endif
+
+		::free(g_methodsTable);
+		g_methodsTable = NULL;
+		g_renderType = RenderType::None;
+	}
+}
+
+kiero::RenderType::Enum kiero::getRenderType()
+{
+	return g_renderType;
+}
+
+#if KIERO_ARCH_X64
+uint64_t* kiero::getMethodsTable()
+{
+	return g_methodsTable;
+}
+#else
+uint32_t* kiero::getMethodsTable()
+{
+	return g_methodsTable;
+}
+#endif
+
+
+//void kiero::bind(uint16_t _index, void* _original, void* _function)
+int kiero::bind(uint16_t _index, void** _original, void* _function)
+{
+	// TODO: Need own detour function
+
+#ifdef KIERO_USE_MINHOOK
+	if (g_renderType > 0)
+	{
+		//MH_CreateHook((void*)g_methodsTable[_index], _function, &_original);
+		int r1 = MH_CreateHook((void*)g_methodsTable[_index], _function, _original);
+		int r2 = MH_EnableHook((void*)g_methodsTable[_index]);
+
+
+		return r1 == MH_OK && r2 == MH_OK ? 1 : 0;
+	}
+	return 0;
+#endif
+}
+
+int kiero::unbind() {
+	int ret = -1;
+	if (g_renderType > 0)
+	{
+		MH_DisableHook(MH_ALL_HOOKS);
+		ret = MH_RemoveHook(MH_ALL_HOOKS);
+		
+		kiero::shutdown();
+		//MessageBoxA(NULL, MH_StatusToString((MH_STATUS)ret), "", 0);
+		//MH_DisableHook((void*)g_methodsTable[_index]);
+		//MH_RemoveHook((void*)g_methodsTable[_index]);
+		//MH_CreateHook((void*)g_methodsTable[_index], _function, &_original);
+
+	}
+	return ret;
+}

+ 31 - 0
gm/gm.sln

@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31624.102
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gm", "gm\gm.vcxproj", "{395C3072-C2D9-4CF8-A742-5D809EA95627}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{395C3072-C2D9-4CF8-A742-5D809EA95627}.Debug|x64.ActiveCfg = Debug|x64
+		{395C3072-C2D9-4CF8-A742-5D809EA95627}.Debug|x64.Build.0 = Debug|x64
+		{395C3072-C2D9-4CF8-A742-5D809EA95627}.Debug|x86.ActiveCfg = Debug|Win32
+		{395C3072-C2D9-4CF8-A742-5D809EA95627}.Debug|x86.Build.0 = Debug|Win32
+		{395C3072-C2D9-4CF8-A742-5D809EA95627}.Release|x64.ActiveCfg = Release|x64
+		{395C3072-C2D9-4CF8-A742-5D809EA95627}.Release|x64.Build.0 = Release|x64
+		{395C3072-C2D9-4CF8-A742-5D809EA95627}.Release|x86.ActiveCfg = Release|Win32
+		{395C3072-C2D9-4CF8-A742-5D809EA95627}.Release|x86.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {FB1BD768-AB27-4B02-B562-AEC4A68BFE41}
+	EndGlobalSection
+EndGlobal

+ 16 - 0
gm/gm/Resource.h

@@ -0,0 +1,16 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ 生成的包含文件。
+// 使用者 gm.rc
+
+#define IDS_APP_TITLE			103
+
+// 新对象的下一组默认值
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE	101
+#define _APS_NEXT_COMMAND_VALUE		40001
+#define _APS_NEXT_CONTROL_VALUE		1000
+#define _APS_NEXT_SYMED_VALUE		101
+#endif
+#endif

+ 159 - 0
gm/gm/algorithm/AStar.hpp

@@ -0,0 +1,159 @@
+#pragma once
+
+#include<list>
+#include <set>
+#include <algorithm>
+#include <list>
+#include <vector>
+
+using std::list;
+
+using std::set;
+using std::list;
+using std::vector;
+class AStar {
+public:
+	struct Vec2i { 
+		int x, y;
+		bool operator==(const Vec2i& rhs)const {
+			return x == rhs.x&&y == rhs.y;
+		}
+		Vec2i operator+(const Vec2i& rhs)const {
+			return Vec2i{ x + rhs.x,y + rhs.y };
+		}
+	};
+	struct Node {
+		int F, G;
+		Vec2i pos;
+		Node* parent;
+		//Node(int)
+		Node() :F(0), G(0), parent{ nullptr }{
+
+		}
+
+		/*Node& operator=(const Node& rhs) {
+			F = rhs.F;
+			G = rhs.G;
+			H = rhs.H;
+			pos = rhs.pos;
+			return *this;
+		}*/
+
+	};
+	struct Nodeless
+	{
+		bool operator()(const Node& lhs, const Node& rhs) const {
+			return lhs.pos.x < rhs.pos.y || (lhs.pos.x == rhs.pos.x && lhs.pos.y < rhs.pos.y);
+		}
+	};
+	struct Vec2less {
+		bool operator()(const Vec2i& lhs, const Vec2i& rhs) const {
+			return lhs.x < rhs.x || (lhs.x == rhs.x && lhs.y < rhs.y);
+		}
+	};
+	AStar() {
+		_start.x = _start.y = 0;
+		_end.x = _end.y = 0;
+		//_start < _end;
+
+	}
+	bool outside(Vec2i pos) {
+		return pos.x<0 || pos.x>_mapSize.x || pos.y<0 || pos.y>_mapSize.y;
+	}
+	void set_map(int w,int h, const vector<Vec2i>& wall) {
+		_mapSize.x = w; _mapSize.y = h;
+		_wallset.clear();
+		for (auto&it : wall) {
+			_wallset.insert(it);
+		}
+		/*	Vector2i tp;
+			for (int i = 0; i <= mapSize.x;++i) {
+				_wallset.insert({ i,0 });
+				_wallset.insert({ 0,i });
+				_wallset.insert({ mapSize.x,i });
+				_wallset.insert({ i,mapSize.y });
+			}*/
+	}
+	void findpath(int beginX, int beginY,int endX,int endY, list<Vec2i>&path) {
+		_openset.clear();
+		_closedset.clear();
+		path.clear();
+		_start.x = beginX; _start.y = beginY;
+		_end.x = endX; _end.y = endY;
+		if (outside(_start) || outside(_end))
+			return;
+	
+		Node curr_node;
+		curr_node.pos = _start;
+		_openset.insert(curr_node);
+		while (!_openset.empty()) {
+			auto S = std::min_element(_openset.begin(), _openset.end(), [](const Node& lhs, const Node& rhs) {return lhs.F < rhs.F; });
+			curr_node = *S;
+			_closedset.insert(curr_node);
+			_openset.erase(S);
+			if (curr_node.pos == _end) {//get it!
+				break;
+			}
+			//生成所有相邻节点
+			Node temp;
+			for (int i = 0; i < 8; ++i) {
+				temp.pos = curr_node.pos + _dir4[i];
+				temp.G = curr_node.G + 1;
+				int H = std::abs(temp.pos.x - _end.x) + std::abs(temp.pos.y - _end.y);
+				temp.F = temp.G + H;
+				if (_closedset.count(temp))
+					continue;
+				if (_wallset.count(temp.pos))
+					continue;
+				if (outside(temp.pos))
+					continue;
+				auto it = _openset.find(temp);
+				//如果节点不在开放节点
+				if (it == _openset.end()) {
+
+					temp.parent = (Node*)&(*_closedset.find(curr_node));
+					_openset.insert(temp);
+				}
+				else {
+					//更新开放节点
+					if (it->F > temp.F) {
+						auto ptr = (Node*)&(*it);
+						ptr->F = temp.F;
+					}
+				}
+			}
+		}
+		//获取路径
+		curr_node.pos = _end;
+		auto endit = _closedset.find(curr_node);
+		if (endit != _closedset.end()) {
+			auto pnode = (Node*)&(*endit);
+			while (pnode)
+			{
+				_pathset.insert(pnode->pos);
+				path.push_back(pnode->pos);
+				pnode = pnode->parent;
+			}
+		}
+
+
+
+	}
+	
+private:
+	//Eigen::
+	Vec2i _start, _end;
+	//地图大小
+	Vec2i _mapSize;
+	//开放节点
+	set<Node, Nodeless> _openset;
+	set<Node, Nodeless> _closedset;
+	//墙节点
+	set<Vec2i, Vec2less> _wallset;
+	//路径节点
+	set<Vec2i, Vec2less> _pathset;
+	//方向
+	Vec2i const  _dir4[8] = { {0,1},{0,-1},{-1,0},{1,0},{1,1},{-1,1},{-1,-1},{1,-1} };
+private:
+};
+

+ 647 - 0
gm/gm/background/Hook/DisplayHook.cpp

@@ -0,0 +1,647 @@
+#include "DisplayHook.h"
+#include <d3d11.h>
+//#include <D3DX11.h>
+#include <d3d10.h>
+//#include <d3dx10.h>
+#include <d3d9.h>
+#include "../../include/sharedmem.h"
+#include "../../include/promutex.h"
+#include <exception>
+#include <ddraw.h>
+
+#include "../../../3rd_party/include/kiero.h"
+#include <gl\gl.h>
+#include <gl\glu.h>
+#include "../../core/globalVar.h"
+#include "../../core/helpfunc.h"
+#include "../../core/opEnv.h"
+#include "../../winapi/query_api.h"
+#include <wingdi.h>
+#include <atlbase.h>
+#include "../display/frameInfo.h"
+#define DEBUG_HOOK 0
+HWND DisplayHook::render_hwnd = NULL;
+int DisplayHook::render_type = 0;
+wchar_t DisplayHook::shared_res_name[256];
+wchar_t DisplayHook::mutex_name[256];
+void* DisplayHook::old_address;
+bool DisplayHook::is_hooked = false;
+static int is_capture;
+
+using ATL::CComPtr;
+
+//dx9 hooked EndScene function
+HRESULT __stdcall dx9_hkEndScene(IDirect3DDevice9* thiz);
+//dx10
+HRESULT __stdcall dx10_hkPresent(IDXGISwapChain* thiz, UINT SyncInterval, UINT Flags);
+//dx11
+HRESULT __stdcall dx11_hkPresent(IDXGISwapChain* thiz, UINT SyncInterval, UINT Flags);
+//opengl_std
+void __stdcall gl_hkglBegin(GLenum mode);
+//opengl dn,nox
+void __stdcall gl_hkwglSwapBuffers(HDC hdc);
+//egl
+unsigned int __stdcall gl_hkeglSwapBuffers(void* dpy, void* surface);
+//glfinish
+void __stdcall gl_hkglFinish(void);
+
+int DisplayHook::setup(HWND hwnd_, int render_type_) {
+	DisplayHook::render_hwnd = hwnd_;
+	wsprintf(DisplayHook::shared_res_name, SHARED_RES_NAME_FORMAT, hwnd_);
+	wsprintf(DisplayHook::mutex_name, MUTEX_NAME_FORMAT, hwnd_);
+
+	int idx = 0;
+	void* address = nullptr;
+	if (render_type_ == RDT_DX_DEFAULT || render_type_ == RDT_DX_D3D9) {
+
+		render_type = kiero::RenderType::D3D9;
+		idx = 42; address = dx9_hkEndScene;
+	}
+	else if (render_type_ == RDT_DX_D3D10) {
+		render_type = kiero::RenderType::D3D10;
+		idx = 8; address = dx10_hkPresent;
+	}
+	else if (render_type_ == RDT_DX_D3D11)
+	{
+		render_type = kiero::RenderType::D3D11;
+		idx = 8; address = dx11_hkPresent;
+	}
+	else if (render_type_ == RDT_GL_DEFAULT || render_type_ == RDT_GL_NOX) {
+		render_type = kiero::RenderType::OpenGL;
+		idx = 2; address = gl_hkwglSwapBuffers;
+	}
+	else if (render_type_ == RDT_GL_STD) {
+		render_type = kiero::RenderType::OpenGL;
+		idx = 0; address = gl_hkglBegin;
+	}
+	else if(render_type_==RDT_GL_ES){
+		render_type = kiero::RenderType::OpenglES;
+		idx = 0; address = gl_hkeglSwapBuffers;
+	}
+	else if(render_type_==RDT_GL_FI){
+		render_type = kiero::RenderType::OpenGL;
+		idx = 3; address = gl_hkglFinish;
+
+	}
+	else {
+		render_type = kiero::RenderType::None;
+	}
+	kiero::Status::Enum ret = kiero::init(render_type);
+	if (ret != kiero::Status::Success) {
+		return ret;
+	}
+		
+
+	is_capture = kiero::bind(idx, &old_address, address);
+	return is_capture;
+}
+
+int DisplayHook::release() {
+	is_capture = 0;
+	int ret = kiero::unbind();
+	return 1;
+}
+
+static void CopyImageData(char*  dst_, const char* src_, int rows_, int cols_,int rowPitch, int fmt_) {
+	//assert(rowsPitch >= cols_ * 4);
+	if (rowPitch == cols_ * (fmt_ == IBF_R8G8B8 ? 3 : 4)) {
+		if (fmt_ == IBF_B8G8R8A8) {
+			::memcpy(dst_, src_, rows_ * cols_ * 4);
+		}
+		else if (fmt_ == IBF_R8G8B8A8) {
+			//pixels count
+			int n = rows_ * cols_;
+			
+			for (int i = 0; i < n; ++i) {
+				dst_[0] = src_[2];//b
+				dst_[1] = src_[1];//g
+				dst_[2] = src_[0];//r
+				dst_[3] = src_[3];//a
+				dst_ += 4; src_ += 4;
+			}
+		}
+		else {
+			//pixels count
+			int n = rows_ * cols_;
+			for (int i = 0; i < n; ++i) {
+				*dst_++ = *src_++;
+				*dst_++ = *src_++;
+				*dst_++ = *src_++;
+				*dst_++ = (char)0xff;//dst is 4 B
+			}
+		}
+	}
+	else {
+		const int dstPitch = cols_ * 4;
+		if (fmt_ == IBF_B8G8R8A8) {
+			for (int i = 0; i < rows_; ++i) {
+				::memcpy(dst_, src_, dstPitch);
+				dst_ += dstPitch;
+				src_ += rowPitch;
+			}
+			
+		}
+		else if (fmt_ == IBF_R8G8B8A8) {
+			//pixels count
+			
+			for (int i = 0; i < rows_; ++i) {
+				for (int j = 0; j < cols_; ++j) {
+					const char* p = src_ + j * 4;//offset 
+					dst_[0] = p[2];//b
+					dst_[1] = p[1];//g
+					dst_[2] = p[0];//r
+					dst_[3] = p[3];//a
+					dst_ += 4;//notirc that dst ptr is increasing
+				}
+				src_ += rowPitch;//row increase
+				
+			}
+			
+		}
+		else {
+			for (int i = 0; i < rows_; ++i) {
+				for (int j = 0; j < cols_; ++j) {
+					const char* p = src_ + j * 3;//offset 
+					dst_[0] = p[0];//b
+					dst_[1] = p[1];//g
+					dst_[2] = p[2];//r
+					dst_[3] = (char)0xff;//a
+					dst_ += 4;//notice that dst ptr is increasing
+				}
+				src_ += rowPitch;//row increase
+
+			}
+		}
+	}
+	
+}
+
+static DXGI_FORMAT GetDxgiFormat(DXGI_FORMAT format) {
+	if (format == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB) {
+		return DXGI_FORMAT_B8G8R8A8_UNORM;
+	}
+	if (format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) {
+		return DXGI_FORMAT_R8G8B8A8_UNORM;
+	}
+	return format;
+}
+
+static void formatFrameInfo(void* dst,HWND hwnd, int w, int h) {
+	static FrameInfo frameInfo = {};
+	frameInfo.hwnd = (unsigned __int64)hwnd;
+	frameInfo.frameId++;
+	frameInfo.time = ::GetTickCount();
+	frameInfo.width = w;
+	frameInfo.height = h;
+	frameInfo.fmtChk();
+	memcpy(dst, &frameInfo, sizeof(frameInfo));
+}
+
+
+//------------------------dx9-------------------------------
+//screen capture
+HRESULT dx9_capture(LPDIRECT3DDEVICE9 pDevice) {
+	//save bmp
+	//setlog("dx9screen_capture");
+	HRESULT hr = NULL;
+	CComPtr<IDirect3DSurface9> pSurface;
+	hr = pDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pSurface);
+	if (FAILED(hr)) return hr;
+
+	D3DSURFACE_DESC surface_Desc;
+	hr = pSurface->GetDesc(&surface_Desc);
+	if (FAILED(hr)) return hr;
+
+	CComPtr<IDirect3DTexture9> pTex;
+	CComPtr<IDirect3DSurface9> pTexSurface;
+	hr = pDevice->CreateTexture(surface_Desc.Width,
+		surface_Desc.Height,
+		1,
+		0,
+		surface_Desc.Format,
+		D3DPOOL_SYSTEMMEM, // 必须为这个
+		&pTex, NULL);
+	if (hr < 0) {
+		return hr;
+	}
+	hr = pTex->GetSurfaceLevel(0, &pTexSurface);
+	if (hr < 0)return hr;
+	hr = pDevice->GetRenderTargetData(pSurface, pTexSurface);
+
+	D3DLOCKED_RECT lockedRect;
+
+	pTex->LockRect(0, &lockedRect, NULL, D3DLOCK_READONLY);
+	// 取像素
+	sharedmem mem;
+	promutex mutex;
+	if (mem.open(DisplayHook::shared_res_name) && mutex.open(DisplayHook::mutex_name)) {
+		mutex.lock();
+		uchar* pshare = mem.data<byte>();
+		formatFrameInfo(pshare,DisplayHook::render_hwnd, surface_Desc.Width, surface_Desc.Height);
+		memcpy(pshare + sizeof(FrameInfo), (byte*)lockedRect.pBits, lockedRect.Pitch*surface_Desc.Height);
+		mutex.unlock();
+	}
+	pTex->UnlockRect(0);
+	
+	return hr;
+}
+//dx9 hooked EndScene function
+HRESULT STDMETHODCALLTYPE dx9_hkEndScene(IDirect3DDevice9* thiz)
+{
+	typedef long(__stdcall* EndScene)(LPDIRECT3DDEVICE9);
+	auto ret = ((EndScene)DisplayHook::old_address)(thiz);
+	if (is_capture)
+		dx9_capture(thiz);
+
+	return ret;
+}
+//------------------------------------------------------------
+
+//-----------------------dx10----------------------------------
+//screen capture
+void dx10_capture(IDXGISwapChain* pswapchain) {
+	using Texture2D = ID3D10Texture2D * ;
+
+	HRESULT hr;
+	ID3D10Device *pdevices = nullptr;
+	ID3D10Resource* backbuffer = nullptr;
+	Texture2D textDst = nullptr;
+	//LPD3D10BLOB pblob = nullptr;
+
+	//setlog("before GetBuffer");
+	hr = pswapchain->GetBuffer(0, __uuidof(ID3D10Resource), (void**)&backbuffer);
+	if (hr < 0) {
+		setlog("pswapchain->GetBuffer error code=%d", hr);
+		is_capture = 0;
+		return;
+	}
+	backbuffer->GetDevice(&pdevices);
+
+	if (!pdevices) {
+		//setlog(" pswapchain->GetDevice false");
+		backbuffer->Release();
+		is_capture = 0;
+		return;
+	}
+	//auto p
+
+	DXGI_SWAP_CHAIN_DESC desc;
+	pswapchain->GetDesc(&desc);;
+	//backbuffer->GetDesc(&desc);
+	// If texture is multisampled, then we can use ResolveSubresource to copy it into a non-multisampled texture
+	//Texture2D textureResolved = nullptr;
+
+
+	D3D10_TEXTURE2D_DESC textDesc = {};
+	textDesc.Format = GetDxgiFormat(desc.BufferDesc.Format);
+	textDesc.Width = desc.BufferDesc.Width;
+	textDesc.Height = desc.BufferDesc.Height;
+	textDesc.MipLevels = 1;
+	textDesc.ArraySize = 1;
+	textDesc.SampleDesc.Count = 1;
+	textDesc.Usage = D3D10_USAGE_STAGING;
+	textDesc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
+	hr = pdevices->CreateTexture2D(&textDesc, nullptr, &textDst);
+	if (hr < 0) {
+		pdevices->Release();
+		backbuffer->Release();
+		return;
+	}
+
+	pdevices->CopyResource(textDst, backbuffer);
+
+	D3D10_MAPPED_TEXTURE2D mapText = { 0,0 };
+
+	hr = textDst->Map(0, D3D10_MAP_READ, 0, &mapText);
+
+	//hr = pD3DX10SaveTextureToMemory(textureDest, D3DX10_IMAGE_FILE_FORMAT::D3DX10_IFF_BMP, &pblob, 0);
+	if (hr < 0) {
+		setlog("textDst->Map false,hr=%d", hr);
+		is_capture = 0;
+		return;
+	}
+
+	int fmt = IBF_R8G8B8A8;
+	if (textDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM ||
+		textDesc.Format == DXGI_FORMAT_B8G8R8X8_UNORM ||
+		textDesc.Format == DXGI_FORMAT_B8G8R8A8_TYPELESS ||
+		textDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB ||
+		textDesc.Format == DXGI_FORMAT_B8G8R8X8_TYPELESS ||
+		textDesc.Format == DXGI_FORMAT_B8G8R8X8_UNORM_SRGB)
+	{
+		fmt = IBF_B8G8R8A8;
+	}
+
+	sharedmem mem;
+	promutex mutex;
+	if (mem.open(DisplayHook::shared_res_name) && mutex.open(DisplayHook::mutex_name)) {
+
+		mutex.lock();
+		//memcpy(mem.data<char>(), mapText.pData, textDesc.Width*textDesc.Height * 4);
+		uchar* pshare = mem.data<byte>();
+		formatFrameInfo(pshare,DisplayHook::render_hwnd, textDesc.Width, textDesc.Height);
+		CopyImageData((char*)pshare+ sizeof(FrameInfo), (char*)mapText.pData, textDesc.Height, textDesc.Width, mapText.RowPitch, fmt);
+		mutex.unlock();
+	}
+	else {
+
+#if DEBUG_HOOK
+		setlog("mem.open(xhook::shared_res_name) && mutex.open(xhook::mutex_name)");
+#endif // DEBUG_HOOK
+
+	}
+	//release
+	SAFE_RELEASE(textDst);
+	SAFE_RELEASE(pdevices);
+	SAFE_RELEASE(backbuffer);
+	//pblob->Release();
+	//setlog("pblob->Release()");
+}
+//dx10 hook Present
+HRESULT STDMETHODCALLTYPE dx10_hkPresent(IDXGISwapChain* thiz, UINT SyncInterval, UINT Flags) {
+	typedef long(__stdcall* Present_t)(IDXGISwapChain* pswapchain, UINT x1, UINT x2);
+	if (is_capture)
+		dx10_capture(thiz);
+	return ((Present_t)DisplayHook::old_address)(thiz, SyncInterval, Flags);
+	//thiz.
+}
+//------------------------------------------------------------
+
+//------------------------dx11----------------------------------
+//screen capture
+void dx11_capture(IDXGISwapChain* swapchain) {
+
+	//setlog("d3d11 cap");
+	using Texture2D = ID3D11Texture2D * ;
+	HRESULT hr = 0;
+	IDXGIResource* backbufferptr = nullptr;
+	ID3D11Resource* backbuffer = nullptr;
+	Texture2D textDst = nullptr;
+	ID3D11Device* device = nullptr;
+	ID3D11DeviceContext* context = nullptr;
+
+	hr = swapchain->GetBuffer(0, __uuidof(IDXGIResource), (void**)&backbufferptr);
+	if (hr < 0) {
+		setlog("pswapchain->GetBuffer,error code=%X", hr);
+		is_capture = 0;
+		return;
+	}
+	hr = backbufferptr->QueryInterface(__uuidof(ID3D11Resource), (void**)&backbuffer);
+	if (hr < 0) {
+		setlog("backbufferptr->QueryInterface,error code=%X", hr);
+		is_capture = 0;
+		return;
+	}
+	hr = swapchain->GetDevice(__uuidof(ID3D11Device), (void**)&device);
+	if (hr < 0) {
+		setlog("swapchain->GetDevice hr=%X", hr);
+		is_capture = 0;
+		return;
+	}
+	DXGI_SWAP_CHAIN_DESC desc;
+	hr = swapchain->GetDesc(&desc);
+	if (hr < 0) {
+		setlog("swapchain->GetDesc hr=%X", hr);
+		is_capture = 0;
+		return;
+	}
+
+	D3D11_TEXTURE2D_DESC textDesc = { };
+	textDesc.Format = GetDxgiFormat(desc.BufferDesc.Format);
+	textDesc.Width = desc.BufferDesc.Width;
+	textDesc.Height = desc.BufferDesc.Height;
+	textDesc.MipLevels = 1;
+	textDesc.ArraySize = 1;
+	textDesc.SampleDesc.Count = 1;
+	textDesc.Usage = D3D11_USAGE_STAGING;
+	textDesc.BindFlags = 0;
+	textDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+	textDesc.MiscFlags = 0;
+	hr = device->CreateTexture2D(&textDesc, nullptr, &textDst);
+	if (hr < 0) {
+		setlog("device->CreateTexture2D,error code=%d", hr);
+		is_capture = 0;
+		return;
+	}
+	//DXGI_KEY
+	device->GetImmediateContext(&context);
+	if (!context) {
+		setlog("!context");
+		is_capture = 0;
+		return;
+	}
+
+	context->CopyResource(textDst, backbuffer);
+
+	D3D11_MAPPED_SUBRESOURCE mapSubres = { 0,0,0 };
+
+	//hr = pD3DX11SaveTextureToMemory(context, textureDst, D3DX11_IMAGE_FILE_FORMAT::D3DX11_IFF_BMP, &pblob, 0);
+	hr = context->Map(textDst, 0, D3D11_MAP_READ, 0, &mapSubres);
+	if (hr < 0) {
+		setlog("context->Map error code=%d", hr);
+		is_capture = 0;
+		return;
+	}
+	//DXGI_FORMAT_R8G8B8A8_UNORM4
+	int fmt = IBF_R8G8B8A8;
+	if (textDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM ||
+		textDesc.Format == DXGI_FORMAT_B8G8R8X8_UNORM ||
+		textDesc.Format == DXGI_FORMAT_B8G8R8A8_TYPELESS ||
+		textDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB ||
+		textDesc.Format == DXGI_FORMAT_B8G8R8X8_TYPELESS ||
+		textDesc.Format == DXGI_FORMAT_B8G8R8X8_UNORM_SRGB)
+	{
+		fmt = IBF_B8G8R8A8;
+	}
+
+	sharedmem mem;
+	promutex mutex;
+	static int cnt = 10;
+	if (mem.open(DisplayHook::shared_res_name) && mutex.open(DisplayHook::mutex_name)) {
+		mutex.lock();
+		uchar* pshare = mem.data<byte>();
+		formatFrameInfo(pshare, DisplayHook::render_hwnd, textDesc.Width, textDesc.Height);
+		//CopyImageData((char*)pshare + sizeof(FrameInfo), (char*)mapText.pData, textDesc.Height, textDesc.Width, fmt);
+		static_assert(sizeof(FrameInfo) == 28);
+ 
+		CopyImageData((char*)pshare + sizeof(FrameInfo), (char*)mapSubres.pData, textDesc.Height, textDesc.Width, mapSubres.RowPitch, fmt);
+		mutex.unlock();
+	}
+	else {
+		is_capture = 0;
+#if DEBUG_HOOK
+		setlog("!mem.open(xhook::%s)&&mutex.open(xhook::%s)", xhook::shared_res_name, xhook::mutex_name);
+#endif // DEBUG_HOOK
+
+	}
+	static bool first = true;
+	if (first) {
+		int tf = textDesc.Format;
+
+		setlog("textDesc.Format= %d,fmt=%d textDesc.Height=%d\n textDesc.Width=%d\n  mapSubres.DepthPitch=%d\n mapSubres.RowPitch=%d\n",
+			tf, fmt,
+			textDesc.Height,
+			textDesc.Width,
+			mapSubres.DepthPitch,
+			mapSubres.RowPitch
+		);
+		first = false;
+	}
+	context->Unmap(textDst, 0);
+	SAFE_RELEASE(backbufferptr);
+	SAFE_RELEASE(backbuffer);
+	SAFE_RELEASE(device);
+	SAFE_RELEASE(textDst);
+	SAFE_RELEASE(context);
+	//if (pblob)pblob->Release();
+}
+
+//hooked present
+HRESULT __stdcall dx11_hkPresent(IDXGISwapChain* thiz, UINT SyncInterval, UINT Flags) {
+	typedef long(__stdcall* Present_t)(IDXGISwapChain* pswapchain, UINT x1, UINT x2);
+	if (is_capture)
+		dx11_capture(thiz);
+	return ((Present_t)DisplayHook::old_address)(thiz, SyncInterval, Flags);
+}
+//------------------------------------------------------------
+
+//-----------------------opengl-----------------------------
+//screen capture
+long gl_capture() {
+	using glPixelStorei_t = decltype(glPixelStorei)*;
+	using glReadBuffer_t = decltype(glReadBuffer)*;
+	using glGetIntegerv_t = decltype(glGetIntegerv)*;
+	using glReadPixels_t = decltype(glReadPixels)*;
+
+	auto pglPixelStorei = (glPixelStorei_t)query_api("opengl32.dll", "glPixelStorei");
+	auto pglReadBuffer = (glReadBuffer_t)query_api("opengl32.dll", "glReadBuffer");
+	auto pglGetIntegerv = (glGetIntegerv_t)query_api("opengl32.dll", "glGetIntegerv");
+	auto pglReadPixels = (glReadPixels_t)query_api("opengl32.dll", "glReadPixels");
+	if (!pglPixelStorei || !pglReadBuffer || !pglGetIntegerv || !pglReadPixels) {
+		is_capture = 0;
+#if DEBUG_HOOK
+		setlog("error.!pglPixelStorei || !pglReadBuffer || !pglGetIntegerv || !pglReadPixels");
+#endif // DEBUG_HOOK
+
+		return 0;
+	}
+	RECT rc;
+	::GetClientRect(DisplayHook::render_hwnd, &rc);
+	int width = rc.right - rc.left, height = rc.bottom - rc.top;
+
+	pglPixelStorei(GL_PACK_ALIGNMENT, 1);
+	pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+	pglReadBuffer(GL_FRONT);
+
+	sharedmem mem;
+	promutex mutex;
+	if (mem.open(DisplayHook::shared_res_name) && mutex.open(DisplayHook::mutex_name)) {
+		mutex.lock();
+		uchar* pshare = mem.data<byte>();
+		formatFrameInfo(pshare,DisplayHook::render_hwnd, width, height);
+		pglReadPixels(0, 0, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pshare+ sizeof(FrameInfo));
+		mutex.unlock();
+	}
+	else {
+		is_capture = 0;
+#if DEBUG_HOOK
+		setlog(L"egl !mem.open(xhook::%s)&&mutex.open(xhook::%s)", xhook::shared_res_name, xhook::mutex_name);
+#endif // DEBUG_HOOK
+
+	}
+	//setlog("gl screen ok");
+	return 0;
+}
+// hook glBegin or wglSwapLayerBuffers
+
+void __stdcall gl_hkglBegin(GLenum mode) {
+	static DWORD t = 0;
+	using glBegin_t = decltype(glBegin)*;
+
+	if (is_capture)
+		gl_capture();
+	((glBegin_t)DisplayHook::old_address)(mode);
+}
+
+void __stdcall gl_hkwglSwapBuffers(HDC hdc) {
+	using wglSwapBuffers_t = void(__stdcall*) (HDC hdc);
+	if (is_capture)
+		gl_capture();
+	((wglSwapBuffers_t)DisplayHook::old_address)(hdc);
+	
+}
+
+
+
+
+
+
+//---------------------OPENGL ES------------------------------
+//es 类似 opengl 截图,只是模块不同
+long egl_capture() {
+	using glPixelStorei_t = decltype(glPixelStorei)*;
+	using glReadBuffer_t = decltype(glReadBuffer)*;
+	using glGetIntegerv_t = decltype(glGetIntegerv)*;
+	using glReadPixels_t = decltype(glReadPixels)*;
+
+	auto pglPixelStorei = (glPixelStorei_t)query_api("libglesv2.dll", "glPixelStorei");
+	auto pglReadBuffer = (glReadBuffer_t)query_api("libglesv2.dll", "glReadBuffer");
+	auto pglGetIntegerv = (glGetIntegerv_t)query_api("libglesv2.dll", "glGetIntegerv");
+	auto pglReadPixels = (glReadPixels_t)query_api("libglesv2.dll", "glReadPixels");
+	if (!pglPixelStorei || !pglReadBuffer || !pglGetIntegerv || !pglReadPixels) {
+		//is_capture = 0;
+#if DEBUG_HOOK
+		setlog(L"egl !mem.open(xhook::%s)&&mutex.open(xhook::%s)", xhook::shared_res_name, xhook::mutex_name);
+#endif // DEBUG_HOOK
+
+		return 0;
+	}
+	RECT rc;
+	::GetClientRect(DisplayHook::render_hwnd, &rc);
+	int width = rc.right - rc.left, height = rc.bottom - rc.top;
+
+	pglPixelStorei(GL_PACK_ALIGNMENT, 1);
+	pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+	pglReadBuffer(GL_FRONT);
+
+	sharedmem mem;
+	promutex mutex;
+	if (mem.open(DisplayHook::shared_res_name) && mutex.open(DisplayHook::mutex_name)) {
+		mutex.lock();
+		uchar* pshare = mem.data<byte>();
+		formatFrameInfo(pshare,DisplayHook::render_hwnd, width, height);
+		pglReadPixels(0, 0, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pshare + sizeof(FrameInfo));
+		//pglReadPixels(0, 0, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, mem.data<byte>());
+		mutex.unlock();
+	}
+	else {
+		is_capture = 0;
+#if DEBUG_HOOK
+		setlog(L"egl !mem.open(xhook::%s)&&mutex.open(xhook::%s)", xhook::shared_res_name, xhook::mutex_name);
+#endif // DEBUG_HOOK
+
+	}
+	//setlog("gl screen ok");
+	return 0;
+}
+
+unsigned int __stdcall gl_hkeglSwapBuffers(void* dpy, void* surface) {
+	using eglSwapBuffers_t = decltype(gl_hkeglSwapBuffers)*;
+	if (is_capture)
+		egl_capture();
+	return ((eglSwapBuffers_t)DisplayHook::old_address)(dpy, surface);
+	
+}
+
+
+void __stdcall gl_hkglFinish(void) {
+	using glFinish_t = decltype(glFinish)*;
+	if (is_capture)
+		gl_capture();
+	((glFinish_t)DisplayHook::old_address)();
+}
+
+
+
+
+

+ 30 - 0
gm/gm/background/Hook/DisplayHook.h

@@ -0,0 +1,30 @@
+//#pragma once
+#ifndef __DX9HOOK_H_
+#define __DX9HOOK_H_
+#include "../../core/globalVar.h"
+
+class DisplayHook
+{
+public:
+	/*target window hwnd*/
+	static HWND render_hwnd;
+	static int render_type;
+	/*name of ...*/
+	static wchar_t shared_res_name[256];
+	static wchar_t mutex_name[256];
+	static void *old_address;
+	static bool is_hooked ;
+	//
+	static int setup(HWND hwnd_, int render_type_);
+	static int release();
+};
+//以下函数用于HOOK DX9
+
+//此函数做以下工作
+/*
+1.hook相关函数
+2.设置共享内存,互斥量
+3.截图(hook)至共享内存
+*/
+
+#endif // !__DX9HOOK_H_

+ 65 - 0
gm/gm/background/Hook/HookExport.cpp

@@ -0,0 +1,65 @@
+#include "HookExport.h"
+#include "DisplayHook.h"
+#include "InputHook.h"
+#include "../../core/opEnv.h"
+int refCount = 0;
+//--------------export function--------------------------
+long __stdcall SetDisplayHook(HWND hwnd_, int render_type_)
+{
+    int ret = 0;
+    opEnv::m_showErrorMsg = 2; //this code is excuate in hookde process,so its better not show meesageBox(avoid suspend the work thread)
+    if (!DisplayHook::is_hooked)
+    {
+      ret  = DisplayHook::setup(hwnd_, render_type_);
+      DisplayHook::is_hooked = ret == 1;
+      refCount += DisplayHook::is_hooked;
+    }
+    else {
+        //setlog("warning: ")
+        ret = 1;
+    }
+    return ret;
+}
+
+long __stdcall ReleaseDisplayHook()
+{
+    int ret = 0;
+    if (DisplayHook::is_hooked){
+        DisplayHook::is_hooked = false;
+        ret = DisplayHook::release();
+        refCount--;
+        if(refCount==0){
+            ::FreeLibraryAndExitThread(static_cast<HMODULE>(opEnv::getInstance()), 0);
+        }
+        
+    }
+  
+  
+    return ret;
+}
+
+long __stdcall SetInputHook(HWND hwnd_, int input_type_)
+{
+    int ret = 0;
+    if (!InputHook::is_hooked)
+    {
+        ret = InputHook::setup(hwnd_, input_type_);
+        InputHook::is_hooked = ret == 1;
+         refCount += InputHook::is_hooked;
+    }
+    return ret;
+}
+
+long __stdcall ReleaseInputHook()
+{
+    if (InputHook::is_hooked)
+    {
+        InputHook::release();
+        InputHook::is_hooked = false;
+         refCount--;
+        if(refCount==0){
+            ::FreeLibraryAndExitThread(static_cast<HMODULE>(opEnv::getInstance()), 0);
+        }
+    }
+    return 1;
+}

+ 18 - 0
gm/gm/background/Hook/HookExport.h

@@ -0,0 +1,18 @@
+#include "../../core/globalVar.h"
+
+
+//描述: 设置显示Hook
+//返回值:1 成功,0失败
+DLL_API long __stdcall SetDisplayHook(HWND hwnd_, int render_type_);
+
+//描述: 释放显示Hook
+//返回值:1 成功,0失败
+DLL_API long __stdcall ReleaseDisplayHook();
+
+//描述: 设置输入Hook
+//返回值:1 成功,0失败
+DLL_API long __stdcall SetInputHook(HWND hwnd_, int input_type_);
+
+//描述: 释放输入Hook
+//返回值:1 成功,0失败
+DLL_API long __stdcall ReleaseInputHook();

+ 263 - 0
gm/gm/background/Hook/InputHook.cpp

@@ -0,0 +1,263 @@
+
+#include "InputHook.h"
+#include "../../core/opEnv.h"
+#include "../../core/helpfunc.h"
+#include "opMessage.h"
+#include "../../winapi/query_api.h"
+#include "MinHook.h"
+
+#include "dinput.h"
+#include <vector>
+
+const GUID OP_IID_IDirectInput8W = {0xBF798031, 0x483A, 0x4DA2, 0xAA, 0x99, 0x5D, 0x64, 0xED, 0x36, 0x97, 0x00};
+const GUID OP_GUID_SysMouse = {0x6F1D2B60, 0xD5A0, 0x11CF, 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00};
+/*target window hwnd*/
+HWND InputHook::input_hwnd;
+int InputHook::input_type;
+/*name of ...*/
+wchar_t InputHook::shared_res_name[256];
+wchar_t InputHook::mutex_name[256];
+void *InputHook::old_address;
+//
+opMouseState InputHook::m_mouseState;
+bool InputHook::is_hooked = false;
+
+WNDPROC gRawWindowProc = 0;
+std::vector<void *> gDinputVtb;
+std::vector<void *> gDinputVtbRaw;
+
+const int indexAcquire = 7;
+const int indexGetDeviceState = 9;
+const int indexPoll = 25;
+
+int getDinputVtb();
+
+HRESULT __stdcall hkAcquire(IDirectInputDevice8W *this_);
+
+HRESULT __stdcall hkPoll(IDirectInputDevice8W *this_);
+
+HRESULT __stdcall hkGetDeviceState(IDirectInputDevice8W *this_, DWORD size, LPVOID ptr);
+
+LRESULT CALLBACK opWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+int InputHook::setup(HWND hwnd_, int input_type_)
+{
+    if (!IsWindow(hwnd_))
+        return 0;
+    opEnv::m_showErrorMsg = 2; //write data to file
+    setlog("SetInputHook");
+    if (getDinputVtb() == 1)
+    {
+        MH_Initialize();
+        MH_CreateHook(
+            gDinputVtb[indexGetDeviceState],
+            hkGetDeviceState,
+            &gDinputVtbRaw[indexGetDeviceState]);
+        MH_CreateHook(
+            gDinputVtb[indexPoll],
+            hkPoll,
+            &gDinputVtbRaw[indexPoll]);
+        MH_EnableHook(NULL);
+        gRawWindowProc = reinterpret_cast<WNDPROC>(SetWindowLongPtrA(hwnd_, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(opWndProc)));
+        InputHook::input_hwnd = hwnd_;
+    }
+    else
+    {
+        setlog("getDinputVtb false!");
+    }
+
+    return gRawWindowProc ? 1 : -1;
+}
+int InputHook::release()
+{
+    LONG_PTR ptr = 0;
+    if (gRawWindowProc)
+    {
+        MH_RemoveHook(NULL);
+        MH_Uninitialize();
+        ptr = SetWindowLongPtrA(InputHook::input_hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(gRawWindowProc));
+    }
+    return ptr ? 1 : 0;
+    return 0;
+}
+
+void InputHook::upDataPos(LPARAM lp, int key, bool down)
+{
+    m_mouseState.lAxisX = lp & 0xffff;
+    m_mouseState.lAxisY = (lp >> 16) & 0xffff;
+    setlog("upDataPos x=%d, y=%d", m_mouseState.lAxisX, m_mouseState.lAxisY);
+    if (0 <= key && key < 3)
+    {
+        m_mouseState.abButtons[key] = down ? 0x80 : 0;
+    }
+}
+
+int getDinputVtb()
+{
+    using DirectInput8Create_t = decltype(DirectInput8Create);
+    auto pDirectInput8Create = reinterpret_cast<DirectInput8Create_t *>(query_api("dinput8.dll", "DirectInput8Create"));
+    if (pDirectInput8Create)
+    {
+        WNDCLASSEX windowClass;
+        windowClass.cbSize = sizeof(WNDCLASSEX);
+        windowClass.style = CS_HREDRAW | CS_VREDRAW;
+        windowClass.lpfnWndProc = DefWindowProc;
+        windowClass.cbClsExtra = 0;
+        windowClass.cbWndExtra = 0;
+        windowClass.hInstance = GetModuleHandle(NULL);
+        windowClass.hIcon = NULL;
+        windowClass.hCursor = NULL;
+        windowClass.hbrBackground = NULL;
+        windowClass.lpszMenuName = NULL;
+        windowClass.lpszClassName = L"Kiero";
+        windowClass.hIconSm = NULL;
+
+        ::RegisterClassEx(&windowClass);
+
+        HWND window = ::CreateWindowW(windowClass.lpszClassName, L"Kiero DirectX Window", WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, NULL, NULL, windowClass.hInstance, NULL);
+        LPDIRECTINPUT8 pDinput = NULL;
+
+        if (pDirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
+                                OP_IID_IDirectInput8W, (VOID **)&pDinput, NULL) < 0)
+        {
+            ::DestroyWindow(window);
+            ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+            setlog("pDirectInput8Create false!");
+            return -1;
+        }
+
+        LPDIRECTINPUTDEVICE8 pMouse = NULL;
+        if (pDinput->CreateDevice(OP_GUID_SysMouse, &pMouse, NULL) < 0)
+        {
+            ::DestroyWindow(window);
+            ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+            setlog("CreateDevice false!");
+            return -2;
+        }
+        gDinputVtb.resize(32);
+        gDinputVtbRaw.resize(32);
+        ::memcpy(&gDinputVtb[0], *(size_t **)pMouse, 32 * sizeof(size_t));
+
+        ::DestroyWindow(window);
+        ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
+
+        return 1;
+        //MH_Initialize();
+    }
+    else
+    {
+        setlog("dinput8 not found");
+        return 0;
+    }
+}
+
+HRESULT __stdcall hkAcquire(IDirectInputDevice8W *this_)
+{
+    return DI_OK;
+}
+
+HRESULT __stdcall hkPoll(IDirectInputDevice8W *this_)
+{
+    return DI_OK;
+}
+
+void EndianSwap(char *pData, int startIndex, int length)
+{
+    int i,cnt,end,start;
+    cnt = length / 2;
+    start = startIndex;
+    end  = startIndex + length - 1;
+    char tmp;
+    for (i = 0; i < cnt; i++)
+    {
+        tmp            = pData[start+i];
+        pData[start+i] = pData[end-i];
+        pData[end-i]   = tmp;
+    }
+}
+
+HRESULT __stdcall hkGetDeviceState(IDirectInputDevice8W *this_, DWORD size, LPVOID ptr)
+{
+    //setlog("called hkGetDeviceState");
+    using GetDeviceState_t = decltype(hkGetDeviceState);
+
+    if (size == sizeof(opMouseState))
+    {
+        opMouseState state = {};
+        //setlog("called opMouseState");
+        // state.lAxisX = InputHook::m_mouseState.lAxisX;
+        // state.lAxisY = InputHook::m_mouseState.lAxisY;
+        // state.abButtons[0]
+        state = InputHook::m_mouseState;
+        //EndianSwap((char*)&state,0, sizeof(state));
+        memcpy(ptr, &state, sizeof(state));
+        return DI_OK;
+    }
+    else if (size == sizeof(DIMOUSESTATE))
+    {
+        DIMOUSESTATE state = {};
+        setlog("called DIMOUSESTATE");
+
+        state.lX = InputHook::m_mouseState.lAxisX;
+        state.lY = InputHook::m_mouseState.lAxisY;
+
+        memcpy(ptr, &state, sizeof(state));
+        return DI_OK;
+    }
+    else if (size == sizeof(DIMOUSESTATE2))
+    {
+        DIMOUSESTATE2 state = {};
+        setlog("called DIMOUSESTATE2");
+        state.lX = InputHook::m_mouseState.lAxisX;
+        state.lY = InputHook::m_mouseState.lAxisY;
+        memcpy(ptr, &state, sizeof(state));
+        return DI_OK;
+    }
+    else
+    {
+        return reinterpret_cast<GetDeviceState_t *>(gDinputVtbRaw[indexGetDeviceState])(this_, size, ptr);
+    }
+}
+
+LRESULT CALLBACK opWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    setlog("%04X message", message);
+    switch (message)
+    {
+    case OP_WM_MOUSEMOVE:
+    {
+        InputHook::upDataPos(lParam, -1, false);
+        setlog("OP_WM_MOUSEMOVE message");
+        break;
+    }
+    case OP_WM_LBUTTONUP:
+        InputHook::upDataPos(lParam, 0, false);
+        setlog("OP_WM_LBUTTONUP message");
+        break;
+    case OP_WM_LBUTTONDOWN:
+        InputHook::upDataPos(lParam, 0, true);
+        setlog("OP_WM_LBUTTONDOWN message");
+        break;
+    case OP_WM_MBUTTONDOWN:
+        InputHook::upDataPos(lParam, 1, true);
+        setlog("OP_WM_MBUTTONDOWN message");
+        break;
+    case OP_WM_MBUTTONUP:
+        InputHook::upDataPos(lParam, 1, false);
+        setlog("OP_WM_MBUTTONUP message");
+        break;
+    case OP_WM_RBUTTONDOWN:
+        InputHook::upDataPos(lParam, 2, true);
+        setlog("OP_WM_RBUTTONDOWN message");
+        break;
+    case OP_WM_RBUTTONUP:
+        InputHook::upDataPos(lParam, 2, false);
+        setlog("OP_WM_RBUTTONUP message");
+        break;
+    case OP_WM_MOUSEWHEEL:
+        //InputHook::upDataPos(wParam,2,true);
+        setlog("OP_WM_MOUSEWHEEL message");
+        break;
+    }
+    return CallWindowProcA(gRawWindowProc, InputHook::input_hwnd, message, wParam, lParam);
+}

+ 33 - 0
gm/gm/background/Hook/InputHook.h

@@ -0,0 +1,33 @@
+#ifndef __INPUT_HOOK_H
+#define __INPUT_HOOK_H
+
+#include "../../core/globalVar.h"
+
+struct opMouseState
+{
+	LONG lAxisX;
+	LONG lAxisY;
+	BYTE abButtons[3];
+	BYTE bPadding; // Structure must be DWORD multiple in size.
+};
+
+class InputHook
+{
+public:
+	/*target window hwnd*/
+	static HWND input_hwnd;
+	static int input_type;
+	/*name of ...*/
+	static wchar_t shared_res_name[256];
+	static wchar_t mutex_name[256];
+	static void *old_address;
+	static bool is_hooked;
+	//
+	static int setup(HWND hwnd_, int input_type_);
+	static int release();
+	//LParam is pos,key:-1-2,means null, left mid and right, down means keyState
+	static void upDataPos(LPARAM, int key, bool down);
+	static opMouseState m_mouseState;
+};
+
+#endif

+ 55 - 0
gm/gm/background/Hook/dinput.md

@@ -0,0 +1,55 @@
+## dinput鼠标和键盘消息获取简介
+### dinput的普通流程
+```c++
+//1. 注册DirectInput并获取IDirectInput接口指针
+DirectInput8Create( GetModuleHandle( NULL ), DIRECTINPUT_VERSION,IID_IDirectInput8, ( VOID** )&g_pDI, NULL )
+//2. 获取系统鼠标
+g_pDI->CreateDevice( GUID_SysMouse, &g_pMouse, NULL )
+//3. 设置数据格式
+g_pMouse->SetDataFormat( &g_dfMouse)
+//4. 为该设备实例建立协作级别。合作级别决定了设备的这个实例如何与设备的其他实例和系统的其余部分交互。
+/*
+hwnd
+Window handle to be associated with the device. This parameter must be a valid top-level window handle that belongs to the process. The window associated with the device must not be destroyed while it is still active in a DirectInput device.
+dwFlags
+Flags that describe the cooperative level associated with the device. The following flags are defined:
+DISCL_BACKGROUND
+该应用程序需要后台访问。如果授予后台访问权限,则可以随时获取设备,即使关联的窗口不是活动窗口。
+DISCL_EXCLUSIVE
+该应用程序需要独占访问。如果授予独占访问权限,则设备的其他实例在获取该设备时无法获得对该设备的独占访问权限。但是,始终允许对设备进行非独占访问,即使另一个应用程序已获得独占访问权限。以独占模式获取鼠标或键盘设备的应用程序在收到 WM_ENTERSIZEMOVE 和 WM_ENTERMENULOOP 消息时应始终取消获取设备.否则,用户无法操作菜单或移动和调整窗口大小。
+DISCL_FOREGROUND
+该应用程序需要前台访问。如果授予前台访问权限,则当关联的窗口移动到后台时,设备将自动取消获取。
+DISCL_NONEXCLUSIVE
+该应用程序需要非独占访问。对设备的访问不会干扰正在访问同一设备的其他应用程序
+DISCL_NOWINKEY
+禁用 Windows 徽标键。设置此标志可确保用户不会无意中退出应用程序。但请注意,当显示默认操作映射用户界面 (UI) 时,DISCL_NOWINKEY 不起作用,只要该 UI 存在,Windows 徽标键就会正常运行
+*/
+g_pMouse->SetCooperativeLevel( hDlg, DISCL_NONEXCLUSIVE |
+                                                    DISCL_FOREGROUND ) )
+//5.从 DirectInput 设备上的轮询对象中检索数据,如果设备不需要轮询,则调用此方法无效。如果不定期轮询需要轮询的设备,则不会从该设备接收新数据。调用此方法会导致 DirectInput 更新设备状态、生成输入事件(如果启用了缓冲数据)并设置通知事件(如果启用了通知)。
+g_pMouse->Poll();
+
+//6. 获得对输入设备的访问
+ hr = g_pMouse->Acquire();
+        while( hr == DIERR_INPUTLOST )
+            hr = g_pMouse->Acquire();
+
+//7. 从设备中检索即时数据。
+g_pMouse->GetDeviceState( sizeof( MouseState ), &ms ) 
+/*
+cbData
+Size of the buffer in the lpvData parameter, in bytes.
+lpvData
+Address of a structure that receives the current state of the device. The format of the data is established by a prior call to the IDirectInputDevice8::SetDataFormat method.
+*/
+
+```
+The five predefined data formats require corresponding device state structures according to the following table:
+
+| Data format |State structure|
+|---|---|
+c_dfDIMouse	|DIMOUSESTATE
+c_dfDIMouse2	|DIMOUSESTATE2
+c_dfDIKeyboard|	array of 256 bytes
+c_dfDIJoystick|	DIJOYSTATE
+c_dfDIJoystick2|	DIJOYSTATE2

+ 13 - 0
gm/gm/background/Hook/opMessage.h

@@ -0,0 +1,13 @@
+#ifndef __OP_MESSAGE_H_
+#define __OP_MESSAGE_H_
+#include <WinUser.h>
+#define OP_MAKE_MESSAGE(msg) (WM_USER + msg)
+#define OP_WM_MOUSEMOVE (WM_USER + WM_MOUSEMOVE)
+#define OP_WM_LBUTTONUP (WM_USER + WM_LBUTTONUP)
+#define OP_WM_LBUTTONDOWN (WM_USER + WM_LBUTTONDOWN)
+#define OP_WM_MBUTTONDOWN (WM_USER + WM_MBUTTONDOWN)
+#define OP_WM_MBUTTONUP (WM_USER + WM_MBUTTONUP)
+#define OP_WM_RBUTTONDOWN (WM_USER + WM_RBUTTONDOWN)
+#define OP_WM_RBUTTONUP (WM_USER + WM_RBUTTONUP)
+#define OP_WM_MOUSEWHEEL (WM_USER + WM_MOUSEWHEEL)
+#endif

+ 94 - 0
gm/gm/background/display/IDisplay.cpp

@@ -0,0 +1,94 @@
+//#include "stdafx.h"
+#include "IDisplay.h"
+#include "./core/globalVar.h"
+#include "./core/helpfunc.h"
+IDisplay::IDisplay()
+	:_hwnd(NULL), _shmem(nullptr), _pmutex(nullptr),
+	_bind_state(0), _width(0), _height(0),
+	_client_x(0), _client_y(0)
+{
+
+}
+
+
+IDisplay::~IDisplay()
+{
+	bind_release();
+	_bind_state = 0;
+}
+
+long IDisplay::Bind(HWND hwnd, long flag) {
+	//step 1 check window exists
+	if (!::IsWindow(hwnd)) {
+		return 0;
+	}
+	_hwnd = hwnd;
+	//step 2. 准备资源
+	bind_init();
+	//step 3. 调用特定的绑定函数
+
+	if (BindEx(hwnd, flag) == 1) {
+		_bind_state = 1;
+	}
+	else {
+		bind_release();
+		_bind_state = 0;
+	}
+		
+
+	return _bind_state;
+
+}
+
+long IDisplay::UnBind() {
+	//setlog("UnBind(");
+	if (_bind_state) {
+		UnBindEx();
+	}
+	bind_release();
+	_bind_state = 0;
+	return 1;
+}
+
+long IDisplay::bind_init() {
+	int res_size = 0;
+	RECT rc;
+	assert(::IsWindow(_hwnd));
+	::GetWindowRect(_hwnd, &rc);
+	res_size = (rc.right - rc.left) * (rc.bottom - rc.top) * 4+sizeof(FrameInfo);
+	wsprintf(_shared_res_name, SHARED_RES_NAME_FORMAT, _hwnd);
+	wsprintf(_mutex_name, MUTEX_NAME_FORMAT, _hwnd);
+	//setlog(L"mem=%s mutex=%s", _shared_res_name, _mutex_name);
+	//bind_release();
+	try {
+		_shmem = new sharedmem();
+		_shmem->open_create(_shared_res_name, res_size);
+		_pmutex = new promutex();
+		_pmutex->open_create(_mutex_name);
+	}
+	catch (std::exception& e) {
+		setlog("bkdisplay::bind_init() %s exception:%s", _shared_res_name, e.what());
+	}
+
+	return 0;
+}
+
+long IDisplay::bind_release() {
+	SAFE_DELETE(_shmem);
+	SAFE_DELETE(_pmutex);
+
+	_hwnd = NULL;
+	//_image_data = nullptr;
+	return 0;
+}
+
+void IDisplay::getFrameInfo(FrameInfo& info) {
+	_pmutex->lock();
+	memcpy(&info, _shmem->data<uchar>(), sizeof(FrameInfo));
+	_pmutex->unlock();
+}
+
+//byte* bkdisplay::get_data() {
+//	return _shmem->data<byte>();
+//}
+

+ 68 - 0
gm/gm/background/display/IDisplay.h

@@ -0,0 +1,68 @@
+#ifndef __IDISPLAY_H_
+#define __IDISPLAY_H_
+#include <exception>
+#include "./include/promutex.h"
+#include "./include/sharedmem.h"
+#include "frameInfo.h"
+struct Image;
+class IDisplay
+{
+public:
+	IDisplay();
+	 ~IDisplay();
+	//bind window
+	long Bind(HWND hwnd, long flag);
+	//unbind window
+	long UnBind();
+	//unbind window
+	//virtual long UnBind(HWND hwnd) = 0;
+	virtual bool requestCapture(int x1, int y1, int w, int h, Image& img) = 0;
+	
+
+	promutex* get_mutex() {
+		return _pmutex;
+	}
+
+	long get_height() {
+		return _height;
+	}
+
+	long get_width() {
+		return _width;
+	}
+	void getFrameInfo(FrameInfo& info);
+private:
+	
+	long bind_init();
+	
+	long bind_release();
+
+	long _bind_state;
+protected:
+	virtual long BindEx(HWND hwnd, long flag)=0;
+	virtual long UnBindEx() = 0;
+
+	HWND _hwnd;
+
+	sharedmem* _shmem;
+	
+	promutex* _pmutex;
+
+	wchar_t _shared_res_name[256];
+
+	wchar_t _mutex_name[256];
+
+	//
+	int _render_type;
+
+	long _width;
+	long _height;
+
+	int _client_x, _client_y;
+	//need capture rect
+	//RECT rect;
+	
+};
+
+#endif
+

+ 17 - 0
gm/gm/background/display/frameInfo.h

@@ -0,0 +1,17 @@
+#ifndef __FRAME_INFO_H_
+#define __FRAME_INFO_H_
+#pragma pack(1)
+struct FrameInfo {
+	unsigned __int64 hwnd;
+	unsigned __int32 frameId;
+	unsigned __int32 time;
+	unsigned __int32 width;
+	unsigned __int32 height;
+	unsigned __int32 chk;
+	void fmtChk() {
+		chk = (hwnd >> 32) ^ (hwnd & 0xffffffffull) ^ frameId ^ time ^ width ^ height;
+	}
+	
+};
+#pragma pack()
+#endif // !__FRAME_INFO_H_

+ 307 - 0
gm/gm/background/display/opDxGL.cpp

@@ -0,0 +1,307 @@
+
+//#include "stdafx.h"
+
+#include "opDxGL.h"
+#include "./core/globalVar.h"
+#include "./core/helpfunc.h"
+#include "./core/opEnv.h"
+#include <exception>
+#include "BlackBone/Process/Process.h"
+#include "BlackBone/Process/RPC/RemoteFunction.hpp"
+
+#include "./include/Image.hpp"
+
+#include <sstream>
+opDxGL::opDxGL() :IDisplay(),m_opPath(opEnv::getBasePath())
+{
+}
+
+
+opDxGL::~opDxGL()
+{
+	//do clear
+	UnBindEx();
+}
+
+
+long opDxGL::BindEx(HWND hwnd, long render_type) {
+	//setlog("BindEx");
+	_hwnd = hwnd;
+	long bind_ret = 0;
+	if (render_type == RDT_GL_NOX) {
+		bind_ret = BindNox(hwnd, render_type);
+	}
+	else {
+		_render_type = render_type;
+		RECT rc;
+		//获取客户区大小
+		::GetClientRect(hwnd, &rc);
+		_width = rc.right - rc.left;
+		_height = rc.bottom - rc.top;
+		//bind_init();
+		if (render_type == RDT_GL_NOX) {
+		}
+		DWORD id;
+		::GetWindowThreadProcessId(_hwnd, &id);
+
+
+
+		//attach 进程
+		blackbone::Process proc;
+		NTSTATUS hr;
+
+		hr = proc.Attach(id);
+
+
+		if (NT_SUCCESS(hr)) {
+			wstring dllname = opEnv::getOpName();
+			//检查是否与插件相同的32/64位,如果不同,则使用另一种dll
+			BOOL is64 = proc.modules().GetMainModule()->type == blackbone::eModType::mt_mod64;
+			if (is64 != OP64) {
+				dllname = is64 ? L"op_x64.dll" : L"op_x86.dll";
+			}
+
+			bool injected = false;
+			//判断是否已经注入
+			auto _dllptr = proc.modules().GetModule(dllname);
+			auto mods = proc.modules().GetAllModules();
+			if (_dllptr) {
+				injected = true;
+			}
+			else {
+				wstring opFile = m_opPath + L"\\" + dllname;
+				if (::PathFileExistsW(opFile.data())) {
+					auto iret = proc.modules().Inject(opFile);
+					injected = (iret ? true : false);
+				}
+				else {
+					setlog(L"file:<%s> not exists!", opFile.data());
+				}
+
+			}
+			if (injected) {
+				//setlog("before MakeRemoteFunction");
+				using my_func_t = long(__stdcall*)(HWND, int);
+				auto pSetXHook = blackbone::MakeRemoteFunction<my_func_t>(proc, dllname, "SetDisplayHook");
+				if (pSetXHook) {
+					//setlog("after MakeRemoteFunction");
+					auto cret = pSetXHook(hwnd, render_type);
+					//setlog("after pSetXHook");
+					bind_ret = cret.result();
+					//setlog("after result");
+				}
+				else {
+					//setlog(L"remote function not found.");
+				}
+			}
+			else {
+				setlog(L"Inject false.");
+			}
+		}
+		else {
+			setlog(L"attach false.");
+		}
+		
+		proc.Detach();
+		//setlog("after Detach");
+	}
+
+	if (bind_ret == -1) {
+		setlog("UnknownError");
+	}
+	else if (bind_ret == -2) {
+		setlog("NotSupportedError");
+	}
+	else if (bind_ret == -3) {
+		setlog("ModuleNotFoundError");
+	}
+	return bind_ret;
+}
+//long bkdo::UnBind(HWND hwnd) {
+//	_hwnd = hwnd;
+//	_bind_state = 1;
+//	return UnBind();
+//}
+
+long opDxGL::UnBindEx() {
+	//setlog("bkdo::UnBindEx()");
+	if (_render_type == RDT_GL_NOX)
+		return UnBindNox();
+	DWORD id;
+	::GetWindowThreadProcessId(_hwnd, &id);
+
+	//attach 进程s
+	blackbone::Process proc;
+	NTSTATUS hr;
+	//setlog("bkdo::Attach");
+	hr = proc.Attach(id);
+
+	if (NT_SUCCESS(hr)) {
+		wstring dllname =  opEnv::getOpName();
+		//检查是否与插件相同的32/64位,如果不同,则使用另一种dll
+		BOOL is64 = proc.modules().GetMainModule()->type == blackbone::eModType::mt_mod64;
+		if (is64 != OP64) {
+			dllname = is64 ? L"op_x64.dll" : L"op_x86.dll";
+		}
+		//setlog(L"bkdo::dllname=%s",dllname);
+		using my_func_t = long(__stdcall*)(void);
+		auto pUnXHook = blackbone::MakeRemoteFunction<my_func_t>(proc, dllname, "ReleaseDisplayHook");
+		if (pUnXHook) {
+			//setlog(L"bkdo::pUnXHook");
+			pUnXHook();
+			//BOOL fret = ::FreeLibrary((HMODULE)proc.modules().GetModule(dllname)->baseAddress);
+			//if (!fret)setlog("fret=%d", fret);
+			/*proc.modules().RemoveManualModule(dllname,
+				is64 ? blackbone::eModType::mt_mod64 : blackbone::eModType::mt_mod32);*/
+		}
+		else {
+			setlog(L"get unhook ptr false.");
+		}
+	}
+	else {
+		setlog("blackbone::MakeRemoteFunction false,errcode:%X,pid=%d,hwnd=%d", hr, id, _hwnd);
+	}
+	//setlog(L"bkdo::Detach");
+	proc.Detach();
+	//bind_release();
+	return 1;
+}
+
+long opDxGL::BindNox(HWND hwnd, long render_type) {
+	_render_type = render_type;
+	_hwnd = hwnd;
+	RECT rc;
+	//获取客户区大小
+	::GetClientRect(hwnd, &rc);
+	_width = rc.right - rc.left;
+	_height = rc.bottom - rc.top;
+	//bind_init();
+
+
+
+	//attach 进程
+	blackbone::Process proc;
+	NTSTATUS hr = -1;
+
+
+	wstring dllname = L"op_x64.dll";
+
+
+	hr = proc.Attach(L"NoxVMHandle.exe");
+
+	long bind_ret = 0;
+
+	if (NT_SUCCESS(hr)) {
+		/*_process.Resume();*/
+		bool injected = false;
+		//判断是否已经注入
+		auto _dllptr = proc.modules().GetModule(dllname);
+		auto mods = proc.modules().GetAllModules();
+		if (_dllptr) {
+			injected = true;
+		}
+		else {
+			wstring opFile = m_opPath + L"\\" + dllname;
+			if (::PathFileExistsW(opFile.data())) {
+				auto iret = proc.modules().Inject(opFile);
+				injected = (iret ? true : false);
+			}
+			else {
+				setlog(L"file:<%s> not exists!", opFile.data());
+			}
+		}
+		if (injected) {
+			using my_func_t = long(__stdcall*)(HWND, int);
+			auto pSetXHook = blackbone::MakeRemoteFunction<my_func_t>(proc, dllname, "SetDisplayHook");
+			if (pSetXHook) {
+				auto cret = pSetXHook(hwnd, render_type);
+				bind_ret = cret.result();
+			}
+			else {
+				setlog(L"remote function not found.");
+			}
+		}
+		else {
+			setlog(L"Inject false.");
+		}
+
+
+
+	}
+	else {
+		setlog(L"attach false.");
+	}
+	proc.Detach();
+
+
+	return bind_ret;
+}
+
+long opDxGL::UnBindNox() {
+
+	//attach 进程
+	blackbone::Process proc;
+	NTSTATUS hr;
+
+	hr = proc.Attach(L"NoxVMHandle.exe");
+	wstring dllname = L"op_x64.dll";
+
+
+	if (NT_SUCCESS(hr)) {
+
+		using my_func_t = long(__stdcall*)(void);
+		auto pUnXHook = blackbone::MakeRemoteFunction<my_func_t>(proc, dllname, "ReleaseDisplayHook");
+		if (pUnXHook) {
+			pUnXHook();
+
+			/*BOOL fret = ::FreeLibrary((HMODULE)proc.modules().GetModule(dllname)->baseAddress);
+			if (!fret)setlog("fret=%d", fret);*/
+		}
+		else {
+			setlog(L"get unhook ptr false.");
+		}
+	}
+	else {
+		setlog("blackbone::MakeRemoteFunction false,errcode:%Xhwnd=%d", hr, _hwnd);
+	}
+
+	proc.Detach();
+
+	return 1;
+}
+
+
+
+bool opDxGL::requestCapture(int x1, int y1, int w, int h, Image& img) {
+	img.create(w, h);
+	_pmutex->lock();
+	uchar* const ppixels = _shmem->data<byte>() + sizeof(FrameInfo);
+	FrameInfo* pInfo = (FrameInfo*)_shmem->data<byte>();
+	static bool first = true;
+	if (first&&(pInfo->width != _width || pInfo->height != _height)) {
+		first = false;
+		std::wstringstream ss(std::wstringstream::in | std::wstringstream::out);
+		ss << (*pInfo);
+		setlog(L"error pInfo->width != _width || pInfo->height != _height\nframe info:\n%s", ss.str().data());
+	
+	}
+
+
+	if (GET_RENDER_TYPE(_render_type) == RENDER_TYPE::DX) {//NORMAL
+
+		for (int i = 0; i < h; i++) {
+			memcpy(img.ptr<uchar>(i), ppixels + (i + y1) * 4 * _width + x1 * 4, 4 * w);
+		}
+	}
+	else {
+
+		for (int i = 0; i < h; i++) {
+			memcpy(img.ptr<uchar>(i), ppixels + (_height - 1 - i - y1) * _width * 4 + x1 * 4, 4 * w);
+		}
+	}
+
+
+	_pmutex->unlock();
+	return true;
+}
+

+ 31 - 0
gm/gm/background/display/opDxGL.h

@@ -0,0 +1,31 @@
+#pragma once
+#ifndef __DXBACKGROUND_H_
+#define __DXBACKGROUND_H_
+
+#include "IDisplay.h"
+struct Image;
+class opDxGL : public IDisplay
+{
+public:
+	opDxGL();
+	~opDxGL();
+	//1
+	long BindEx(HWND hwnd, long render_type) override;
+
+	/*long UnBind(HWND hwnd);*/
+
+	long UnBindEx() override;
+
+	virtual bool requestCapture(int x1, int y1, int w, int h, Image &img) override;
+
+	//nox mode
+	long BindNox(HWND hwnd, long render_type);
+	//
+	long UnBindNox();
+
+private:
+	//blackbone::Process _process;
+	wstring m_opPath;
+};
+
+#endif

+ 252 - 0
gm/gm/background/display/opGDI.cpp

@@ -0,0 +1,252 @@
+//#include "stdafx.h"
+#include "opGDI.h"
+
+#include <atlimage.h>
+
+#include <fstream>
+
+#include "../../winapi/WinApi.h"
+#include "./include/Image.hpp"
+#include "globalVar.h"
+#include "helpfunc.h"
+opGDI::opGDI() {
+  _render_type = 0;
+  dx_ = 0;
+  dy_ = 0;
+  // 4*2^22=16*2^20=16MB
+  //_image_data = new byte[MAX_IMAGE_WIDTH*MAX_IMAGE_WIDTH * 4];
+}
+
+opGDI::~opGDI() {
+  // SAFE_DELETE_ARRAY(_image_data);
+}
+
+long opGDI::BindEx(HWND hwnd, long render_type) {
+  if (!::IsWindow(hwnd)) return 0;
+  _hwnd = hwnd;
+  _render_type = render_type;
+
+  if (render_type == RDT_NORMAL) {
+    RECT rc, rc2;
+    ::GetWindowRect(_hwnd, &rc);
+    ::GetClientRect(hwnd, &rc2);
+
+    _width = rc2.right - rc2.left;
+    _height = rc2.bottom - rc2.top;
+    POINT pt = {0};
+    ::ClientToScreen(hwnd, &pt);
+    dx_ = pt.x - rc.left;
+    dy_ = pt.y - rc.top;
+    _hdc = ::GetDC(NULL);
+  } else {  // client size
+    RECT rc, rc2;
+    ::GetWindowRect(_hwnd, &rc);
+    ::GetClientRect(hwnd, &rc2);
+    _width = rc2.right - rc2.left;
+    _height = rc2.bottom - rc2.top;
+    POINT pt = {0};
+    ::ClientToScreen(hwnd, &pt);
+    dx_ = pt.x - rc.left;
+    dy_ = pt.y - rc.top;
+    /*setlog("dx=%d dy=%d", dx_, dy_);*/
+    if (_render_type == RDT_GDI) {
+      _hdc = ::GetDC(_hwnd);
+      HWND topHwnd = WinApi::GetTopWindowSp(_hwnd);
+      long dwExStyle = 0;
+      if (GetPropA(topHwnd, "opstyle_flag")) {
+        dwExStyle = GetWindowLongA(topHwnd, GWL_EXSTYLE);
+      } else {
+        dwExStyle = GetWindowLongA(topHwnd, GWL_EXSTYLE);
+        SetPropA(topHwnd, "opstyle", (HANDLE)dwExStyle);
+        SetPropA(topHwnd, "opstyle_flag", (HANDLE)HANDLE_FLAG_INHERIT);
+      }
+      // dmIsWindowTransParent((int)InfoStruct, (int)topHwnd, (int)&v44,
+      // (int)&v42, (int)&v45);
+      SetWindowLongA(topHwnd, GWL_EXSTYLE, dwExStyle | WS_EX_LAYERED);
+      // SetWindowTransparent((int)InfoStruct, (int)topHwnd, 16711935, 0, 1);
+      UpdateWindow(topHwnd);
+
+    } else if (RDT_GDI_DX2 == render_type) {
+      _hdc = ::GetDC(_hwnd);
+      _device_caps = GetDeviceCaps(_hdc, BITSPIXEL);
+    } else {
+      HWND dx2TopHwnd = WinApi::GetTopWindowSp(_hwnd);
+      GetPropA(dx2TopHwnd, "opstyle");
+      long dx2ExStyle = 0;
+      if (GetPropA(dx2TopHwnd, "opstyle_flag")) {
+        dx2ExStyle = GetWindowLongA(dx2TopHwnd, GWL_EXSTYLE);
+      } else {
+        dx2ExStyle = GetWindowLongA(dx2TopHwnd, GWL_EXSTYLE);
+        SetPropA(dx2TopHwnd, "opstyle", (HANDLE)dx2ExStyle);
+        SetPropA(dx2TopHwnd, "opstyle_flag", (HANDLE)HANDLE_FLAG_INHERIT);
+      }
+      // dmIsWindowTransParent((int)InfoStruct, (int)dx2TopHwnd, (int)&v45,
+      // (int)&v42, (int)&v44);
+      SetWindowLongA(dx2TopHwnd, GWL_EXSTYLE, dx2ExStyle | WS_EX_LAYERED);
+      // SetWindowTransparent((int)InfoStruct, (int)dx2TopHwnd, 0, 255, 2);
+      UpdateWindow(dx2TopHwnd);
+      // InfoStruct[11] = 3;
+
+      _hdc = ::GetDC(_hwnd);
+    }
+  }
+
+  if (_hdc == NULL) {
+    setlog("hdc == NULL", _hdc);
+    return 0;
+  }
+
+  //创建一个与指定设备兼容的内存设备上下文环境
+  _hmdc = CreateCompatibleDC(_hdc);
+  if (_hmdc == NULL) {
+    setlog("CreateCompatibleDC false");
+    return -2;
+  }
+
+  // updata_screen();
+  return 1;
+}
+
+long opGDI::UnBindEx() {
+  // setlog("bkgdi::UnBindEx()");
+  _hbmpscreen = (HBITMAP)SelectObject(_hmdc, _hbmp_old);
+  // delete[dwLen_2]hDib;
+  if (_hdc) DeleteDC(_hdc);
+  _hdc = NULL;
+  if (_hmdc) DeleteDC(_hmdc);
+  _hmdc = NULL;
+
+  if (_hbmpscreen) DeleteObject(_hbmpscreen);
+  _hbmpscreen = NULL;
+  // if (_hbmp_old)DeleteObject(_hbmp_old); _hbmp_old = NULL;
+  return 1;
+}
+
+bool opGDI::requestCapture(int x1, int y1, int w, int h, Image& img) {
+  // step 1.判断 窗口是否存在
+  if (!::IsWindow(_hwnd)) return 0;
+  img.create(w, h);
+  if (_render_type == RDT_NORMAL) {  // normal 拷贝的大小为实际需要的大小
+    //
+    /*	int w = rect.right - rect.left;
+            int h = rect.bottom - rect.top;*/
+    _hbmpscreen = CreateCompatibleBitmap(
+        _hdc, w, h);  //创建与指定的设备环境相关的设备兼容的位图
+    _hbmp_old = (HBITMAP)SelectObject(
+        _hmdc, _hbmpscreen);  //选择一对象到指定的设备上下文环境中
+
+    _bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
+    _bfh.bfSize = _bfh.bfOffBits + w * h * 4;
+    _bfh.bfType = static_cast<WORD>(0x4d42);
+
+    _bih.biBitCount = 32;  //每个像素字节大小
+    _bih.biCompression = BI_RGB;
+    _bih.biHeight = h;  //高度
+    _bih.biPlanes = 1;
+    _bih.biSize = sizeof(BITMAPINFOHEADER);
+    _bih.biSizeImage = w * h * 4;  //图像数据大小
+    _bih.biWidth = w;              //宽度
+
+    //对指定的源设备环境区域中的像素进行位块(bit_block)转换
+
+    RECT rc;
+    ::GetWindowRect(_hwnd, &rc);
+    // setlog("rect left =%d top =%d, dx =%d, dy = %d", rc.left, rc.top, dx_,
+    // dy_);
+    int src_x = x1 + rc.left + dx_;
+    int src_y = y1 + rc.top + dy_;
+    if (BitBlt(_hmdc, 0, 0, w, h, _hdc, src_x, src_y, SRCCOPY)) {
+      // ok
+    } else {
+      setlog("error in bitbit");
+    }
+
+    //函数获取指定兼容位图的位,然后将其作一个DIB—设备无关位图(Device-Independent
+    // Bitmap)使用的指定格式复制到一个缓冲区中 _pmutex->lock();
+    uchar* pshare = _shmem->data<byte>();
+    fmtFrameInfo(pshare, _hwnd, w, h);
+    GetDIBits(_hmdc, _hbmpscreen, 0L, (DWORD)h, pshare + sizeof(FrameInfo),
+              (LPBITMAPINFO)&_bih, (DWORD)DIB_RGB_COLORS);
+
+    //_pmutex->unlock();
+    if (_hbmpscreen) DeleteObject(_hbmpscreen);
+    _hbmpscreen = NULL;
+
+    //将数据拷贝到目标注意实际数据是反的
+
+    for (int i = 0; i < h; i++) {
+      memcpy(img.ptr<uchar>(i), _shmem->data<byte>() + (h - 1 - i) * 4 * w,
+             4 * w);
+    }
+  } else if (RDT_GDI_DX2 == _render_type) {
+    ATL::CImage image;
+    image.Create(w, h, _device_caps);
+    BitBlt(image.GetDC(), x1, y1, w, h, _hdc, 0, 0, SRCCOPY);
+    img.read(&image);
+    image.ReleaseDC();
+  } else {  // gdi ... 由于printwindow 函数的原因
+            // 截取大小为实际的窗口大小,在后续的处理中,需要转化成客户区大小
+    //
+    RECT rc;
+    ::GetWindowRect(_hwnd, &rc);
+    int ww = rc.right - rc.left;
+    int wh = rc.bottom - rc.top;
+    // setlog("_w w=%d %d _h h=%d %d,dx=%d dy=%d", _width, w, _height, h, dx_,
+    // dy_);
+    _hbmpscreen = CreateCompatibleBitmap(
+        _hdc, ww, wh);  //创建与指定的设备环境相关的设备兼容的位图
+    _hbmp_old = (HBITMAP)SelectObject(
+        _hmdc, _hbmpscreen);  //选择一对象到指定的设备上下文环境中
+
+    _bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
+    _bfh.bfSize = _bfh.bfOffBits + ww * wh * 4;
+    _bfh.bfType = static_cast<WORD>(0x4d42);
+
+    _bih.biBitCount = 32;  //每个像素字节大小
+    _bih.biCompression = BI_RGB;
+    _bih.biHeight = wh;  //高度
+    _bih.biPlanes = 1;
+    _bih.biSize = sizeof(BITMAPINFOHEADER);
+    _bih.biSizeImage = ww * wh * 4;  //图像数据大小
+    _bih.biWidth = ww;               //宽度
+
+    //对指定的源设备环境区域中的像素进行位块(bit_block)转换
+
+    if (_render_type == RDT_GDI) {
+      ::PrintWindow(_hwnd, _hmdc, 0);
+
+    } else {
+      ::UpdateWindow(_hwnd);
+      //::RedrawWindow(_hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE |
+      //:RDW_ALLCHILDREN | RDW_FRAME);
+      ::PrintWindow(_hwnd, _hmdc, 0);
+    }
+    //函数获取指定兼容位图的位,然后将其作一个DIB—设备无关位图(Device-Independent
+    // Bitmap)使用的指定格式复制到一个缓冲区中 _pmutex->lock();
+    uchar* pshare = _shmem->data<byte>();
+    fmtFrameInfo(pshare, _hwnd, w, h);
+    GetDIBits(_hmdc, _hbmpscreen, 0L, (DWORD)wh, pshare + sizeof(FrameInfo),
+              (LPBITMAPINFO)&_bih, (DWORD)DIB_RGB_COLORS);
+
+    if (_hbmpscreen) DeleteObject(_hbmpscreen);
+    _hbmpscreen = NULL;
+
+    //将数据拷贝到目标注意实际数据是反的(注意偏移)
+    auto ppixels = _shmem->data<byte>() + sizeof(FrameInfo);
+    for (int i = 0; i < h; i++) {
+      memcpy(img.ptr<uchar>(i),
+             ppixels + (wh - 1 - i - y1 - dy_) * 4 * ww + (x1 + dx_) * 4,
+             4 * w);
+    }
+  }
+  return 1;
+}
+void opGDI::fmtFrameInfo(void* dst, HWND hwnd, int w, int h) {
+  m_frameInfo.hwnd = (unsigned __int64)hwnd;
+  m_frameInfo.frameId++;
+  m_frameInfo.time = ::GetTickCount();
+  m_frameInfo.width = w;
+  m_frameInfo.height = h;
+  m_frameInfo.fmtChk();
+  memcpy(dst, &m_frameInfo, sizeof(m_frameInfo));
+}

+ 43 - 0
gm/gm/background/display/opGDI.h

@@ -0,0 +1,43 @@
+#pragma once
+#ifndef __BKDISPLAY_H_
+#define __BKDISPLAY_H_
+#include <thread>
+#include "optype.h"
+#include "IDisplay.h"
+struct Image;
+class opGDI:public IDisplay
+{
+public:
+	opGDI();
+	~opGDI();
+	//绑定
+	long BindEx(HWND _hwnd, long render_type) override;
+	//long UnBind(HWND hwnd);
+	//解绑
+	long UnBindEx() override;
+	
+	
+	//long updata_screen();
+
+	//byte* get_data() override;
+
+	virtual bool requestCapture(int x1, int y1, int w, int h, Image& img)override;
+	
+private:
+	//设备句柄
+	HDC _hdc = NULL;
+	int _device_caps = 0;
+	HDC _hmdc = NULL;
+	//位图句柄
+	HBITMAP _hbmpscreen = NULL;
+	HBITMAP _hbmp_old = NULL;
+	//bmp 文件头
+	BITMAPFILEHEADER _bfh = { 0 };
+	BITMAPINFOHEADER _bih = { 0 };//位图信息头
+	int dx_, dy_;//去除标题栏
+	//bytearray temp_src;
+	FrameInfo m_frameInfo;
+	void fmtFrameInfo(void* dst,HWND hwnd, int w, int h);
+};
+
+#endif

+ 210 - 0
gm/gm/background/keypad/Bkkeypad.cpp

@@ -0,0 +1,210 @@
+//#include "stdafx.h"
+#include "Bkkeypad.h"
+//#include "globalVar.h"
+//#include "helpfunc.h"
+//
+//static uint oem_code(uint key){
+//	short code[256] = { 0 };
+//	code['q'] = 0x10; code['a'] = 0x1e;
+//	code['w'] = 0x11; code['s'] = 0x1f;
+//	code['e'] = 0x12; code['d'] = 0x20;
+//	code['r'] = 0x13; code['f'] = 0x21;
+//	code['t'] = 0x14; code['g'] = 0x22;
+//	code['y'] = 0x15; code['h'] = 0x23;
+//	code['u'] = 0x16; code['j'] = 0x24;
+//	code['i'] = 0x17; code['k'] = 0x25;
+//	code['o'] = 0x18; code['l'] = 0x26;
+//	code['p'] = 0x19; code[':'] = 0x27; code[';'] = 0x27;
+//	
+//	code['z'] = 0x2c;
+//	code['x'] = 0x2d; 
+//	code['c'] = 0x2e; 
+//	code['v'] = 0x2f; 
+//	code['b'] = 0x30; 
+//	code['n'] = 0x31; 
+//	code['m'] = 0x32;
+//	return code[key & 0xffu];
+//	
+//}
+//
+bkkeypad::bkkeypad():_hwnd(0),_mode(0)
+{
+}
+//
+//
+bkkeypad::~bkkeypad()
+{
+	UnBind();
+}
+//
+//long bkkeypad::Bind(HWND hwnd, long mode) {
+//	if (!::IsWindow(hwnd))
+//		return 0;
+//	_hwnd = hwnd;
+//	_mode = mode;
+//	return 1;
+//}
+//
+long bkkeypad::UnBind() {
+	_hwnd = NULL;
+	_mode = 0;
+	return 1;
+}
+//
+//long bkkeypad::GetKeyState(long vk_code) {
+//	vk_code = toupper(vk_code);
+//	return 0x8000 & ::GetAsyncKeyState(vk_code);
+//}
+//
+//long bkkeypad::KeyDown(long vk_code) {
+//	long ret = 0;
+//	vk_code=toupper(vk_code);
+//	
+//	switch (_mode) {
+//	case INPUT_TYPE::IN_NORMAL:
+//	{
+//		POINT pt;
+//	
+//	
+//		INPUT Input = { 0 };
+//		Input.type = INPUT_KEYBOARD;
+//		Input.ki.wVk = vk_code;
+//		Input.ki.dwFlags = 0;
+//		
+//		/*The function returns the number of events that it successfully inserted into the keyboard or mouse input stream.
+//		If the function returns zero, the input was already blocked by another thread.
+//		To get extended error information, call GetLastError.
+//		This function fails when it is blocked by UIPI.
+//		Note that neither GetLastError nor the return value will indicate the failure was caused by UIPI blocking.
+//		*/
+//		ret = ::SendInput(1, &Input, sizeof(INPUT));
+//		break;
+//	}
+//
+//	case INPUT_TYPE::IN_WINDOWS: {
+//		/*Specification of WM_KEYDOWN :*/
+//
+//		/*wParam
+//
+//			Specifies the virtual - key code of the nonsystem key.
+//		lParam
+//			Specifies the repeat count, scan code, extended - key flag, context code,
+//			previous key - state flag, 
+//			and transition - state flag, as shown in the following table.
+//			0 - 15
+//			Specifies the repeat count for the current message.The value is 
+//			the number of times the keystroke is 
+//			autorepeated as a result of the user holding down the key.If the 
+//			keystroke is held long enough, multiple messages are sent.However, 
+//			the repeat count is not cumulative.
+//			16 - 23
+//			Specifies the scan code.The value depends on the OEM.
+//			24
+//			Specifies whether the key is an extended key, such as the 
+//			right - hand ALT and CTRL keys that 
+//			appear on an enhanced 101 - or 102 - key keyboard.The value 
+//			is 1 if it is an extended key; otherwise, it is 0.
+//			25 - 28
+//			Reserved; do not use.
+//			29
+//			Specifies the context code.The value is always 0 for a WM_KEYDOWN message.
+//			30
+//			Specifies the previous key state.The value is 1 if the key 
+//			is down before the message is sent, or it is zero if the key is up.
+//			31
+//			Specifies the transition state.The value is always zero for a WM_KEYDOWN message.*/
+//	
+//		DWORD lparam = 1u;
+//		if (vk_code == VK_RCONTROL)
+//			lparam |= 1u << 24;
+//		lparam |= oem_code(vk_code) << 16;
+//		ret = ::PostMessageW(_hwnd, WM_KEYDOWN, vk_code, lparam);
+//		//ret = ::SendMessageW(_hwnd, WM_KEYDOWN, vk_code, 0);
+//		if (ret == 0)setlog("error code=%d", GetLastError());
+//		break;
+//	}
+//	}
+//	
+//	
+//	return ret;
+//}
+//
+//long bkkeypad::KeyUp(long vk_code) {
+//	long ret = 0;
+//	vk_code = toupper(vk_code);
+//	switch (_mode) {
+//	case INPUT_TYPE::IN_NORMAL:
+//	{
+//		POINT pt;
+//
+//
+//		INPUT Input = { 0 };
+//		Input.type = INPUT_KEYBOARD;
+//		Input.ki.wVk = vk_code;
+//		Input.ki.dwFlags = KEYEVENTF_KEYUP;
+//
+//		/*The function returns the number of events that it successfully inserted into the keyboard or mouse input stream.
+//		If the function returns zero, the input was already blocked by another thread.
+//		To get extended error information, call GetLastError.
+//		This function fails when it is blocked by UIPI.
+//		Note that neither GetLastError nor the return value will indicate the failure was caused by UIPI blocking.
+//		*/
+//		ret = ::SendInput(1, &Input, sizeof(INPUT));
+//		break;
+//	}
+//
+//	case INPUT_TYPE::IN_WINDOWS: {
+//		/*Specification of WM_KEYUP
+//		wParam
+//			Specifies the virtual - key code of the nonsystem key.
+//			lParam
+//			Specifies the repeat count, scan code, extended - key flag, context code,
+//			previous key - state flag, and transition - state flag, as shown in the following table.
+//			0 - 15
+//			Specifies the repeat count for the current message.The value is the number of times the keystroke is
+//			autorepeated as a result of the user holding down the key.
+//			The repeat count is always one for a WM_KEYUP message.
+//			16 - 23
+//			Specifies the scan code.The value depends on the OEM.
+//			24
+//			Specifies whether the key is an extended key, such as the right - hand ALT and CTRL keys that
+//			appear on an enhanced 101 - or 102 - key keyboard.The value is 1 if it is an extended key; otherwise, it is 0.
+//			25 - 28
+//			Reserved; do not use.
+//			29
+//			Specifies the context code.The value is always 0 for a WM_KEYUP message.
+//			30
+//			Specifies the previous key state.The value is always 1 for a WM_KEYUP message.
+//			31
+//			Specifies the transition state.The value is always 1 for a WM_KEYUP message.*/
+//		//ret = ::SendMessageW(_hwnd, WM_KEYUP, vk_code, 0);
+//		DWORD lparam = 1u;
+//		if (vk_code == VK_RCONTROL)lparam |= 1u << 24;
+//		lparam |= oem_code(vk_code) << 16;
+//		lparam |= 1u << 30;
+//		lparam |= 1u << 31;
+//		ret = ::PostMessageW(_hwnd, WM_KEYUP, vk_code, lparam);
+//		if (ret == 0)setlog("error2 code=%d", GetLastError());
+//		break;
+//	}
+//	}
+//
+//
+//	return ret;
+//}
+//
+//long bkkeypad::WaitKey(long vk_code, long time_out) {
+//	auto deadline = ::GetTickCount() + time_out;
+//	while (::GetTickCount() < deadline) {
+//		if (GetKeyState(vk_code))
+//			return 1;
+//		::Sleep(1);
+//	}
+//	return 0;
+//}
+//
+//long bkkeypad::KeyPress(long vk_code) {
+//	KeyDown(vk_code);
+//	
+//	return KeyUp(vk_code);
+//}

+ 32 - 0
gm/gm/background/keypad/Bkkeypad.h

@@ -0,0 +1,32 @@
+#pragma once
+#include "core/optype.h"
+class bkkeypad
+{
+public:
+	bkkeypad();
+
+	virtual ~bkkeypad();
+
+	virtual long Bind(HWND hwnd, long mode) = 0;
+
+	virtual long UnBind();
+
+	virtual long GetKeyState(long vk_code) = 0;
+
+	virtual long KeyDown(long vk_code) = 0;
+
+	//virtual long GetKeyState(long vk_code);
+
+	virtual long KeyUp(long vk_code) = 0;
+
+	virtual long WaitKey(long vk_code, long time_out) = 0;
+
+	virtual long KeyPress(long vk_code) = 0;
+protected:
+	HWND _hwnd;
+	int _mode;
+};
+
+
+
+

+ 206 - 0
gm/gm/background/keypad/winkeypad.cpp

@@ -0,0 +1,206 @@
+//#include "stdafx.h"
+#include "winkeypad.h"
+#include "./core/globalVar.h"
+#include "./core/helpfunc.h"
+
+static uint oem_code(uint key) {
+	short code[256] = { 0 };
+	code['q'] = 0x10; code['a'] = 0x1e;
+	code['w'] = 0x11; code['s'] = 0x1f;
+	code['e'] = 0x12; code['d'] = 0x20;
+	code['r'] = 0x13; code['f'] = 0x21;
+	code['t'] = 0x14; code['g'] = 0x22;
+	code['y'] = 0x15; code['h'] = 0x23;
+	code['u'] = 0x16; code['j'] = 0x24;
+	code['i'] = 0x17; code['k'] = 0x25;
+	code['o'] = 0x18; code['l'] = 0x26;
+	code['p'] = 0x19; code[':'] = 0x27; code[';'] = 0x27;
+
+	code['z'] = 0x2c;
+	code['x'] = 0x2d;
+	code['c'] = 0x2e;
+	code['v'] = 0x2f;
+	code['b'] = 0x30;
+	code['n'] = 0x31;
+	code['m'] = 0x32;
+	return code[key & 0xffu];
+
+}
+
+winkeypad::winkeypad():bkkeypad()
+{
+}
+
+
+winkeypad::~winkeypad()
+{
+	//UnBind();
+}
+
+long winkeypad::Bind(HWND hwnd, long mode) {
+	if (!::IsWindow(hwnd))
+		return 0;
+	_hwnd = hwnd;
+	_mode = mode;
+	return 1;
+}
+
+long winkeypad::UnBind() {
+	_hwnd = NULL;
+	_mode = 0;
+	return 1;
+}
+
+long winkeypad::GetKeyState(long vk_code) {
+	vk_code = toupper(vk_code);
+	return 0x8000 & ::GetAsyncKeyState(vk_code);
+}
+
+long winkeypad::KeyDown(long vk_code) {
+	long ret = 0;
+	vk_code = toupper(vk_code);
+
+	switch (_mode) {
+	case INPUT_TYPE::IN_NORMAL:
+	{
+	
+		INPUT Input = { 0 };
+		Input.type = INPUT_KEYBOARD;
+		Input.ki.wVk = (WORD)vk_code;
+		Input.ki.dwFlags = 0;
+
+		/*The function returns the number of events that it successfully inserted into the keyboard or mouse input stream.
+		If the function returns zero, the input was already blocked by another thread.
+		To get extended error information, call GetLastError.
+		This function fails when it is blocked by UIPI.
+		Note that neither GetLastError nor the return value will indicate the failure was caused by UIPI blocking.
+		*/
+		ret = ::SendInput(1, &Input, sizeof(INPUT));
+		break;
+	}
+
+	case INPUT_TYPE::IN_WINDOWS: {
+		/*Specification of WM_KEYDOWN :*/
+
+		/*wParam
+
+			Specifies the virtual - key code of the nonsystem key.
+		lParam
+			Specifies the repeat count, scan code, extended - key flag, context code,
+			previous key - state flag,
+			and transition - state flag, as shown in the following table.
+			0 - 15
+			Specifies the repeat count for the current message.The value is
+			the number of times the keystroke is
+			autorepeated as a result of the user holding down the key.If the
+			keystroke is held long enough, multiple messages are sent.However,
+			the repeat count is not cumulative.
+			16 - 23
+			Specifies the scan code.The value depends on the OEM.
+			24
+			Specifies whether the key is an extended key, such as the
+			right - hand ALT and CTRL keys that
+			appear on an enhanced 101 - or 102 - key keyboard.The value
+			is 1 if it is an extended key; otherwise, it is 0.
+			25 - 28
+			Reserved; do not use.
+			29
+			Specifies the context code.The value is always 0 for a WM_KEYDOWN message.
+			30
+			Specifies the previous key state.The value is 1 if the key
+			is down before the message is sent, or it is zero if the key is up.
+			31
+			Specifies the transition state.The value is always zero for a WM_KEYDOWN message.*/
+
+		DWORD lparam = 1u;
+		if (vk_code == VK_RCONTROL)
+			lparam |= 1u << 24;
+		lparam |= oem_code(vk_code) << 16;
+		ret = ::PostMessageW(_hwnd, WM_KEYDOWN, vk_code, lparam);
+		//ret = ::SendMessageW(_hwnd, WM_KEYDOWN, vk_code, 0);
+		if (ret == 0)setlog("error code=%d", GetLastError());
+		break;
+	}
+	}
+
+
+	return ret;
+}
+
+long winkeypad::KeyUp(long vk_code) {
+	long ret = 0;
+	vk_code = toupper(vk_code);
+	switch (_mode) {
+	case INPUT_TYPE::IN_NORMAL:
+	{
+		
+		INPUT Input = { 0 };
+		Input.type = INPUT_KEYBOARD;
+		Input.ki.wVk = vk_code;
+		Input.ki.dwFlags = KEYEVENTF_KEYUP;
+
+		/*The function returns the number of events that it successfully inserted into the keyboard or mouse input stream.
+		If the function returns zero, the input was already blocked by another thread.
+		To get extended error information, call GetLastError.
+		This function fails when it is blocked by UIPI.
+		Note that neither GetLastError nor the return value will indicate the failure was caused by UIPI blocking.
+		*/
+		ret = ::SendInput(1, &Input, sizeof(INPUT));
+		break;
+	}
+
+	case INPUT_TYPE::IN_WINDOWS: {
+		/*Specification of WM_KEYUP
+		wParam
+			Specifies the virtual - key code of the nonsystem key.
+			lParam
+			Specifies the repeat count, scan code, extended - key flag, context code,
+			previous key - state flag, and transition - state flag, as shown in the following table.
+			0 - 15
+			Specifies the repeat count for the current message.The value is the number of times the keystroke is
+			autorepeated as a result of the user holding down the key.
+			The repeat count is always one for a WM_KEYUP message.
+			16 - 23
+			Specifies the scan code.The value depends on the OEM.
+			24
+			Specifies whether the key is an extended key, such as the right - hand ALT and CTRL keys that
+			appear on an enhanced 101 - or 102 - key keyboard.The value is 1 if it is an extended key; otherwise, it is 0.
+			25 - 28
+			Reserved; do not use.
+			29
+			Specifies the context code.The value is always 0 for a WM_KEYUP message.
+			30
+			Specifies the previous key state.The value is always 1 for a WM_KEYUP message.
+			31
+			Specifies the transition state.The value is always 1 for a WM_KEYUP message.*/
+			//ret = ::SendMessageW(_hwnd, WM_KEYUP, vk_code, 0);
+		DWORD lparam = 1u;
+		if (vk_code == VK_RCONTROL)lparam |= 1u << 24;
+		lparam |= oem_code(vk_code) << 16;
+		lparam |= 1u << 30;
+		lparam |= 1u << 31;
+		ret = ::PostMessageW(_hwnd, WM_KEYUP, vk_code, lparam);
+		if (ret == 0)setlog("error2 code=%d", GetLastError());
+		break;
+	}
+	}
+
+
+	return ret;
+}
+
+long winkeypad::WaitKey(long vk_code, long time_out) {
+	auto deadline = ::GetTickCount() + time_out;
+	while (::GetTickCount() < deadline) {
+		if (GetKeyState(vk_code))
+			return 1;
+		::Sleep(1);
+	}
+	return 0;
+}
+
+long winkeypad::KeyPress(long vk_code) {
+	KeyDown(vk_code);
+
+	return KeyUp(vk_code);
+}

+ 30 - 0
gm/gm/background/keypad/winkeypad.h

@@ -0,0 +1,30 @@
+#pragma once
+#ifndef _WIN_KEYPAD_H_
+#define _WIN_KEYPAD_H_
+#include "Bkkeypad.h"
+class winkeypad:public bkkeypad
+{
+public:
+	winkeypad();
+
+	virtual ~winkeypad();
+
+	virtual long Bind(HWND hwnd, long mode);
+
+	virtual long UnBind();
+
+	virtual long GetKeyState(long vk_code);
+
+	virtual long KeyDown(long vk_code);
+
+	//virtual long GetKeyState(long vk_code);
+
+	virtual long KeyUp(long vk_code);
+
+	virtual long WaitKey(long vk_code, long time_out);
+
+	virtual long KeyPress(long vk_code);
+};
+#endif // !_WIN_KEYPAD_H_
+
+

+ 311 - 0
gm/gm/background/mouse/opMouseDx.cpp

@@ -0,0 +1,311 @@
+//#include "stdafx.h"
+#include "opMouseDx.h"
+#include "../core/globalVar.h"
+#include "../core/helpfunc.h"
+#include "BlackBone/Process/Process.h"
+#include "BlackBone/Process/RPC/RemoteFunction.hpp"
+#include "../core/opEnv.h"
+#include "../HOOK/opMessage.h"
+opMouseDx::opMouseDx()
+	: _hwnd(NULL), _mode(0), _x(0), _y(0), _dpi(getDPI())
+{
+}
+
+opMouseDx::~opMouseDx()
+{
+	_hwnd = NULL;
+}
+
+long opMouseDx::Bind(HWND h, int mode)
+{
+	_hwnd = h;
+	_mode = mode;
+	DWORD id;
+	::GetWindowThreadProcessId(_hwnd, &id);
+
+	//attach 进程
+	blackbone::Process proc;
+	NTSTATUS hr;
+
+	hr = proc.Attach(id);
+	long ret = 0;
+	if (NT_SUCCESS(hr))
+	{
+		wstring dllname = opEnv::getOpName();
+		//检查是否与插件相同的32/64位,如果不同,则使用另一种dll
+		BOOL is64 = proc.modules().GetMainModule()->type == blackbone::eModType::mt_mod64;
+		if (is64 != OP64)
+		{
+			dllname = is64 ? L"op_x64.dll" : L"op_x86.dll";
+		}
+
+		bool injected = false;
+		//判断是否已经注入
+		auto _dllptr = proc.modules().GetModule(dllname);
+		auto mods = proc.modules().GetAllModules();
+		if (_dllptr)
+		{
+			injected = true;
+		}
+		else
+		{
+			wstring opFile = opEnv::getBasePath() + L"\\" + dllname;
+			if (::PathFileExistsW(opFile.data()))
+			{
+				auto iret = proc.modules().Inject(opFile);
+				injected = (iret ? true : false);
+			}
+			else
+			{
+				setlog(L"file:<%s> not exists!", opFile.data());
+			}
+		}
+		if (injected)
+		{
+			using my_func_t = long(__stdcall *)(HWND, int);
+			auto PSetInputHook = blackbone::MakeRemoteFunction<my_func_t>(proc, dllname, "SetInputHook");
+			if (PSetInputHook)
+			{
+				//setlog("after MakeRemoteFunction");
+				auto cret = PSetInputHook(_hwnd, _mode);
+				//setlog("after pSetXHook");
+				ret = cret.result();
+				//setlog("after result");
+			}
+			else
+			{
+				setlog(L"remote function 'SetInputHook' not found.");
+			}
+		}
+		else
+		{
+			setlog(L"Inject false.");
+		}
+	}
+	else
+	{
+		setlog(L"attach false.");
+	}
+
+	proc.Detach();
+	//setlog("after Detach");
+
+	return 1;
+}
+
+long opMouseDx::UnBind()
+{
+	DWORD id;
+	::GetWindowThreadProcessId(_hwnd, &id);
+
+	//attach 进程
+	blackbone::Process proc;
+	NTSTATUS hr;
+
+	hr = proc.Attach(id);
+	long ret = 0;
+	if (NT_SUCCESS(hr))
+	{
+		wstring dllname = opEnv::getOpName();
+		//检查是否与插件相同的32/64位,如果不同,则使用另一种dll
+		BOOL is64 = proc.modules().GetMainModule()->type == blackbone::eModType::mt_mod64;
+		if (is64 != OP64)
+		{
+			dllname = is64 ? L"op_x64.dll" : L"op_x86.dll";
+		}
+		using my_func_t = long(__stdcall *)();
+		auto pReleaseInputHook = blackbone::MakeRemoteFunction<my_func_t>(proc, dllname, "ReleaseInputHook");
+		if (pReleaseInputHook)
+		{
+			//setlog("after MakeRemoteFunction");
+			auto cret = pReleaseInputHook();
+			//setlog("after pSetXHook");
+			ret = cret.result();
+			//setlog("after result");
+		}
+		else
+		{
+			setlog(L"remote function 'ReleaseInputHook' not found.");
+		}
+	}
+	else
+	{
+		setlog(L"attach false.");
+	}
+
+	proc.Detach();
+	//setlog("after Detach");
+	_hwnd = 0;
+	_mode = 0;
+	return 1;
+}
+
+long opMouseDx::GetCursorPos(long &x, long &y)
+{
+	BOOL ret = FALSE;
+	POINT pt;
+	ret = ::GetCursorPos(&pt);
+	if (_hwnd != ::GetDesktopWindow())
+	{
+		ret = ::ScreenToClient(_hwnd, &pt);
+	}
+	x = pt.x;
+	y = pt.y;
+	return ret;
+}
+
+long opMouseDx::MoveR(int rx, int ry)
+{
+	return MoveTo(_x + rx, _y + ry);
+}
+
+long opMouseDx::MoveTo(int x, int y)
+{
+	x = x * _dpi;
+	y = y * _dpi;
+	long ret = 0;
+	ret = ::SendMessage(_hwnd, OP_WM_MOUSEMOVE, 0, MAKELPARAM(x, y)) == 0 ? 1 : 0;
+
+	_x = x, _y = y;
+	return ret;
+}
+
+long opMouseDx::MoveToEx(int x, int y, int w, int h)
+{
+
+	if (w >= 2 && h >= 2)
+		return MoveTo(x + rand() % w, y + rand() % h);
+	else
+		return MoveTo(x, y);
+}
+
+long opMouseDx::LeftClick()
+{
+	long ret = 0, ret2 = 0;
+
+	///ret=::PostMessage(_hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(_x, _y));
+	ret = ::SendMessageTimeout(_hwnd, OP_WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(_x, _y), SMTO_BLOCK, 2000, nullptr);
+	//ret = ::SendNotifyMessage(_hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(_x, _y));
+	//::Sleep(100);
+	//ret = ::SendMessage(_hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(_x, _y));
+	ret2 = ::SendMessageTimeout(_hwnd, OP_WM_LBUTTONUP, 0, MAKELPARAM(_x, _y), SMTO_BLOCK, 2000, nullptr);
+
+	return ret && ret2 ? 1 : 0;
+}
+
+long opMouseDx::LeftDoubleClick()
+{
+	long r1, r2;
+	r1 = LeftClick();
+	::Sleep(1);
+	r2 = LeftClick();
+	return r1 & r2 ? 1 : 0;
+}
+
+long opMouseDx::LeftDown()
+{
+	long ret = 0;
+
+	ret = ::SendMessage(_hwnd, OP_WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(_x, _y));
+
+	return ret;
+}
+
+long opMouseDx::LeftUp()
+{
+	long ret = 0;
+
+	ret = ::SendMessage(_hwnd, OP_WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM(_x, _y));
+
+	return ret;
+}
+
+long opMouseDx::MiddleClick()
+{
+	long r1, r2;
+	r1 = MiddleDown();
+	::Sleep(1);
+	r2 = MiddleUp();
+	return r1 & r2 ? 1 : 0;
+}
+
+long opMouseDx::MiddleDown()
+{
+	long ret = 0;
+
+	ret = ::SendMessage(_hwnd, OP_WM_MBUTTONDOWN, MK_MBUTTON, MAKELPARAM(_x, _y));
+
+	return ret;
+}
+
+long opMouseDx::MiddleUp()
+{
+	long ret = 0;
+
+	ret = ::SendMessage(_hwnd, OP_WM_MBUTTONUP, MK_MBUTTON, MAKELPARAM(_x, _y));
+
+	return ret;
+}
+
+long opMouseDx::RightClick()
+{
+	long ret = 0;
+	long r1, r2;
+
+	r1 = ::SendMessage(_hwnd, OP_WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM(_x, _y));
+	r2 = ::SendMessage(_hwnd, OP_WM_RBUTTONUP, MK_RBUTTON, MAKELPARAM(_x, _y));
+	ret = r1 == 0 && r2 == 0 ? 1 : 0;
+
+	return ret;
+}
+
+long opMouseDx::RightDown()
+{
+	long ret = 0;
+
+	ret = ::PostMessage(_hwnd, WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM(_x, _y)) == 0 ? 1 : 0;
+
+	return ret;
+}
+
+long opMouseDx::RightUp()
+{
+	long ret = 0;
+
+	ret = ::PostMessage(_hwnd, OP_WM_RBUTTONUP, MK_RBUTTON, MAKELPARAM(_x, _y));
+
+	return ret;
+}
+
+long opMouseDx::WheelDown()
+{
+	long ret = 0;
+
+	/*
+		wParam
+		The high-order word indicates the distance the wheel is rotated, 
+		expressed in multiples or divisions of WHEEL_DELTA, which is 120. 
+		A positive value indicates that the wheel was rotated forward, away from the user;
+		a negative value indicates that the wheel was rotated backward, toward the user.
+		The low-order word indicates whether various virtual keys are down.
+		This parameter can be one or more of the following values.
+		lParam
+		The low-order word specifies the x-coordinate of the pointer,
+		relative to the upper-left corner of the screen.
+		The high-order word specifies the y-coordinate of the pointer, 
+		relative to the upper-left corner of the screen.
+		*/
+	//If an application processes this message, it should return zero.
+	ret = ::SendMessage(_hwnd, OP_WM_MOUSEWHEEL, MAKEWPARAM(-WHEEL_DELTA, 0), MAKELPARAM(_x, _y)) == 0 ? 1 : 0;
+
+	return ret;
+}
+
+long opMouseDx::WheelUp()
+{
+	long ret = 0;
+
+	ret = ::SendMessage(_hwnd, OP_WM_MOUSEWHEEL, MAKEWPARAM(WHEEL_DELTA, 0), MAKELPARAM(_x, _y)) == 0 ? 1 : 0;
+
+	return ret;
+}

+ 51 - 0
gm/gm/background/mouse/opMouseDx.h

@@ -0,0 +1,51 @@
+#pragma once
+#include "../core/optype.h"
+#include "opMouseWin.h"
+class opMouseDx: public opMouseWin
+{
+public:
+	opMouseDx();
+	virtual ~opMouseDx();
+
+	virtual long Bind(HWND h,int mode);
+
+	virtual long UnBind();
+
+	virtual long GetCursorPos(long&x, long& y);
+
+	virtual long MoveR(int rx, int ry);
+
+	virtual long MoveTo(int x, int y);
+
+	virtual long MoveToEx(int x, int y,int w,int h);
+
+	virtual long LeftClick();
+
+	virtual long LeftDoubleClick();
+
+	virtual long LeftDown();
+
+	virtual long LeftUp();
+
+	virtual long MiddleClick();
+
+	virtual long MiddleDown();
+
+	virtual long MiddleUp();
+
+	virtual long RightClick();
+
+	virtual long RightDown();
+
+	virtual long RightUp();
+
+	virtual long WheelDown();
+
+	virtual long WheelUp();
+private:
+	HWND _hwnd;
+	int _mode;
+	int _x,_y;
+	float _dpi;//screen dpi
+};
+

+ 390 - 0
gm/gm/background/mouse/opMouseWin.cpp

@@ -0,0 +1,390 @@
+//#include "stdafx.h"
+#include "opMouseWin.h"
+#include "./core/globalVar.h"
+#include "./core/helpfunc.h"
+
+float opMouseWin::getDPI() {
+	HDC hdcScreen;
+	hdcScreen = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
+
+	int logx = GetDeviceCaps(hdcScreen, LOGPIXELSX);
+	//int logy = GetDeviceCaps(hdcScreen, LOGPIXELSY);
+	//setlog("logx = %d", logx);
+	if (NULL != hdcScreen)
+	{
+		DeleteDC(hdcScreen);
+	}
+	float dpi = 1.0;
+	if (logx == 96) {
+		dpi = 1.0;
+	}
+	else if (logx == 120) {
+		dpi = 1.25;
+	}
+	else if (logx == 144) {
+		dpi = 1.50;
+	}
+	else if (logx == 192) {
+		dpi = 2.0;
+	}
+
+	return dpi;
+}
+
+opMouseWin::opMouseWin()
+	:_hwnd(NULL), _mode(0), _x(0), _y(0), _dpi(getDPI())
+{
+}
+
+
+opMouseWin::~opMouseWin()
+{
+	_hwnd = NULL;
+}
+
+long opMouseWin::Bind(HWND h,int mode) {
+	_hwnd = h;
+	_mode = mode;
+	return 1;
+}
+
+long opMouseWin::UnBind() {
+	_hwnd = 0; _mode = 0;
+	return 1;
+}
+
+long opMouseWin::GetCursorPos(long& x, long& y) {
+	BOOL ret = FALSE;
+	POINT pt;
+	ret=::GetCursorPos(&pt);
+	if (_hwnd != ::GetDesktopWindow()) {
+		ret = ::ScreenToClient(_hwnd, &pt);
+	}
+	x = pt.x; y = pt.y;
+	return ret;
+}
+
+long opMouseWin::MoveR(int rx, int ry) {
+	return MoveTo(_x + rx, _y + ry);
+}
+
+long opMouseWin::MoveTo(int x, int y) {
+	x = x * _dpi;
+	y = y * _dpi;
+	long ret = 0;
+	switch (_mode) {
+	case INPUT_TYPE::IN_NORMAL:
+	{
+		POINT pt;
+		pt.x = x, pt.y = y;
+		if (_hwnd)
+			::ClientToScreen(_hwnd, &pt);
+		x = pt.x, y = pt.y;
+		//setlog(L"hwnd:%d,pt:%d,%d",_hwnd, 0, y);
+		static double fScreenWidth = ::GetSystemMetrics(SM_CXSCREEN) - 1;
+		static double fScreenHeight = ::GetSystemMetrics(SM_CYSCREEN) - 1;
+		double fx = x * (65535.0f / fScreenWidth);
+		double fy = y * (65535.0f / fScreenHeight);
+		INPUT Input = { 0 };
+		Input.type = INPUT_MOUSE;
+		Input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
+		Input.mi.dx = static_cast<LONG>(fx);
+		Input.mi.dy = static_cast<LONG>(fy);
+		/*The function returns the number of events that it successfully inserted into the keyboard or mouse input stream.
+		If the function returns zero, the input was already blocked by another thread.
+		To get extended error information, call GetLastError.
+		This function fails when it is blocked by UIPI.
+		Note that neither GetLastError nor the return value will indicate the failure was caused by UIPI blocking.
+		*/
+		ret = ::SendInput(1, &Input, sizeof(INPUT)) > 0 ? 1 : 0;
+		break;
+	}
+
+	case INPUT_TYPE::IN_WINDOWS: {
+		ret = ::SendMessage(_hwnd, WM_MOUSEMOVE, 0, MAKELPARAM(x, y)) == 0 ? 1 : 0;
+
+		break;
+	}
+	}
+	_x = x, _y = y;
+	return ret;
+}
+
+long opMouseWin::MoveToEx(int x, int y, int w, int h) {
+
+	if (w >= 2 && h >= 2)
+		return MoveTo(x + rand() % w, y + rand() % h);
+	else
+		return MoveTo(x, y);
+}
+
+long opMouseWin::LeftClick() {
+	long ret = 0, ret2 = 0;
+	switch (_mode) {
+	case INPUT_TYPE::IN_NORMAL: {
+		INPUT Input = { 0 };
+		// left down 
+		Input.type = INPUT_MOUSE;
+		Input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
+		ret = ::SendInput(1, &Input, sizeof(INPUT));
+
+		// left up
+		::ZeroMemory(&Input, sizeof(INPUT));
+		Input.type = INPUT_MOUSE;
+		Input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
+		ret2 = ::SendInput(1, &Input, sizeof(INPUT));
+		break;
+	}
+
+	case INPUT_TYPE::IN_WINDOWS: {
+		///ret=::PostMessage(_hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(_x, _y));
+		ret = ::SendMessageTimeout(_hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(_x, _y), SMTO_BLOCK, 2000, nullptr);
+		//ret = ::SendNotifyMessage(_hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(_x, _y));
+		//::Sleep(100);
+		//ret = ::SendMessage(_hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(_x, _y));
+		ret2=::SendMessageTimeout(_hwnd, WM_LBUTTONUP, 0, MAKELPARAM(_x, _y), SMTO_BLOCK, 2000, nullptr);
+		//ret2 = ::SendMessage(_hwnd, WM_LBUTTONUP, 0, MAKELPARAM(_x, _y));
+		//::SendMessage(_hwnd, WM_CAPTURECHANGED, 0, 0);
+		break;
+	}
+	}
+	return ret && ret2 ? 1 : 0;
+}
+
+long opMouseWin::LeftDoubleClick() {
+	long r1, r2;
+	r1=LeftClick();
+	::Sleep(1);
+	r2=LeftClick();
+	return r1 & r2 ? 1 : 0;
+}
+
+long opMouseWin::LeftDown() {
+	long ret = 0;
+	switch (_mode) {
+	case INPUT_TYPE::IN_NORMAL: {
+		INPUT Input = { 0 };
+		// left down 
+		Input.type = INPUT_MOUSE;
+		Input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
+		ret = ::SendInput(1, &Input, sizeof(INPUT));
+		break;
+	}
+
+	case INPUT_TYPE::IN_WINDOWS: {
+		ret = ::SendMessage(_hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(_x, _y));
+		break;
+	}
+	}
+	return ret;
+}
+
+long opMouseWin::LeftUp() {
+	long ret = 0;
+	switch (_mode) {
+	case INPUT_TYPE::IN_NORMAL: {
+		INPUT Input = { 0 };
+		// left up
+		::ZeroMemory(&Input, sizeof(INPUT));
+		Input.type = INPUT_MOUSE;
+		Input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
+		ret = ::SendInput(1, &Input, sizeof(INPUT));
+		break;
+	}
+
+	case INPUT_TYPE::IN_WINDOWS: {
+		ret = ::SendMessage(_hwnd, WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM(_x, _y));
+		break;
+	}
+	}
+	return ret;
+}
+
+long opMouseWin::MiddleClick() {
+	long r1, r2;
+	r1=MiddleDown();
+	::Sleep(1);
+	r2=MiddleUp();
+	return r1 & r2 ? 1 : 0;
+}
+
+long opMouseWin::MiddleDown() {
+	long ret = 0;
+	switch (_mode) {
+	case INPUT_TYPE::IN_NORMAL: {
+		INPUT Input = { 0 };
+		// left down 
+		Input.type = INPUT_MOUSE;
+		Input.mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN;
+		ret = ::SendInput(1, &Input, sizeof(INPUT));
+		break;
+	}
+
+	case INPUT_TYPE::IN_WINDOWS: {
+		ret = ::SendMessage(_hwnd, WM_MBUTTONDOWN, MK_MBUTTON, MAKELPARAM(_x, _y));
+		break;
+	}
+
+	}
+	return ret;
+}
+
+long opMouseWin::MiddleUp() {
+	long ret = 0;
+	switch (_mode) {
+	case INPUT_TYPE::IN_NORMAL: {
+		INPUT Input = { 0 };
+		// left up
+		::ZeroMemory(&Input, sizeof(INPUT));
+		Input.type = INPUT_MOUSE;
+		Input.mi.dwFlags = MOUSEEVENTF_MIDDLEUP;
+		ret = ::SendInput(1, &Input, sizeof(INPUT));
+		break;
+	}
+
+	case INPUT_TYPE::IN_WINDOWS: {
+		ret = ::SendMessage(_hwnd, WM_MBUTTONUP, MK_MBUTTON, MAKELPARAM(_x, _y));
+		break;
+	}
+	}
+	return ret;
+}
+
+
+long opMouseWin::RightClick() {
+	long ret = 0;
+	long r1, r2;
+	switch (_mode) {
+	case INPUT_TYPE::IN_NORMAL: {
+		INPUT Input = { 0 };
+		// left down 
+		Input.type = INPUT_MOUSE;
+		Input.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
+		r1 = ::SendInput(1, &Input, sizeof(INPUT));
+
+		// left up
+		::ZeroMemory(&Input, sizeof(INPUT));
+		Input.type = INPUT_MOUSE;
+		Input.mi.dwFlags = MOUSEEVENTF_RIGHTUP;
+		r2 = ::SendInput(1, &Input, sizeof(INPUT)) ;
+		ret = r1 > 0 && r2 > 0 ? 1 : 0;
+		break;
+	}
+
+	case INPUT_TYPE::IN_WINDOWS: {
+		r1 = ::SendMessage(_hwnd, WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM(_x, _y));
+		r2 = ::SendMessage(_hwnd, WM_RBUTTONUP, MK_RBUTTON, MAKELPARAM(_x, _y));
+		ret = r1 == 0 && r2 == 0 ? 1 : 0;
+		break;
+	}
+
+	}
+	return ret;
+}
+
+long opMouseWin::RightDown() {
+	long ret = 0;
+	switch (_mode) {
+	case INPUT_TYPE::IN_NORMAL: {
+		INPUT Input = { 0 };
+		// left down 
+		Input.type = INPUT_MOUSE;
+		Input.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
+		ret = ::SendInput(1, &Input, sizeof(INPUT)) > 0 ? 1 : 0;
+		break;
+	}
+	case	INPUT_TYPE::IN_WINDOWS: {
+		ret = ::PostMessage(_hwnd, WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM(_x, _y)) == 0 ? 1 : 0;
+		break;
+	}
+
+	}
+	return ret;
+}
+
+long opMouseWin::RightUp() {
+	long ret = 0;
+	switch (_mode) {
+	case INPUT_TYPE::IN_NORMAL: {
+		INPUT Input = { 0 };
+		// left up
+		::ZeroMemory(&Input, sizeof(INPUT));
+		Input.type = INPUT_MOUSE;
+		Input.mi.dwFlags = MOUSEEVENTF_RIGHTUP;
+		ret = ::SendInput(1, &Input, sizeof(INPUT)) > 0 ? 1 : 0;
+		break;
+	}
+
+	case INPUT_TYPE::IN_WINDOWS: {
+		ret = ::PostMessage(_hwnd, WM_RBUTTONUP, MK_RBUTTON, MAKELPARAM(_x, _y));
+		break;
+	}
+	}
+	return ret;
+}
+
+long opMouseWin::WheelDown() {
+	long ret = 0;
+	switch (_mode) {
+	case INPUT_TYPE::IN_NORMAL: {
+		INPUT Input = { 0 };
+		//down 
+		/*
+		If dwFlags contains MOUSEEVENTF_WHEEL, then dwData specifies the amount of wheel movement.
+		A positive value indicates that the wheel was rotated forward, away from the user;
+		a negative value indicates that the wheel was rotated backward, toward the user. 
+		One wheel click is defined as WHEEL_DELTA, which is 120.
+		*/
+		Input.type = INPUT_MOUSE;
+		Input.mi.dwFlags = MOUSEEVENTF_WHEEL;
+		Input.mi.mouseData = -WHEEL_DELTA;
+		ret = ::SendInput(1, &Input, sizeof(INPUT)) > 0 ? 1 : 0;
+		break;
+	}
+
+	case INPUT_TYPE::IN_WINDOWS: {
+		/*
+		wParam
+		The high-order word indicates the distance the wheel is rotated, 
+		expressed in multiples or divisions of WHEEL_DELTA, which is 120. 
+		A positive value indicates that the wheel was rotated forward, away from the user;
+		a negative value indicates that the wheel was rotated backward, toward the user.
+		The low-order word indicates whether various virtual keys are down.
+		This parameter can be one or more of the following values.
+		lParam
+		The low-order word specifies the x-coordinate of the pointer,
+		relative to the upper-left corner of the screen.
+		The high-order word specifies the y-coordinate of the pointer, 
+		relative to the upper-left corner of the screen.
+		*/
+		//If an application processes this message, it should return zero.
+		ret = ::SendMessage(_hwnd, WM_MOUSEWHEEL, MAKEWPARAM(-WHEEL_DELTA, 0), MAKELPARAM(_x, _y)) == 0 ? 1 : 0;
+		break;
+	}
+
+	
+	}
+	
+	return ret;
+}
+
+long opMouseWin::WheelUp() {
+	long ret = 0;
+	switch (_mode) {
+	case INPUT_TYPE::IN_NORMAL: {
+		INPUT Input = { 0 };
+		// left up
+		Input.type = INPUT_MOUSE;
+		Input.mi.dwFlags = MOUSEEVENTF_WHEEL;
+		Input.mi.mouseData = WHEEL_DELTA;
+		ret = ::SendInput(1, &Input, sizeof(INPUT)) > 0 ? 1 : 0;
+		break;
+	}
+
+	case INPUT_TYPE::IN_WINDOWS: {
+		ret = ::SendMessage(_hwnd, WM_MOUSEWHEEL, MAKEWPARAM(WHEEL_DELTA, 0), MAKELPARAM(_x, _y)) == 0 ? 1 : 0;
+		break;
+	}
+	}
+	return ret;
+}

+ 51 - 0
gm/gm/background/mouse/opMouseWin.h

@@ -0,0 +1,51 @@
+#pragma once
+#include "core/optype.h"
+class opMouseWin
+{
+public:
+	static float getDPI();
+	opMouseWin();
+	virtual ~opMouseWin();
+
+	virtual long Bind(HWND h,int mode);
+
+	virtual long UnBind();
+
+	virtual long GetCursorPos(long&x, long& y);
+
+	virtual long MoveR(int rx, int ry);
+
+	virtual long MoveTo(int x, int y);
+
+	virtual long MoveToEx(int x, int y,int w,int h);
+
+	virtual long LeftClick();
+
+	virtual long LeftDoubleClick();
+
+	virtual long LeftDown();
+
+	virtual long LeftUp();
+
+	virtual long MiddleClick();
+
+	virtual long MiddleDown();
+
+	virtual long MiddleUp();
+
+	virtual long RightClick();
+
+	virtual long RightDown();
+
+	virtual long RightUp();
+
+	virtual long WheelDown();
+
+	virtual long WheelUp();
+private:
+	HWND _hwnd;
+	int _mode;
+	int _x,_y;
+	float _dpi;//screen dpi
+};
+

+ 486 - 0
gm/gm/background/opBackground.cpp

@@ -0,0 +1,486 @@
+//#include "stdafx.h"
+#include <algorithm>
+#include "./core/globalVar.h"
+#include "./core/helpfunc.h"
+#include "opBackground.h"
+
+#include "./display/opGDI.h"
+#include "./display/opDxGL.h""
+
+#include "./keypad/winkeypad.h""
+#include "./mouse/opMouseDx.h"
+opBackground::opBackground() : _hwnd(0), _is_bind(0), _pbkdisplay(nullptr), _bkmouse(new opMouseWin), _keypad(new winkeypad)
+{
+	_display_method = std::make_pair<wstring, wstring>(L"screen", L"");
+}
+
+opBackground::~opBackground()
+{
+	/*_hwnd = NULL;
+	_is_bind = 0;
+	_mode = 0;
+	_bkmouse->UnBind();
+	if (_pbkdisplay) {
+		_pbkdisplay->UnBind();
+		delete _pbkdisplay;
+		_pbkdisplay = nullptr;
+	}*/
+	UnBindWindow();
+	SAFE_DELETE(_bkmouse);
+	SAFE_DELETE(_keypad);
+}
+
+long opBackground::BindWindow(long hwnd, const wstring &sdisplay, const wstring &smouse, const wstring &skeypad, long mode)
+{
+	//step 1.避免重复绑定
+	UnBindWindow();
+	//step 2.check hwnd
+	if (!::IsWindow(HWND(hwnd)))
+	{
+		setlog("Invalid window handles");
+		return 0;
+	}
+
+	int display, mouse, keypad;
+	//step 3.check display... mode
+	if (sdisplay == L"normal")
+		display = RDT_NORMAL;
+	else if (sdisplay == L"gdi")
+		display = RDT_GDI;
+	else if (sdisplay == L"gdi2")
+		display = RDT_GDI2;
+	else if (sdisplay == L"dx2")
+		display = RDT_GDI_DX2;
+	else if (sdisplay == L"dx")
+		display = RDT_DX_DEFAULT;
+	else if (sdisplay == L"dx.d3d9")
+		display = RDT_DX_D3D9;
+	else if (sdisplay == L"dx.d3d10")
+		display = RDT_DX_D3D10;
+	else if (sdisplay == L"dx.d3d11")
+		display = RDT_DX_D3D11;
+	else if (sdisplay == L"opengl")
+		display = RDT_GL_DEFAULT;
+	else if (sdisplay == L"opengl.std")
+		display = RDT_GL_STD;
+	else if (sdisplay == L"opengl.nox")
+		display = RDT_GL_NOX;
+	else if (sdisplay == L"opengl.es")
+		display = RDT_GL_ES;
+	else if (sdisplay == L"opengl.fi")//glFinish
+		display = RDT_GL_FI;
+	else
+	{
+		setlog(L"error display:%s", sdisplay.c_str());
+		return 0;
+	}
+	//check mouse
+	if (smouse == L"normal")
+		mouse = INPUT_TYPE::IN_NORMAL;
+	else if (smouse == L"windows")
+		mouse = INPUT_TYPE::IN_WINDOWS;
+	else if (smouse == L"dx")
+		mouse = INPUT_TYPE::IN_DX;
+	else
+	{
+		setlog(L"error mouse:%s", smouse.c_str());
+		return 0;
+	}
+	//check keypad
+	if (skeypad == L"normal")
+		keypad = INPUT_TYPE::IN_NORMAL;
+	else if (skeypad == L"windows")
+		keypad = INPUT_TYPE::IN_WINDOWS;
+	else
+	{
+		setlog(L"error keypad:%s", sdisplay.c_str());
+		return 0;
+	}
+	//step 4.init
+	_mode = mode;
+	_display = display;
+	_hwnd = (HWND)hwnd;
+	set_display_method(L"screen");
+
+	//step 5. create instance
+	_pbkdisplay = createDisplay(display);
+	_bkmouse = createMouse(mouse);
+	_keypad = createKeypad(keypad);
+
+	if (!_pbkdisplay || !_bkmouse || !_keypad)
+	{
+		setlog("create instance error!");
+		UnBindWindow();
+		return 0;
+	}
+	//step 6.try bind
+	if (_pbkdisplay->Bind((HWND)hwnd, display) != 1 ||
+		_bkmouse->Bind((HWND)hwnd, mouse) != 1 ||
+		_keypad->Bind((HWND)hwnd, keypad) != 1)
+	{
+		UnBindWindow();
+		return 0;
+	}
+
+	//等待线程创建好
+	Sleep(200);
+
+	_is_bind = 1;
+	return 1;
+}
+
+long opBackground::UnBindWindow()
+{
+	//to do
+	//clear ....
+	_hwnd = NULL;
+	_is_bind = 0;
+	_mode = 0;
+
+	if (_pbkdisplay)
+	{
+		_pbkdisplay->UnBind();
+		SAFE_DELETE(_pbkdisplay);
+	}
+	if (_bkmouse)
+	{
+		_bkmouse->UnBind();
+		SAFE_DELETE(_bkmouse);
+	}
+	if (_keypad)
+	{
+		_keypad->UnBind();
+		SAFE_DELETE(_keypad);
+	}
+	//恢复为前台(默认)
+	_bkmouse = new opMouseWin;
+	_keypad = new winkeypad;
+
+	return 1;
+}
+
+long opBackground::GetBindWindow()
+{
+	return (long)_hwnd;
+}
+
+long opBackground::IsBind()
+{
+	return _pbkdisplay ? 1 : 0;
+}
+
+//long bkbase::GetCursorPos(int& x, int& y) {
+//	POINT pt;
+//	auto r = ::GetCursorPos(&pt);
+//	x = pt.x; y = pt.y;
+//	return r;
+//}
+
+long opBackground::GetDisplay()
+{
+	return _display;
+}
+
+//byte* bkbase::GetScreenData() {
+//	if (get_display_method().first == L"screen") {
+//		return _pbkdisplay ? _pbkdisplay->get_data() : nullptr;
+//	}
+//	else {
+//		if (get_display_method().first == L"pic") {
+//			return _pic.pdata;
+//		}
+//		if (get_display_method().first == L"mem") {
+//
+//#if OP64==1
+//			auto ptr= (byte*)_wtoi64(get_display_method().second.data());
+//#else
+//			auto ptr = (byte*)_wtoi(get_display_method().second.data());
+//#endif //
+//
+//			auto pbfh = (BITMAPFILEHEADER*)ptr;
+//			return ptr + pbfh->bfOffBits;
+//	}
+//		return nullptr;
+//}
+//
+//
+//}
+
+void opBackground::lock_data()
+{
+	if (_pbkdisplay)
+	{
+		auto p = _pbkdisplay->get_mutex();
+		if (p)
+			p->lock();
+	}
+}
+
+void opBackground::unlock_data()
+{
+	if (_pbkdisplay)
+	{
+		auto p = _pbkdisplay->get_mutex();
+		if (p)
+			p->unlock();
+	}
+}
+
+long opBackground::get_height()
+{
+	auto &displayMethod = get_display_method();
+	if (displayMethod.first == L"pic")
+	{
+		return _pic.height;
+	}
+	else if (displayMethod.first == L"mem")
+	{
+		auto strPtr = displayMethod.second;
+#if OP64 == 1
+		auto ptr = (byte *)_wtoi64(strPtr.data());
+#else
+		auto ptr = (byte *)_wtoi(strPtr.data());
+#endif //
+
+		auto bih = (BITMAPINFOHEADER *)(ptr + sizeof(BITMAPFILEHEADER));
+		return bih->biHeight < 0 ? -bih->biHeight : bih->biHeight;
+	}
+	else
+	{
+		return _pbkdisplay ? _pbkdisplay->get_height() : 0;
+	}
+}
+
+long opBackground::get_width()
+{
+	auto &displayMethod = get_display_method();
+	if (displayMethod.first == L"pic")
+	{
+		return _pic.width;
+	}
+	else if (displayMethod.first == L"mem")
+	{
+		auto strPtr = displayMethod.second;
+#if OP64 == 1
+		auto ptr = (byte *)_wtoi64(strPtr.data());
+#else
+		auto ptr = (byte *)_wtoi(strPtr.data());
+#endif //
+
+		auto bih = (BITMAPINFOHEADER *)(ptr + sizeof(BITMAPFILEHEADER));
+		return bih->biWidth;
+	}
+	else
+	{
+		return _pbkdisplay ? _pbkdisplay->get_width() : 0;
+	}
+}
+
+long opBackground::RectConvert(long &x1, long &y1, long &x2, long &y2)
+{
+
+	/*if (_pbkdisplay && (_display == RENDER_TYPE::NORMAL || _display == RENDER_TYPE::GDI)) {
+		x1 += _pbkdisplay->_client_x; y1 += _pbkdisplay->_client_y;
+		x2 += _pbkdisplay->_client_x; y2 += _pbkdisplay->_client_y;
+	}*/
+
+	x2 = std::min<long>(this->get_width(), x2);
+	y2 = std::min<long>(this->get_height(), y2);
+	if (x1 < 0 || y1 < 0 || x1 >= x2 || y1 >= y2)
+	{
+		setlog(L"invalid rectangle:%d %d %d %d", x1, y1, x2, y2);
+		return 0;
+	}
+	//if (_pbkdisplay) {
+	//	if (_display == RDT_NORMAL) {//cap rect
+	//		_pbkdisplay->rect.left = x1;
+	//		_pbkdisplay->rect.top = y1;
+	//		_pbkdisplay->rect.right = x2;
+	//		_pbkdisplay->rect.bottom = y2;
+	//	}
+	//	else {
+	//		_pbkdisplay->rect.left = 0;
+	//		_pbkdisplay->rect.top = 0;
+	//		_pbkdisplay->rect.right = _pbkdisplay->get_width();
+	//		_pbkdisplay->rect.bottom =_pbkdisplay->get_height();
+	//	}
+	//
+	//}
+	return 1;
+}
+
+long opBackground::get_image_type()
+{
+
+	if (_display_method.first == L"pic")
+		return 0;
+	else if (_display_method.first == L"mem")
+	{
+
+		return 1;
+	}
+	else
+	{
+		switch (GET_RENDER_TYPE(_display))
+		{
+		case RENDER_TYPE::NORMAL:
+			return -2;
+		case RENDER_TYPE::GDI:
+			return -1;
+		case RENDER_TYPE::DX:
+			return 0;
+		case RENDER_TYPE::OPENGL:
+			return -1;
+		default:
+			return 0;
+		}
+	}
+}
+
+bool opBackground::check_bind()
+{
+	//已绑定
+	if (IsBind())
+		return true;
+	//显示模式非屏幕
+	if (get_display_method().first != L"screen")
+	{
+		if (get_display_method().first == L"pic")
+		{ //load pic first
+			wstring fullpath;
+			if (Path2GlobalPath(get_display_method().second, _curr_path, fullpath))
+			{
+				_pic.read(fullpath.data());
+			}
+		}
+		return true;
+	}
+
+	//绑定前台桌面
+	return BindWindow((long)::GetDesktopWindow(), L"normal", L"normal", L"normal", 0);
+}
+
+const std::pair<wstring, wstring> &opBackground::get_display_method() const
+{
+	return _display_method;
+}
+
+long opBackground::set_display_method(const wstring &method)
+{
+	if (method == L"screen")
+	{
+		_display_method.first = method;
+		_display_method.second.clear();
+		return 1;
+	}
+	else
+	{
+		auto idx = method.find(L"pic:");
+		if (idx != wstring::npos)
+		{
+			_display_method.first = L"pic";
+			_display_method.second = method.substr(idx + 4);
+			_pic.read(_display_method.second.data());
+			return 1;
+		}
+		idx = method.find(L"mem:");
+		if (idx != wstring::npos)
+		{
+			auto strPtr = method.substr(idx + 4);
+#if OP64 == 1
+			auto ptr = (byte *)_wtoi64(strPtr.data());
+#else
+			auto ptr = (byte *)_wtoi(strPtr.data());
+#endif //
+
+			if (ptr == nullptr)
+			{
+				return 0;
+			}
+			BITMAPFILEHEADER bfh = {0}; //bmp file header
+			BITMAPINFOHEADER bih = {0}; //bmp info header
+			memcpy(&bfh, ptr, sizeof(bfh));
+			memcpy(&bih, ptr + sizeof(bfh), sizeof(bih));
+
+			if (bfh.bfType != static_cast<WORD>(0x4d42))
+				return 0;
+
+			if (bih.biHeight < 0)
+			{ //正常拷贝
+				int h = -bih.biHeight;
+				_pic.create(bih.biWidth, h);
+				/*setlog("mem w=%d h=%d chk=%d",
+					bih.biWidth, h,
+					_pic.size() * 4 == bih.biSizeImage ? 1 : 0);*/
+				memcpy(_pic.pdata, ptr + sizeof(bfh) + sizeof(bih), _pic.size() * 4);
+			}
+			else
+			{ //倒过来拷贝
+				int h = bih.biHeight;
+				_pic.create(bih.biWidth, h);
+				for (int i = 0; i < h; i++)
+				{
+					memcpy(_pic.ptr<uchar>(i),
+						   ptr + sizeof(bfh) + sizeof(bih) + (h - 1 - i) * bih.biWidth * 4,
+						   bih.biWidth * 4);
+				}
+			}
+			_display_method.first = L"mem";
+			_display_method.second = strPtr;
+
+			return 1;
+		}
+		return 0;
+	}
+}
+
+bool opBackground::requestCapture(int x1, int y1, int w, int h, Image &img)
+{
+	wstring method = get_display_method().first;
+	if (method == L"screen")
+		return _pbkdisplay->requestCapture(x1, y1, w, h, img);
+	else if (method == L"pic" || method == L"mem")
+	{
+		img.create(w, h);
+		for (int i = 0; i < h; i++)
+			memcpy(img.ptr<uchar>(i), _pic.ptr<uchar>(i + y1) + x1 * 4, w * 4);
+		return true;
+	}
+	return false;
+}
+
+IDisplay *opBackground::createDisplay(int mode)
+{
+	IDisplay *pans = 0;
+
+	if (mode == RDT_NORMAL || GET_RENDER_TYPE(mode) == RENDER_TYPE::GDI)
+	{
+		pans = new opGDI();
+	}
+	else if (GET_RENDER_TYPE(mode) == RENDER_TYPE::DX)
+	{
+		pans = new opDxGL;
+	}
+	else if (GET_RENDER_TYPE(mode) == RENDER_TYPE::OPENGL)
+		pans = new opDxGL;
+	else
+		pans = 0;
+	return pans;
+}
+
+opMouseWin *opBackground::createMouse(int mode)
+{
+	if (mode == INPUT_TYPE::IN_NORMAL || mode == INPUT_TYPE::IN_WINDOWS)
+		return new opMouseWin();
+	else if (mode == INPUT_TYPE::IN_DX)
+	{
+		return new opMouseDx();
+	}
+	//return 0;
+}
+
+bkkeypad *opBackground::createKeypad(int mode)
+{
+	return new winkeypad();
+	//return 0;
+}

+ 64 - 0
gm/gm/background/opBackground.h

@@ -0,0 +1,64 @@
+#pragma once
+#ifndef __BACKBASE_H_
+#define __BACKBASE_H_
+#include <string>
+#include "include/Image.hpp"
+
+#include "./display/IDisplay.h"
+
+#include "./mouse/opMouseWin.h"
+#include "./keypad/Bkkeypad.h"
+
+
+using std::wstring;
+
+
+class opBackground
+{
+public:
+	
+	opBackground();
+	~opBackground();
+public:
+	virtual long BindWindow(long hwnd, const wstring& sdisplay, const wstring& smouse, const wstring& skeypad, long mode);
+	virtual long UnBindWindow();
+	virtual long GetBindWindow();
+	virtual long IsBind();
+	//virtual long GetCursorPos(int& x, int& y);
+	
+	long GetDisplay();
+	/*byte* GetScreenData();*/
+	void lock_data();
+	void unlock_data();
+	long get_height();
+	long get_width();
+	long RectConvert(long&x1, long&y1, long&x2, long&y2);
+	//0:normal;-1 reserve 1 need cut
+	long get_image_type();
+	//����Ƿ�󶨻�������ǰ̨
+	bool check_bind();
+	const std::pair<wstring, wstring>& get_display_method()const;
+	long set_display_method(const wstring& method);
+
+	bool requestCapture(int x1,int y1,int w,int h,Image& img);
+private:
+	HWND _hwnd;
+	int _is_bind;
+	int _display;
+	int _mode;
+	std::pair<wstring,wstring> _display_method;
+	Image _pic;
+
+	IDisplay* createDisplay(int mode);
+	opMouseWin* createMouse(int mode);
+	bkkeypad* createKeypad(int mode);
+public:
+	IDisplay* _pbkdisplay;
+	opMouseWin* _bkmouse;
+	bkkeypad* _keypad;
+	wstring _curr_path;
+	
+};
+#endif
+
+

+ 23 - 0
gm/gm/core/Cmder.h

@@ -0,0 +1,23 @@
+#pragma once
+#include "Pipe.h"
+class Cmder : public Pipe {
+public:
+	void on_read(const string& ss)override {
+		_readed += ss;
+
+	}
+	string GetCmdStr(const string&cmd,size_t milseconds) {
+		open(cmd);
+		if (is_open()) {
+			auto deadline = clock()+milseconds;
+			while (is_open()&& clock()<deadline) {
+				std::this_thread::sleep_for(std::chrono::milliseconds(1));
+			}
+			close();
+		}
+		return _readed;
+	}
+private:
+	string _readed;
+
+};

+ 112 - 0
gm/gm/core/Pipe.cpp

@@ -0,0 +1,112 @@
+//#include "stdafx.h"
+#include "Pipe.h"
+#include <iostream>
+#include<chrono>
+#include  "globalVar.h"
+#include "helpfunc.h"
+Pipe::Pipe()
+{
+	_hread = _hwrite = _hread2 = _hwrite2 = nullptr;
+	_hprocess = nullptr;
+	_reading = 0;
+	_pthread = nullptr;
+}
+
+
+
+
+Pipe::~Pipe()
+{
+	close();
+}
+
+int Pipe::open(const string& cmd) {
+	_ai.nLength = sizeof(SECURITY_ATTRIBUTES);
+	_ai.bInheritHandle = true;
+	_ai.lpSecurityDescriptor = nullptr;
+	if (!CreatePipe(&_hread, &_hwrite, &_ai, 0))
+		return -1;
+	if (!CreatePipe(&_hread2, &_hwrite2, &_ai, 0))
+		return -2;
+	GetStartupInfoA(&_si);
+	_si.cb = sizeof(STARTUPINFO);
+	_si.hStdError = _hwrite;
+	_si.hStdOutput = _hwrite;
+	_si.hStdInput = _hread2;
+	_si.wShowWindow = SW_HIDE;
+	_si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
+	char buf[0xff];
+	memcpy(buf, cmd.data(), sizeof(char) * (1 + cmd.length()));
+	if (!CreateProcessA(NULL, buf, nullptr, nullptr, true, NULL, nullptr, nullptr, &_si, &_pi))
+		return -3;
+	_reading = 1;
+	_pthread = new std::thread(&Pipe::reader, this);
+	return 1;
+}
+
+int Pipe::close() {
+	if (_reading) {
+		_reading = 0;
+		on_write("exit");
+
+		if (::WaitForSingleObject(_pi.hProcess, 1000) == WAIT_TIMEOUT) {
+			::TerminateProcess(_pi.hProcess, 0);
+			TerminateThread(_pthread->native_handle(), -1);
+		}
+		else {
+
+		}
+
+		_pthread->join();
+
+
+	}
+	SAFE_DELETE(_pthread);
+	SAFE_CLOSE(_hread);
+	SAFE_CLOSE(_hwrite);
+	SAFE_CLOSE(_hwrite2);
+	SAFE_CLOSE(_hread2);
+	SAFE_CLOSE(_pi.hProcess);
+	SAFE_CLOSE(_pi.hThread);
+	return 0;
+}
+
+void Pipe::on_read(const string& info) {
+	std::cout << info << std::endl;
+}
+
+int Pipe::on_write(const string& info) {
+	if (_reading) {
+		unsigned long wlen = 0;
+
+		return WriteFile(_hwrite2, info.data(), info.length() * sizeof(char), &wlen, nullptr);
+	}
+	return 0;
+}
+
+void Pipe::reader() {
+	const static int buf_size = 1 << 10;
+	char buf[buf_size];
+	unsigned long read_len = 0;
+	while (_reading) {
+		memset(buf, 0, buf_size * sizeof(char));
+		if (ReadFile(_hread, buf, buf_size - 1, &read_len, NULL)) {
+			//setlog("readed:%s", buf);
+			on_read(buf);
+		}
+		else {
+			_reading = 0;
+			break;
+		}
+	}
+}
+
+bool Pipe::is_open() {
+	if (_reading) {
+		DWORD code = 0;
+		::GetExitCodeProcess(_pi.hProcess, &code);
+		return code == STILL_ACTIVE;
+	}
+	return false;
+}
+

+ 28 - 0
gm/gm/core/Pipe.h

@@ -0,0 +1,28 @@
+#pragma once
+#include <windows.h>
+#include <string>
+#include <thread>
+class Pipe
+{
+public:
+	using handle_t = HANDLE;
+	using string=std::string;
+	Pipe();
+	virtual ~Pipe();
+	int open(const string& cmd);
+	int close();
+	virtual void on_read(const string& info);
+	virtual int on_write(const string& info);
+	bool is_open();
+private:
+	handle_t _hread, _hwrite;
+	handle_t _hread2, _hwrite2;
+	handle_t _hprocess;
+	SECURITY_ATTRIBUTES _ai;
+	PROCESS_INFORMATION _pi;
+	STARTUPINFOA _si;
+	int _reading;
+	std::thread* _pthread;
+	void reader();
+};
+

+ 13 - 0
gm/gm/core/globalVar.cpp

@@ -0,0 +1,13 @@
+//#include "stdafx.h"
+#include "optype.h"
+#include "globalVar.h"
+#include <time.h>
+
+//HINSTANCE gInstance;
+
+//int gShowError = 1;
+
+//wstring m_opPath;
+
+//wstring g_op_name;
+

+ 96 - 0
gm/gm/core/globalVar.h

@@ -0,0 +1,96 @@
+#pragma once
+#ifndef __GLOBALVAR_H_
+#define __GLOBALVAR_H_
+#include "optype.h"
+#define SAFE_CLOSE(h)   \
+	if (h)              \
+		CloseHandle(h); \
+	h = NULL;
+template <class Type>
+void SAFE_DELETE(Type *&ptr)
+{
+	delete ptr;
+	ptr = nullptr;
+}
+
+#define SAFE_DELETE_ARRAY(ptr) \
+	if (ptr)                   \
+		delete[] ptr;          \
+	ptr = nullptr
+
+#define SAFE_RELEASE(obj) \
+	if (obj)              \
+		obj->Release();   \
+	obj = nullptr
+
+//#define _sto_wstring(s) boost::locale::conv::to_utf<wchar_t>(s, "GBK")
+//#define _wsto_string(s)  boost::locale::conv::from_utf(s,"GBK")
+
+#define DLL_API extern "C" _declspec(dllexport)
+//normal windows,gdi;,dx;opengl;
+enum RENDER_TYPE
+{
+	NORMAL = 0,
+	GDI = 1,
+	DX = 2,
+	OPENGL = 3
+};
+
+#define MAKE_RENDER(type, flag) ((type << 16) | flag)
+
+#define GET_RENDER_TYPE(t) (t >> 16)
+
+#define GET_RENDER_FLAG(t) (t & 0xffff)
+
+constexpr int RDT_NORMAL = MAKE_RENDER(NORMAL, 0);
+constexpr int RDT_GDI = MAKE_RENDER(GDI, 0);
+constexpr int RDT_GDI2 = MAKE_RENDER(GDI, 1);
+constexpr int RDT_GDI_DX2 = MAKE_RENDER(GDI, 2);
+constexpr int RDT_DX_DEFAULT = MAKE_RENDER(DX, 0);
+constexpr int RDT_DX_D3D9 = MAKE_RENDER(DX, 1);
+constexpr int RDT_DX_D3D10 = MAKE_RENDER(DX, 2);
+constexpr int RDT_DX_D3D11 = MAKE_RENDER(DX, 3);
+constexpr int RDT_GL_DEFAULT = MAKE_RENDER(OPENGL, 0);
+constexpr int RDT_GL_STD = MAKE_RENDER(OPENGL, 1);
+constexpr int RDT_GL_NOX = MAKE_RENDER(OPENGL, 2);
+constexpr int RDT_GL_ES = MAKE_RENDER(OPENGL, 3);
+constexpr int RDT_GL_FI = MAKE_RENDER(OPENGL, 4); //glFinish
+
+enum INPUT_TYPE
+{
+	IN_NORMAL = 0,
+	IN_WINDOWS = 1,
+	IN_DX = 2
+};
+//define Image byte format
+constexpr int IBF_R8G8B8A8 = 0;
+constexpr int IBF_B8G8R8A8 = 1;
+constexpr int IBF_R8G8B8 = 2;
+
+//const size_t MAX_IMAGE_WIDTH = 1<<11;
+//const size_t SHARED_MEMORY_SIZE = 1080 * 1928 * 4;
+
+constexpr auto SHARED_RES_NAME_FORMAT = L"op_mutex_%d";
+constexpr auto MUTEX_NAME_FORMAT = L"op_shared_mem_%d";
+
+#ifndef _M_X64
+#define OP64 0
+#else
+#define OP64 1
+#endif
+
+#define _TOSTRING(x) #x
+
+#define MAKE_OP_VERSION(a, b, c, d) _TOSTRING(a##.##b##.##c##.##d)
+
+#define OP_VERSION MAKE_OP_VERSION(0, 4, 0, 0)
+//模块句柄
+//extern HINSTANCE gInstance;
+//是否显示错误信息
+//extern int gShowError;
+//op 路径
+//extern wstring m_opPath;
+
+//extern wstring g_op_name;
+
+#endif

+ 221 - 0
gm/gm/core/helpfunc.cpp

@@ -0,0 +1,221 @@
+//#include "stdafx.h"
+#include "helpfunc.h"
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <shlwapi.h>
+#include "globalVar.h"
+#include "opEnv.h"
+//#define USE_BOOST_STACK_TRACE
+#ifdef USE_BOOST_STACK_TRACE
+#include <boost/stacktrace.hpp>
+#endif
+
+std::wstring _s2wstring(const std::string&s) {
+	size_t nlen = s.length();
+
+	wchar_t* m_char;
+	int len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), nlen, NULL, 0);
+	m_char = new wchar_t[len + 1];
+	MultiByteToWideChar(CP_ACP, 0, s.data(), nlen, m_char, len);
+	m_char[len] = '\0';
+	std::wstring ws(m_char);
+	delete[] m_char;
+	return ws;
+}
+
+std::string _ws2string(const std::wstring&ws) {
+	// std::string strLocale = setlocale(LC_ALL, "");
+	// const wchar_t* wchSrc = ws.c_str();
+	// size_t nDestSize = wcstombs(NULL, wchSrc, 0) + 1;
+	// char *chDest = new char[nDestSize];
+	// memset(chDest, 0, nDestSize);
+	// wcstombs(chDest, wchSrc, nDestSize);
+	// std::string strResult = chDest;
+	// delete[]chDest;
+	// setlocale(LC_ALL, strLocale.c_str());
+	//return strResult;
+	int nlen = ws.length();
+
+	char* m_char;
+	int len = WideCharToMultiByte(CP_ACP, 0, ws.data(), nlen, NULL, 0, NULL, NULL);
+	m_char = new char[len + 1];
+	WideCharToMultiByte(CP_ACP, 0, ws.data(), nlen, m_char, len, NULL, NULL);
+	m_char[len] = '\0';
+	std::string s(m_char);
+	delete[] m_char;
+	return s;
+}
+
+long Path2GlobalPath(const std::wstring&file, const std::wstring& curr_path, std::wstring& out) {
+	if (::PathFileExistsW(file.c_str())) {
+		out = file;
+		return 1;
+	}
+	out.clear();
+	out = curr_path + L"\\" + file;
+	if (::PathFileExistsW(out.c_str())) {
+		return 1;
+	}
+	return 0;
+}
+
+long setlog(const wchar_t* format, ...) {
+	va_list args;
+	wchar_t buf[512];
+	va_start(args, format);
+	vswprintf(buf, format, args);
+	va_end(args);
+	wstring tmpw = buf;
+	string tmps = _ws2string(tmpw);
+	
+	return setlog(tmps.data());
+}
+
+long setlog(const char* format, ...) {
+	std::stringstream ss(std::wstringstream::in | std::wstringstream::out);
+	va_list args;
+	char buf[512];
+	SYSTEMTIME sys;
+	GetLocalTime(&sys);
+	char tm[128];
+	sprintf(tm, "[%4d/%02d/%02d %02d:%02d:%02d.%03d]",
+		sys.wYear, sys.wMonth, sys.wDay,
+		sys.wHour, sys.wMinute, sys.wSecond,
+		sys.wMilliseconds);
+	va_start(args, format);
+	vsprintf(buf, format, args);
+	va_end(args);
+	ss << tm << (OP64 == 1 ? "x64" : "x32") << "info: " << buf << std::endl;
+#ifdef USE_BOOST_STACK_TRACE
+	ss << "<stack>\n"
+		<< boost::stacktrace::stacktrace() << std::endl;
+#endif // USE_BOOST_STACK_TRACE
+
+	
+	string s = ss.str();
+	if (opEnv::m_showErrorMsg == 1) {
+		MessageBoxA(NULL, s.data(), "error", MB_ICONERROR);
+	}
+	else if (opEnv::m_showErrorMsg == 2) {
+		/*	wchar_t dll_path[MAX_PATH];
+			::GetModuleFileNameW(gInstance, dll_path, MAX_PATH);
+			wstring fname = dll_path;
+			fname = fname.substr(0, fname.rfind(L'\\'));
+			fname += L"\\op.log";*/
+		std::fstream file;
+		file.open("__op.log", std::ios::app | std::ios::out);
+		if (!file.is_open())
+			return 0;
+		file << s << std::endl;
+		file.close();
+	}
+	else if (opEnv::m_showErrorMsg == 3) {
+		std::cout << s << std::endl;
+	}
+
+	return 1;
+}
+
+void split(const std::wstring& s, std::vector<std::wstring>& v, const std::wstring& c)
+{
+	std::wstring::size_type pos1, pos2;
+	size_t len = s.length();
+	pos2 = s.find(c);
+	pos1 = 0;
+	v.clear();
+	while (std::wstring::npos != pos2)
+	{
+		v.emplace_back(s.substr(pos1, pos2 - pos1));
+
+		pos1 = pos2 + c.size();
+		pos2 = s.find(c, pos1);
+	}
+	if (pos1 != len)
+		v.emplace_back(s.substr(pos1));
+}
+
+void split(const std::string& s, std::vector<std::string>& v, const std::string& c)
+{
+	std::string::size_type pos1, pos2;
+	size_t len = s.length();
+	pos2 = s.find(c);
+	pos1 = 0;
+	v.clear();
+	while (std::string::npos != pos2)
+	{
+		v.emplace_back(s.substr(pos1, pos2 - pos1));
+
+		pos1 = pos2 + c.size();
+		pos2 = s.find(c, pos1);
+	}
+	if (pos1 != len)
+		v.emplace_back(s.substr(pos1));
+}
+
+void wstring2upper(std::wstring& s) {
+	std::transform(s.begin(), s.end(),s.begin(), towupper);
+}
+
+void string2upper(std::string& s) {
+	std::transform(s.begin(), s.end(), s.begin(), toupper);
+}
+
+void wstring2lower(std::wstring& s) {
+	std::transform(s.begin(), s.end(), s.begin(), towlower);
+}
+
+void string2lower(std::string& s) {
+	std::transform(s.begin(), s.end(), s.begin(), tolower);
+}
+
+void replacea(string& str, const string&oldval, const string& newval) {
+	size_t x0 = 0, dx = newval.length() - oldval.length() + 1;
+	size_t idx = str.find(oldval, x0);
+	while (idx != -1 && x0 >= 0) {
+		str.replace(idx, oldval.length(), newval);
+		x0 = idx + dx;
+		idx = str.find(oldval, x0);
+	}
+}
+
+void replacew(wstring& str, const wstring&oldval, const wstring& newval) {
+	size_t x0 = 0, dx = newval.length() - oldval.length() + 1;
+	size_t idx = str.find(oldval, x0);
+	while (idx != -1 && x0 >= 0) {
+		str.replace(idx, oldval.length(), newval);
+		x0 = idx + dx;
+		idx = str.find(oldval, x0);
+	}
+}
+
+std::ostream& operator<<(std::ostream& o, point_t const& rhs) {
+	o << rhs.x << "," << rhs.y;
+	return o;
+}
+
+std::wostream& operator<<(std::wostream& o, point_t const& rhs) {
+	o << rhs.x << L"," << rhs.y;
+	return o;
+}
+
+std::ostream& operator<<(std::ostream& o, FrameInfo const& rhs) {
+	o << "hwnd:" << rhs.hwnd << std::endl
+		<< "frameId:" << rhs.frameId << std::endl
+		<< "time:" << rhs.time << std::endl
+		<< "height" << rhs.height << std::endl
+		<< "width:" << rhs.width << std::endl;
+	return o;
+}
+std::wostream& operator<<(std::wostream& o, FrameInfo const& rhs) {
+	o << L"hwnd:" << rhs.hwnd << std::endl
+		<< L"frameId:" << rhs.frameId << std::endl
+		<< L"time:" << rhs.time << std::endl
+		<< L"height" << rhs.height << std::endl
+		<< L"width:" << rhs.width << std::endl;
+	return o;
+}
+
+
+

+ 91 - 0
gm/gm/core/helpfunc.h

@@ -0,0 +1,91 @@
+#pragma once
+#ifndef __HELPFUCN_H_
+#define __HELPFUNC_H_
+#include "optype.h"
+#include "../background/display/frameInfo.h"
+std::wstring _s2wstring(const std::string&s);
+std::string _ws2string(const std::wstring&s);
+//将路径转化为全局路径
+long Path2GlobalPath(const std::wstring&file, const std::wstring& curr_path, std::wstring& out);
+
+void split(const std::wstring& s, std::vector<std::wstring>& v, const std::wstring& c);
+void split(const std::string& s, std::vector<std::string>& v, const std::string& c);
+
+void wstring2upper(std::wstring& s);
+void string2upper(std::string& s);
+
+void wstring2lower(std::wstring& s);
+void string2lower(std::string& s);
+
+void replacea(string& str, const string&oldval, const string& newval);
+void replacew(wstring& str, const wstring&oldval, const wstring& newval);
+
+
+//for debug
+long setlog(const wchar_t* format, ...);
+//
+long setlog(const char* format, ...);
+
+int inline hex2bin(int c) {
+	return c <= L'9' ? c - L'0' : c - L'A' + 10;
+};
+
+int inline bin2hex(int c) {
+	int ans = 0;
+	int c1 = c >> 4 & 0xf;
+	int c2 = c & 0xf;
+	ans |= (c1 <= 9 ? c1 + L'0' : c1 + 'A' - 10) << 8;
+	ans |= c2 <= 9 ? c2 + L'0' : c2 + 'A' - 10;
+	return ans;
+};
+
+constexpr int PTY(uint pt) {
+	return pt >> 16;
+}
+
+constexpr int PTX(uint pt) {
+	return pt & 0xffff;
+}
+
+template<typename T>
+void nextVal(const T& t, int* next) {
+	next[0] = -1;
+	int k = -1, j = 0;
+	while (j < (int)t.size()-1) {
+		if (k == -1 || t[k] == t[j]) {
+			k++;
+			j++;
+			next[j] = k;
+		}
+		else {
+			k = next[k];
+		}
+	}
+}
+template<typename T>
+int kmp(const T& s, const T& t) {
+	vector<int> next(t.size());
+	nextVal(t, next.data());
+	int i = 0, j = 0;
+	while (i < (int)s.size() && j < (int)t.size()) {
+		if (j == -1 || s[i] == t[j]) {
+			i++;
+			j++;
+		}
+		else {
+			j = next[j];
+		}
+	}
+	return j == s.size() ? i - j : -1;
+}
+
+std::ostream& operator<<(std::ostream& o, point_t const& rhs);
+std::wostream& operator<<(std::wostream& o, point_t const& rhs);
+
+std::ostream& operator<<(std::ostream& o, FrameInfo const& rhs);
+std::wostream& operator<<(std::wostream& o, FrameInfo const& rhs);
+
+#endif // !__TOOL_H_
+
+
+

+ 31 - 0
gm/gm/core/opEnv.cpp

@@ -0,0 +1,31 @@
+#include "opEnv.h"
+#include <windows.h>
+void* opEnv::m_instance = nullptr;
+std::wstring opEnv::m_basePath;
+std::wstring opEnv::m_opName;
+int opEnv::m_showErrorMsg = 1;
+void opEnv::setInstance(void *instance)
+{
+    m_instance = instance;
+     wchar_t buff[512]={};
+    ::GetModuleFileNameW(static_cast<HINSTANCE>(m_instance),buff,512);
+    std::wstring s(buff);
+    size_t index =s.rfind(L"\\");
+    if(index!=s.npos){
+        m_basePath = s.substr(0,index);
+        m_opName = s.substr(index + 1);
+    }
+}
+void *opEnv::getInstance()
+{
+    return m_instance;
+}
+
+std::wstring opEnv::getBasePath(){
+   
+    return m_basePath;
+}
+
+std::wstring opEnv::getOpName(){
+    return m_opName;
+}

+ 18 - 0
gm/gm/core/opEnv.h

@@ -0,0 +1,18 @@
+#ifndef __OPENV_H_
+#define __OPENV_H_
+#include <string>
+class opEnv
+{
+public:
+    static void setInstance(void *instance);
+    static void *getInstance();
+    static std::wstring getBasePath();
+    static std::wstring getOpName();
+    static int m_showErrorMsg;
+private:
+    static void *m_instance;
+    static std::wstring m_basePath;
+    static std::wstring m_opName;
+    
+};
+#endif

+ 95 - 0
gm/gm/core/optype.h

@@ -0,0 +1,95 @@
+#pragma once
+#ifndef __optype_h_
+#define __optype_h_
+#include <Windows.h>
+#include <assert.h>
+
+#include <map>
+#include <string>
+#include <vector>
+using uint = unsigned int;
+using uchar = unsigned char;
+
+using std::map;
+using std::string;
+using std::vector;
+using std::wstring;
+
+using bytearray = std::vector<uchar>;
+
+struct point_t {
+  int x, y;
+  point_t() : x(0), y(0) {}
+  point_t(int x_, int y_) : x(x_), y(y_) {}
+  bool operator<(const point_t& rhs) const {
+    if (std::abs(y - rhs.y) < 9)
+      return x < rhs.x;
+    else
+      return y < rhs.y;
+  }
+  bool operator==(const point_t& rhs) const { return x == rhs.x && y == rhs.y; }
+};
+
+using vpoint_t = std::vector<point_t>;
+//(5,3) --> (2, 2, 1)
+class NumberGen {
+  int _q, _r;
+
+ public:
+  NumberGen(int n, int cnt) : _q(n / cnt), _r(n % cnt) {}
+  int operator[](int idx) const { return idx < _r ? _q + 1 : _q; }
+};
+
+struct rect_t {
+  rect_t() : x1(0), y1(0), x2(0), y2(0) {}
+  rect_t(int x1_, int y1_, int x2_, int y2_)
+      : x1(x1_), y1(y1_), x2(x2_), y2(y2_) {}
+  int x1, y1;
+  int x2, y2;
+  int width() const { return x2 - x1; }
+  int height() const { return y2 - y1; }
+  rect_t& shrinkRect(int w, int h) {
+    x2 -= w;
+    y2 -= h;
+    x2 += 1;
+    y2 += 1;
+    return *this;
+  }
+  bool valid() const { return 0 <= x1 && x1 < x2 && 0 <= y1 && y1 < y2; }
+
+  void divideBlock(int count, bool vertical, std::vector<rect_t>& blocks) {
+    assert(valid());
+
+    assert(count > 0);
+    blocks.resize(count);
+    if (vertical) {
+      NumberGen gen(height(), count);
+      int basey = y1;
+      for (int i = 0; i < count; ++i) {
+        blocks[i] = rect_t(x1, basey, x2, basey + gen[i]);
+        basey += gen[i];
+      }
+
+    } else {
+      NumberGen gen(width(), count);
+      int basex = x1;
+      for (int i = 0; i < count; ++i) {
+        blocks[i] = rect_t(basex, y1, basex + gen[i], y2);
+        basex += gen[i];
+      }
+    }
+    assert(blocks.back().x2 == x2);
+    assert(blocks.back().y2 == y2);
+  }
+};
+
+using vrect_t = std::vector<rect_t>;
+
+struct point_desc_t {
+  int id;
+  point_t pos;
+};
+
+using vpoint_desc_t = std::vector<point_desc_t>;
+
+#endif

+ 24 - 0
gm/gm/framework.h

@@ -0,0 +1,24 @@
+#pragma once
+
+#include "targetver.h"
+#define WIN32_LEAN_AND_MEAN             // 从 Windows 头文件中排除极少使用的内容
+#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS      // 部分 CString 构造函数将是显式的
+#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS         // 移除对话框中的 MFC 控件支持
+
+#ifndef VC_EXTRALEAN
+#define VC_EXTRALEAN            // 从 Windows 头文件中排除极少使用的内容
+#endif
+
+#include <afx.h>
+#include <afxwin.h>         // MFC 核心组件和标准组件
+#include <afxext.h>         // MFC 扩展
+#ifndef _AFX_NO_OLE_SUPPORT
+#include <afxdtctl.h>           // MFC 对 Internet Explorer 4 公共控件的支持
+#endif
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h>                     // MFC 对 Windows 公共控件的支持
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+#include <iostream>
+// Windows 头文件
+#include <windows.h>

+ 47 - 0
gm/gm/gm.cpp

@@ -0,0 +1,47 @@
+// gm.cpp : 定义 DLL 的导出函数。
+//
+
+#include "pch.h"
+#include "framework.h"
+#include "gm.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+
+// 唯一的应用程序对象
+
+CWinApp theApp;
+
+using namespace std;
+
+int main()
+{
+    int nRetCode = 0;
+
+    HMODULE hModule = ::GetModuleHandle(nullptr);
+
+    if (hModule != nullptr)
+    {
+        // 初始化 MFC 并在失败时显示错误
+        if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0))
+        {
+            // TODO: 在此处为应用程序的行为编写代码。
+            wprintf(L"错误: MFC 初始化失败\n");
+            nRetCode = 1;
+        }
+        else
+        {
+            // TODO: 在此处为应用程序的行为编写代码。
+        }
+    }
+    else
+    {
+        // TODO: 更改错误代码以符合需要
+        wprintf(L"错误: GetModuleHandle 失败\n");
+        nRetCode = 1;
+    }
+
+    return nRetCode;
+}

+ 22 - 0
gm/gm/gm.h

@@ -0,0 +1,22 @@
+// 下列 ifdef 块是创建使从 DLL 导出更简单的
+// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 {0}_EXPORTS
+// 符号编译的。在使用此 DLL 的
+// 任何项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
+// {0}_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
+// 符号视为是被导出的。
+#ifdef GM_EXPORTS
+#define GM_API __declspec(dllexport)
+#else
+#define GM_API __declspec(dllimport)
+#endif
+
+// 此类是从 dll 导出的
+class GM_API Cgm {
+public:
+	Cgm(void);
+	// TODO: 在此处添加方法。
+};
+
+extern GM_API int ngm;
+
+GM_API int fngm(void);

BIN
gm/gm/gm.rc


+ 292 - 0
gm/gm/gm.vcxproj

@@ -0,0 +1,292 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>16.0</VCProjectVersion>
+    <Keyword>Win32Proj</Keyword>
+    <ProjectGuid>{395c3072-c2d9-4cf8-a742-5d809ea95627}</ProjectGuid>
+    <RootNamespace>gm</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>Dynamic</UseOfMfc>
+    <PreferredToolArchitecture>x86</PreferredToolArchitecture>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>Dynamic</UseOfMfc>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>Dynamic</UseOfMfc>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>Dynamic</UseOfMfc>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;_DEBUG;GM_EXPORTS;_WINDOWS;_USRDLL;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_SILENCE_CXX17_RESULT_OF_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+      <AdditionalIncludeDirectories>.;..\..\Blackbone\src;..\3rd_party\include;..\..\Blackbone\src\3rd_party\AsmJit;.\core</AdditionalIncludeDirectories>
+      <LanguageStandard>stdcpp17</LanguageStandard>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableUAC>false</EnableUAC>
+      <AdditionalLibraryDirectories>../3rd_party/lib/x86;../../Blackbone/build/Win32/Debug(DLL);..\..\Blackbone\src\3rd_party\BeaEngine\Win32\DLL;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>BlackBone.lib;minhook.lib;BeaEngine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib</AdditionalDependencies>
+      <IgnoreSpecificDefaultLibraries>
+      </IgnoreSpecificDefaultLibraries>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;NDEBUG;GM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableUAC>false</EnableUAC>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>_DEBUG;GM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableUAC>false</EnableUAC>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>NDEBUG;GM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableUAC>false</EnableUAC>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="algorithm\AStar.hpp" />
+    <ClInclude Include="background\display\frameInfo.h" />
+    <ClInclude Include="background\display\IDisplay.h" />
+    <ClInclude Include="background\display\opDxGL.h" />
+    <ClInclude Include="background\display\opGDI.h" />
+    <ClInclude Include="background\Hook\DisplayHook.h" />
+    <ClInclude Include="background\Hook\HookExport.h" />
+    <ClInclude Include="background\Hook\InputHook.h" />
+    <ClInclude Include="background\Hook\opMessage.h" />
+    <ClInclude Include="background\keypad\Bkkeypad.h" />
+    <ClInclude Include="background\keypad\winkeypad.h" />
+    <ClInclude Include="background\mouse\opMouseDx.h" />
+    <ClInclude Include="background\mouse\opMouseWin.h" />
+    <ClInclude Include="background\opBackground.h" />
+    <ClInclude Include="core\Cmder.h" />
+    <ClInclude Include="core\globalVar.h" />
+    <ClInclude Include="core\helpfunc.h" />
+    <ClInclude Include="core\opEnv.h" />
+    <ClInclude Include="core\optype.h" />
+    <ClInclude Include="core\Pipe.h" />
+    <ClInclude Include="imageProc\ImageLoc.h" />
+    <ClInclude Include="imageProc\ImageProc.h" />
+    <ClInclude Include="imageProc\imageView.hpp" />
+    <ClInclude Include="libop.h" />
+    <ClInclude Include="winapi\Injecter.h" />
+    <ClInclude Include="winapi\MemoryEx.h" />
+    <ClInclude Include="winapi\query_api.h" />
+    <ClInclude Include="winapi\WinApi.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\3rd_party\src\kiero.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="background\display\IDisplay.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="background\display\opDxGL.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="background\display\opGDI.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="background\Hook\DisplayHook.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="background\Hook\HookExport.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="background\Hook\InputHook.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="background\keypad\Bkkeypad.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="background\keypad\winkeypad.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="background\mouse\opMouseDx.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="background\mouse\opMouseWin.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="background\opBackground.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="core\globalVar.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="core\helpfunc.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="core\opEnv.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="core\Pipe.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="imageProc\ImageLoc.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="imageProc\ImageProc.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="libop.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="winapi\Injecter.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="winapi\MemoryEx.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="winapi\query_api.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="winapi\WinApi.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="gm.def" />
+    <None Include="res\gm.rc2" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="framework.h" />
+    <ClInclude Include="gm.h" />
+    <ClInclude Include="pch.h" />
+    <ClInclude Include="Resource.h" />
+    <ClInclude Include="targetver.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="gm.cpp" />
+    <ClCompile Include="pch.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="gm.rc" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 243 - 0
gm/gm/gm.vcxproj.filters

@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="源文件">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="头文件">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
+    </Filter>
+    <Filter Include="资源文件">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+    <Filter Include="winapi">
+      <UniqueIdentifier>{823a46bd-4d01-4fed-a473-7d90f7d4a27d}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="imgproc">
+      <UniqueIdentifier>{6e31b5ed-9643-4c1b-8ce6-964f39e0b46a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="core">
+      <UniqueIdentifier>{e1cbefe9-af15-451a-86a8-fae70c2d118a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="background">
+      <UniqueIdentifier>{b815eeb0-2170-4258-9efe-a36f3790e66a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="background\display">
+      <UniqueIdentifier>{d591a4be-fd38-4110-b985-6d81ff952d03}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="background\hook">
+      <UniqueIdentifier>{5fa40581-fcb1-41ff-b641-2621cab5d2a4}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="background\keypad">
+      <UniqueIdentifier>{f34584f9-ca4c-467b-8d5f-7e5be38c2ab5}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="background\mouse">
+      <UniqueIdentifier>{312b897f-bcdf-4f0b-b40b-c55fcb8a7e6a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="algorithm">
+      <UniqueIdentifier>{5ca942b8-3084-428d-a0e6-08473030e58c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="keroi">
+      <UniqueIdentifier>{823eedf1-d42a-492e-af1c-dd352261eb11}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="pch.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rd_party\src\kiero.cpp">
+      <Filter>keroi</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="gm.def">
+      <Filter>源文件</Filter>
+    </None>
+    <None Include="res\gm.rc2">
+      <Filter>资源文件</Filter>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="framework.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="targetver.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="Resource.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="libop.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="gm.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="pch.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="winapi\Injecter.h">
+      <Filter>winapi</Filter>
+    </ClInclude>
+    <ClInclude Include="winapi\MemoryEx.h">
+      <Filter>winapi</Filter>
+    </ClInclude>
+    <ClInclude Include="winapi\query_api.h">
+      <Filter>winapi</Filter>
+    </ClInclude>
+    <ClInclude Include="winapi\WinApi.h">
+      <Filter>winapi</Filter>
+    </ClInclude>
+    <ClInclude Include="imageProc\ImageLoc.h">
+      <Filter>imgproc</Filter>
+    </ClInclude>
+    <ClInclude Include="imageProc\ImageProc.h">
+      <Filter>imgproc</Filter>
+    </ClInclude>
+    <ClInclude Include="imageProc\imageView.hpp">
+      <Filter>imgproc</Filter>
+    </ClInclude>
+    <ClInclude Include="core\Cmder.h">
+      <Filter>core</Filter>
+    </ClInclude>
+    <ClInclude Include="core\globalVar.h">
+      <Filter>core</Filter>
+    </ClInclude>
+    <ClInclude Include="core\helpfunc.h">
+      <Filter>core</Filter>
+    </ClInclude>
+    <ClInclude Include="core\opEnv.h">
+      <Filter>core</Filter>
+    </ClInclude>
+    <ClInclude Include="core\optype.h">
+      <Filter>core</Filter>
+    </ClInclude>
+    <ClInclude Include="core\Pipe.h">
+      <Filter>core</Filter>
+    </ClInclude>
+    <ClInclude Include="background\opBackground.h">
+      <Filter>background</Filter>
+    </ClInclude>
+    <ClInclude Include="background\display\frameInfo.h">
+      <Filter>background\display</Filter>
+    </ClInclude>
+    <ClInclude Include="background\display\IDisplay.h">
+      <Filter>background\display</Filter>
+    </ClInclude>
+    <ClInclude Include="background\display\opDxGL.h">
+      <Filter>background\display</Filter>
+    </ClInclude>
+    <ClInclude Include="background\display\opGDI.h">
+      <Filter>background\display</Filter>
+    </ClInclude>
+    <ClInclude Include="background\Hook\DisplayHook.h">
+      <Filter>background\hook</Filter>
+    </ClInclude>
+    <ClInclude Include="background\Hook\HookExport.h">
+      <Filter>background\hook</Filter>
+    </ClInclude>
+    <ClInclude Include="background\Hook\InputHook.h">
+      <Filter>background\hook</Filter>
+    </ClInclude>
+    <ClInclude Include="background\Hook\opMessage.h">
+      <Filter>background\hook</Filter>
+    </ClInclude>
+    <ClInclude Include="background\keypad\Bkkeypad.h">
+      <Filter>background\keypad</Filter>
+    </ClInclude>
+    <ClInclude Include="background\keypad\winkeypad.h">
+      <Filter>background\keypad</Filter>
+    </ClInclude>
+    <ClInclude Include="background\mouse\opMouseDx.h">
+      <Filter>background\mouse</Filter>
+    </ClInclude>
+    <ClInclude Include="background\mouse\opMouseWin.h">
+      <Filter>background\mouse</Filter>
+    </ClInclude>
+    <ClInclude Include="algorithm\AStar.hpp">
+      <Filter>algorithm</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="gm.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
+    <ClCompile Include="pch.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="gm.rc">
+      <Filter>资源文件</Filter>
+    </ResourceCompile>
+    <ClCompile Include="libop.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
+    <ClCompile Include="winapi\Injecter.cpp">
+      <Filter>winapi</Filter>
+    </ClCompile>
+    <ClCompile Include="winapi\MemoryEx.cpp">
+      <Filter>winapi</Filter>
+    </ClCompile>
+    <ClCompile Include="winapi\query_api.cpp">
+      <Filter>winapi</Filter>
+    </ClCompile>
+    <ClCompile Include="winapi\WinApi.cpp">
+      <Filter>winapi</Filter>
+    </ClCompile>
+    <ClCompile Include="imageProc\ImageLoc.cpp">
+      <Filter>imgproc</Filter>
+    </ClCompile>
+    <ClCompile Include="imageProc\ImageProc.cpp">
+      <Filter>imgproc</Filter>
+    </ClCompile>
+    <ClCompile Include="core\globalVar.cpp">
+      <Filter>core</Filter>
+    </ClCompile>
+    <ClCompile Include="core\helpfunc.cpp">
+      <Filter>core</Filter>
+    </ClCompile>
+    <ClCompile Include="core\opEnv.cpp">
+      <Filter>core</Filter>
+    </ClCompile>
+    <ClCompile Include="core\Pipe.cpp">
+      <Filter>core</Filter>
+    </ClCompile>
+    <ClCompile Include="background\opBackground.cpp">
+      <Filter>background</Filter>
+    </ClCompile>
+    <ClCompile Include="background\display\IDisplay.cpp">
+      <Filter>background\display</Filter>
+    </ClCompile>
+    <ClCompile Include="background\display\opDxGL.cpp">
+      <Filter>background\display</Filter>
+    </ClCompile>
+    <ClCompile Include="background\display\opGDI.cpp">
+      <Filter>background\display</Filter>
+    </ClCompile>
+    <ClCompile Include="background\Hook\DisplayHook.cpp">
+      <Filter>background\hook</Filter>
+    </ClCompile>
+    <ClCompile Include="background\Hook\HookExport.cpp">
+      <Filter>background\hook</Filter>
+    </ClCompile>
+    <ClCompile Include="background\Hook\InputHook.cpp">
+      <Filter>background\hook</Filter>
+    </ClCompile>
+    <ClCompile Include="background\keypad\Bkkeypad.cpp">
+      <Filter>background\keypad</Filter>
+    </ClCompile>
+    <ClCompile Include="background\keypad\winkeypad.cpp">
+      <Filter>background\keypad</Filter>
+    </ClCompile>
+    <ClCompile Include="background\mouse\opMouseDx.cpp">
+      <Filter>background\mouse</Filter>
+    </ClCompile>
+    <ClCompile Include="background\mouse\opMouseWin.cpp">
+      <Filter>background\mouse</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>

+ 1400 - 0
gm/gm/imageProc/ImageLoc.cpp

@@ -0,0 +1,1400 @@
+//#include "stdafx.h"
+#include "ImageLoc.h"
+
+#include <assert.h>
+#include <time.h>
+
+#include <numeric>
+
+#include "../core/helpfunc.h"
+#include "imageView.hpp"
+using std::to_wstring;
+//检查是否为透明图,返回透明像素个数, 四角颜色相同且透明颜色数量在50%-99%范围内
+int check_transparent(Image *img) {
+  if (img->width < 2 || img->height < 2) return 0;
+  uint c0 = *img->begin();
+  bool x = c0 == img->at<uint>(0, img->width - 1) &&
+           c0 == img->at<uint>(img->height - 1, 0) &&
+           c0 == img->at<uint>(img->height - 1, img->width - 1);
+  if (!x) return 0;
+
+  int ct = 0;
+  for (auto it : *img)
+    if (it == c0) ++ct;
+  int total = img->height * img->width;
+  return total * 0.5 <= ct && ct < total ? ct : 0;
+}
+
+void get_match_points(const Image &img, vector<uint> &points) {
+  points.clear();
+  uint cbk = *img.begin();
+  for (int i = 0; i < img.height; ++i) {
+    for (int j = 0; j < img.width; ++j)
+      if (cbk != img.at<uint>(i, j)) points.push_back((i << 16) | j);
+  }
+}
+
+void gen_next(const Image &img, vector<int> &next) {
+  next.resize(img.width * img.height);
+
+  auto t = img.ptr<int>(0);
+  auto p = next.data();
+  p[0] = -1;
+  int k = -1, j = 0;
+  while (j < next.size() - 1) {
+    if (k == -1 || t[k] == t[j]) {
+      k++;
+      j++;
+      p[j] = k;
+    } else {
+      k = p[k];
+    }
+  }
+}
+
+void Connectivity(const ImageBin &bin, ImageBin &rec) {}
+
+void extractConnectivity(const ImageBin &src, int threshold,
+                         std::vector<ImageBin> &out) {
+  ImageBin bin = src;
+  for (auto &it : bin) {
+    it = it > threshold ? 0xffu : 0;
+  }
+  ImageBin rec;
+  rec.create(bin.width, bin.height);
+  for (auto &it : rec) {
+    it = 0;
+  }
+}
+struct MatchContext {
+  imageView view;
+  Image *pic;
+  ImageBin *gray;
+  color_t dfcolor;
+  int tnorm;
+  vector<uint> &points;
+  int use_ts_match;
+};
+
+enum PicMatchType { PicMatchRGB = 0, PicMatchGray = 1, PicMatchTrans = 2 };
+
+// template <int picMatchType>
+// point_t PicViewMatch(MatchContext context, double sim, bool *stop) {
+//   return point_t();
+// }
+// template <>
+// point_t PicViewMatch<PicMatchGray>(MatchContext context, double sim,
+//                                    bool *stop) {
+//   // 计算最大误差
+//   int max_err_ct =
+//       (context.pic->height * context.pic->width - context.use_ts_match) *
+//       (1.0 - sim);
+//   rect_t &block = context.view._block;
+//   for (int i = block.y1; i < block.y2; ++i) {
+//     for (int j = block.x1; j < block.x2; ++j) {
+//       if (*stop) return point_t(-1, -1);
+//       // 开始匹配
+//       // quick check
+//       if ((double)abs(context.tnorm -
+//                       region_sum(x, y, x + timg->width, y + timg->height)) /
+//               (double)context.tnorm >
+//           1.0 - sim)
+//         return 0;
+//       int err = 0;
+//       int maxErr = (1.0 - sim) * tnorm;
+//       for (int i = 0; i < context.gray->height; i++) {
+//         auto ptr = context.view._src.ptr(y + i) + x;
+//         auto ptr2 = timg->ptr(i);
+//         for (int j = 0; j < timg->width; j++) {
+//           err += abs(*ptr - *ptr2);
+//           ptr++;
+//           ptr2++;
+//         }
+//         if (err > maxErr) return 0;
+//       }
+
+//       return 1;
+//       // simple_match<false>(j, i, pic, dfcolor,tnorm, sim));
+//       if (match_ret) {
+//         *stop = true;
+//         return point_t(j + _x1 + _dx, i + _y1 + _dy);
+//       }
+
+//     }  // end for j
+//   }    // end for i
+//   return point_t(-1, -1);
+//}
+
+ImageBase::ImageBase() : m_threadPool(std::thread::hardware_concurrency()) {
+  _x1 = _y1 = 0;
+  _dx = _dy = 0;
+}
+
+ImageBase::~ImageBase() {}
+
+void ImageBase::set_offset(int x1, int y1) {
+  _x1 = x1;
+  _y1 = y1;
+}
+
+long ImageBase::GetPixel(long x, long y, color_t &cr) {
+  auto p = _src.ptr<color_t>(0);
+  // setlog("%d", _src.width);
+  // static_assert(sizeof(color_t) == 4);
+  cr = *p;
+  return 1;
+}
+
+long ImageBase::CmpColor(color_t color, std::vector<color_df_t> &colors,
+                         double sim) {
+  for (auto &it : colors) {
+    if (IN_RANGE(color, it.color, it.df)) return 1;
+  }
+
+  return 0;
+}
+
+long ImageBase::FindColor(vector<color_df_t> &colors, int dir, long &x,
+                          long &y) {
+  for (auto &it : colors) {  //对每个颜色描述
+
+    for (int i = 0; i < _src.height; ++i) {
+      auto p = _src.ptr<color_t>(i);
+      for (int j = 0; j < _src.width; ++j) {
+        if (IN_RANGE(*(p + j), it.color, it.df)) {
+          x = j + _x1 + _dx;
+          y = i + _y1 + _dy;
+          return 1;
+        }
+        p++;
+      }
+    }
+  }
+
+  x = y = -1;
+  return 0;
+}
+
+long ImageBase::FindColorEx(vector<color_df_t> &colors, std::wstring &retstr) {
+  retstr.clear();
+  int find_ct = 0;
+  for (int i = 0; i < _src.height; ++i) {
+    auto p = _src.ptr<color_t>(i);
+    for (int j = 0; j < _src.width; ++j) {
+      for (auto &it : colors) {  //对每个颜色描述
+        if (IN_RANGE(*p, it.color, it.df)) {
+          retstr += std::to_wstring(j + _x1 + _dx) + L"," +
+                    std::to_wstring(i + _y1 + _dy);
+          retstr += L"|";
+          ++find_ct;
+          // return 1;
+          if (find_ct > _max_return_obj_ct) goto _quick_break;
+          break;
+        }
+      }
+      p++;
+    }
+  }
+_quick_break:
+  if (!retstr.empty() && retstr.back() == L'|') retstr.pop_back();
+  return find_ct;
+}
+
+long ImageBase::FindMultiColor(std::vector<color_df_t> &first_color,
+                               std::vector<pt_cr_df_t> &offset_color,
+                               double sim, long dir, long &x, long &y) {
+  int max_err_ct = offset_color.size() * (1. - sim);
+  int err_ct;
+  for (int i = 0; i < _src.height; ++i) {
+    auto p = _src.ptr<color_t>(i);
+    for (int j = 0; j < _src.width; ++j) {
+      // step 1. find first color
+      for (auto &it : first_color) {  //对每个颜色描述
+        if (IN_RANGE(*p, it.color, it.df)) {
+          //匹配其他坐标
+          err_ct = 0;
+          for (auto &off_cr : offset_color) {
+              int ptX = j + off_cr.x;
+              int ptY = i + off_cr.y;
+              if (ptX >= 0 && ptX < _src.width && ptY >= 0 && ptY < _src.height) {
+                  color_t currentColor = _src.at<color_t>(ptY, ptX);
+                  if (!CmpColor(currentColor, off_cr.crdfs, sim))
+                      ++err_ct;
+              }
+              else {
+                  ++err_ct;
+              }
+              if (err_ct > max_err_ct) goto _quick_break;
+           
+          }
+          // ok
+          x = j + _x1 + _dx, y = i + _y1 + _dy;
+          return 1;
+        }
+      }
+    _quick_break:
+      p++;
+    }
+  }
+  x = y = -1;
+  return 0;
+}
+
+long ImageBase::FindMultiColorEx(std::vector<color_df_t> &first_color,
+                                 std::vector<pt_cr_df_t> &offset_color,
+                                 double sim, long dir, std::wstring &retstr) {
+  int max_err_ct = offset_color.size() * (1. - sim);
+  int err_ct;
+  int find_ct = 0;
+  for (int i = 0; i < _src.height; ++i) {
+    auto p = _src.ptr<color_t>(i);
+    for (int j = 0; j < _src.width; ++j) {
+      // step 1. find first color
+      for (auto &it : first_color) {  //对每个颜色描述
+        if (IN_RANGE(*p, it.color, it.df)) {
+          //匹配其他坐标
+          err_ct = 0;
+          for (auto &off_cr : offset_color) {
+           /* color_t currentColor = _src.at<color_t>(j + off_cr.x, i + off_cr.y);
+            if (!CmpColor(currentColor, off_cr.crdfs, sim)) ++err_ct;
+            if (err_ct > max_err_ct) goto _quick_break;*/
+
+            //
+            int ptX = j + off_cr.x;
+            int ptY = i + off_cr.y;
+            if (ptX >= 0 && ptX < _src.width && ptY >= 0 && ptY < _src.height) {
+                color_t currentColor = _src.at<color_t>(ptY, ptX);
+                if (!CmpColor(currentColor, off_cr.crdfs, sim))
+                    ++err_ct;
+            }
+            else {
+                ++err_ct;
+            }
+            if (err_ct > max_err_ct) goto _quick_break;
+          }
+
+          // ok
+          retstr +=
+              to_wstring(j + _x1 + _dx) + L"," + to_wstring(i + _y1 + _dy);
+          retstr += L"|";
+          ++find_ct;
+          if (find_ct > _max_return_obj_ct)
+            goto _quick_return;
+          else
+            goto _quick_break;
+        }
+      }
+    _quick_break:
+      p++;
+    }
+  }
+_quick_return:
+  if (!retstr.empty() && retstr.back() == L'|') retstr.pop_back();
+  return find_ct;
+  // x = y = -1;
+}
+
+long ImageBase::FindPic(std::vector<Image *> &pics, color_t dfcolor, double sim,
+                        long &x, long &y) {
+  x = y = -1;
+  vector<uint> points;
+  int match_ret = 0;
+  ImageBin gimg;
+  _gray.fromImage4(_src);
+  record_sum(_gray);
+  int tnorm;
+  //将小循环放在最外面,提高处理速度
+  for (int pic_id = 0; pic_id < pics.size(); ++pic_id) {
+    auto pic = pics[pic_id];
+    int use_ts_match = check_transparent(pic);
+    if (use_ts_match)
+      get_match_points(*pic, points);
+    else {
+      gimg.fromImage4(*pic);
+      tnorm = sum(gimg.begin(), gimg.end());
+    }
+
+    for (int i = 0; i < _src.height; ++i) {
+      for (int j = 0; j < _src.width; ++j) {
+        // step 1. 边界检查
+        if (i + pic->height > _src.height || j + pic->width > _src.width)
+          continue;
+        // step 2. 计算最大误差
+        int max_err_ct =
+            (pic->height * pic->width - use_ts_match) * (1.0 - sim);
+        // step 3. 开始匹配
+
+        /*match_ret = (use_ts_match ? trans_match<false>(j, i, pic, dfcolor,
+           points, max_err_ct) : simple_match<false>(j, i, pic, dfcolor,
+           max_err_ct));*/
+        match_ret = (use_ts_match ? trans_match<false>(j, i, pic, dfcolor,
+                                                       points, max_err_ct)
+                                  : real_match(j, i, &gimg, tnorm, sim));
+        // simple_match<false>(j, i, pic, dfcolor,tnorm, sim));
+        if (match_ret) {
+          x = j + _x1 + _dx;
+          y = i + _y1 + _dy;
+          return pic_id;
+        }
+
+      }  // end for j
+    }    // end for i
+  }      // end for pics
+  return -1;
+}
+
+long ImageBase::FindPicTh(std::vector<Image *> &pics, color_t dfcolor,
+                          double sim, long &x, long &y) {
+  x = y = -1;
+  vector<uint> points;
+  int match_ret = 0;
+  ImageBin gimg;
+  _gray.fromImage4(_src);
+  record_sum(_gray);
+  int tnorm;
+  std::vector<rect_t> blocks;
+  //将小循环放在最外面,提高处理速度
+  for (int pic_id = 0; pic_id < pics.size(); ++pic_id) {
+    auto pic = pics[pic_id];
+    int use_ts_match = check_transparent(pic);
+    if (use_ts_match)
+      get_match_points(*pic, points);
+    else {
+      gimg.fromImage4(*pic);
+      tnorm = sum(gimg.begin(), gimg.end());
+    }
+    auto pgimg = &gimg;
+    rect_t matchRect(0, 0, _src.width, _src.height);
+    matchRect.shrinkRect(pic->width, pic->height);
+    if (!matchRect.valid()) continue;
+    matchRect.divideBlock(m_threadPool.getThreadNum(),
+                          matchRect.width() > matchRect.height(), blocks);
+    std::vector<std::future<point_t>> results;
+    bool stop = false;
+    for (size_t i = 0; i < m_threadPool.getThreadNum(); ++i) {
+      results.push_back(m_threadPool.enqueue(
+          [this, dfcolor, points, pgimg, tnorm](rect_t &block, Image *pic,
+                                                int use_ts_match, double sim,
+                                                bool *stop) {
+            // 计算最大误差
+            int max_err_ct =
+                (pic->height * pic->width - use_ts_match) * (1.0 - sim);
+            for (int i = block.y1; i < block.y2; ++i) {
+              for (int j = block.x1; j < block.x2; ++j) {
+                if (*stop) return point_t(-1, -1);
+                // 开始匹配
+                int match_ret =
+                    (use_ts_match ? trans_match<false>(j, i, pic, dfcolor,
+                                                       points, max_err_ct)
+                                  : real_match(j, i, pgimg, tnorm, sim));
+                // simple_match<false>(j, i, pic, dfcolor,tnorm, sim));
+                if (match_ret) {
+                  *stop = true;
+                  return point_t(j + _x1 + _dx, i + _y1 + _dy);
+                }
+
+              }  // end for j
+            }    // end for i
+            return point_t(-1, -1);
+          },
+          blocks[i], pic, use_ts_match, sim, &stop));
+      // results.push_back(r);
+    }
+    // wait all
+    for (auto &&f : results) {
+      point_t p = f.get();
+      if (p.x != -1) {
+        x = p.x;
+        y = p.y;
+        // return pic_id;
+      }
+    }
+    if (x != -1) {
+      return pic_id;
+    }
+
+  }  // end for pics
+  return -1;
+}
+
+long ImageBase::FindPicEx(std::vector<Image *> &pics, color_t dfcolor,
+                          double sim, vpoint_desc_t &vpd) {
+  int obj_ct = 0;
+  vpd.clear();
+  vector<uint> points;
+  bool nodfcolor = color2uint(dfcolor) == 0;
+  int match_ret = 0;
+  ImageBin gimg;
+  _gray.fromImage4(_src);
+  record_sum(_gray);
+  int tnorm;
+  for (int pic_id = 0; pic_id < pics.size(); ++pic_id) {
+    auto pic = pics[pic_id];
+    int use_ts_match = check_transparent(pic);
+
+    if (use_ts_match)
+      get_match_points(*pic, points);
+    else {
+      gimg.fromImage4(*pic);
+      tnorm = sum(gimg.begin(), gimg.end());
+    }
+    for (int i = 0; i < _src.height; ++i) {
+      for (int j = 0; j < _src.width; ++j) {
+        // step 1. 边界检查
+        if (i + pic->height > _src.height || j + pic->width > _src.width)
+          continue;
+        // step 2. 计算最大误差
+        int max_err_ct =
+            (pic->height * pic->width - use_ts_match) * (1.0 - sim);
+        // step 3. 开始匹配
+      
+        match_ret = (use_ts_match ? trans_match<false>(j, i, pic, dfcolor,
+                                                       points, max_err_ct)
+                                  : real_match(j, i, &gimg, tnorm, sim));
+        if (match_ret) {
+          point_desc_t pd = {pic_id, point_t(j + _x1 + _dx, i + _y1 + _dy)};
+
+          vpd.push_back(pd);
+          ++obj_ct;
+          if (obj_ct > _max_return_obj_ct) goto _quick_return;
+        }
+
+      }  // end for j
+    }    // end for i
+  }      // end for pics
+_quick_return:
+
+  return obj_ct;
+}
+
+long ImageBase::FindPicExTh(std::vector<Image*>& pics, color_t dfcolor,
+    double sim, vpoint_desc_t& vpd) {
+    vpd.clear();
+    int obj_ct = 0;
+    vector<uint> points;
+    int match_ret = 0;
+    ImageBin gimg;
+    _gray.fromImage4(_src);
+    record_sum(_gray);
+    int tnorm;
+    std::vector<rect_t> blocks;
+    //将小循环放在最外面,提高处理速度
+    for (int pic_id = 0; pic_id < pics.size(); ++pic_id) {
+        auto pic = pics[pic_id];
+        int use_ts_match = check_transparent(pic);
+        if (use_ts_match)
+            get_match_points(*pic, points);
+        else {
+            gimg.fromImage4(*pic);
+            tnorm = sum(gimg.begin(), gimg.end());
+        }
+        auto pgimg = &gimg;
+        rect_t matchRect(0, 0, _src.width, _src.height);
+        matchRect.shrinkRect(pic->width, pic->height);
+        if (!matchRect.valid()) continue;
+        matchRect.divideBlock(m_threadPool.getThreadNum(),
+            matchRect.width() > matchRect.height(), blocks);
+        std::vector<std::future<vpoint_t>> results;
+        for (size_t i = 0; i < m_threadPool.getThreadNum(); ++i) {
+            results.push_back(m_threadPool.enqueue(
+                [this, dfcolor, points, pgimg, tnorm](rect_t& block, Image* pic,
+                    int use_ts_match, double sim)->vpoint_t {
+                        vpoint_t vp;
+                        // 计算最大误差
+                        int max_err_ct =
+                            (pic->height * pic->width - use_ts_match) * (1.0 - sim);
+                        for (int i = block.y1; i < block.y2; ++i) {
+                            for (int j = block.x1; j < block.x2; ++j) {
+                                // 开始匹配
+                                int match_ret =
+                                    (use_ts_match ? trans_match<false>(j, i, pic, dfcolor,
+                                        points, max_err_ct)
+                                        : real_match(j, i, pgimg, tnorm, sim));
+                                // simple_match<false>(j, i, pic, dfcolor,tnorm, sim));
+                                if (match_ret) {
+                                    vp.push_back(point_t(j + _x1 + _dx, i + _y1 + _dy));
+                                }
+
+                            }  // end for j
+                        }    // end for i
+                        return vp;
+                },
+                blocks[i], pic, use_ts_match, sim));
+            // results.push_back(r);
+        }
+        // wait all
+        for (auto&& f : results) {
+            vpoint_t vp = f.get();
+            if (vp.size()>0) {
+               
+                for (auto& p : vp) {
+                    point_desc_t pd = { pic_id,p };
+
+                    vpd.push_back(pd);
+                    ++obj_ct;
+                    if (obj_ct > _max_return_obj_ct) goto _quick_return;
+                }
+
+                // return pic_id;
+            }
+        }
+
+    }  
+_quick_return:
+
+    return obj_ct;
+}
+
+long ImageBase::FindColorBlock(double sim, long count, long height, long width,
+                               long &x, long &y) {
+  x = y = -1;
+  record_sum(_binary);
+  for (int i = 0; i <= _binary.height - height; ++i) {
+    for (int j = 0; j < _binary.width - width; ++j) {
+      if (region_sum(j, i, j + width, i + height) >= count) {
+        x = j + _x1 + _dx;
+        y = i + _y1 + _dy;
+        return 1;
+      }
+    }
+  }
+  return -1;
+}
+
+long ImageBase::FindColorBlockEx(double sim, long count, long height,
+                                 long width, std::wstring &retstr) {
+  record_sum(_binary);
+  int cnt = 0;
+  for (int i = 0; i <= _binary.height - height; ++i) {
+    for (int j = 0; j < _binary.width - width; ++j) {
+      if (region_sum(j, i, j + width, i + height) >= count) {
+        wchar_t buff[20];
+        wsprintfW(buff, L"%d,%d|", j + _x1 + _dx, i + _y1 + _dy);
+        retstr += buff;
+        ++cnt;
+        if (cnt > _max_return_obj_ct) goto _quick_return;
+      }
+    }
+  }
+_quick_return:
+  if (cnt) {
+    retstr.pop_back();
+  }
+  return cnt;
+}
+
+long ImageBase::Ocr(Dict &dict, double sim, wstring &retstr) {
+  retstr.clear();
+  std::map<point_t, wstring> ps;
+  bin_ocr(dict, sim, ps);
+  for (auto &it : ps) {
+    retstr += it.second;
+  }
+  return 1;
+}
+
+long ImageBase::OcrEx(Dict &dict, double sim, std::wstring &retstr) {
+  retstr.clear();
+  std::map<point_t, wstring> ps;
+  bin_ocr(dict, sim, ps);
+  // x1,y1,str....|x2,y2,str2...|...
+  int find_ct = 0;
+  for (auto &it : ps) {
+    retstr += std::to_wstring(it.first.x + _x1 + _dx);
+    retstr += L",";
+    retstr += std::to_wstring(it.first.y + _y1 + _dy);
+    retstr += L",";
+    retstr += it.second;
+    retstr += L"|";
+    ++find_ct;
+    if (find_ct > _max_return_obj_ct) break;
+  }
+  if (!retstr.empty() && retstr.back() == L'|') retstr.pop_back();
+  return find_ct;
+}
+
+long ImageBase::FindStr(Dict &dict, const vector<wstring> &vstr, double sim,
+                        long &retx, long &rety) {
+  retx = rety = -1;
+
+  //查找字符 返回坐标
+  // step 1. 找出频幕中所有字符及其坐标信息
+  std::map<point_t, wstring> ps;
+  bin_ocr(dict, sim, ps);
+  // step 2. 拼接字符 形成完整字符串
+  wstring str;
+  for (auto &it : ps) str.append(it.second);
+  // step 3. 在完整字符中查找目标字符串,并记录 索引
+  int idx = -1;
+  int oneIndex = -1;
+  for (int i = 0; i < vstr.size(); ++i) {
+    idx = str.find(vstr[i]);
+    if (idx != -1) {
+      oneIndex = i;
+      break;
+    }
+  }
+  // step 4.根据索引给出对应 坐标 并返回
+  if (idx != -1) {  // locate it
+    int curr_len = 0;
+    for (auto &it : ps) {
+      curr_len += it.second.length();
+      if (curr_len < idx + 1) continue;
+      if (it.second.find(str[idx]) != -1) {
+        retx = it.first.x + _x1 + _dx;
+        rety = it.first.y + _y1 + _dy;
+        return oneIndex;
+      }
+    }
+    //这里进行断言,表示不会走到这一步
+    assert(0);
+  }
+
+  return -1;
+}
+
+long ImageBase::FindStrEx(Dict &dict, const vector<wstring> &vstr, double sim,
+                          std::wstring &retstr) {
+  //描述:查找屏幕指定位置的字符(或者字符串)位置,返回所有出现的坐标(注意与FindStr接口的区别)!!!
+  //----------------------步骤-----------------
+  // step 1. 获取指定位置的字符及坐标信息
+  // step 2. 拼接字符,形成完整字符串 str
+  // step 2.对每个目标字符 ti , 查找其在str中的位置,并记录 index(如果存在)
+  // step 4.根据index ,获取其坐标,并将坐标转化为字符串,拼接到返回值
+  // step 5. 回到第3步
+
+  retstr.clear();
+  std::map<point_t, wstring> ps;
+  // step 1.
+  bin_ocr(dict, sim, ps);
+  // setp 2.
+  wstring str;
+  for (auto &it : ps) {
+    str.append(it.second);
+  }
+  // step 3.
+  int find_ct = 0;
+  for (int i = 0; i < vstr.size(); ++i) {
+    int index = -1, old = -1;
+    do {
+      index = str.find(vstr[i], old + 1);
+      if (index == -1) {  // failed!!
+        break;
+      }
+      // step 4
+      int current_len = 0;
+      for (auto &it : ps) {
+        //注意 字符长度要大于index 才记录坐标
+        current_len += it.second.length();
+        if (current_len < index + 1) continue;
+        if (it.second.find(str[index]) != -1) {
+          //记录坐标
+          wchar_t buff[20] = {0};
+          //注意加偏移
+          wsprintf(buff, L"%d,%d,%d|", i, it.first.x + _x1 + _dx,
+                   it.first.y + _y1 + _dy);
+          retstr.append(buff);
+          ++find_ct;
+          if (find_ct > _max_return_obj_ct)
+            goto _quick_return;
+          else
+            break;
+          // to do 这里还需要修改
+        }
+      }  // end for ps
+      old = index;
+    } while (1);
+  }
+_quick_return:
+  if (!retstr.empty() && retstr.back() == L'|') retstr.pop_back();
+  return find_ct;
+}
+
+long ImageBase::FindLine(double sim, std::wstring &outStr) {
+  outStr.clear();
+  int h =
+      sqrt(_binary.width * _binary.width + _binary.height * _binary.height) + 2;
+  _sum.create(360, h);
+  //行:距离,列:角度
+  _sum.fill(0);
+  for (int i = 0; i < _binary.height; i++) {
+    for (int j = 0; j < _binary.width; j++) {
+      if (_binary.at(i, j) == WORD_COLOR) {
+        for (int t = 0; t < 360; t++) {
+          int d =
+              j * cos(t * 0.0174532925) + i * sin(t * 0.0174532925);  //可以优化
+          assert(d <= h);
+          if (d >= 0) _sum.at<int>(d, t)++;
+        }
+      }
+    }
+  }
+  int maxRow = 0, maxCol = 0;
+  int maxval = -1;
+  for (int i = 0; i < _sum.height; i++) {
+    for (int j = 0; j < _sum.width; j++) {
+      if (_sum.at<int>(i, j) > maxval) {
+        maxRow = i;
+        maxCol = j;
+        maxval = _sum.at<int>(i, j);
+      }
+    }
+  }
+  // setlog("degree=%d,dis=%d,val=%d", maxCol, maxRow, maxval);
+  wchar_t buffer[256];
+  wsprintf(buffer, L"%d,%d", maxCol, maxRow);
+  outStr = buffer;
+  return maxval;
+}
+
+template <bool nodfcolor>
+long ImageBase::simple_match(long x, long y, Image *timg, color_t dfcolor,
+                             int tnorm, double sim) {
+  int err_ct = 0;
+  // quick check
+  if ((double)abs(tnorm - region_sum(x, y, x + timg->width, y + timg->height)) >
+      (double)tnorm * (1.0 - sim))
+    return 0;
+  int max_error = (1.0 - sim) * timg->size();
+  uint *pscreen_top, *pscreen_bottom, *pimg_top, *pimg_bottom;
+  pscreen_top = _src.ptr<uint>(y) + x;
+  pscreen_bottom = _src.ptr<uint>(y + timg->height - 1) + x;
+  pimg_top = timg->ptr<uint>(0);
+  pimg_bottom = timg->ptr<uint>(timg->height - 1);
+  while (pscreen_top <= pscreen_bottom) {
+    auto ps1 = pscreen_top, ps2 = pscreen_top + timg->width - 1;
+    auto ps3 = pscreen_bottom, ps4 = pscreen_bottom + timg->width - 1;
+    auto pt1 = pimg_top, pt2 = pimg_top + timg->width - 1;
+    auto pt3 = pimg_bottom, pt4 = pimg_bottom + timg->width - 1;
+    while (ps1 <= ps2) {
+      if (nodfcolor) {
+        if (*ps1++ != *pt1++) ++err_ct;  // top left
+        if (*ps2-- != *pt2--) ++err_ct;  // top right
+        if (*ps3++ != *pt3++) ++err_ct;  // bottom left
+        if (*ps4-- != *pt4--) ++err_ct;  // bottom right
+      } else {
+        if (!IN_RANGE(*(color_t *)ps1++, *(color_t *)pt1++, dfcolor)) ++err_ct;
+        if (!IN_RANGE(*(color_t *)ps2--, *(color_t *)pt2--, dfcolor)) ++err_ct;
+        if (!IN_RANGE(*(color_t *)ps3++, *(color_t *)pt3++, dfcolor)) ++err_ct;
+        if (!IN_RANGE(*(color_t *)ps4--, *(color_t *)pt4--, dfcolor)) ++err_ct;
+      }
+
+      if (err_ct > max_error) return 0;
+    }
+    pscreen_top += _src.width;
+    pscreen_bottom -= _src.width;
+  }
+
+  return 1;
+}
+template <bool nodfcolor>
+long ImageBase::trans_match(long x, long y, Image *timg, color_t dfcolor,
+                            vector<uint> pts, int max_error) {
+  int err_ct = 0, k, dx, dy;
+  int left, right;
+  left = 0;
+  right = pts.size() - 1;
+  while (left <= right) {
+    auto it = pts[left];
+    if (nodfcolor) {
+      if (_src.at<uint>(y + PTY(pts[left]), x + PTX(pts[left])) !=
+          timg->at<uint>(PTY(pts[left]), PTX(pts[left])))
+        ++err_ct;
+      if (_src.at<uint>(y + PTY(pts[right]), x + PTX(pts[right])) !=
+          timg->at<uint>(PTY(pts[right]), PTX(pts[right])))
+        ++err_ct;
+    } else {
+      color_t cr1, cr2;
+      cr1 = _src.at<color_t>(y + PTY(pts[left]), x + PTX(pts[left]));
+      cr2 = timg->at<color_t>(PTY(pts[left]), PTX(pts[left]));
+      if (!IN_RANGE(cr1, cr2, dfcolor)) ++err_ct;
+      cr1 = _src.at<color_t>(y + PTY(pts[right]), x + PTX(pts[right]));
+      cr2 = timg->at<color_t>(PTY(pts[right]), PTX(pts[right]));
+      if (!IN_RANGE(cr1, cr2, dfcolor)) ++err_ct;
+    }
+
+    ++left;
+    --right;
+    if (err_ct > max_error) return 0;
+  }
+  return 1;
+}
+
+long ImageBase::real_match(long x, long y, ImageBin *timg, int tnorm,
+                           double sim) {
+  // quick check
+  if ((double)abs(tnorm - region_sum(x, y, x + timg->width, y + timg->height)) /
+          (double)tnorm >
+      1.0 - sim)
+    return 0;
+  int err = 0;
+  int maxErr = (1.0 - sim) * tnorm;
+  for (int i = 0; i < timg->height; i++) {
+    auto ptr = _gray.ptr(y + i) + x;
+    auto ptr2 = timg->ptr(i);
+    for (int j = 0; j < timg->width; j++) {
+      err += abs(*ptr - *ptr2);
+      ptr++;
+      ptr2++;
+    }
+    if (err > maxErr) return 0;
+  }
+
+  return 1;
+}
+
+void ImageBase::record_sum(const ImageBin &gray) {
+  //为了减少边界判断,这里多多加一行一列
+  _sum.create(gray.width + 1, gray.height + 1);
+  _sum.fill(0);
+  int m = _sum.height;
+  int n = _sum.width;
+  for (int i = 1; i < m; i++) {
+    for (int j = 1; j < n; j++) {
+      int s = 0;
+
+      s += _sum.at<int>(i - 1, j);
+
+      s += _sum.at<int>(i, j - 1);
+
+      s -= _sum.at<int>(i - 1, j - 1);
+      s += (int)gray.at(i - 1, j - 1);
+      _sum.at<int>(i, j) = s;
+    }
+  }
+}
+
+int ImageBase::region_sum(int x1, int y1, int x2, int y2) {
+  int ans = _sum.at<int>(y2, x2) - _sum.at<int>(y2, x1) - _sum.at<int>(y1, x2) +
+            _sum.at<int>(y1, x1);
+  return ans;
+}
+
+constexpr int MIN_CUT_W = 5;
+constexpr int MIN_CUT_H = 2;
+
+int ImageBase::get_bk_color(inputbin bin) {
+  int y[256] = {0};
+  auto ptr = bin.pixels.data();
+  int n = bin.pixels.size();
+  for (int i = 0; i < n; ++i) y[ptr[i]]++;
+  // scan max
+  int m = 0;
+  for (int i = 1; i < 256; ++i) {
+    if (y[i] > y[m]) m = i;
+  }
+  return m;
+}
+
+void ImageBase::bgr2binary(vector<color_df_t> &colors) {
+  if (_src.empty()) return;
+  int ncols = _src.width, nrows = _src.height;
+  _binary.fromImage4(_src);
+  for (int i = 0; i < nrows; ++i) {
+    auto psrc = _src.ptr<color_t>(i);
+
+    auto pbin = _binary.ptr(i);
+    for (int j = 0; j < ncols; ++j) {
+      uchar g1 = psrc->toGray();
+      *pbin = WORD_BKCOLOR;
+      for (auto &it : colors) {  //对每个颜色描述
+        if (abs(g1 - it.color.toGray()) <= it.df.toGray()) {
+          *pbin = WORD_COLOR;
+          break;
+        }
+      }
+      ++pbin;
+      ++psrc;
+    }
+  }
+  //_binary.create(ncols, nrows);
+  // for (int i = 0; i < nrows; ++i) {
+  //	auto psrc = _src.ptr<color_t>(i);
+  //	auto pbin = _binary.ptr(i);
+  //	for (int j = 0; j < ncols; ++j) {
+  //		*pbin = WORD_BKCOLOR;
+  //		for (auto& it : colors) {//对每个颜色描述
+  //			if (IN_RANGE(*psrc, it.color, it.df)) {
+  //				*pbin = WORD_COLOR;
+  //				break;
+  //			}
+  //		}
+  //		++pbin; ++psrc;
+  //	}
+  //}
+  // test
+  // cv::imwrite("src.png", _src);
+  // cv::imwrite("binary.png", _binary);
+}
+
+//二值化
+void ImageBase::bgr2binarybk(const vector<color_df_t> &bk_colors) {
+  //创建二值图
+  _binary.create(_src.width, _src.height);
+  memset(_binary.pixels.data(), WORD_BKCOLOR, _binary.size());
+  int n = _binary.size();
+  auto pdst = _binary.data();
+  if (bk_colors.size() == 0) {  // auto
+    //转为灰度图
+    _gray.fromImage4(_src);
+
+    //获取背景颜色
+    int bkcolor = get_bk_color(_gray);
+
+    auto pgray = _gray.data();
+    for (int i = 0; i < n; ++i) {
+      pdst[i] =
+          (std::abs((int)pgray[i] - bkcolor) < 20 ? WORD_BKCOLOR : WORD_COLOR);
+    }
+  } else {
+    for (auto bk : bk_colors) {
+      for (int i = 0; i < n; ++i) {
+        auto c = (color_t *)(_src.pdata + i * 4);
+        if (!IN_RANGE(*c, bk.color, bk.df)) pdst[i] = WORD_COLOR;
+      }
+    }
+  }
+}
+
+//垂直方向投影到x轴
+void ImageBase::binshadowx(const rect_t &rc, std::vector<rect_t> &out_put) {
+  // qDebug("in x rc:%d,%d,%d,%d", rc.x1, rc.y1, rc.x2, rc.y2);
+  out_put.clear();
+  // ys.clear();
+  // Mat paintx(binary.size(), CV_8UC1, cv::Scalar(255));
+  // //创建一个全白图片,用作显示
+
+  // int* blackcout = new int[binary.cols];
+  std::vector<int> vx;
+  vx.resize(_binary.width);
+  memset(&vx[0], 0, _binary.width * 4);
+  for (int j = rc.x1; j < rc.x2; j++) {
+    for (int i = rc.y1; i < rc.y2; i++) {
+      if (_binary.at(i, j) == WORD_COLOR) {
+        vx[j]++;  //垂直投影按列在x轴进行投影
+      }
+    }
+  }
+
+  int startindex = 0;
+  int endindex = 0;
+  bool inblock = false;  //是否遍历到字符位置
+  rect_t roi;
+  for (int j = rc.x1; j < rc.x2; j++) {
+    if (!inblock && vx[j] != 0)  //进入有字符区域
+    {
+      inblock = true;
+      startindex = j;
+      // std::cout << "startindex:" << startindex << std::endl;
+    }
+    // if (inblock&&vx[j] == 0) //进入空白区
+    else if (inblock && vx[j] == 0 &&
+             j - startindex >= MIN_CUT_W)  //进入空白区域,且宽度不小于1
+    {
+      endindex = j;
+      inblock = false;
+      // Mat roi = binary.colRange(startindex, endindex + 1);
+
+      roi.x1 = startindex;
+      roi.y1 = rc.y1;
+      roi.x2 = endindex;
+      roi.y2 = rc.y2;
+      // qDebug("out xrc:%d,%d,%d,%d", roi.x1, roi.y1, roi.x2, roi.y2);
+      out_put.push_back(roi);
+    }
+  }
+  // special case
+  if (inblock) {
+    roi.x1 = startindex;
+    roi.y1 = rc.y1;
+    roi.x2 = rc.x2;
+    roi.y2 = rc.y2;
+    out_put.push_back(roi);
+  }
+}
+//投影到y轴
+void ImageBase::binshadowy(const rect_t &rc, std::vector<rect_t> &out_put) {
+  // qDebug("in y rc:%d,%d,%d,%d", rc.x1, rc.y1, rc.x2, rc.y2);
+  out_put.clear();
+  //是否为白色或者黑色根据二值图像的处理得来
+  // Mat painty(binary.size(), CV_8UC1, cv::Scalar(255)); //初始化为全白
+  //水平投影
+  // int* pointcount = new int[binary.rows]; //在二值图片中记录行中特征点的个数
+  std::vector<int> vy;
+  vy.resize(_binary.height);
+  memset(&vy[0], 0, _binary.height * 4);  //注意这里需要进行初始化
+
+  for (int i = rc.y1; i < rc.y2; i++) {
+    for (int j = rc.x1; j < rc.x2; j++) {
+      if (_binary.at(i, j) == WORD_COLOR) {
+        vy[i]++;  //记录每行中黑色点的个数 //水平投影按行在y轴上的投影
+      }
+    }
+  }
+
+  // std::vector<Mat> result;
+  int startindex = 0;
+  int endindex = 0;
+  bool inblock = false;  //是否遍历到字符位置
+  rect_t roi;
+  for (int i = rc.y1; i < rc.y2; i++) {
+    if (!inblock && vy[i] != 0)  //进入有字符区域
+    {
+      inblock = true;
+      startindex = i;
+      // std::cout << "startindex:" << startindex << std::endl;
+    }
+    // if (inblock&&vy[i] == 0) //进入空白区
+    if (inblock && vy[i] == 0 &&
+        i - startindex >= MIN_CUT_H)  //进入空白区,且高度不小于1
+    {
+      endindex = i;
+      inblock = false;
+
+      roi.x1 = rc.x1;
+      roi.y1 = startindex;
+      roi.x2 = rc.x2;
+      roi.y2 = endindex;
+      out_put.push_back(roi);
+    }
+  }
+
+  if (inblock) {
+    roi.x1 = rc.x1;
+    roi.y1 = startindex;
+    roi.x2 = rc.x2;
+    roi.y2 = rc.y2;
+    out_put.push_back(roi);
+  }
+}
+
+void ImageBase::bin_image_cut(int min_word_h, const rect_t &inrc,
+                              rect_t &outrc) {
+  //水平裁剪,缩小高度
+  std::vector<int> v;
+  outrc = inrc;
+  int i, j;
+  v.resize(_binary.height);
+  for (auto &it : v) it = 0;
+  for (i = inrc.y1; i < inrc.y2; ++i) {
+    for (j = inrc.x1; j < inrc.x2; ++j)
+      v[i] += (_binary.at(i, j) == WORD_COLOR ? 1 : 0);
+  }
+  i = inrc.y1;
+  while (v[i] == 0) i++;
+  outrc.y1 = i;
+  i = inrc.y2 - 1;
+  while (v[i] == 0) i--;
+  if (i + 1 - outrc.y1 > min_word_h) outrc.y2 = i + 1;
+  //垂直裁剪.缩小宽度
+  v.resize(_binary.width);
+  for (auto &it : v) it = 0;
+
+  for (i = inrc.y1; i < inrc.y2; ++i) {
+    for (j = inrc.x1; j < inrc.x2; ++j)
+      v[j] += _binary.at(i, j) == WORD_COLOR ? 1 : 0;
+  }
+  i = inrc.x1;
+  while (v[i] == 0) i++;
+  outrc.x1 = i;
+  i = inrc.x2 - 1;
+  while (v[i] == 0) i--;
+  outrc.x2 = i + 1;
+}
+
+void ImageBase::get_rois(int min_word_h, std::vector<rect_t> &vroi) {
+  vroi.clear();
+  std::vector<rect_t> vrcx, vrcy;
+  rect_t rc;
+  rc.x1 = rc.y1 = 0;
+  rc.x2 = _binary.width;
+  rc.y2 = _binary.height;
+  binshadowy(rc, vrcy);
+  for (int i = 0; i < vrcy.size(); ++i) {
+    binshadowx(vrcy[i], vrcx);
+    for (int j = 0; j < vrcx.size(); j++) {
+      if (vrcx[j].width() >= min_word_h)
+        bin_image_cut(min_word_h, vrcx[j], vrcx[j]);
+      vroi.push_back(vrcx[j]);
+    }
+  }
+}
+
+inline int full_match(const ImageBin &binary, rect_t &rc, const uint8_t *data) {
+  //匹配
+  int idx = 0;
+  for (int x = rc.x1; x < rc.x2; ++x) {
+    for (int y = rc.y1; y < rc.y2; ++y) {
+      int val = GET_BIT(data[idx / 8], idx & 7);
+      if (binary.at(y, x) != val) return 0;
+      idx++;
+    }
+  }
+  return 1;
+}
+
+inline int part_match(const ImageBin &binary, rect_t &rc, int max_error,
+                      const uint8_t *data) {
+  //匹配
+  //匹配
+  int err_ct = 0;
+  int idx = 0;
+  for (int x = rc.x1; x < rc.x2; ++x) {
+    for (int y = rc.y1; y < rc.y2; ++y) {
+      int val = GET_BIT(data[idx / 8], idx & 7);
+      if (binary.at(y, x) != val) {
+        ++err_ct;
+        if (err_ct > max_error) return 0;
+      }
+      idx++;
+    }
+  }
+  return 1;
+}
+
+inline void fill_rect(ImageBin &record, const rect_t &rc) {
+  int w = rc.width();
+  for (int y = rc.y1; y < rc.y2; ++y) {
+    uchar *p = record.ptr(y) + rc.x1;
+    memset(p, 1, sizeof(uchar) * w);
+  }
+}
+
+int binarySearch(const word1_t a[], int bidx, int eidx, int target)  //循环实现
+{
+  int low = bidx, high = eidx, middle;
+  while (low < high) {
+    middle = (low + high) / 2;
+    if (target == a[middle].info.bit_cnt)
+      return middle;
+    else if (target > a[middle].info.bit_cnt)
+      low = middle + 1;
+    else if (target < a[middle].info.bit_cnt)
+      high = middle;
+  }
+  return -1;
+};
+
+//完全匹配 待识别文字不能含有任何噪声
+/*
+算法
+f(p,size) 为从点p开始,大小为size的矩形块像素之和,这个函数使用查表法快速计算
+字库:D 字的像素范围:m-M 字的大小范围:size_min-size_max
+识别图像:src
+for each point in src:
+        if f(p,size_max)<m //像素太少
+                continue;
+        if f(p,size_min)>M //像素太多
+                continue;
+        //像素合适
+        for each w in D
+                if f(p,w_size)==w_cnt
+                        ok=match(...) //作最后的匹配
+                        if ok
+                                add w to result;
+                                delete rect(p,w_size);
+                        else
+                                continue;//to next w
+                        endif
+                end
+        end
+end
+*/
+void ImageBase::_bin_ocr(const Dict &dict,
+                         std::map<point_t, std::wstring> &ps) {
+  int px, py;
+  if (_binary.empty()) return;
+  //
+  record_sum(_binary);
+  // find cnt range
+  // find width and height range;
+  int cnt_min = 255 * 255, cnt_max = 0;
+  int w_min = 255, h_min = 255;
+  int w_max = 0, h_max = 0;
+  for (auto &it : dict.words) {
+    cnt_min = min(cnt_min, it.info.bit_cnt);
+    cnt_max = max(cnt_max, it.info.bit_cnt);
+    w_min = min(w_min, it.info.w);
+    h_min = min(h_min, it.info.h);
+    w_max = max(w_max, it.info.w);
+    h_max = max(h_max, it.info.h);
+  }
+
+  //将所有字库按照大小分成几类,对于每个大小根据像素密度查找对应的符合字库
+  auto makeinfo = [](int begin, int end, int szh, int szw) {
+    return std::make_pair(begin << 16 | end, szh << 8 | szw);
+  };
+  vector<std::pair<int, int>> dict_sz;
+  auto &vword = dict.words;
+  // 32 begin(8)
+  dict_sz.push_back(makeinfo(0, 0, dict.words[0].info.h, dict.words[0].info.w));
+  for (int i = 1; i < vword.size(); i++) {
+    int sz = vword[i].info.h << 8 | vword[i].info.w;
+    if (dict_sz.back().second != sz) {
+      dict_sz.back().first |= i;                       // fix old end
+      dict_sz.push_back(std::make_pair(i << 16, sz));  // add new begin
+    }
+  }
+  dict_sz.back().first |= vword.size();
+
+  //遍历行
+  for (py = 0; py < _binary.height - h_min + 1; ++py) {
+    //遍历列
+    for (px = 0; px < _binary.width - w_min + 1; ++px) {
+      if (_record.at(py, px)) continue;
+      //检测像素密度
+      if (region_sum(px, py, min(px + w_max, _binary.width),
+                     min(py + h_max, _binary.height)) < cnt_min)  // too less
+        continue;
+      if (region_sum(px, py, px + w_min, py + h_min) > cnt_max)  // too much
+        continue;
+      point_t pt;
+      pt.x = px;
+      pt.y = py;
+      int k = 0;
+      for (int k = 0; k < dict_sz.size(); k++) {
+        int h = dict_sz[k].second >> 8, w = dict_sz[k].second & 0xff;
+        rect_t crc;
+        crc.x1 = px;
+        crc.y1 = py;
+        crc.x2 = px + w;
+        crc.y2 = py + h;
+        //边界检查
+        if (crc.y2 > _binary.height || crc.x2 > _binary.width) continue;
+
+        int fidx = dict_sz[k].first >> 16, eidx = dict_sz[k].first & 0xffff;
+
+        // quick check
+        int cnt_src = region_sum(crc.x1, crc.y1, crc.x2, crc.y2);
+        if (cnt_src < vword[fidx].info.bit_cnt ||
+            cnt_src > vword[eidx - 1].info.bit_cnt)
+          continue;
+        int tidx = binarySearch(&vword[0], fidx, eidx, cnt_src);
+        if (tidx == -1) continue;
+        int tleft = tidx, tright = tidx;
+        while (tleft > 0 && vword[tleft - 1].info.bit_cnt == cnt_src) --tleft;
+        while (tright < eidx && vword[tright].info.bit_cnt == cnt_src) ++tright;
+        int matched = 0;
+        // match
+        tidx = tleft;
+        while (tidx < tright) {
+          auto &it = vword[tidx++];
+          matched = full_match(_binary, crc, it.data.data());
+          if (matched) {
+            // final check
+            // check right col is empty/background
+            int rs = 0;
+            if (crc.x2 < _binary.width) {
+              for (int k = crc.y1; k < crc.y2; k++) rs += _binary.at(k, crc.x2);
+            }
+            if (rs < it.info.h / 2) {
+              ps[pt] = it.info.name;
+              fill_rect(_record, crc);
+              // break;//words
+              break;
+            } else {
+              // not matched
+              matched = 0;
+            }
+          }
+        }
+        if (matched) break;
+      }  // end for words
+    }    // end for j
+  }      // end for i
+}
+//模糊匹配 待识别区域可以含有噪声
+void ImageBase::_bin_ocr(const Dict &dict, double sim,
+                         std::map<point_t, std::wstring> &ps) {
+  int px, py, y;
+  if (_binary.empty()) return;
+  //
+  record_sum(_binary);
+  // find cnt range
+  // find width and height range;
+  int cnt_min = 255 * 255, cnt_max = 0;
+  int w_min = 255, h_min = 255;
+  int w_max = 0, h_max = 0;
+  for (auto &it : dict.words) {
+    cnt_min = min(cnt_min, it.info.bit_cnt);
+    cnt_max = max(cnt_max, it.info.bit_cnt);
+    w_min = min(w_min, it.info.w);
+    h_min = min(h_min, it.info.h);
+    w_max = max(w_max, it.info.w);
+    h_max = max(h_max, it.info.h);
+  }
+  int matched = 0;
+  //遍历行
+  for (py = 0; py < _binary.height - h_min + 1; ++py) {
+    //遍历列
+    for (px = 0; px < _binary.width - w_min + 1; ++px) {
+      if (_record.at(py, px)) continue;
+      //检测像素密度
+      if (region_sum(px, py, min(px + w_max, _binary.width),
+                     min(py + h_max, _binary.height)) <
+          cnt_min * sim)  // too less
+        continue;
+      if (region_sum(px, py, px + w_min, py + h_min) > cnt_max * (2 - sim))
+        continue;
+      point_t pt;
+      pt.x = px;
+      pt.y = py;
+      //遍历字库
+      // assert(i != 4 || j != 3);
+      int k = 0;
+      for (auto &it : dict.words) {
+        rect_t crc;
+        crc.x1 = px;
+        crc.y1 = py;
+        crc.x2 = px + it.info.w;
+        crc.y2 = py + it.info.h;
+        //边界检查
+        if (crc.y2 > _binary.height || crc.x2 > _binary.width) continue;
+        // quick check
+
+        int error = (1 - sim) * it.info.w * it.info.h;
+        if (abs(region_sum(crc.x1, crc.y1, crc.x2, crc.y2) - it.info.bit_cnt) >
+            error)
+          continue;
+        // match
+        matched = part_match(_binary, crc, error, it.data.data());
+
+        if (matched) {
+          // final check
+          // check right col is empty/background
+          int rs = 0;
+          if (crc.x2 < _binary.width) {
+            for (int k = crc.y1; k < crc.y2; k++) rs += _binary.at(k, crc.x2);
+          }
+          if (rs <= it.info.h / 2) {
+            ps[pt] = it.info.name;
+            fill_rect(_record, crc);
+            // break;//words
+            break;
+          } else {
+            // not matched
+            matched = 0;
+          }
+        }
+      }  // end for words
+         // if (matched)break;
+    }    // end for j
+  }      // end for i
+}
+
+void ImageBase::bin_ocr(const Dict &dict, double sim,
+                        std::map<point_t, std::wstring> &ps) {
+  ps.clear();
+  if (dict.words.empty()) return;
+  if (_binary.empty()) return;
+  _record.create(_binary.width, _binary.height);
+  memset(_record.data(), 0, sizeof(uchar) * _record.width * _record.height);
+
+  if (sim > 1.0 - 1e-5) {
+    _bin_ocr(dict, ps);
+  } else {
+    sim = 0.5 + sim / 2;
+
+    _bin_ocr(dict, sim, ps);
+  }
+}

+ 184 - 0
gm/gm/imageProc/ImageLoc.h

@@ -0,0 +1,184 @@
+#pragma once
+#ifndef __IMAGELOC_H_
+#define __IMAGELOC_H_
+/*
+常见的图像算法,例如图像查找,颜色序列匹配(多点着色)
+由于ocr与图像查找类似,故也在类ImageLoc中实现
+*/
+#include <vector>
+#include "../core/optype.h"
+#include <string>
+#include "../include/Dict.h"
+#include "../include/color.h"
+#include "./compute/ThreadPool.h"
+inline int HEX2INT(wchar_t c) {
+	if (L'0' <= c && c <= L'9')
+		return c - L'0';
+	if (L'A' <= c && c <= L'Z')
+		return c - L'A' + 10;
+	if (L'a' <= c && c <= L'z')
+		return c - L'a' + 10;
+	return 0;
+}
+
+
+#define SET_BIT(x, idx) (x |= 1u << (idx))
+
+#define GET_BIT(x, idx) ((x >> (idx)) & 1u)
+
+using img_names = std::vector<std::wstring>;
+//检查是否为透明图
+int check_transparent(Image* img);
+//获取匹配点
+void get_match_points(const Image& img, vector<int>&points);
+//generate next index for kmp
+void gen_next(const Image& img, vector<int>& next);
+//sum of all pixels
+int inline sum(uchar* begin, uchar* end) {
+	int s = 0;
+	while (begin != end)
+		s += *begin++;
+	return s;
+}
+
+void extractConnectivity(const ImageBin& src, int threshold, std::vector<ImageBin>& out);
+
+
+struct gray_diff_t{
+	gray_diff_t(color_df_t const& cd):gray(cd.color.toGray()),diff(cd.df.toGray()){
+
+	}
+	unsigned char gray;
+	unsigned char diff;
+};
+/*
+此类用于实现一些图像功能,如图像定位,简单ocr等
+*/
+class ImageBase
+{
+public:
+	
+	const static int _max_return_obj_ct = 1800;
+
+	using vcolor_diff_t = vector<color_df_t>;//rgb color-diff
+	using vgray_diff_t =vector<gray_diff_t>;//gray
+
+	ImageBase();
+
+	~ImageBase();
+
+	//brief:输入图像,建立图形矩阵,在图像操作前调用
+	//image_data:	4子节对齐的像素指针
+	//widht:		图像宽度
+	//hegith:		h
+	//x1,y1,x2,y2 拷贝区域
+	//type:			输入类型,type=0表示正常输入,为-1时表示倒置输入
+	//long input_image(byte* psrc, int cols, int height,long x1,long y1,long x2,long y2, int type = 0);
+
+	void set_offset(int x1, int y1);
+	
+	long is_valid(long x, long y) {
+		return x >= 0 && y >= 0 && x < _src.width && y < _src.height;
+	}
+
+	long GetPixel(long x, long y, color_t&cr);
+
+	long CmpColor(color_t color, std::vector<color_df_t>&colors, double sim);
+
+	long FindColor(std::vector<color_df_t>&colors,int dir, long&x, long&y);
+
+	long FindColorEx(std::vector<color_df_t>&colors, std::wstring& retstr);
+
+	long FindMultiColor(std::vector<color_df_t>&first_color, std::vector<pt_cr_df_t>& offset_color, double sim, long dir, long&x, long&y);
+
+	long FindMultiColorEx(std::vector<color_df_t>&first_color, std::vector<pt_cr_df_t>& offset_color, double sim, long dir, std::wstring& retstr);
+
+	long FindPic(std::vector<Image*>&pics,color_t dfcolor,double sim, long&x, long&y);
+
+	long FindPicTh(std::vector<Image*>&pics,color_t dfcolor,double sim, long&x, long&y);
+
+	long FindPicEx(std::vector<Image*>& pics, color_t dfcolor, double sim, vpoint_desc_t& vpd);
+
+	long FindPicExTh(std::vector<Image*>& pics, color_t dfcolor, double sim, vpoint_desc_t& vpd);
+
+	long FindColorBlock(double sim, long count, long height, long width, long& x, long& y);
+
+	long FindColorBlockEx(double sim, long count, long height, long width, std::wstring& retstr);
+
+	long Ocr(Dict& dict, double sim, std::wstring& ret_str);
+
+	long OcrEx(Dict& dict, double sim, std::wstring& out_str);
+
+	long FindStr(Dict& dict, const vector<wstring>& vstr,  double sim, long& retx, long& rety);
+
+	long FindStrEx(Dict& dict, const vector<wstring>& vstr, double sim, std::wstring& out_str);
+	//描述:查找目标图像中的直线
+	//输入:精度
+	//输出:outStr:直线描述[法线角度,直线到原点的距离];ret:该直线上的点的数量
+	long FindLine(double sim, std::wstring& outStr);
+private:
+	//rgb像素匹配
+	template<bool nodfcolor>
+	long simple_match(long x, long y, Image* timg, color_t dfcolor,int tnrom, double sim);
+	//透明图匹配
+	template<bool nodfcolor>
+	long trans_match(long x, long y, Image* timg, color_t dfcolor, vector<uint>points, int max_error);
+	//灰度匹配
+	long real_match(long x, long y, ImageBin* timg, int tnorm, double sim);
+	//记录和
+	void record_sum(const ImageBin & gray);
+	//[x1,x2),[y1,y2)
+	int region_sum(int x1, int y1, int x2, int y2);
+
+	
+
+	int get_bk_color(inputbin bin);
+
+	
+	
+	//垂直方向投影,投到x轴
+	void binshadowx(const rect_t& rc, std::vector<rect_t>& out_put);
+	//水平方向投影,投到(y)轴
+	void binshadowy(const rect_t& rc, std::vector<rect_t>&out_put);
+
+
+	
+	//ocr 完全匹配模式
+	void _bin_ocr(const Dict& dict, std::map<point_t, std::wstring>&ps);
+	//ocr 模糊匹配模式
+	void _bin_ocr(const Dict& dict,double sim, std::map<point_t, std::wstring>&ps);
+	//ocr wrapper
+	//template<int _type>
+	//void bin_ocr(const Image& binary, Image& record, const Dict& dict, int* max_error, std::wstring& outstr);
+public:
+	/*
+	if(abs(cr-src)<=df) pixel=1;
+	else pixel=0;
+	*/
+	void bgr2binary(vector<color_df_t>& colors);
+	//二值化 auto
+	void bgr2binarybk(const vector<color_df_t>& bk_colors);
+	//图像裁剪
+	void bin_image_cut(int min_word_h, const rect_t& inrc, rect_t& outrc);
+	void get_rois(int min_word_h, std::vector<rect_t>& vroi);
+	//ocr识别,返回识别到的字及对应坐标
+
+	void bin_ocr(const Dict& dict, double sim, std::map<point_t, std::wstring>&ps);
+
+
+public:
+	Image _src;
+	ImageBin _gray;
+	ImageBin _record;
+	ImageBin _binary;
+	Image _sum;
+private:
+	//起始点
+	int _x1, _y1;
+	//偏移
+	int _dx, _dy;
+	ThreadPool m_threadPool;
+};
+
+#endif
+

+ 524 - 0
gm/gm/imageProc/ImageProc.cpp

@@ -0,0 +1,524 @@
+//#include "stdafx.h"
+#include "ImageProc.h"
+#include "../core/helpfunc.h"
+#include <fstream>
+#include <bitset>
+#include <algorithm>
+#include <sstream>
+ImageProc::ImageProc()
+{
+	_curr_idx = 0;
+	_enable_cache = 1;
+}
+
+ImageProc::~ImageProc()
+{
+}
+
+long ImageProc::Capture(const std::wstring &file)
+{
+	wstring fpath = file;
+	if (fpath.find(L'\\') == -1)
+		fpath = _curr_path + L"\\" + fpath;
+
+	return _src.write(fpath.data());
+}
+
+long ImageProc::CmpColor(long x, long y, const std::wstring &scolor, double sim)
+{
+	std::vector<color_df_t> vcolor;
+	str2colordfs(scolor, vcolor);
+	return ImageBase::CmpColor(_src.at<color_t>(0, 0), vcolor, sim);
+}
+
+long ImageProc::FindColor(const wstring &color, double sim, long dir, long &x, long &y)
+{
+	std::vector<color_df_t> colors;
+	str2colordfs(color, colors);
+	//setlog("%s cr size=%d",colors[0].color.tostr().data(), colors.size());
+	//setlog("sim:,dir:%d", dir);
+	return ImageBase::FindColor(colors, dir, x, y);
+}
+
+long ImageProc::FindColoEx(const wstring &color, double sim, long dir, wstring &retstr)
+{
+	std::vector<color_df_t> colors;
+	str2colordfs(color, colors);
+	return ImageBase::FindColorEx(colors, retstr);
+}
+
+long ImageProc::FindMultiColor(const wstring &first_color, const wstring &offset_color, double sim, long dir, long &x, long &y)
+{
+	std::vector<color_df_t> vfirst_color;
+	str2colordfs(first_color, vfirst_color);
+	std::vector<wstring> vseconds;
+	split(offset_color, vseconds, L",");
+	std::vector<pt_cr_df_t> voffset_cr;
+	pt_cr_df_t tp;
+	for (auto &it : vseconds)
+	{
+		size_t id1, id2;
+		id1 = it.find(L'|');
+		id2 = (id1 == wstring::npos ? wstring::npos : it.find(L'|', id1));
+		if (id2 != wstring::npos)
+		{
+			swscanf(it.c_str(), L"%d|%d", &tp.x, &tp.y);
+			if (id2 + 1 != it.length())
+				str2colordfs(it.substr(id2 + 1), tp.crdfs);
+			else
+				break;
+			voffset_cr.push_back(tp);
+		}
+	}
+	return ImageBase::FindMultiColor(vfirst_color, voffset_cr, sim, dir, x, y);
+}
+
+long ImageProc::FindMultiColorEx(const wstring &first_color, const wstring &offset_color, double sim, long dir, wstring &retstr)
+{
+	std::vector<color_df_t> vfirst_color;
+	str2colordfs(first_color, vfirst_color);
+	std::vector<wstring> vseconds;
+	split(offset_color, vseconds, L",");
+	std::vector<pt_cr_df_t> voffset_cr;
+	pt_cr_df_t tp;
+	for (auto &it : vseconds)
+	{
+		size_t id1, id2;
+		id1 = it.find(L'|');
+		id2 = (id1 == wstring::npos ? wstring::npos : it.find(L'|', id1));
+		if (id2 != wstring::npos)
+		{
+			swscanf(it.c_str(), L"%d|%d", &tp.x, &tp.y);
+			if (id2 + 1 != it.length())
+				str2colordfs(it.substr(id2 + 1), tp.crdfs);
+			else
+				break;
+			voffset_cr.push_back(tp);
+		}
+	}
+	return ImageBase::FindMultiColorEx(vfirst_color, voffset_cr, sim, dir, retstr);
+}
+//图形定位
+long ImageProc::FindPic(const std::wstring &files, const wstring &delta_colors, double sim, long dir, long &x, long &y)
+{
+	vector<Image *> vpic;
+	//vector<color_t> vcolor;
+	color_t dfcolor;
+	vector<std::wstring> vpic_name;
+	files2mats(files, vpic, vpic_name);
+	dfcolor.str2color(delta_colors);
+	//str2colors(delta_colors, vcolor);
+	sim = 0.5 + sim / 2;
+	//long ret = ImageBase::FindPic(vpic, dfcolor, sim, x, y);
+	long ret = ImageBase::FindPicTh(vpic, dfcolor, sim, x, y);
+	//清理缓存
+	if (!_enable_cache)
+		_pic_cache.clear();
+	return ret;
+}
+//
+long ImageProc::FindPicEx(const std::wstring &files, const wstring &delta_colors, double sim, long dir, wstring &retstr, bool returnID)
+{
+	vector<Image *> vpic;
+	vpoint_desc_t vpd;
+	//vector<color_t> vcolor;
+	color_t dfcolor;
+	vector<std::wstring> vpic_name;
+	files2mats(files, vpic, vpic_name);
+	dfcolor.str2color(delta_colors);
+	sim = 0.5 + sim / 2;
+	long ret = ImageBase::FindPicExTh(vpic, dfcolor, sim, vpd);
+	std::wstringstream ss(std::wstringstream::in|std::wstringstream::out);
+	if (returnID)
+	{
+		for (auto &it : vpd)
+		{
+			ss << it.id << L"," << it.pos << L"|";
+		}
+	}
+	else
+	{
+		for (auto &it : vpd)
+		{
+			ss << vpic_name[it.id] << L"," << it.pos << L"|";
+		}
+	}
+	//清理缓存
+	if (!_enable_cache)
+		_pic_cache.clear();
+	retstr = ss.str();
+	if (vpd.size())
+		retstr.pop_back();
+	return ret;
+}
+
+long ImageProc::FindColorBlock(const wstring &color, double sim, long count, long height, long width, long &x, long &y)
+{
+
+	vector<color_df_t> colors;
+	if (str2colordfs(color, colors) == 0)
+	{
+		bgr2binary(colors);
+	}
+	else
+	{
+		bgr2binarybk(colors);
+	}
+	return ImageBase::FindColorBlock(sim, count, height, width, x, y);
+}
+
+long ImageProc::FindColorBlockEx(const wstring &color, double sim, long count, long height, long width, wstring &retstr)
+{
+	vector<color_df_t> colors;
+	if (str2colordfs(color, colors) == 0)
+	{
+		bgr2binary(colors);
+	}
+	else
+	{
+		bgr2binarybk(colors);
+	}
+	return ImageBase::FindColorBlockEx(sim, count, height, width, retstr);
+}
+
+long ImageProc::SetDict(int idx, const wstring &file_name)
+{
+	if (idx < 0 || idx >= _max_dict)
+		return 0;
+	_dicts[idx].clear();
+	wstring fullpath;
+	if (Path2GlobalPath(file_name, _curr_path, fullpath))
+	{
+		if (fullpath.substr(fullpath.length() - 4) == L".txt")
+			_dicts[idx].read_dict_dm(_ws2string(fullpath));
+		else
+			_dicts[idx].read_dict(_ws2string(fullpath));
+	}
+	else
+	{
+		setlog(L"file '%s' does not exist", file_name.c_str());
+	}
+
+	return _dicts[idx].empty() ? 0 : 1;
+}
+
+long ImageProc::SetMemDict(int idx, void *data, long size)
+{
+	if (idx < 0 || idx >= _max_dict)
+		return 0;
+	_dicts[idx].clear();
+	_dicts[idx].read_memory_dict_dm((const char *)data, size);
+	return _dicts[idx].empty() ? 0 : 1;
+}
+
+long ImageProc::UseDict(int idx)
+{
+	if (idx < 0 || idx >= _max_dict)
+		return 0;
+	_curr_idx = idx;
+	return 1;
+}
+
+long ImageProc::OCR(const wstring &color, double sim, std::wstring &out_str)
+{
+	out_str.clear();
+	vector<color_df_t> colors;
+	if (str2colordfs(color, colors) == 0)
+	{
+		bgr2binary(colors);
+	}
+	else
+	{
+		bgr2binarybk(colors);
+	}
+	if (sim < 0. || sim > 1.)
+		sim = 1.;
+	long s;
+	s = ImageBase::Ocr(_dicts[_curr_idx], sim, out_str);
+	return s;
+}
+
+wstring ImageProc::GetColor(long x, long y)
+{
+	color_t cr;
+	if (ImageBase::GetPixel(x, y, cr))
+	{
+		return _s2wstring(cr.tostr());
+	}
+	else
+	{
+		return L"";
+	}
+}
+
+int ImageProc::str2colordfs(const wstring &color_str, std::vector<color_df_t> &colors)
+{
+	std::vector<wstring> vstr, vstr2;
+	color_df_t cr;
+	colors.clear();
+	int ret = 0;
+	if (color_str.empty())
+	{ //default
+		return 1;
+	}
+	if (color_str[0] == L'@')
+	{ //bk color info
+		ret = 1;
+	}
+	split(ret ? color_str.substr(1) : color_str, vstr, L"|");
+	for (auto &it : vstr)
+	{
+		split(it, vstr2, L"-");
+		cr.color.str2color(vstr2[0]);
+		cr.df.str2color(vstr2.size() == 2 ? vstr2[1] : L"000000");
+		colors.push_back(cr);
+	}
+	return ret;
+}
+
+void ImageProc::str2colors(const wstring &color, std::vector<color_t> &vcolor)
+{
+	std::vector<wstring> vstr, vstr2;
+	color_t cr;
+	vcolor.clear();
+	split(color, vstr, L"|");
+	for (auto &it : vstr)
+	{
+		cr.str2color(it);
+		vcolor.push_back(cr);
+	}
+}
+
+long ImageProc::LoadPic(const wstring &files)
+{
+	//std::vector<wstring>vstr, vstr2;
+	std::vector<wstring> vstr;
+	int loaded = 0;
+	split(files, vstr, L"|");
+	wstring tp;
+	for (auto &it : vstr)
+	{
+		//路径转化
+		if (!Path2GlobalPath(it, _curr_path, tp))
+			continue;
+		//先在缓存中查找
+		if (!_pic_cache.count(tp))
+		{
+			_pic_cache[tp].read(tp.data());
+		}
+		//已存在于缓存中的文件也算加载成功
+		loaded++;
+	}
+	return loaded;
+}
+
+long ImageProc::FreePic(const wstring &files)
+{
+	std::vector<wstring> vstr;
+	int loaded = 0;
+	split(files, vstr, L"|");
+	wstring tp;
+	for (auto &it : vstr)
+	{
+		//看当前目录
+		auto cache_it = _pic_cache.find(it);
+		//没查到再看一下资源目录
+		if (cache_it == _pic_cache.end())
+		{
+			cache_it = _pic_cache.find(_curr_path + L"\\" + it);
+		}
+		//查到了就释放
+		if (cache_it != _pic_cache.end())
+		{
+			cache_it->second.release();
+			_pic_cache.erase(cache_it);
+			loaded++;
+		}
+	}
+	return loaded;
+}
+
+long ImageProc::LoadMemPic(const wstring &file_name, void *data, long size)
+{
+	try
+	{
+		if (!_pic_cache.count(file_name))
+		{
+			_pic_cache[file_name].read(data, size);
+		}
+	}
+	catch (...)
+	{
+		return 0;
+	}
+	return 1;
+}
+
+void ImageProc::files2mats(const wstring &files, std::vector<Image *> &vpic, std::vector<wstring> &vstr)
+{
+	//std::vector<wstring>vstr, vstr2;
+	Image *pm;
+	vpic.clear();
+	split(files, vstr, L"|");
+	wstring tp;
+	for (auto &it : vstr)
+	{
+		//先在缓存中查找是否已加载,包括从内存中加载的文件
+		if (_pic_cache.count(it))
+		{
+			pm = &_pic_cache[it];
+		}
+		else
+		{
+			//路径转化
+			if (!Path2GlobalPath(it, _curr_path, tp))
+				continue;
+			//再检测一次,包括绝对路径的文件
+			if (_pic_cache.count(tp))
+			{
+				pm = &_pic_cache[tp];
+			}
+			else
+			{
+				_pic_cache[tp].read(tp.data());
+				pm = &_pic_cache[tp];
+			}
+		}
+		vpic.push_back(pm);
+	}
+}
+
+long ImageProc::OcrEx(const wstring &color, double sim, std::wstring &out_str)
+{
+	out_str.clear();
+	vector<color_df_t> colors;
+	if (str2colordfs(color, colors) == 0)
+	{
+		bgr2binary(colors);
+	}
+	else
+	{
+		bgr2binarybk(colors);
+	}
+	if (sim < 0. || sim > 1.)
+		sim = 1.;
+
+	return ImageBase::OcrEx(_dicts[_curr_idx], sim, out_str);
+}
+
+long ImageProc::FindStr(const wstring &str, const wstring &color, double sim, long &retx, long &rety)
+{
+	vector<wstring> vstr;
+	vector<color_df_t> colors;
+	split(str, vstr, L"|");
+	if (str2colordfs(color, colors) == 0)
+	{
+		bgr2binary(colors);
+	}
+	else
+	{
+		bgr2binarybk(colors);
+	}
+	if (sim < 0. || sim > 1.)
+		sim = 1.;
+	return ImageBase::FindStr(_dicts[_curr_idx], vstr, sim, retx, rety);
+}
+
+long ImageProc::FindStrEx(const wstring &str, const wstring &color, double sim, std::wstring &out_str)
+{
+	out_str.clear();
+	vector<wstring> vstr;
+	vector<color_df_t> colors;
+	split(str, vstr, L"|");
+	if (str2colordfs(color, colors) == 0)
+	{
+		bgr2binary(colors);
+	}
+	else
+	{
+		bgr2binarybk(colors);
+	}
+	if (sim < 0. || sim > 1.)
+		sim = 1.;
+	return ImageBase::FindStrEx(_dicts[_curr_idx], vstr, sim, out_str);
+}
+
+long ImageProc::OcrAuto(double sim, std::wstring &retstr)
+{
+	retstr.clear();
+
+	if (sim < 0. || sim > 1.)
+		sim = 1.;
+	vector<color_df_t> colors;
+	bgr2binarybk(colors);
+	return ImageBase::Ocr(_dicts[_curr_idx], sim, retstr);
+	//_tes.SetImage(_src.pdata, _src.width, _src.height, 4, _src.width * 4);
+	//_tes.gette
+	return 0;
+}
+
+long ImageProc::OcrFromFile(const wstring &files, const wstring &color, double sim, std::wstring &retstr)
+{
+	retstr.clear();
+	if (sim < 0. || sim > 1.)
+		sim = 1.;
+	wstring fullpath;
+	vector<color_df_t> colors;
+	str2colordfs(color, colors);
+	if (Path2GlobalPath(files, _curr_path, fullpath))
+	{
+		_src.read(fullpath.data());
+		if (str2colordfs(color, colors) == 0)
+		{
+			bgr2binary(colors);
+		}
+		else
+		{
+			bgr2binarybk(colors);
+		}
+		if (sim < 0. || sim > 1.)
+			sim = 1.;
+
+		return ImageBase::Ocr(_dicts[_curr_idx], sim, retstr);
+	}
+	return 0;
+}
+
+long ImageProc::OcrAutoFromFile(const wstring &files, double sim, std::wstring &retstr)
+{
+	retstr.clear();
+	if (sim < 0. || sim > 1.)
+		sim = 1.;
+	wstring fullpath;
+
+	if (Path2GlobalPath(files, _curr_path, fullpath))
+	{
+		_src.read(fullpath.data());
+		vector<color_df_t> colors;
+		bgr2binarybk(colors);
+
+		return ImageBase::Ocr(_dicts[_curr_idx], sim, retstr);
+	}
+	return 0;
+}
+
+long ImageProc::FindLine(const wstring &color, double sim, wstring &retStr)
+{
+	retStr.clear();
+	vector<color_df_t> colors;
+	if (str2colordfs(color, colors) == 0)
+	{
+		bgr2binary(colors);
+	}
+	else
+	{
+		bgr2binarybk(colors);
+	}
+	if (sim < 0. || sim > 1.)
+		sim = 1.;
+
+	_src.write(L"_src.bmp");
+	_gray.write(L"gray.bmp");
+	_binary.write(L"_binary.bmp");
+	return ImageBase::FindLine(sim, retStr);
+}

+ 95 - 0
gm/gm/imageProc/ImageProc.h

@@ -0,0 +1,95 @@
+#pragma once
+#include <string>
+#include "ImageLoc.h"
+#include <map>
+//#include <tesseract/baseapi.h>
+using std::wstring;
+/*
+此类为图像处理,包含以下工作
+1.像素比较,查找
+2.颜色转化
+3.图像定位
+4.简单OCR
+5....
+*/
+class ImageProc:public ImageBase
+{
+public:
+	const static int _max_dict = 10;
+	
+	ImageProc();
+	~ImageProc();
+	//
+	long Capture(const std::wstring& file);
+
+	long CmpColor(long x, long y, const std::wstring& scolor, double sim);
+
+	long FindColor(const wstring& color,double sim,long dir, long&x, long&y);
+
+	long FindColoEx(const wstring& color, double sim, long dir, wstring& retstr);
+
+	long FindMultiColor(const wstring& first_color,const wstring& offset_color, double sim, long dir, long&x, long&y);
+
+	long FindMultiColorEx(const wstring& first_color, const wstring& offset_color, double sim, long dir, wstring& retstr);
+	//图形定位
+	long FindPic(const std::wstring& files,const wstring& delta_colors, double sim,long dir, long& x, long &y);
+	//
+	long FindPicEx(const std::wstring& files, const wstring& delta_colors, double sim, long dir, wstring& retstr, bool returnID = true);
+
+	long FindColorBlock(const wstring&  color, double sim, long count, long height, long width, long& x, long& y);
+
+	long FindColorBlockEx(const wstring&  color, double sim, long count, long height, long width, wstring& retstr);
+
+	std::wstring GetColor(long x, long y);
+
+	long SetMemDict(int idx, void* data,long size);
+
+	long SetDict(int idx,const wstring& file);
+
+	long UseDict(int idx);
+
+	long OCR(const wstring& color, double sim, std::wstring& out_str);
+
+	long OcrEx(const wstring& color, double sim, std::wstring& out_str);
+
+	long FindStr(const wstring& str, const wstring& color, double sim, long& retx,long& rety);
+
+	long FindStrEx(const wstring& str, const wstring& color, double sim, std::wstring& out_str);
+
+	long OcrAuto(double sim, std::wstring& retstr);
+
+	long OcrFromFile(const wstring& files,const wstring& color, double sim, std::wstring& retstr);
+
+	long OcrAutoFromFile(const wstring& files, double sim, std::wstring& retstr);
+
+	long FindLine(const wstring& color, double sim, wstring& retStr);
+	
+	long LoadPic(const wstring& files);
+
+	long FreePic(const wstring& files);
+
+	long LoadMemPic(const wstring& file_name, void* data, long size);
+private:
+	//字库
+	Dict _dicts[_max_dict];
+	//当前字库索引
+	int _curr_idx;
+	
+public:
+	//当前目录
+	wstring _curr_path;
+	//图片缓存
+	std::map<wstring, Image> _pic_cache;
+	//是否使用图片缓存,默认开启
+	int _enable_cache;
+
+	//tesseract::TessBaseAPI _tes;
+	
+	
+private:
+	//RETURN TYPE 0:word colors info; 1:bk color info
+	int str2colordfs(const wstring& color_str, std::vector<color_df_t>& colors);
+	void str2colors(const wstring& color, std::vector<color_t>& vcolor);
+	void files2mats(const wstring& files, std::vector<Image*>& vpic, std::vector<wstring>& vstr);
+};
+

+ 13 - 0
gm/gm/imageProc/compute/ThreadPool.cpp

@@ -0,0 +1,13 @@
+#include "ThreadPool.h"
+
+// the destructor joins all threads
+ThreadPool::~ThreadPool() {
+	{
+		std::unique_lock<std::mutex> lock(queue_mutex);
+		stop = true;
+	}
+	condition.notify_all();
+	for (std::thread& worker : workers) {
+		worker.join();
+	}
+}

+ 100 - 0
gm/gm/imageProc/compute/ThreadPool.h

@@ -0,0 +1,100 @@
+#ifndef THREAD_POOL_H
+#define THREAD_POOL_H
+
+#include <vector>
+#include <queue>
+#include <memory>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <future>
+#include <functional>
+#include <stdexcept>
+
+class ThreadPool {
+public:
+    ThreadPool(size_t);
+    template<class F, class... Args>
+    auto enqueue(F&& f, Args&&... args) 
+        -> std::future<typename std::result_of<F(Args...)>::type>;
+    ~ThreadPool();
+    size_t getThreadNum()const{
+        return workers.size();
+    }
+private:
+    // need to keep track of threads so we can join them
+    std::vector< std::thread > workers;
+    // the task queue
+    std::queue< std::function<void()> > tasks;
+    
+    // synchronization
+    std::mutex queue_mutex;
+    std::condition_variable condition;
+    bool stop;
+};
+ 
+// the constructor just launches some amount of workers
+inline ThreadPool::ThreadPool(size_t threads)
+    :   stop(false)
+{
+    for(size_t i = 0;i<threads;++i)
+        workers.emplace_back(
+            [this]
+            {
+                for(;;)
+                {
+                    std::function<void()> task;
+
+                    {
+                        std::unique_lock<std::mutex> lock(this->queue_mutex);
+                        this->condition.wait(lock,
+                            [this]{ return this->stop || !this->tasks.empty(); });
+                        if(this->stop && this->tasks.empty())
+                            return;
+                        task = std::move(this->tasks.front());
+                        this->tasks.pop();
+                    }
+
+                    task();
+                }
+            }
+        );
+}
+
+// add new work item to the pool
+template<class F, class... Args>
+auto ThreadPool::enqueue(F&& f, Args&&... args) 
+    -> std::future<typename std::result_of<F(Args...)>::type>
+{
+    using return_type = typename std::result_of<F(Args...)>::type;
+
+    auto task = std::make_shared< std::packaged_task<return_type()> >(
+            std::bind(std::forward<F>(f), std::forward<Args>(args)...)
+        );
+        
+    std::future<return_type> res = task->get_future();
+    {
+        std::unique_lock<std::mutex> lock(queue_mutex);
+
+        // don't allow enqueueing after stopping the pool
+        if(stop)
+            throw std::runtime_error("enqueue on stopped ThreadPool");
+
+        tasks.emplace([task](){ (*task)(); });
+    }
+    condition.notify_one();
+    return res;
+}
+
+// the destructor joins all threads
+inline ThreadPool::~ThreadPool()
+{
+    {
+        std::unique_lock<std::mutex> lock(queue_mutex);
+        stop = true;
+    }
+    condition.notify_all();
+    for(std::thread &worker: workers)
+        worker.join();
+}
+#endif

+ 24 - 0
gm/gm/imageProc/imageView.hpp

@@ -0,0 +1,24 @@
+#ifndef __IMAGE_VIEW_H
+#define __IMAGE_VIEW_H
+#include "../core/optype.h"
+#include "../include/Image.hpp"
+class imageView {
+ private:
+  
+
+ public:
+  imageView(ImageBin const& src, rect_t const& block);
+  imageView(imageView const&) = delete;
+  ~imageView();
+
+  /* data */
+  const ImageBin& _src;
+  rect_t _block;
+};
+
+imageView::imageView(ImageBin const& src, rect_t const& block)
+    : _src(src), _block(block) {}
+
+imageView::~imageView() {}
+
+#endif

+ 380 - 0
gm/gm/include/Dict.h

@@ -0,0 +1,380 @@
+#pragma once
+#ifndef __DICT_H_
+#define __DICT_H_
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <fstream>
+#include <sstream>
+#include "bitfunc.h"
+#include "Image.hpp"
+#include "../core/helpfunc.h"
+//#define SET_BIT(x, idx) x |= 1u << (idx)
+
+//#define GET_BIT(x, idx) (((x )>> (idx)) & 1u)
+const int op_dict_version = 2;
+
+
+/*
+第 0 代字库
+*/
+struct word_info_t {
+	//char of word
+	wchar_t _char[4];
+	//char height
+	__int16 width, height;
+	//char bit ct
+	__int32 bit_count;
+	word_info_t() :width(0), height(0), bit_count(0) { memset(_char, 0, sizeof(_char)); }
+	bool operator==(const word_info_t& rhs) {
+		return width == rhs.width && height == rhs.height;
+	}
+	bool operator!=(const word_info_t& rhs) {
+		return width != rhs.width && height == rhs.height;
+	}
+
+};
+struct word_t {
+
+	
+	//32 bit a col
+	using cline_t = unsigned __int32;
+	word_info_t info;
+	//char col line
+	cline_t clines[32];
+	bool operator==(const word_t& rhs) {
+		if (info != rhs.info)
+			return false;
+		for (int i = 0; i < info.width; ++i)
+			if (clines[i] != rhs.clines[i])
+				return false;
+		return true;
+	}
+	void set_chars(const std::wstring&s) {
+		memcpy(info._char, s.c_str(), min(sizeof(info._char), (s.length() + 1) * sizeof(wchar_t)));
+	}
+	//从 dm 字库中 的一个点阵转化为op的点阵
+	void fromDm(const wchar_t* str, int ct,const std::wstring& w) {
+		int bin[50] = { 0 };
+		constexpr int DM_DICT_HEIGTH = 11;
+		ct = min(ct, 88);
+		int i = 0;
+		auto hex2bin = [](wchar_t c) {
+			return c <= L'9' ? c - L'0' : c - L'A'+10;
+		};
+		while (i < ct) {
+			
+			bin[i / 2] = (hex2bin(str[i]) << 4) | (hex2bin(str[i+1]));
+			i += 2;
+		}
+		//
+		int cols = (ct * 4) / DM_DICT_HEIGTH;
+		memset(this, 0x0, sizeof(*this));
+		for (int j = 0; j < cols; ++j) {
+			for (int i = 0; i < 11; ++i) {
+				int idx = j * 11 + i;
+				if (GET_BIT(bin[idx>>3],7-(idx&7))) {
+					SET_BIT(clines[j], 31-i);
+					++info.bit_count;
+				}
+					
+			}
+		}
+		info.height = DM_DICT_HEIGTH;
+		info.width = cols;
+		set_chars(w);
+	}
+};
+/*
+第 1 代字库
+*/
+struct word1_info {
+	uint8_t w, h;//max is 255 2B
+	uint16_t bit_cnt;//max is 255*255=65025<65536 4B
+	wchar_t name[8];//name 12B
+	word1_info() :w(0), h(0), bit_cnt(0) {}
+};
+struct word1_t {
+	word1_info info;
+	vector<uint8_t> data;//size is (w*h+7)/8
+	bool operator==(const word1_t& rhs){
+		if (info.w!=rhs.info.w|| info.h != rhs.info.h||info.bit_cnt!=rhs.info.bit_cnt)
+			return false;
+		for (size_t i=0;i<data.size();i++)
+			if (data[i] != rhs.data[i])
+				return false;
+		return true;
+	}
+	void set_chars(const std::wstring& s) {
+		int nlen = s.length() < 8 ? s.length() : 7;
+		memcpy(info.name, s.c_str(),nlen*2);
+		info.name[nlen] = L'\0';
+	}
+	void from_word(word_t& wd) {
+		info.w = (uint8_t)wd.info.width;
+		info.h = wd.info.height;
+		init();
+		info.bit_cnt = wd.info.bit_count;
+		memcpy(info.name, wd.info._char, 4 * sizeof(wchar_t));
+		info.name[3] = 0;
+		int idx = 0;
+		
+		for (int x = 0; x < info.w; x++) {
+			for (int y = 0; y < info.h; y++) {
+				if (GET_BIT(wd.clines[x], 31-y))
+					SET_BIT(data[idx / 8], idx & 7);
+				idx++;
+			}
+		}
+	}
+
+
+
+	void init() {
+		data.resize((info.w * info.h + 7) / 8);
+		std::fill(data.begin(), data.end(), 0);
+	}
+};
+
+
+
+
+struct Dict {
+	//v0 v1
+	struct dict_info_t {
+		__int16 _this_ver;//0 1
+		__int16 _word_count;
+		//check code=_this_ver^_word_count
+		__int32 _check_code;
+		dict_info_t() :_this_ver(1), _word_count(0) { _check_code = _word_count ^ _this_ver; }
+	};
+	dict_info_t info;
+	Dict() {}
+	std::vector<word1_t>words;
+	void read_dict(const std::string&s) {
+		if (s.empty())
+			return;
+		if (s.find(".txt") != -1)
+			return read_dict_dm(s);
+		clear();
+		std::fstream file;
+		file.open(s, std::ios::in | std::ios::binary);
+		if (!file.is_open())
+			return;
+		//读取头信息
+		file.read((char*)&info, sizeof(info));
+		
+		//校验
+		if (info._this_ver==0&&info._check_code == (info._this_ver^info._word_count)) {
+			//old dict format
+			words.resize(info._word_count);
+			info._this_ver = 1;
+			word_t tmp;
+			for (size_t i = 0; i < words.size(); i++) {
+				file.read((char*)&tmp, sizeof(tmp));
+				words[i].from_word(tmp);
+			}
+			//file.read((char*)&words[0], sizeof(word_t)*info._word_count);
+		}
+		else if (info._this_ver == 1 && info._check_code == (info._this_ver ^ info._word_count)) {
+			//new dict format
+			words.resize(info._word_count);
+			word1_info head;
+			for (size_t i = 0; i < words.size(); i++) {
+				file.read((char*)&head, sizeof(head));
+			
+				words[i].info = head;
+				int nlen = (head.w * head.h + 7) / 8;
+				words[i].data.resize(nlen);
+				file.read((char*)words[i].data.data(), nlen);
+			}
+		}
+		file.close();
+		sort_dict();
+	}
+	void read_dict_dm(const std::string&s) {
+		clear();
+		std::fstream file;
+		file.open(s, std::ios::in);
+		if (!file.is_open())
+			return;
+		//读取信息
+		std::wstring ss;
+		std::string str;
+		while (std::getline(file, str)) {
+			std::string strLocale = setlocale(LC_ALL, "");
+			const char* chSrc = str.c_str();
+			size_t nDestSize = mbstowcs(NULL, chSrc, 0) + 1;
+			wchar_t* wchDest = new wchar_t[nDestSize];
+			wmemset(wchDest, 0, nDestSize);
+			mbstowcs(wchDest, chSrc, nDestSize);
+			std::wstring wstrResult = wchDest;
+			delete[]wchDest;
+			setlocale(LC_ALL, strLocale.c_str());
+			ss = wstrResult;
+			size_t idx1 = ss.find(L'$');
+			auto idx2=ss.find(L'$',idx1+1);
+			word_t wd;
+			word1_t wd1;
+			wstring name;
+			if (idx1 != -1&&idx2!=-1) {
+				ss[idx1] = L'0';
+				name = ss.substr(idx1 + 1, idx2 - idx1 - 1);
+				wd.fromDm(ss.data(), idx1, name);
+				wd1.from_word(wd);
+				wd1.set_chars(name);
+				add_word(wd1);
+				
+			}
+		}
+		file.close();
+		sort_dict();
+	}
+
+	void read_memory_dict_dm(const char* buf,size_t size) {
+		clear();
+		std::stringstream file;
+		file.write(buf, size);
+ 
+		//读取信息
+		std::wstring ss;
+		std::string str;
+		while (std::getline(file, str)) {
+			std::string strLocale = setlocale(LC_ALL, "");
+			const char* chSrc = str.c_str();
+			size_t nDestSize = mbstowcs(NULL, chSrc, 0) + 1;
+			wchar_t* wchDest = new wchar_t[nDestSize];
+			wmemset(wchDest, 0, nDestSize);
+			mbstowcs(wchDest, chSrc, nDestSize);
+			std::wstring wstrResult = wchDest;
+			delete[]wchDest;
+			setlocale(LC_ALL, strLocale.c_str());
+			ss = wstrResult;
+			size_t idx1 = ss.find(L'$');
+			auto idx2 = ss.find(L'$', idx1 + 1);
+			word_t wd;
+			word1_t wd1;
+			wstring name;
+			if (idx1 != -1 && idx2 != -1) {
+				ss[idx1] = L'0';
+				name = ss.substr(idx1 + 1, idx2 - idx1 - 1);
+				wd.fromDm(ss.data(), idx1, name);
+				wd1.from_word(wd);
+				wd1.set_chars(name);
+				add_word(wd1);
+
+			}
+		}
+		sort_dict();
+	}
+
+
+	void write_dict(const std::string&s) {
+		std::fstream file;
+		file.open(s, std::ios::out | std::ios::binary);
+		if (!file.is_open())
+			return;
+		//删除所有空的字符
+		auto it = words.begin();
+		while (it != words.end()) {
+			if (it->info.name[0] == L'\0')
+				it = words.erase(it);
+			else
+				++it;
+		}
+		info._word_count = words.size();
+		//设置校验
+
+		info._check_code = info._this_ver^info._word_count;
+		//写入信息
+		file.write((char*)&info, sizeof(info));
+		//写入数据
+		for (int i = 0; i < words.size(); i++) {
+			file.write((char*)&words[i].info, sizeof(word1_info));
+			file.write((char*)words[i].data.data(), words[i].data.size());
+		}
+		file.close();
+	}
+	void add_word(const ImageBin& binary, const rect_t& rc) {
+		int x2 = min(rc.x1 + 255, rc.x2);
+		int y2 = min(rc.y1 + 255, rc.y2);
+		word1_t word;
+		word.info.w = x2 - rc.x1;
+		word.info.h = y2 - rc.y1;
+		word.info.bit_cnt = 0;
+		word.init();
+		//word.data.resize((word.info.w * word.info.h + 7) / 8);
+		int idx = 0;
+		for (int j = rc.x1; j < x2; ++j) {
+			for (int i = rc.y1; i < y2; ++i) {
+				auto val = binary.at(i, j);
+				if (val == 1) {
+					SET_BIT(word.data[idx / 8],idx & 7);
+					
+					++word.info.bit_cnt;
+				}
+				++idx;
+					
+			}
+		}
+		auto it = find(word);
+		if (words.empty()||it==words.end()) {
+			word.set_chars(L"");
+			
+			words.push_back(word);
+			info._word_count = words.size();
+		}
+		else {//only change char
+			//word.set_chars(c);
+		}
+
+	}
+
+	void sort_dict() {
+		//sort dict(size: big --> small ,cnt: small -->big)
+		std::stable_sort(words.begin(), words.end(),
+			[](const word1_t& lhs, const word1_t& rhs) {
+				int dh = lhs.info.h - rhs.info.h;
+			int dw = lhs.info.w - rhs.info.w;
+			return dh > 0 || (dh == 0 && dw > 0) ||
+				(dh == 0 && dw == 0 && lhs.info.bit_cnt < rhs.info.bit_cnt);
+		});
+	}
+
+	void add_word(const word1_t&word) {
+		auto it = find(word);
+		if (words.empty()||it==words.end()) {
+			words.push_back(word);
+		}
+		else {
+			it->set_chars(word.info.name);
+		}
+		info._word_count = words.size();
+	}
+	void clear() {
+		info._word_count = 0;
+		words.clear();
+	}
+	std::vector<word1_t>::iterator find(const word1_t&word) {
+		for (auto it = words.begin(); it != words.end(); ++it)
+			if (*it == word)return it;
+		return words.end();
+	}
+
+	void erase(const word1_t&word) {
+		auto it = find(word);
+		if (!words.empty() && it !=words.end())
+			words.erase(it);
+		info._word_count = words.size();
+	}
+
+	int size() const{
+		return info._word_count;
+	}
+
+	bool empty()const {
+		return size() == 0;
+	}
+};
+
+#endif

+ 319 - 0
gm/gm/include/Image.hpp

@@ -0,0 +1,319 @@
+#pragma once
+#ifndef __IMAGE_H_
+#define __IMAGE_H_
+#include <vector>
+
+#include <atlimage.h>
+struct Image
+{
+	using iterator = unsigned __int32*;
+	Image() :width(0), height(0), pdata(nullptr) {
+	}
+	Image(int w, int h) :pdata(nullptr) {
+		
+		create(w, h);
+	}
+	//copy ctr
+	Image(const Image& rhs) :pdata(nullptr) {
+		
+		if (rhs.empty()) {
+			this->clear();
+		}
+		else {
+			this->create(rhs.width, rhs.height);
+			memcpy(this->pdata, rhs.pdata, width*height * 4);
+		}
+
+	}
+	~Image() {
+		release();
+	}
+	
+	void create(int w, int h) {
+		width = w, height = h;
+		if (!pdata) {
+			pdata = (unsigned char*)malloc(w*h * 4);
+		}
+		else {
+			pdata = (unsigned char*)realloc(pdata, w*h * 4);
+		}
+		if (pdata == nullptr)throw("memory not enough");
+	}
+	void release() {
+		width = height = 0;
+		if (pdata)free(pdata);
+		pdata = nullptr;
+	}
+
+	int size() {
+		return width * height;
+	}
+	void clear() {
+		width = height = 0;
+	}
+
+	bool empty()const {
+		return width == 0;
+	}
+
+	Image& operator=(const Image& rhs) {
+		if (rhs.empty()) {
+			this->clear();
+		}
+		else if (this != &rhs) {
+			this->create(rhs.width, rhs.height);
+			memcpy(this->pdata, rhs.pdata, width*height * 4);
+		}
+		return *this;
+	}
+	bool read(LPCTSTR file) {
+		clear();
+		ATL::CImage img;
+		HRESULT hr = img.Load(file);
+		if (hr == S_OK) {
+			create(img.GetWidth(), img.GetHeight());
+			translate((unsigned char*)img.GetBits(), img.GetBPP() / 8, img.GetPitch());
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+	bool read(void* pMemData, long  len) {
+		clear();
+		ATL::CImage img;
+		auto hGlobal =  GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, len);
+		if (hGlobal)
+		{
+			void* pData = GlobalLock(hGlobal);
+			memcpy_s(pData, len, pMemData, len);
+			GlobalUnlock(hGlobal);
+		}
+		else {
+			return false;
+		}
+		
+		IStream* pStream = NULL;
+		if (CreateStreamOnHGlobal(hGlobal, TRUE, &pStream) != S_OK) {
+			GlobalFree(hGlobal);
+			return false;
+		}
+		HRESULT hr = img.Load(pStream);
+		if (hr == S_OK) {
+			pStream->Release();
+			GlobalFree(hGlobal);
+			create(img.GetWidth(), img.GetHeight());
+			translate((unsigned char*)img.GetBits(), img.GetBPP() / 8, img.GetPitch());
+			return true;
+		}
+		else {
+			GlobalFree(hGlobal);
+			return false;
+		}
+	}
+
+	bool read(ATL::CImage* img) {
+		translate((unsigned char*)img->GetBits(), img->GetBPP() / 8, img->GetPitch());
+		return true;
+	}
+
+	bool write(LPCTSTR file) {
+		if (empty())
+			return false;
+		ATL::CImage img;
+		
+		img.Create(width, height, 32);
+		auto pdst = (unsigned char*)img.GetBits();
+		auto psrc = pdata;
+		int pitch = img.GetPitch();
+		for (int i = 0; i < height; ++i) {
+			for (int j = 0; j < width; ++j) {
+				((int*)pdst)[j] = ((int*)psrc)[j];
+			}
+			pdst += pitch;
+			psrc += width * 4;
+		}
+		return img.Save(file) == S_OK;
+	}
+	void translate(unsigned char* psrc, int pixSize, int pitch) {
+		auto pdst = pdata;
+		//gray
+		if (pixSize == 1) {
+			for (int i = 0; i < height; ++i) {
+				for (int j = 0; j < width; ++j) {
+					*pdst++ = psrc[j];
+					*pdst++ = psrc[j];
+					*pdst++ = psrc[j];
+					*pdst++ = 0xff;
+				}
+				psrc += pitch;
+
+			}
+		}//bgr
+		else if (pixSize == 3) {
+			for (int i = 0; i < height; ++i) {
+				for (int j = 0; j < width; ++j) {
+					*pdst++ = psrc[j * 3 + 0];
+					*pdst++ = psrc[j * 3 + 1];
+					*pdst++ = psrc[j * 3 + 2];
+					*pdst++ = 0xff;
+				}
+				psrc += pitch;
+
+			}
+		}
+		else if (pixSize == 4) {
+			for (int i = 0; i < height; ++i) {
+				for (int j = 0; j < width; ++j) {
+					*pdst++ = psrc[j * 4 + 0];
+					*pdst++ = psrc[j * 4 + 1];
+					*pdst++ = psrc[j * 4 + 2];
+					*pdst++ = psrc[j * 4 + 3];
+				}
+				psrc += pitch;
+
+			}
+		}
+	}
+	template<typename Tp>
+	Tp at(int y, int x)const {
+		return ((Tp*)pdata)[y*width + x];
+	}
+	template<typename Tp>
+	Tp& at(int y, int x) {
+		return ((Tp*)pdata)[y*width + x];
+	}
+	template<typename Tp>
+	Tp* ptr(int y) {
+		return (Tp*)(pdata + y * width * 4);
+	}
+
+	template<typename Tp>
+	const Tp* ptr(int y)const {
+		return (Tp*)(pdata + y * width * 4);
+	}
+
+	iterator begin() {
+		return (iterator)pdata;
+	}
+	iterator end() {
+		return (iterator)pdata + width * height;
+	}
+
+	iterator begin()const {
+		return (iterator)pdata;
+	}
+	iterator end()const {
+		return (iterator)pdata + width * height;
+	}
+
+	void fill(unsigned int val) {
+		std::fill(begin(), end(), val);
+	}
+	void fill(int row,int col,int h,int w,unsigned int val) {
+		for (int i = 0; i < h; ++i) {
+			auto p = ptr<unsigned int>(row + i)+col;
+			std::fill(p,p + w,val);
+		}
+	}
+	int width, height;
+	unsigned char* pdata;
+};
+//单通道图像
+struct ImageBin {
+	using iterator = unsigned char*;
+	ImageBin() :width(0), height(0) {}
+	ImageBin(const ImageBin& rhs) {
+		this->width = rhs.width;
+		this->height = rhs.height;
+		this->pixels = rhs.pixels;
+	}
+	void create(int w, int h) {
+		width = w, height = h;
+		pixels.resize(w*h);
+	}
+	void clear() {
+		width = height = 0;
+	}
+	int size()const {
+		return width*height;
+	}
+	bool empty()const {
+		return width == 0;
+	}
+	unsigned char* data() {
+		return pixels.data();
+	}
+	ImageBin& operator=(const ImageBin& rhs) {
+		this->width = rhs.width;
+		this->height = rhs.height;
+		this->pixels = rhs.pixels;
+		return *this;
+	}
+	unsigned char at(int y,int x)const {
+		return pixels[y*width + x];
+	}
+	unsigned char& at(int y, int x) {
+		return pixels[y*width + x];
+	}
+
+	unsigned char* ptr(int y) {
+		return pixels.data() + y * width;
+	}
+
+	unsigned char const* ptr(int y) const{
+		return pixels.data() + y * width;
+	}
+
+	void fromImage4(const Image& img4) {
+		create(img4.width, img4.height);
+		auto psrc = img4.pdata;
+		for (size_t i = 0; i < pixels.size(); ++i) {
+			//pixels[i] = (psrc[0] + psrc[1] + psrc[2]) / 3;
+			// Gray = (R*299 + G*587 + B*114 + 500) / 1000
+			pixels[i] = (psrc[2] * 299 + psrc[1] * 587 + psrc[0] * 114 + 500) / 1000;
+			psrc += 4;
+		}
+	}
+
+	bool write(LPCTSTR file) {
+		if (empty())
+			return false;
+		ATL::CImage img;
+
+		img.Create(width, height, 32);
+		auto pdst = (unsigned char*)img.GetBits();
+		auto psrc = pixels.data();
+		int pitch = img.GetPitch();
+		for (int i = 0; i < height; ++i) {
+			for (int j = 0; j < width; ++j) {
+				//((int*)pdst)[j] = ((int*)psrc)[j];
+				uchar v = psrc[j] == 1 ? 0xff : 0;
+				pdst[j*4] = pdst[j*4 + 1] = pdst[j*4 + 2] =v;
+				pdst[j * 4 + 3] = 0xff;
+			
+			}
+			pdst += pitch;
+			psrc += width;
+		}
+		return img.Save(file) == S_OK;
+	}
+
+	iterator begin() {
+		return pixels.data();
+	}
+	iterator end() {
+		return pixels.data() + pixels.size();
+	}
+	int width, height;
+	std::vector<unsigned char> pixels;
+};
+
+
+using inputimg = const Image&;
+using outputimg = Image&;
+
+using inputbin = const ImageBin&;
+using outputbin = ImageBin & ;
+
+#endif

+ 22 - 0
gm/gm/include/bitfunc.h

@@ -0,0 +1,22 @@
+#pragma once
+#ifndef __BITFUNC_H_
+#define __BITFUNC_H_
+template<typename T>
+constexpr void SET_BIT(T& x,int idx) {
+	x |= 1u << idx;
+}
+template<typename T>
+constexpr int GET_BIT(T x, int idx) {
+	return (x >> idx) & 1u;
+}
+
+template<typename T>
+constexpr int get_bit_count(T x) {
+	int s = 0;
+	while (x) {
+		s += x & 1;
+		x >>= 1;
+	}
+	return s;
+}
+#endif

+ 75 - 0
gm/gm/include/color.h

@@ -0,0 +1,75 @@
+#pragma once
+#ifndef __COLOR_H_
+#define __COLOR_H_
+#include <algorithm>
+#include "../core/optype.h"
+#define WORD_BKCOLOR 0
+#define WORD_COLOR 1
+//#include "../Tool.h"
+#include <math.h>
+#define color2uint(color) (*(uint*)&color)
+template<typename T>
+constexpr T OP_ABS(T x) {
+	return x < 0 ? -x : x;
+}
+template<typename T>
+constexpr bool IN_RANGE(T lhs, T rhs, T df) { 
+	return OP_ABS(lhs.b-rhs.b)<=df.b
+		&&OP_ABS(lhs.g-rhs.g)<=df.g
+		&&OP_ABS(lhs.r-rhs.r)<=df.r;
+}
+//��ɫ�ṹ
+
+//#pragma pack(push)
+#pragma pack(1)
+struct color_t {
+	//b is in low address ,alpha is in high address
+	uchar b, g, r, alpha;
+	color_t() :b(0), g(0), r(0), alpha(0) {}
+	color_t(int b_, int g_, int r_) :b(b_), g(g_), r(r_),alpha(0xffu) {}
+	
+	color_t& str2color(const std::wstring& s) {
+		int r = 0, g = 0, b = 0;
+		std::wstring ss = s; 
+		std::transform(ss.begin(), ss.end(), ss.begin(), ::towupper);
+		int cnt = swscanf(ss.c_str(), L"%02X%02X%02X", &r, &g, &b);
+		this->b = b; this->r = r; this->g = g;
+		return *this;
+	}
+	color_t& str2color(const std::string&s) {
+		int r, g, b;
+		std::string ss = s;
+		std::transform(ss.begin(), ss.end(), ss.begin(), ::toupper);
+		int cnt = sscanf(ss.c_str(), "%02X%02X%02X", &r, &g, &b);
+		this->b = b; this->r = r; this->g = g;
+		return *this;
+	}
+	std::string tostr() {
+		char buff[10];
+		sprintf(buff, "%02X%02X%02X", r, g, b);
+		return buff;
+	}
+	std::wstring towstr() {
+		wchar_t buff[10];
+		wsprintf(buff, L"%02X%02X%02X", r, g, b);
+		return buff;
+	}
+	uchar toGray() const{
+		return (r * 299 + g * 587 + b * 114 + 500) / 1000;
+	}
+};
+#pragma pack()
+//��ɫ-ƫɫ�ṹ
+struct color_df_t {
+	//��ɫ
+	color_t color;
+	//ƫɫ
+	color_t df;
+};
+//����-��ɫ-ƫɫ�ṹ
+struct pt_cr_df_t {
+	int x, y;
+	std::vector<color_df_t> crdfs;
+};
+
+#endif

+ 298 - 0
gm/gm/include/libop.h

@@ -0,0 +1,298 @@
+// libop的声明
+/*
+所有op的开放接口都从此cpp类衍生而出
+*/
+#pragma once
+
+#include <string>
+#include<map>
+#include<vector>
+//forward declare
+class WinApi;
+class opBackground;
+class ImageProc;
+
+using bytearray = std::vector<unsigned char>;
+#ifdef U_STATIC_IMPLEMENTATION
+#define OP_API
+#else
+#ifndef OP_API 
+#if defined(OP_EXPORTS)
+#define OP_API __declspec(dllexport)
+#else
+#define OP_API __declspec(dllimport)
+#endif
+#endif
+#endif
+// libop
+#undef FindWindow
+#undef FindWindowEx
+#undef SetWindowText
+
+
+
+class OP_API libop{
+	
+public:
+	
+	libop();
+	~libop();
+	//复制构造
+	libop(libop const&) = delete;
+	libop& operator=(libop const rhs) = delete;
+private:
+	
+	//一些共用变量
+
+	//1. Windows API
+	WinApi* _winapi;
+	// background module
+	opBackground* _bkproc;
+	//image process
+	ImageProc* _image_proc;
+	// work path
+	std::wstring _curr_path;
+	
+	std::map<std::wstring, long> _vkmap;
+	bytearray _screenData;
+	bytearray _screenDataBmp;
+	std::wstring m_opPath;
+public:
+	//---------------基本设置/属性-------------------
+
+	//1.版本号Version
+	std::wstring Ver();
+	//设置目录
+	void SetPath(const wchar_t* path, long* ret);
+	//获取目录
+	void GetPath(std::wstring& ret);
+	//获取插件目录
+	void GetBasePath(std::wstring& ret);
+	//返回当前对象的ID值,这个值对于每个对象是唯一存在的。可以用来判定两个对象是否一致
+	void GetID(long* ret);
+	//
+	void GetLastError(long* ret);
+	//设置是否弹出错误信息,默认是打开 0:关闭,1:显示为信息框,2:保存到文件,3:输出到标准输出
+	void SetShowErrorMsg(long show_type, long* ret);
+	
+	//sleep
+	void Sleep(long millseconds, long* ret);
+	//Process
+	//inject dll
+	void InjectDll(const wchar_t* process_name,const wchar_t* dll_name, long* ret);
+	//设置是否开启或者关闭插件内部的图片缓存机制
+	void EnablePicCache(long enable, long* ret);
+	//取上次操作的图色区域,保存为file(24位位图)
+	void CapturePre(const wchar_t* file_name, long* ret);
+	//---------------------algorithm-------------------------------
+	//A星算法
+	void AStarFindPath(long mapWidth,long mapHeight,const wchar_t* disable_points,long beginX,long beginY, long endX,long endY,std::wstring& ret);
+	//
+	void FindNearestPos(const wchar_t* all_pos, long type, long x, long y, std::wstring& ret);
+	//--------------------windows api------------------------------
+	//根据指定条件,枚举系统中符合条件的窗口
+	void EnumWindow(long parent, const wchar_t* title, const wchar_t* class_name, long filter, std::wstring& ret);
+	//根据指定进程以及其它条件,枚举系统中符合条件的窗口
+	void EnumWindowByProcess(const wchar_t* process_name, const wchar_t* title, const wchar_t* class_name, long filter, std::wstring& ret);
+	//根据指定进程名,枚举系统中符合条件的进程PID
+	void EnumProcess(const wchar_t* name, std::wstring& ret);
+	//把窗口坐标转换为屏幕坐标
+	void ClientToScreen(long ClientToScreen, long* x, long* y, long* bret);
+	//查找符合类名或者标题名的顶层可见窗口
+	void FindWindow(const wchar_t* class_name, const wchar_t* title, long* ret);
+	//根据指定的进程名字,来查找可见窗口
+	void FindWindowByProcess(const wchar_t* process_name, const wchar_t* class_name, const wchar_t* title, long* ret);
+	//根据指定的进程Id,来查找可见窗口
+	void FindWindowByProcessId(long process_id, const wchar_t* class_name, const wchar_t* title, long* ret);
+	//查找符合类名或者标题名的顶层可见窗口,如果指定了parent,则在parent的第一层子窗口中查找
+	void FindWindowEx(long parent, const wchar_t* class_name, const wchar_t* title, long* ret);
+	//获取窗口客户区域在屏幕上的位置
+	void GetClientRect(long hwnd, long* x1, long* y1, long* x2, long* y2, long* ret);
+	//获取窗口客户区域的宽度和高度
+	void GetClientSize(long hwnd, long* width, long* height, long* ret);
+	//获取顶层活动窗口中具有输入焦点的窗口句柄
+	void GetForegroundFocus(long* ret);
+	//获取顶层活动窗口,可以获取到按键自带插件无法获取到的句柄
+	void GetForegroundWindow(long* ret);
+	//获取鼠标指向的可见窗口句柄
+	void GetMousePointWindow(long* ret);
+	//获取给定坐标的可见窗口句柄
+	void GetPointWindow(long x, long y, long* ret);
+	//根据指定的pid获取进程详细信息
+	void GetProcessInfo(long pid, std::wstring& ret);
+	//获取特殊窗口
+	void GetSpecialWindow(long flag, long* ret);
+	//获取给定窗口相关的窗口句柄
+	void GetWindow(long hwnd, long flag, long* ret);
+	//获取窗口的类名
+	void GetWindowClass(long hwnd, std::wstring& ret);
+	//获取指定窗口所在的进程ID
+	void GetWindowProcessId(long hwnd, long* ret);
+	//获取指定窗口所在的进程的exe文件全路径
+	void GetWindowProcessPath(long hwnd, std::wstring& ret);
+	//获取窗口在屏幕上的位置
+	void GetWindowRect(long hwnd, long* x1, long* y1, long* x2, long* y2, long* ret);
+	//获取指定窗口的一些属性
+	void GetWindowState(long hwnd, long flag, long* ret);
+	//获取窗口的标题
+	void GetWindowTitle(long hwnd, std::wstring& rettitle);
+	//移动指定窗口到指定位置
+	void MoveWindow(long hwnd, long x, long y, long* ret);
+	//把屏幕坐标转换为窗口坐标
+	void ScreenToClient(long hwnd, long* x, long* y, long* ret);
+	//向指定窗口发送粘贴命令
+	void SendPaste(long hwnd, long* ret);
+	//设置窗口客户区域的宽度和高度
+	void SetClientSize(long hwnd, long width, long hight, long* ret);
+	//设置窗口的状态
+	void SetWindowState(long hwnd, long flag, long* ret);
+	//设置窗口的大小
+	void SetWindowSize(long hwnd, long width, long height, long* ret);
+	//设置窗口的标题
+	void SetWindowText(long hwnd, const wchar_t* title, long* ret);
+	//设置窗口的透明度
+	void SetWindowTransparent(long hwnd, long trans, long* ret);
+	//向指定窗口发送文本数据
+	void SendString(long hwnd, const wchar_t* str, long* ret);
+	//向指定窗口发送文本数据-输入法
+	void SendStringIme(long hwnd, const wchar_t* str, long* ret);
+	//运行可执行文件,可指定模式
+	void RunApp(const wchar_t* cmdline, long mode, long* ret);
+	//运行可执行文件,可指定显示模式
+	void WinExec(const wchar_t* cmdline, long cmdshow, long* ret);
+
+	//运行命令行并返回结果
+	void GetCmdStr(const wchar_t* cmd,long millseconds, std::wstring& retstr);
+
+	//--------------------Background -----------------------
+	//bind window and beign capture screen
+	void BindWindow(long hwnd, const wchar_t* display, const wchar_t* mouse, const wchar_t* keypad, long mode,long *ret);
+	//
+	void UnBindWindow(long* ret);
+	//--------------------mouse & keyboard------------------
+	//获取鼠标位置.
+	void GetCursorPos(long* x, long* y, long* ret);
+	//鼠标相对于上次的位置移动rx,ry.
+	void MoveR(long x, long y, long* ret);
+	//把鼠标移动到目的点(x,y)
+	void MoveTo(long x, long y, long* ret);
+	//把鼠标移动到目的范围内的任意一点
+	void MoveToEx(long x, long y,long w,long h, long* ret);
+	//按下鼠标左键
+	void LeftClick(long* ret);
+	//双击鼠标左键
+	void LeftDoubleClick(long* ret);
+	//按住鼠标左键
+	void LeftDown(long* ret);
+	//弹起鼠标左键
+	void LeftUp(long* ret);
+	//按下鼠标中键
+	void MiddleClick(long* ret);
+	//按住鼠标中键
+	void MiddleDown(long* ret);
+	//弹起鼠标中键
+	void MiddleUp(long* ret);
+	//按下鼠标右键
+	void RightClick(long* ret);
+	//按住鼠标右键
+	void RightDown(long* ret);
+	//弹起鼠标右键
+	void RightUp(long* ret);
+	//滚轮向下滚
+	void WheelDown(long* ret);
+	//滚轮向上滚
+	void WheelUp(long* ret);
+	//获取指定的按键状态.(前台信息,不是后台)
+	void GetKeyState(long vk_code, long* ret);
+	//按住指定的虚拟键码
+	void KeyDown(long vk_code, long* ret);
+	//按住指定的虚拟键码
+	void KeyDownChar(const wchar_t* vk_code, long* ret);
+	//弹起来虚拟键vk_code
+	void KeyUp(long vk_code, long* ret);
+	//弹起来虚拟键vk_code
+	void KeyUpChar(const wchar_t* vk_code, long* ret);
+	//等待指定的按键按下 (前台,不是后台)
+	void WaitKey(long vk_code,long time_out, long* ret);
+	//发送字符串
+	//long SendString(long HWND)
+	//弹起来虚拟键vk_code
+	void KeyPress(long vk_code, long* ret);
+	void KeyPressChar(const wchar_t* vk_code, long* ret);
+
+	//--------------------image and color-----------------------
+	//抓取指定区域(x1, y1, x2, y2)的图像, 保存为file
+	void Capture(long x1, long y1, long x2, long y2, const wchar_t* file_name, long* ret);
+	//比较指定坐标点(x,y)的颜色
+	void CmpColor(long x, long y,const wchar_t* color,double sim, long* ret);
+	//查找指定区域内的颜色
+	void FindColor(long x1, long y1, long x2, long y2, const wchar_t* color,double sim,long dir, long* x, long* y, long* ret);
+	//查找指定区域内的所有颜色
+	void FindColorEx(long x1, long y1, long x2, long y2, const wchar_t* color, double sim,long dir, std::wstring& retstr);
+	//根据指定的多点查找颜色坐标
+	void FindMultiColor(long x1, long y1, long x2, long y2, const wchar_t* first_color, const wchar_t* offset_color, double sim, long dir, long* x, long* y, long* ret);
+	//根据指定的多点查找所有颜色坐标
+	void FindMultiColorEx(long x1, long y1, long x2, long y2, const wchar_t* first_color, const wchar_t* offset_color, double sim, long dir,std::wstring& retstr);
+	//查找指定区域内的图片
+	void FindPic(long x1,long y1,long x2,long y2,const wchar_t* files, const wchar_t* delta_color,double sim,long dir,long* x,long* y,long* ret);
+	//查找多个图片
+	void FindPicEx(long x1, long y1, long x2, long y2, const wchar_t* files, const wchar_t* delta_color, double sim, long dir,std::wstring& retstr);
+	//
+	//这个函数可以查找多个图片, 并且返回所有找到的图像的坐标.此函数同FindPicEx.只是返回值不同.(file1,x,y|file2,x,y|...)
+	void FindPicExS(long x1, long y1, long x2, long y2, const wchar_t* files, const wchar_t* delta_color, double sim, long dir, std::wstring& retstr);
+	//查找指定区域内的颜色块,颜色格式"RRGGBB-DRDGDB",注意,和按键的颜色格式相反
+	void FindColorBlock(long x1, long y1, long x2, long y2, const wchar_t*  color, double sim, long count, long height, long width, long* x, long* y, long* ret);
+	//查找指定区域内的所有颜色块, 颜色格式"RRGGBB-DRDGDB", 注意, 和按键的颜色格式相反
+	void FindColorBlockEx(long x1, long y1, long x2, long y2, const wchar_t*  color, double sim, long count, long height, long width, std::wstring& retstr);
+	//获取(x,y)的颜色
+	void GetColor(long x, long y, std::wstring& ret);
+	//
+	//设置图像输入方式,默认窗口截图
+	void SetDisplayInput(const wchar_t* mode, long* ret);
+
+	void LoadPic(const wchar_t* file_name, long* ret);
+
+	void FreePic(const wchar_t* file_name, long* ret);
+	//从内存加载要查找的图片
+	void LoadMemPic(const wchar_t* file_name,void* data,long size, long* ret);
+	//
+	void GetScreenData(long x1, long y1, long x2, long y2, void** data,long* ret);
+	//
+	void GetScreenDataBmp(long x1, long y1, long x2, long y2, void** data,long* size, long* ret);
+	//
+	void GetScreenFrameInfo(long* frame_id, long* time);
+	//
+	void MatchPicName(const wchar_t* pic_name, std::wstring& retstr);
+	//----------------------ocr-------------------------
+	//设置字库文件
+	void SetDict(long idx, const wchar_t* file_name, long* ret);
+	//设置内存字库文件
+	void SetMemDict(long idx, const wchar_t* data, long size, long* ret);
+	//使用哪个字库文件进行识别
+	void UseDict(long idx,  long* ret);
+	//识别屏幕范围(x1,y1,x2,y2)内符合color_format的字符串,并且相似度为sim,sim取值范围(0.1-1.0),
+	void Ocr(long x1, long y1, long x2, long y2, const wchar_t* color, double sim,std::wstring& ret_str);
+	//回识别到的字符串,以及每个字符的坐标.
+	void OcrEx(long x1, long y1, long x2, long y2, const wchar_t* color, double sim, std::wstring& ret_str);
+	//在屏幕范围(x1,y1,x2,y2)内,查找string(可以是任意个字符串的组合),并返回符合color_format的坐标位置
+	void FindStr(long x1, long y1, long x2, long y2,const wchar_t* strs, const wchar_t* color, double sim, long* retx,long* rety,long* ret);
+	//返回符合color_format的所有坐标位置
+	void FindStrEx(long x1, long y1, long x2, long y2, const wchar_t* strs, const wchar_t* color, double sim,std::wstring& retstr);
+	//识别屏幕范围(x1,y1,x2,y2)内的字符串,自动二值化,而无需指定颜色
+	void OcrAuto(long x1, long y1, long x2, long y2, double sim, std::wstring& ret_str);
+	//从文件中识别图片
+	void OcrFromFile(const wchar_t* file_name,const wchar_t* color_format, double sim, std::wstring& retstr);
+	//从文件中识别图片,无需指定颜色
+	void OcrAutoFromFile(const wchar_t* file_name, double sim, std::wstring& retstr);
+	//查找频幕中的直线
+	void FindLine(long x1, long y1, long x2, long y2, const wchar_t* color, double sim, std::wstring& retstr);
+	
+	//向某进程写入数据
+	void WriteData(long hwnd, const wchar_t* address, const wchar_t* data, long size, long* ret);
+	//读取数据
+	void ReadData(long hwnd, const wchar_t* address, long size, std::wstring& retstr);
+		
+};
+
+
+

+ 57 - 0
gm/gm/include/promutex.h

@@ -0,0 +1,57 @@
+#pragma once
+#include <windows.h>
+#include <string>
+#include <assert.h>
+using std::wstring;
+class promutex
+{
+public:
+	explicit promutex():_hmutex(NULL) {
+	}
+	~promutex() {
+		if (_hmutex) {
+			unlock();
+			::CloseHandle(_hmutex);
+			_hmutex = NULL;
+		}
+	}
+	bool open_create(const wstring& name_) {
+		HANDLE temp;
+		temp = OpenMutexW(MUTEX_ALL_ACCESS, FALSE, name_.data());
+		if (!temp) {
+			temp = CreateMutexW(NULL, FALSE, name_.data());
+		}
+		if (temp) {
+			_hmutex = temp;
+			return true;
+		}
+		else {
+			return false;
+		}
+		
+	}
+	bool open(const wstring& name_) {
+		HANDLE temp;
+		temp = OpenMutexW(MUTEX_ALL_ACCESS, FALSE, name_.data());
+		if (temp) {
+			_hmutex = temp;
+			return true;
+		}
+		return false;
+
+	}
+	void lock() {
+		::WaitForSingleObject(_hmutex, INFINITE);
+	}
+
+	DWORD try_lock(size_t time_) {
+		return ::WaitForSingleObject(_hmutex, time_);
+	}
+	void unlock() {
+		assert(_hmutex);
+		::ReleaseMutex(_hmutex);
+	}
+protected:
+private:
+	HANDLE _hmutex;
+};

+ 77 - 0
gm/gm/include/sharedmem.h

@@ -0,0 +1,77 @@
+#pragma once
+#include <windows.h>
+#include <string>
+using std::wstring;
+class sharedmem
+{
+public:
+	explicit sharedmem(const wstring& name_,size_t size_):_hmap(nullptr),_paddress(nullptr),_ismaped(0){
+		open_create(name_, size_);
+
+	}
+	sharedmem() :_hmap(nullptr),_paddress(nullptr), _ismaped(0) {
+
+	}
+	~sharedmem() {
+		close();
+	}
+	/*open or create a shared memory*/
+	bool open_create(const wstring& name_, size_t size_) {
+		auto temph = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, name_.data());
+		if (!temph) {
+			temph = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size_, name_.data());
+			if (!temph)
+				return false;
+			
+		}
+		_hmap = temph;
+		if (!_ismaped)
+			_paddress = MapViewOfFile(_hmap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
+		_ismaped = 1;
+		return true;
+		
+	}
+	/*open only*/
+	bool open(const wstring& name_) {
+		auto temph = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, name_.data());
+		if (temph)
+			_hmap = temph;
+		else
+			return false;
+		if (!_ismaped)
+			_paddress = MapViewOfFile(_hmap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
+		_ismaped = 1;
+		return true;
+
+	}
+	/*close the shared memory*/
+	void close() {
+		if (_ismaped)
+			UnmapViewOfFile(_paddress);
+		if (_hmap)
+			CloseHandle(_hmap);
+		_hmap = NULL;
+		_ismaped = 0;
+		_paddress = nullptr;
+	}
+	template<typename T>
+	T& at(int idx_) {
+		//assert(_hmap&&_paddress);
+		return (T)_paddress[idx_];
+	}
+	template<typename T>
+	T* data() {
+		return (T*)_paddress;
+	}
+protected:
+	/*sharedmem operator=(const sharedmem& rhs) {
+		return rhs;
+	}*/
+private:
+	//handle of shared file map
+	HANDLE _hmap;
+	//address of shared memory
+	void* _paddress;
+	//state of is maped
+	int _ismaped;
+};

+ 1261 - 0
gm/gm/libop.cpp

@@ -0,0 +1,1261 @@
+// OpInterface.cpp: OpInterface 的实现
+
+#include "libop.h"
+#include "./core/optype.h"
+#include "./core/globalVar.h"
+#include "./core/helpfunc.h"
+#include "./core/opEnv.h"
+#include "./winapi/WinApi.h"
+#include "./background/opBackground.h"
+#include "./ImageProc/ImageProc.h"
+#include "./core/Cmder.h"
+#include "./winapi/Injecter.h"
+
+#include "./algorithm/AStar.hpp"
+#include "./winapi/MemoryEx.h"
+#include <fstream>
+#include <filesystem>
+#include <regex>
+
+#undef FindWindow
+#undef FindWindowEx
+#undef SetWindowText
+
+
+const int small_block_size = 10;
+
+libop::libop()
+{
+	_winapi = new WinApi;
+	_bkproc = new opBackground;
+	_image_proc = new ImageProc;
+
+	//初始化目录
+	wchar_t buff[256];
+	::GetCurrentDirectoryW(256, buff);
+	_curr_path = buff;
+	_image_proc->_curr_path = _curr_path;
+	//初始化键码表
+	_vkmap[L"back"] = VK_BACK;
+	_vkmap[L"ctrl"] = VK_CONTROL;
+	_vkmap[L"alt"] = 18;
+	_vkmap[L"shift"] = VK_SHIFT;
+	_vkmap[L"win"] = VK_LWIN;
+	_vkmap[L"space"] = L' ';
+	_vkmap[L"tab"] = VK_TAB;
+	_vkmap[L"esc"] = VK_CANCEL;
+	_vkmap[L"enter"] = L'\r';
+	_vkmap[L"up"] = VK_UP;
+	_vkmap[L"down"] = VK_DOWN;
+	_vkmap[L"left"] = VK_LEFT;
+	_vkmap[L"right"] = VK_RIGHT;
+	_vkmap[L"f1"] = VK_F1;
+	_vkmap[L"f2"] = VK_F2;
+	_vkmap[L"f3"] = VK_F3;
+	_vkmap[L"f4"] = VK_F4;
+	_vkmap[L"f5"] = VK_F5;
+	_vkmap[L"f6"] = VK_F6;
+	_vkmap[L"f7"] = VK_F7;
+	_vkmap[L"f8"] = VK_F8;
+	_vkmap[L"f9"] = VK_F9;
+	_vkmap[L"f10"] = VK_F10;
+	_vkmap[L"f11"] = VK_F11;
+	_vkmap[L"f12"] = VK_F12;
+
+	m_opPath = opEnv::getBasePath();
+}
+
+libop::~libop()
+{
+	delete _winapi;
+	delete _bkproc;
+	delete _image_proc;
+}
+
+std::wstring libop::Ver()
+{
+
+	//Tool::setlog("address=%d,str=%s", ver, ver);
+	return _T(OP_VERSION);
+}
+
+void libop::SetPath(const wchar_t *path, long *ret)
+{
+	wstring fpath = path;
+	replacew(fpath, L"/", L"\\");
+	if (fpath.find(L'\\') != -1 && ::PathFileExistsW(fpath.data()))
+	{
+		_curr_path = fpath;
+		_image_proc->_curr_path = _curr_path;
+		_bkproc->_curr_path = _curr_path;
+		*ret = 1;
+	}
+	else
+	{
+
+		if (!fpath.empty() && fpath[0] != L'\\')
+			fpath = _curr_path + L'\\' + fpath;
+		else
+			fpath = _curr_path + fpath;
+		if (::PathFileExistsW(fpath.data()))
+		{
+			_curr_path = path;
+			_image_proc->_curr_path = _curr_path;
+			_bkproc->_curr_path = _curr_path;
+			*ret = 1;
+		}
+		else
+			*ret = 0;
+	}
+}
+
+void libop::GetPath(std::wstring &path)
+{
+	path = _curr_path;
+}
+
+void libop::GetBasePath(std::wstring &path)
+{
+	path = opEnv::getBasePath();
+}
+
+void libop::GetID(long *ret)
+{
+	*ret = (long)this;
+}
+
+void libop::GetLastError(long *ret)
+{
+	*ret = ::GetLastError();
+}
+
+void libop::SetShowErrorMsg(long show_type, long *ret)
+{
+	opEnv::m_showErrorMsg = show_type;
+	*ret = 1;
+}
+
+void libop::Sleep(long millseconds, long *ret)
+{
+	::Sleep(millseconds);
+	*ret = 1;
+}
+
+void libop::InjectDll(const wchar_t *process_name, const wchar_t *dll_name, long *ret)
+{
+	auto proc = _ws2string(process_name);
+	auto dll = _ws2string(dll_name);
+	long hwnd;
+	FindWindowByProcess(process_name, L"", L"", &hwnd);
+	long pid;
+	GetWindowProcessId(hwnd, &pid);
+	*ret = 0;
+	if (Injecter::EnablePrivilege(TRUE))
+	{
+		long error_code = 0;
+		*ret = Injecter::InjectDll(pid, dll_name, error_code);
+	}
+	else
+	{
+		setlog("EnablePrivilege false erro_code=%08X ", ::GetLastError());
+	}
+}
+
+void libop::EnablePicCache(long enable, long *ret)
+{
+	_image_proc->_enable_cache = enable;
+	*ret = 1;
+}
+
+void libop::CapturePre(const wchar_t *file, LONG *ret)
+{
+	*ret = _image_proc->Capture(file);
+}
+
+void libop::AStarFindPath(long mapWidth, long mapHeight, const wchar_t *disable_points, long beginX, long beginY, long endX, long endY, std::wstring &path)
+{
+	AStar as;
+	using Vec2i = AStar::Vec2i;
+	vector<Vec2i> walls;
+	vector<wstring> vstr;
+	Vec2i tp;
+	split(disable_points, vstr, L"|");
+	for (auto &it : vstr)
+	{
+		if (swscanf(it.c_str(), L"%d,%d", &tp.x, &tp.y) != 2)
+			break;
+		walls.push_back(tp);
+	}
+	list<Vec2i> paths;
+
+	as.set_map(mapWidth, mapHeight, walls);
+	as.findpath(beginX, beginY, endX, endY, paths);
+	wstring pathstr;
+	wchar_t buf[20];
+	for (auto it = paths.rbegin(); it != paths.rend(); ++it)
+	{
+		auto v = *it;
+		wsprintf(buf, L"%d,%d", v.x, v.y);
+		pathstr += buf;
+		pathstr.push_back(L'|');
+	}
+	if (!pathstr.empty())
+		pathstr.pop_back();
+}
+
+void libop::FindNearestPos(const wchar_t *all_pos, long type, long x, long y, std::wstring &ret)
+{
+	const wchar_t *p = 0;
+	wchar_t buf[256] = {0};
+	wchar_t rs[256] = {0};
+	double old = 1e9;
+	long rx = -1, ry = -1;
+	std::wstring s = std::regex_replace(all_pos, std::wregex(L","), L" ");
+	p = s.data();
+	while (*p)
+	{
+		long x2, y2;
+		bool ok = false;
+		if (type == 1)
+		{
+
+			if (swscanf(p, L"%d %d", &x2, &y2) == 2)
+			{
+				ok = true;
+			}
+		}
+		else
+		{
+			if (swscanf(p, L"%s %d %d", buf, &x2, &y2) == 3)
+			{
+				ok = true;
+			}
+		}
+		if (ok)
+		{
+			double compareDis = (x - x2) * (x - x2) + (y - y2) * (y - y2);
+			if (compareDis < old)
+			{
+				rx = x2;
+				ry = y2;
+				old = compareDis;
+				wcscpy(rs, buf);
+			}
+		}
+		while (*p && *p != L'|')
+			++p;
+		if (*p)
+			++p;
+	}
+	if (rs[0])
+	{
+		wcscpy(buf, rs);
+		wsprintf(rs, L"%s,%d,%d", buf, rx, ry);
+	}
+	else if (type == 1 && rx != -1)
+	{
+		wsprintf(rs, L"%d,%d", rx, ry);
+	}
+	ret = rs;
+}
+
+void libop::EnumWindow(long parent, const wchar_t *title, const wchar_t *class_name, long filter, std::wstring &retstr)
+{
+	// TODO: 在此添加实现代码
+	std::unique_ptr<wchar_t> retstring(new wchar_t[MAX_PATH * 200]);
+	memset(retstring.get(), 0, sizeof(wchar_t) * MAX_PATH * 200);
+	_winapi->EnumWindow((HWND)parent, title, class_name, filter, retstring.get());
+	//*retstr=_bstr_t(retstring);
+	retstr = retstring.get();
+}
+
+void libop::EnumWindowByProcess(const wchar_t *process_name, const wchar_t *title, const wchar_t *class_name, long filter, std::wstring &retstring)
+{
+	// TODO: 在此添加实现代码
+	std::unique_ptr<wchar_t> retstr(new wchar_t[MAX_PATH * 200]);
+	memset(retstr.get(), 0, sizeof(wchar_t) * MAX_PATH * 200);
+	_winapi->EnumWindow((HWND)0, title, class_name, filter, retstr.get(), process_name);
+	//*retstring=_bstr_t(retstr);
+
+	retstring = retstr.get();
+}
+
+void libop::EnumProcess(const wchar_t *name, std::wstring &retstring)
+{
+	// TODO: 在此添加实现代码
+	std::unique_ptr<wchar_t> retstr(new wchar_t[MAX_PATH * 200]);
+	memset(retstr.get(), 0, sizeof(wchar_t) * MAX_PATH * 200);
+	_winapi->EnumProcess(name, retstr.get());
+	//*retstring=_bstr_t(retstr);
+	retstring = retstr.get();
+}
+
+void libop::ClientToScreen(long ClientToScreen, long *x, long *y, long *bret)
+{
+	// TODO: 在此添加实现代码
+
+	*bret = _winapi->ClientToScreen(ClientToScreen, *x, *y);
+}
+
+void libop::FindWindow(const wchar_t *class_name, const wchar_t *title, long *rethwnd)
+{
+	// TODO: 在此添加实现代码
+	*rethwnd = _winapi->FindWindow(class_name, title);
+}
+
+void libop::FindWindowByProcess(const wchar_t *process_name, const wchar_t *class_name, const wchar_t *title, long *rethwnd)
+{
+	// TODO: 在此添加实现代码
+	_winapi->FindWindowByProcess(class_name, title, *rethwnd, process_name);
+}
+
+void libop::FindWindowByProcessId(long process_id, const wchar_t *class_name, const wchar_t *title, long *rethwnd)
+{
+	// TODO: 在此添加实现代码
+	_winapi->FindWindowByProcess(class_name, title, *rethwnd, NULL, process_id);
+}
+
+void libop::FindWindowEx(long parent, const wchar_t *class_name, const wchar_t *title, long *rethwnd)
+{
+	// TODO: 在此添加实现代码
+	*rethwnd = _winapi->FindWindowEx(parent, class_name, title);
+}
+
+void libop::GetClientRect(long hwnd, long *x1, long *y1, long *x2, long *y2, long *nret)
+{
+	// TODO: 在此添加实现代码
+
+	*nret = _winapi->GetClientRect(hwnd, *x1, *y1, *x2, *y2);
+}
+
+void libop::GetClientSize(long hwnd, long *width, long *height, long *nret)
+{
+	// TODO: 在此添加实现代码
+
+	*nret = _winapi->GetClientSize(hwnd, *width, *height);
+}
+
+void libop::GetForegroundFocus(long *rethwnd)
+{
+	// TODO: 在此添加实现代码
+	*rethwnd = (LONG)::GetFocus();
+}
+
+void libop::GetForegroundWindow(long *rethwnd)
+{
+	// TODO: 在此添加实现代码
+	*rethwnd = (LONG)::GetForegroundWindow();
+}
+
+void libop::GetMousePointWindow(long *rethwnd)
+{
+	// TODO: 在此添加实现代码
+	//::Sleep(2000);
+	_winapi->GetMousePointWindow(*rethwnd);
+}
+
+void libop::GetPointWindow(long x, long y, long *rethwnd)
+{
+	// TODO: 在此添加实现代码
+	_winapi->GetMousePointWindow(*rethwnd, x, y);
+}
+
+void libop::GetProcessInfo(long pid, std::wstring &retstring)
+{
+	// TODO: 在此添加实现代码
+
+	wchar_t retstr[MAX_PATH] = {0};
+	_winapi->GetProcessInfo(pid, retstr);
+	//* retstring=_bstr_t(retstr);
+
+	retstring = retstr;
+}
+
+void libop::GetSpecialWindow(long flag, long *rethwnd)
+{
+	// TODO: 在此添加实现代码
+	*rethwnd = 0;
+	if (flag == 0)
+		*rethwnd = (LONG)GetDesktopWindow();
+	else if (flag == 1)
+	{
+		*rethwnd = (LONG)::FindWindowW(L"Shell_TrayWnd", NULL);
+	}
+}
+
+void libop::GetWindow(long hwnd, long flag, long *nret)
+{
+	// TODO: 在此添加实现代码
+	_winapi->GetWindow(hwnd, flag, *nret);
+}
+
+void libop::GetWindowClass(long hwnd, std::wstring &retstring)
+{
+	// TODO: 在此添加实现代码
+	wchar_t classname[MAX_PATH] = {0};
+	::GetClassName((HWND)hwnd, classname, MAX_PATH);
+	//* retstring=_bstr_t(classname);
+
+	retstring = classname;
+}
+
+void libop::GetWindowProcessId(long hwnd, long *nretpid)
+{
+	// TODO: 在此添加实现代码
+	DWORD pid = 0;
+	::GetWindowThreadProcessId((HWND)hwnd, &pid);
+	*nretpid = pid;
+}
+
+void libop::GetWindowProcessPath(long hwnd, std::wstring &retstring)
+{
+	// TODO: 在此添加实现代码
+	DWORD pid = 0;
+	::GetWindowThreadProcessId((HWND)hwnd, &pid);
+	wchar_t process_path[MAX_PATH] = {0};
+	_winapi->GetProcesspath(pid, process_path);
+	//* retstring=_bstr_t(process_path);
+
+	retstring = process_path;
+}
+
+void libop::GetWindowRect(long hwnd, long *x1, long *y1, long *x2, long *y2, long *nret)
+{
+	// TODO: 在此添加实现代码
+
+	RECT winrect;
+	*nret = ::GetWindowRect((HWND)hwnd, &winrect);
+	*x1 = winrect.left;
+	*y1 = winrect.top;
+	*x2 = winrect.right;
+	*y2 = winrect.bottom;
+}
+
+void libop::GetWindowState(long hwnd, long flag, long *rethwnd)
+{
+	// TODO: 在此添加实现代码
+	*rethwnd = _winapi->GetWindowState(hwnd, flag);
+}
+
+void libop::GetWindowTitle(long hwnd, std::wstring &rettitle)
+{
+	// TODO: 在此添加实现代码
+	wchar_t title[MAX_PATH] = {0};
+	::GetWindowTextW((HWND)hwnd, title, MAX_PATH);
+	//* rettitle=_bstr_t(title);
+
+	rettitle = title;
+}
+
+void libop::MoveWindow(long hwnd, long x, long y, long *nret)
+{
+	// TODO: 在此添加实现代码
+	RECT winrect;
+	::GetWindowRect((HWND)hwnd, &winrect);
+	int width = winrect.right - winrect.left;
+	int hight = winrect.bottom - winrect.top;
+	*nret = ::MoveWindow((HWND)hwnd, x, y, width, hight, false);
+}
+
+void libop::ScreenToClient(long hwnd, long *x, long *y, long *nret)
+{
+	// TODO: 在此添加实现代码
+
+	POINT point;
+	*nret = ::ScreenToClient((HWND)hwnd, &point);
+	*x = point.x;
+	*y = point.y;
+}
+
+void libop::SendPaste(long hwnd, long *nret)
+{
+	// TODO: 在此添加实现代码
+	*nret = _winapi->SendPaste(hwnd);
+}
+
+void libop::SetClientSize(long hwnd, long width, long hight, long *nret)
+{
+	// TODO: 在此添加实现代码
+	*nret = _winapi->SetWindowSize(hwnd, width, hight);
+}
+
+void libop::SetWindowState(long hwnd, long flag, long *nret)
+{
+	// TODO: 在此添加实现代码
+	*nret = _winapi->SetWindowState(hwnd, flag);
+}
+
+void libop::SetWindowSize(long hwnd, long width, long height, long *nret)
+{
+	// TODO: 在此添加实现代码
+	*nret = _winapi->SetWindowSize(hwnd, width, height, 1);
+}
+
+void libop::SetWindowText(long hwnd, const wchar_t *title, long *nret)
+{
+	// TODO: 在此添加实现代码
+	//*nret=gWindowObj.TSSetWindowState(hwnd,flag);
+	*nret = ::SetWindowTextW((HWND)hwnd, title);
+}
+
+void libop::SetWindowTransparent(long hwnd, long trans, long *nret)
+{
+	// TODO: 在此添加实现代码
+	*nret = _winapi->SetWindowTransparent(hwnd, trans);
+}
+
+void libop::SendString(long hwnd, const wchar_t *str, long *ret)
+{
+	*ret = _winapi->SendString((HWND)hwnd, str);
+}
+
+void libop::SendStringIme(long hwnd, const wchar_t *str, long *ret)
+{
+	*ret = _winapi->SendStringIme((HWND)hwnd, str);
+}
+
+void libop::RunApp(const wchar_t *cmdline, long mode, long *ret)
+{
+	*ret = _winapi->RunApp(cmdline, mode);
+}
+
+void libop::WinExec(const wchar_t *cmdline, long cmdshow, long *ret)
+{
+	auto str = _ws2string(cmdline);
+	*ret = ::WinExec(str.c_str(), cmdshow) > 31 ? 1 : 0;
+}
+
+void libop::GetCmdStr(const wchar_t *cmd, long millseconds, std::wstring &retstr)
+{
+	auto strcmd = _ws2string(cmd);
+	Cmder cd;
+	auto str = cd.GetCmdStr(strcmd, millseconds <= 0 ? 5 : millseconds);
+	retstr = _s2wstring(str);
+}
+
+void libop::BindWindow(long hwnd, const wchar_t *display, const wchar_t *mouse, const wchar_t *keypad, long mode, long *ret)
+{
+	if (_bkproc->IsBind())
+		_bkproc->UnBindWindow();
+	*ret = _bkproc->BindWindow(hwnd, display, mouse, keypad, mode);
+	if (*ret == 1)
+	{
+		//_image_proc->set_offset(_bkproc->_pbkdisplay->_client_x, _bkproc->_pbkdisplay->_client_y);
+	}
+}
+
+void libop::UnBindWindow(long *ret)
+{
+	*ret = _bkproc->UnBindWindow();
+}
+
+void libop::GetCursorPos(long *x, long *y, long *ret)
+{
+
+	*ret = _bkproc->_bkmouse->GetCursorPos(*x, *y);
+}
+
+void libop::MoveR(long x, long y, long *ret)
+{
+	*ret = _bkproc->_bkmouse->MoveR(x, y);
+}
+//把鼠标移动到目的点(x,y)
+void libop::MoveTo(long x, long y, long *ret)
+{
+	*ret = _bkproc->_bkmouse->MoveTo(x, y);
+}
+
+void libop::MoveToEx(long x, long y, long w, long h, long *ret)
+{
+	*ret = _bkproc->_bkmouse->MoveToEx(x, y, w, h);
+}
+
+void libop::LeftClick(long *ret)
+{
+	*ret = _bkproc->_bkmouse->LeftClick();
+}
+
+void libop::LeftDoubleClick(long *ret)
+{
+	*ret = _bkproc->_bkmouse->LeftDoubleClick();
+}
+
+void libop::LeftDown(long *ret)
+{
+	*ret = _bkproc->_bkmouse->LeftDown();
+}
+
+void libop::LeftUp(long *ret)
+{
+	*ret = _bkproc->_bkmouse->LeftUp();
+}
+
+void libop::MiddleClick(long *ret)
+{
+	*ret = _bkproc->_bkmouse->MiddleClick();
+}
+
+void libop::MiddleDown(long *ret)
+{
+	*ret = _bkproc->_bkmouse->MiddleDown();
+}
+
+void libop::MiddleUp(long *ret)
+{
+	*ret = _bkproc->_bkmouse->MiddleUp();
+}
+
+void libop::RightClick(long *ret)
+{
+	*ret = _bkproc->_bkmouse->RightClick();
+}
+
+void libop::RightDown(long *ret)
+{
+	*ret = _bkproc->_bkmouse->RightDown();
+}
+
+void libop::RightUp(long *ret)
+{
+	*ret = _bkproc->_bkmouse->RightUp();
+}
+
+void libop::WheelDown(long *ret)
+{
+	*ret = _bkproc->_bkmouse->WheelDown();
+}
+
+void libop::WheelUp(long *ret)
+{
+	*ret = _bkproc->_bkmouse->WheelUp();
+}
+
+void libop::GetKeyState(long vk_code, long *ret)
+{
+	*ret = _bkproc->_keypad->GetKeyState(vk_code);
+}
+
+void libop::KeyDown(long vk_code, long *ret)
+{
+	*ret = _bkproc->_keypad->KeyDown(vk_code);
+}
+
+void libop::KeyDownChar(const wchar_t *vk_code, long *ret)
+{
+	auto nlen = wcslen(vk_code);
+	*ret = 0;
+	if (nlen > 0)
+	{
+		wstring s = vk_code;
+		wstring2lower(s);
+		long vk = _vkmap.count(s) ? _vkmap[s] : vk_code[0];
+		*ret = _bkproc->_keypad->KeyDown(vk);
+	}
+}
+
+void libop::KeyUp(long vk_code, long *ret)
+{
+	*ret = _bkproc->_keypad->KeyUp(vk_code);
+}
+
+void libop::KeyUpChar(const wchar_t *vk_code, long *ret)
+{
+	auto nlen = wcslen(vk_code);
+	*ret = 0;
+	if (nlen > 0)
+	{
+		wstring s = vk_code;
+		wstring2lower(s);
+		long vk = _vkmap.count(s) ? _vkmap[s] : vk_code[0];
+		*ret = _bkproc->_keypad->KeyUp(vk);
+	}
+}
+
+void libop::WaitKey(long vk_code, long time_out, long *ret)
+{
+	if (time_out < 0)
+		time_out = 0;
+	*ret = _bkproc->_keypad->WaitKey(vk_code, time_out);
+}
+
+void libop::KeyPress(long vk_code, long *ret)
+{
+
+	*ret = _bkproc->_keypad->KeyPress(vk_code);
+}
+
+void libop::KeyPressChar(const wchar_t *vk_code, long *ret)
+{
+	auto nlen = wcslen(vk_code);
+	*ret = 0;
+	if (nlen > 0)
+	{
+		//setlog(vk_code);
+		wstring s = vk_code;
+		wstring2lower(s);
+		long vk = _vkmap.count(s) ? _vkmap[s] : vk_code[0];
+		*ret = _bkproc->_keypad->KeyPress(vk);
+	}
+}
+
+//抓取指定区域(x1, y1, x2, y2)的图像, 保存为file
+void libop::Capture(long x1, long y1, long x2, long y2, const wchar_t *file_name, long *ret)
+{
+
+	*ret = 0;
+
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+
+			*ret = _image_proc->Capture(file_name);
+		}
+	}
+}
+//比较指定坐标点(x,y)的颜色
+void libop::CmpColor(long x, long y, const wchar_t *color, DOUBLE sim, long *ret)
+{
+	//LONG rx = -1, ry = -1;
+	long tx = x + small_block_size, ty = y + small_block_size;
+	*ret = 0;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x, y, tx, ty))
+	{
+		if (!_bkproc->requestCapture(x, y, small_block_size, small_block_size, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x, y);
+			*ret = _image_proc->CmpColor(x, y, color, sim);
+		}
+	}
+}
+//查找指定区域内的颜色
+void libop::FindColor(long x1, long y1, long x2, long y2, const wchar_t *color, DOUBLE sim, long dir, long *x, long *y, long *ret)
+{
+
+	*ret = 0;
+	*x = *y = -1;
+
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			*ret = _image_proc->FindColor(color, sim, dir, *x, *y);
+		}
+	}
+}
+//查找指定区域内的所有颜色
+void libop::FindColorEx(long x1, long y1, long x2, long y2, const wchar_t *color, DOUBLE sim, long dir, std::wstring &retstr)
+{
+	//wstring str;
+	retstr.clear();
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->FindColoEx(color, sim, dir, retstr);
+		}
+	}
+	
+}
+//根据指定的多点查找颜色坐标
+void libop::FindMultiColor(long x1, long y1, long x2, long y2, const wchar_t *first_color, const wchar_t *offset_color, DOUBLE sim, long dir, long *x, long *y, long *ret)
+{
+
+	*ret = 0;
+	*x = *y = -1;
+
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			*ret = _image_proc->FindMultiColor(first_color, offset_color, sim, dir, *x, *y);
+		}
+
+		/*if (*ret) {
+			rx += x1; ry += y1;
+			rx -= _bkproc->_pbkdisplay->_client_x;
+			ry -= _bkproc->_pbkdisplay->_client_y;
+		}*/
+	}
+}
+//根据指定的多点查找所有颜色坐标
+void libop::FindMultiColorEx(long x1, long y1, long x2, long y2, const wchar_t *first_color, const wchar_t *offset_color, DOUBLE sim, long dir, std::wstring &retstr)
+{
+	retstr.clear();
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->FindMultiColorEx(first_color, offset_color, sim, dir, retstr);
+		}
+	}
+	//retstr = str;
+}
+//查找指定区域内的图片
+void libop::FindPic(long x1, long y1, long x2, long y2, const wchar_t *files, const wchar_t *delta_color, DOUBLE sim, long dir, long *x, long *y, long *ret)
+{
+
+	*ret = 0;
+	*x = *y = -1;
+
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			*ret = _image_proc->FindPic(files, delta_color, sim, 0, *x, *y);
+		}
+
+		/*if (*ret) {
+			rx += x1; ry += y1;
+			rx -= _bkproc->_pbkdisplay->_client_x;
+			ry -= _bkproc->_pbkdisplay->_client_y;
+		}*/
+	}
+}
+//查找多个图片
+void libop::FindPicEx(long x1, long y1, long x2, long y2, const wchar_t *files, const wchar_t *delta_color, DOUBLE sim, long dir, std::wstring &retstr)
+{
+
+	//wstring str;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->FindPicEx(files, delta_color, sim, dir, retstr);
+		}
+	}
+	//retstr = str;
+}
+
+void libop::FindPicExS(long x1, long y1, long x2, long y2, const wchar_t *files, const wchar_t *delta_color, double sim, long dir, std::wstring &retstr)
+{
+	//wstring str;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->FindPicEx(files, delta_color, sim, dir, retstr, false);
+		}
+	}
+	//retstr = str;
+}
+
+void libop::FindColorBlock(long x1, long y1, long x2, long y2, const wchar_t *color, double sim, long count, long height, long width, long *x, long *y, long *ret)
+{
+	*ret = 0;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			*ret = _image_proc->FindColorBlock(color, sim, count, height, width, *x, *y);
+		}
+	}
+}
+
+void libop::FindColorBlockEx(long x1, long y1, long x2, long y2, const wchar_t *color, double sim, long count, long height, long width, std::wstring &retstr)
+{
+
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->FindColorBlockEx(color, sim, count, height, width, retstr);
+		}
+	}
+}
+
+//获取(x,y)的颜色
+void libop::GetColor(long x, long y, std::wstring &ret)
+{
+	color_t cr;
+	auto tx = x + small_block_size, ty = y + small_block_size;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x, y, tx, ty))
+	{
+		if (_bkproc->requestCapture(x, y, small_block_size, small_block_size, _image_proc->_src))
+		{
+			_image_proc->set_offset(x, y);
+			cr = _image_proc->_src.at<color_t>(0, 0);
+		}
+		else
+		{
+			setlog("error requestCapture");
+		}
+	}
+	else
+	{
+		//setlog("")
+	}
+
+	ret = cr.towstr();
+}
+
+void libop::SetDisplayInput(const wchar_t *mode, long *ret)
+{
+	*ret = _bkproc->set_display_method(mode);
+}
+
+void libop::LoadPic(const wchar_t *file_name, long *ret)
+{
+	*ret = _image_proc->LoadPic(file_name);
+}
+
+void libop::FreePic(const wchar_t *file_name, long *ret)
+{
+	*ret = _image_proc->FreePic(file_name);
+}
+
+void libop::LoadMemPic(const wchar_t *file_name, void *data, long size, long *ret)
+{
+	*ret = _image_proc->LoadMemPic(file_name, data, size);
+}
+
+void libop::GetScreenData(long x1, long y1, long x2, long y2, void **data, long *ret)
+{
+	*data = nullptr;
+	*ret = 0;
+	auto &img = _image_proc->_src;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_screenData.resize(img.size() * 4);
+			//memcpy(_screenData.data(), img.pdata, img.size()*4);
+			for (int i = 0; i < img.height; i++)
+			{
+				memcpy(_screenData.data() + i * img.width * 4, img.ptr<char>(img.height - 1 - i), img.width * 4);
+			}
+			*data = _screenData.data();
+			*ret = 1;
+		}
+	}
+}
+
+void libop::GetScreenDataBmp(long x1, long y1, long x2, long y2, void **data, long *size, long *ret)
+{
+	*data = 0;
+	*ret = 0;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("rerror requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			auto &img = _image_proc->_src;
+
+			BITMAPFILEHEADER bfh = {0}; //bmp file header
+			BITMAPINFOHEADER bih = {0}; //bmp info header
+			const int szBfh = sizeof(BITMAPFILEHEADER);
+			const int szBih = sizeof(BITMAPINFOHEADER);
+			bfh.bfOffBits = szBfh + szBih;
+			bfh.bfSize = bfh.bfOffBits + img.width * img.height * 4;
+			bfh.bfType = static_cast<WORD>(0x4d42);
+
+			bih.biBitCount = 32; //每个像素字节大小
+			bih.biCompression = BI_RGB;
+			//bih.biHeight = -img.height;//高度 反
+			bih.biHeight = img.height; //高度
+			bih.biPlanes = 1;
+			bih.biSize = sizeof(BITMAPINFOHEADER);
+			bih.biSizeImage = img.width * 4 * img.height; //图像数据大小
+			bih.biWidth = img.width;					  //宽度
+
+			_screenDataBmp.resize(bfh.bfSize);
+			/*	std::ofstream f;
+		f.open("xx.bmp",std::ios::binary);
+		if (f) {
+			f.write((char*)&bfh, sizeof(bfh));
+			f.write((char*)&bih, sizeof(bih));
+			f.write((char*)img.pdata, img.size() * 4);
+		}
+		
+		f.close();*/
+			auto dst = _screenDataBmp.data();
+
+			memcpy(dst, &bfh, sizeof(bfh));
+			memcpy(dst + sizeof(bfh), &bih, sizeof(bih));
+			dst += sizeof(bfh) + sizeof(bih);
+			for (int i = 0; i < img.height; i++)
+			{
+				memcpy(dst + i * img.width * 4, img.ptr<char>(img.height - 1 - i), img.width * 4);
+			}
+			//memcpy(dst + sizeof(bfh)+sizeof(bih), img.pdata, img.size()*4);
+			*data = _screenDataBmp.data();
+			*size = bfh.bfSize;
+			*ret = 1;
+		}
+	}
+}
+
+void libop::GetScreenFrameInfo(long *frame_id, long *time)
+{
+	FrameInfo info = {};
+	if (_bkproc->IsBind())
+	{
+		_bkproc->_pbkdisplay->getFrameInfo(info);
+	}
+	*frame_id = info.frameId;
+	*time = info.time;
+}
+
+void libop::MatchPicName(const wchar_t *pic_name, std::wstring &retstr)
+{
+	retstr.clear();
+	std::wstring s(pic_name);
+	if (s.find(L'/') != s.npos || s.find(L'\\') != s.npos)
+	{
+		setlog("invalid pic_name");
+	}
+
+	s = std::regex_replace(s, std::wregex(L"(\\.|\\(|\\)|\\[|\\]|\\{|\\})"), L"\\$1");
+	/*s = std::regex_replace(s, std::wregex(L"\\("), L"\\(");
+	s = std::regex_replace(s, std::wregex(L"\\)"), L"\\)");
+	s = std::regex_replace(s, std::wregex(L"\\["), L"\\[");
+	s = std::regex_replace(s, std::wregex(L"\\]"), L"\\]");*/
+	s = std::regex_replace(s, std::wregex(L"\\*"), L".*?");
+	s = std::regex_replace(s, std::wregex(L"\\?"), L".?");
+
+	//setlog(s.data());
+	namespace fs = std::filesystem;
+	fs::path path(_curr_path);
+	if (fs::exists(path))
+	{
+		fs::directory_iterator iter(path);
+		std::wstring tmp;
+		std::wregex e(s);
+		for (auto &it : iter)
+		{
+			if (it.status().type() == fs::file_type::regular)
+			{
+				tmp = it.path().filename();
+				try
+				{
+					if (std::regex_match(tmp, e))
+					{
+						retstr += tmp;
+						retstr += L"|";
+					}
+				}
+				catch (...)
+				{
+					setlog("exception!");
+				}
+			}
+		}
+		if (!retstr.empty() && retstr.back() == L'|')
+			retstr.pop_back();
+	}
+}
+
+//设置字库文件
+void libop::SetDict(long idx, const wchar_t *file_name, long *ret)
+{
+	*ret = _image_proc->SetDict(idx, file_name);
+}
+
+//设置内存字库文件
+void libop::SetMemDict(long idx, const wchar_t *data, long size, long *ret)
+{
+	*ret = _image_proc->SetMemDict(idx, (void *)data, size);
+}
+
+//使用哪个字库文件进行识别
+void libop::UseDict(long idx, long *ret)
+{
+	*ret = _image_proc->UseDict(idx);
+}
+//识别屏幕范围(x1,y1,x2,y2)内符合color_format的字符串,并且相似度为sim,sim取值范围(0.1-1.0),
+void libop::Ocr(long x1, long y1, long x2, long y2, const wchar_t *color, DOUBLE sim, std::wstring &retstr)
+{
+	wstring str;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->OCR(color, sim, str);
+		}
+	}
+	retstr = str;
+}
+//回识别到的字符串,以及每个字符的坐标.
+void libop::OcrEx(long x1, long y1, long x2, long y2, const wchar_t *color, DOUBLE sim, std::wstring &retstr)
+{
+	wstring str;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->OcrEx(color, sim, str);
+		}
+	}
+	retstr = str;
+}
+//在屏幕范围(x1,y1,x2,y2)内,查找string(可以是任意个字符串的组合),并返回符合color_format的坐标位置
+void libop::FindStr(long x1, long y1, long x2, long y2, const wchar_t *strs, const wchar_t *color, DOUBLE sim, long *retx, long *rety, long *ret)
+{
+	wstring str;
+	*retx = *rety = -1;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			*ret = _image_proc->FindStr(strs, color, sim, *retx, *rety);
+		}
+	}
+}
+//返回符合color_format的所有坐标位置
+void libop::FindStrEx(long x1, long y1, long x2, long y2, const wchar_t *strs, const wchar_t *color, DOUBLE sim, std::wstring &retstr)
+{
+	wstring str;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->FindStrEx(strs, color, sim, str);
+		}
+	}
+	retstr = str;
+}
+
+void libop::OcrAuto(long x1, long y1, long x2, long y2, DOUBLE sim, std::wstring &retstr)
+{
+	wstring str;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->OcrAuto(sim, str);
+		}
+	}
+	retstr = str;
+}
+
+//从文件中识别图片
+void libop::OcrFromFile(const wchar_t *file_name, const wchar_t *color_format, DOUBLE sim, std::wstring &retstr)
+{
+	wstring str;
+	_image_proc->OcrFromFile(file_name, color_format, sim, str);
+	retstr = str;
+}
+//从文件中识别图片,无需指定颜色
+void libop::OcrAutoFromFile(const wchar_t *file_name, DOUBLE sim, std::wstring &retstr)
+{
+	wstring str;
+	_image_proc->OcrAutoFromFile(file_name, sim, str);
+	retstr = str;
+}
+
+void libop::FindLine(long x1, long y1, long x2, long y2, const wchar_t *color, double sim, wstring &retstr)
+{
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->FindLine(color, sim, retstr);
+		}
+	}
+}
+
+void libop::WriteData(long hwnd, const wchar_t *address, const wchar_t *data, long size, long *ret)
+{
+	*ret = 0;
+	MemoryEx mem;
+	*ret = mem.WriteData((HWND)hwnd, address, data, size);
+}
+//读取数据
+void libop::ReadData(long hwnd, const wchar_t *address, long size, std::wstring &retstr)
+{
+	MemoryEx mem;
+	retstr = mem.ReadData((HWND)hwnd, address, size);
+}

+ 298 - 0
gm/gm/libop.h

@@ -0,0 +1,298 @@
+// libop的声明
+/*
+所有op的开放接口都从此cpp类衍生而出
+*/
+#pragma once
+
+#include <string>
+#include<map>
+#include<vector>
+//forward declare
+class WinApi;
+class opBackground;
+class ImageProc;
+
+using bytearray = std::vector<unsigned char>;
+#ifdef U_STATIC_IMPLEMENTATION
+#define OP_API
+#else
+#ifndef OP_API 
+#if defined(OP_EXPORTS)
+#define OP_API __declspec(dllexport)
+#else
+#define OP_API __declspec(dllimport)
+#endif
+#endif
+#endif
+// libop
+#undef FindWindow
+#undef FindWindowEx
+#undef SetWindowText
+
+
+
+class OP_API libop{
+	
+public:
+	
+	libop();
+	~libop();
+	//复制构造
+	libop(libop const&) = delete;
+	libop& operator=(libop const rhs) = delete;
+private:
+	
+	//一些共用变量
+
+	//1. Windows API
+	WinApi* _winapi;
+	// background module
+	opBackground* _bkproc;
+	//image process
+	ImageProc* _image_proc;
+	// work path
+	std::wstring _curr_path;
+	
+	std::map<std::wstring, long> _vkmap;
+	bytearray _screenData;
+	bytearray _screenDataBmp;
+	std::wstring m_opPath;
+public:
+	//---------------基本设置/属性-------------------
+
+	//1.版本号Version
+	std::wstring Ver();
+	//设置目录
+	void SetPath(const wchar_t* path, long* ret);
+	//获取目录
+	void GetPath(std::wstring& ret);
+	//获取插件目录
+	void GetBasePath(std::wstring& ret);
+	//返回当前对象的ID值,这个值对于每个对象是唯一存在的。可以用来判定两个对象是否一致
+	void GetID(long* ret);
+	//
+	void GetLastError(long* ret);
+	//设置是否弹出错误信息,默认是打开 0:关闭,1:显示为信息框,2:保存到文件,3:输出到标准输出
+	void SetShowErrorMsg(long show_type, long* ret);
+	
+	//sleep
+	void Sleep(long millseconds, long* ret);
+	//Process
+	//inject dll
+	void InjectDll(const wchar_t* process_name,const wchar_t* dll_name, long* ret);
+	//设置是否开启或者关闭插件内部的图片缓存机制
+	void EnablePicCache(long enable, long* ret);
+	//取上次操作的图色区域,保存为file(24位位图)
+	void CapturePre(const wchar_t* file_name, long* ret);
+	//---------------------algorithm-------------------------------
+	//A星算法
+	void AStarFindPath(long mapWidth,long mapHeight,const wchar_t* disable_points,long beginX,long beginY, long endX,long endY,std::wstring& ret);
+	//
+	void FindNearestPos(const wchar_t* all_pos, long type, long x, long y, std::wstring& ret);
+	//--------------------windows api------------------------------
+	//根据指定条件,枚举系统中符合条件的窗口
+	void EnumWindow(long parent, const wchar_t* title, const wchar_t* class_name, long filter, std::wstring& ret);
+	//根据指定进程以及其它条件,枚举系统中符合条件的窗口
+	void EnumWindowByProcess(const wchar_t* process_name, const wchar_t* title, const wchar_t* class_name, long filter, std::wstring& ret);
+	//根据指定进程名,枚举系统中符合条件的进程PID
+	void EnumProcess(const wchar_t* name, std::wstring& ret);
+	//把窗口坐标转换为屏幕坐标
+	void ClientToScreen(long ClientToScreen, long* x, long* y, long* bret);
+	//查找符合类名或者标题名的顶层可见窗口
+	void FindWindow(const wchar_t* class_name, const wchar_t* title, long* ret);
+	//根据指定的进程名字,来查找可见窗口
+	void FindWindowByProcess(const wchar_t* process_name, const wchar_t* class_name, const wchar_t* title, long* ret);
+	//根据指定的进程Id,来查找可见窗口
+	void FindWindowByProcessId(long process_id, const wchar_t* class_name, const wchar_t* title, long* ret);
+	//查找符合类名或者标题名的顶层可见窗口,如果指定了parent,则在parent的第一层子窗口中查找
+	void FindWindowEx(long parent, const wchar_t* class_name, const wchar_t* title, long* ret);
+	//获取窗口客户区域在屏幕上的位置
+	void GetClientRect(long hwnd, long* x1, long* y1, long* x2, long* y2, long* ret);
+	//获取窗口客户区域的宽度和高度
+	void GetClientSize(long hwnd, long* width, long* height, long* ret);
+	//获取顶层活动窗口中具有输入焦点的窗口句柄
+	void GetForegroundFocus(long* ret);
+	//获取顶层活动窗口,可以获取到按键自带插件无法获取到的句柄
+	void GetForegroundWindow(long* ret);
+	//获取鼠标指向的可见窗口句柄
+	void GetMousePointWindow(long* ret);
+	//获取给定坐标的可见窗口句柄
+	void GetPointWindow(long x, long y, long* ret);
+	//根据指定的pid获取进程详细信息
+	void GetProcessInfo(long pid, std::wstring& ret);
+	//获取特殊窗口
+	void GetSpecialWindow(long flag, long* ret);
+	//获取给定窗口相关的窗口句柄
+	void GetWindow(long hwnd, long flag, long* ret);
+	//获取窗口的类名
+	void GetWindowClass(long hwnd, std::wstring& ret);
+	//获取指定窗口所在的进程ID
+	void GetWindowProcessId(long hwnd, long* ret);
+	//获取指定窗口所在的进程的exe文件全路径
+	void GetWindowProcessPath(long hwnd, std::wstring& ret);
+	//获取窗口在屏幕上的位置
+	void GetWindowRect(long hwnd, long* x1, long* y1, long* x2, long* y2, long* ret);
+	//获取指定窗口的一些属性
+	void GetWindowState(long hwnd, long flag, long* ret);
+	//获取窗口的标题
+	void GetWindowTitle(long hwnd, std::wstring& rettitle);
+	//移动指定窗口到指定位置
+	void MoveWindow(long hwnd, long x, long y, long* ret);
+	//把屏幕坐标转换为窗口坐标
+	void ScreenToClient(long hwnd, long* x, long* y, long* ret);
+	//向指定窗口发送粘贴命令
+	void SendPaste(long hwnd, long* ret);
+	//设置窗口客户区域的宽度和高度
+	void SetClientSize(long hwnd, long width, long hight, long* ret);
+	//设置窗口的状态
+	void SetWindowState(long hwnd, long flag, long* ret);
+	//设置窗口的大小
+	void SetWindowSize(long hwnd, long width, long height, long* ret);
+	//设置窗口的标题
+	void SetWindowText(long hwnd, const wchar_t* title, long* ret);
+	//设置窗口的透明度
+	void SetWindowTransparent(long hwnd, long trans, long* ret);
+	//向指定窗口发送文本数据
+	void SendString(long hwnd, const wchar_t* str, long* ret);
+	//向指定窗口发送文本数据-输入法
+	void SendStringIme(long hwnd, const wchar_t* str, long* ret);
+	//运行可执行文件,可指定模式
+	void RunApp(const wchar_t* cmdline, long mode, long* ret);
+	//运行可执行文件,可指定显示模式
+	void WinExec(const wchar_t* cmdline, long cmdshow, long* ret);
+
+	//运行命令行并返回结果
+	void GetCmdStr(const wchar_t* cmd,long millseconds, std::wstring& retstr);
+
+	//--------------------Background -----------------------
+	//bind window and beign capture screen
+	void BindWindow(long hwnd, const wchar_t* display, const wchar_t* mouse, const wchar_t* keypad, long mode,long *ret);
+	//
+	void UnBindWindow(long* ret);
+	//--------------------mouse & keyboard------------------
+	//获取鼠标位置.
+	void GetCursorPos(long* x, long* y, long* ret);
+	//鼠标相对于上次的位置移动rx,ry.
+	void MoveR(long x, long y, long* ret);
+	//把鼠标移动到目的点(x,y)
+	void MoveTo(long x, long y, long* ret);
+	//把鼠标移动到目的范围内的任意一点
+	void MoveToEx(long x, long y,long w,long h, long* ret);
+	//按下鼠标左键
+	void LeftClick(long* ret);
+	//双击鼠标左键
+	void LeftDoubleClick(long* ret);
+	//按住鼠标左键
+	void LeftDown(long* ret);
+	//弹起鼠标左键
+	void LeftUp(long* ret);
+	//按下鼠标中键
+	void MiddleClick(long* ret);
+	//按住鼠标中键
+	void MiddleDown(long* ret);
+	//弹起鼠标中键
+	void MiddleUp(long* ret);
+	//按下鼠标右键
+	void RightClick(long* ret);
+	//按住鼠标右键
+	void RightDown(long* ret);
+	//弹起鼠标右键
+	void RightUp(long* ret);
+	//滚轮向下滚
+	void WheelDown(long* ret);
+	//滚轮向上滚
+	void WheelUp(long* ret);
+	//获取指定的按键状态.(前台信息,不是后台)
+	void GetKeyState(long vk_code, long* ret);
+	//按住指定的虚拟键码
+	void KeyDown(long vk_code, long* ret);
+	//按住指定的虚拟键码
+	void KeyDownChar(const wchar_t* vk_code, long* ret);
+	//弹起来虚拟键vk_code
+	void KeyUp(long vk_code, long* ret);
+	//弹起来虚拟键vk_code
+	void KeyUpChar(const wchar_t* vk_code, long* ret);
+	//等待指定的按键按下 (前台,不是后台)
+	void WaitKey(long vk_code,long time_out, long* ret);
+	//发送字符串
+	//long SendString(long HWND)
+	//弹起来虚拟键vk_code
+	void KeyPress(long vk_code, long* ret);
+	void KeyPressChar(const wchar_t* vk_code, long* ret);
+
+	//--------------------image and color-----------------------
+	//抓取指定区域(x1, y1, x2, y2)的图像, 保存为file
+	void Capture(long x1, long y1, long x2, long y2, const wchar_t* file_name, long* ret);
+	//比较指定坐标点(x,y)的颜色
+	void CmpColor(long x, long y,const wchar_t* color,double sim, long* ret);
+	//查找指定区域内的颜色
+	void FindColor(long x1, long y1, long x2, long y2, const wchar_t* color,double sim,long dir, long* x, long* y, long* ret);
+	//查找指定区域内的所有颜色
+	void FindColorEx(long x1, long y1, long x2, long y2, const wchar_t* color, double sim,long dir, std::wstring& retstr);
+	//根据指定的多点查找颜色坐标
+	void FindMultiColor(long x1, long y1, long x2, long y2, const wchar_t* first_color, const wchar_t* offset_color, double sim, long dir, long* x, long* y, long* ret);
+	//根据指定的多点查找所有颜色坐标
+	void FindMultiColorEx(long x1, long y1, long x2, long y2, const wchar_t* first_color, const wchar_t* offset_color, double sim, long dir,std::wstring& retstr);
+	//查找指定区域内的图片
+	void FindPic(long x1,long y1,long x2,long y2,const wchar_t* files, const wchar_t* delta_color,double sim,long dir,long* x,long* y,long* ret);
+	//查找多个图片
+	void FindPicEx(long x1, long y1, long x2, long y2, const wchar_t* files, const wchar_t* delta_color, double sim, long dir,std::wstring& retstr);
+	//
+	//这个函数可以查找多个图片, 并且返回所有找到的图像的坐标.此函数同FindPicEx.只是返回值不同.(file1,x,y|file2,x,y|...)
+	void FindPicExS(long x1, long y1, long x2, long y2, const wchar_t* files, const wchar_t* delta_color, double sim, long dir, std::wstring& retstr);
+	//查找指定区域内的颜色块,颜色格式"RRGGBB-DRDGDB",注意,和按键的颜色格式相反
+	void FindColorBlock(long x1, long y1, long x2, long y2, const wchar_t*  color, double sim, long count, long height, long width, long* x, long* y, long* ret);
+	//查找指定区域内的所有颜色块, 颜色格式"RRGGBB-DRDGDB", 注意, 和按键的颜色格式相反
+	void FindColorBlockEx(long x1, long y1, long x2, long y2, const wchar_t*  color, double sim, long count, long height, long width, std::wstring& retstr);
+	//获取(x,y)的颜色
+	void GetColor(long x, long y, std::wstring& ret);
+	//
+	//设置图像输入方式,默认窗口截图
+	void SetDisplayInput(const wchar_t* mode, long* ret);
+
+	void LoadPic(const wchar_t* file_name, long* ret);
+
+	void FreePic(const wchar_t* file_name, long* ret);
+	//从内存加载要查找的图片
+	void LoadMemPic(const wchar_t* file_name,void* data,long size, long* ret);
+	//
+	void GetScreenData(long x1, long y1, long x2, long y2, void** data,long* ret);
+	//
+	void GetScreenDataBmp(long x1, long y1, long x2, long y2, void** data,long* size, long* ret);
+	//
+	void GetScreenFrameInfo(long* frame_id, long* time);
+	//
+	void MatchPicName(const wchar_t* pic_name, std::wstring& retstr);
+	//----------------------ocr-------------------------
+	//设置字库文件
+	void SetDict(long idx, const wchar_t* file_name, long* ret);
+	//设置内存字库文件
+	void SetMemDict(long idx, const wchar_t* data, long size, long* ret);
+	//使用哪个字库文件进行识别
+	void UseDict(long idx,  long* ret);
+	//识别屏幕范围(x1,y1,x2,y2)内符合color_format的字符串,并且相似度为sim,sim取值范围(0.1-1.0),
+	void Ocr(long x1, long y1, long x2, long y2, const wchar_t* color, double sim,std::wstring& ret_str);
+	//回识别到的字符串,以及每个字符的坐标.
+	void OcrEx(long x1, long y1, long x2, long y2, const wchar_t* color, double sim, std::wstring& ret_str);
+	//在屏幕范围(x1,y1,x2,y2)内,查找string(可以是任意个字符串的组合),并返回符合color_format的坐标位置
+	void FindStr(long x1, long y1, long x2, long y2,const wchar_t* strs, const wchar_t* color, double sim, long* retx,long* rety,long* ret);
+	//返回符合color_format的所有坐标位置
+	void FindStrEx(long x1, long y1, long x2, long y2, const wchar_t* strs, const wchar_t* color, double sim,std::wstring& retstr);
+	//识别屏幕范围(x1,y1,x2,y2)内的字符串,自动二值化,而无需指定颜色
+	void OcrAuto(long x1, long y1, long x2, long y2, double sim, std::wstring& ret_str);
+	//从文件中识别图片
+	void OcrFromFile(const wchar_t* file_name,const wchar_t* color_format, double sim, std::wstring& retstr);
+	//从文件中识别图片,无需指定颜色
+	void OcrAutoFromFile(const wchar_t* file_name, double sim, std::wstring& retstr);
+	//查找频幕中的直线
+	void FindLine(long x1, long y1, long x2, long y2, const wchar_t* color, double sim, std::wstring& retstr);
+	
+	//向某进程写入数据
+	void WriteData(long hwnd, const wchar_t* address, const wchar_t* data, long size, long* ret);
+	//读取数据
+	void ReadData(long hwnd, const wchar_t* address, long size, std::wstring& retstr);
+		
+};
+
+
+

+ 5 - 0
gm/gm/pch.cpp

@@ -0,0 +1,5 @@
+// pch.cpp: 与预编译标头对应的源文件
+
+#include "pch.h"
+
+// 当使用预编译的头时,需要使用此源文件,编译才能成功。

+ 13 - 0
gm/gm/pch.h

@@ -0,0 +1,13 @@
+// pch.h: 这是预编译标头文件。
+// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
+// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
+// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
+// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。
+
+#ifndef PCH_H
+#define PCH_H
+
+// 添加要在此处预编译的标头
+#include "framework.h"
+
+#endif //PCH_H

+ 6 - 0
gm/gm/targetver.h

@@ -0,0 +1,6 @@
+#pragma once
+
+// // 包含 SDKDDKVer.h 可定义可用的最高版本的 Windows 平台。
+// 如果希望为之前的 Windows 平台构建应用程序,在包含 SDKDDKVer.h 之前请先包含 WinSDKVer.h 并
+// 将 _WIN32_WINNT 宏设置为想要支持的平台。
+#include <SDKDDKVer.h>

+ 98 - 0
gm/gm/winapi/Injecter.cpp

@@ -0,0 +1,98 @@
+//#include "stdafx.h"
+#include "Injecter.h"
+
+
+Injecter::Injecter()
+{
+}
+
+
+Injecter::~Injecter()
+{
+}
+
+BOOL Injecter::EnablePrivilege(BOOL enable)
+{
+	// 得到令牌句柄
+	HANDLE hToken = NULL;
+	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ, &hToken))
+		return FALSE;
+
+	// 得到特权值
+	LUID luid;
+	if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
+		return FALSE;
+
+	// 提升令牌句柄权限
+	TOKEN_PRIVILEGES tp = {};
+	tp.PrivilegeCount = 1;
+	tp.Privileges[0].Luid = luid;
+	tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
+	if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL))
+		return FALSE;
+
+	// 关闭令牌句柄
+	CloseHandle(hToken);
+
+	return TRUE;
+}
+
+
+long Injecter::InjectDll(DWORD pid, LPCTSTR dllPath,long& error_code)
+{
+	
+	auto jhandle=::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
+	/**pid = processInfo.dwProcessId;
+	*process = processInfo.hProcess;*/
+	if (!jhandle) {
+		error_code = ::GetLastError();
+		return -1;
+	}
+	DWORD dllPathSize = ((DWORD)wcslen(dllPath) + 1) * sizeof(TCHAR);
+
+	// 申请内存用来存放DLL路径
+	void* remoteMemory = VirtualAllocEx(jhandle, NULL, dllPathSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+	if (remoteMemory == NULL)
+	{
+		//setlog(L"申请内存失败,错误代码:%u\n", GetLastError());
+		error_code = ::GetLastError();
+		return -2;
+	}
+
+	// 写入DLL路径
+	if (!WriteProcessMemory(jhandle, remoteMemory, dllPath, dllPathSize, NULL))
+	{
+		//setlog(L"写入内存失败,错误代码:%u\n", GetLastError());
+		error_code = ::GetLastError();
+		return -3;
+	}
+
+	// 创建远线程调用LoadLibrary
+	auto lpfn=GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW");
+	if (!lpfn) {
+		error_code = ::GetLastError();
+		return -4;
+	}
+	HANDLE remoteThread = CreateRemoteThread(jhandle, NULL, 0, (LPTHREAD_START_ROUTINE)lpfn, remoteMemory, 0, NULL);
+	if (remoteThread == NULL)
+	{
+		//setlog(L"创建远线程失败,错误代码:%u\n", GetLastError());
+		error_code = ::GetLastError();
+		return -5;
+	}
+	// 等待远线程结束
+	WaitForSingleObject(remoteThread, INFINITE);
+	// 取DLL在目标进程的句柄
+	DWORD remoteModule;
+	GetExitCodeThread(remoteThread, &remoteModule);
+
+	// 恢复线程
+	//ResumeThread(processInfo.hThread);
+
+	// 释放
+	CloseHandle(remoteThread);
+	VirtualFreeEx(jhandle, remoteMemory, dllPathSize, MEM_DECOMMIT);
+	CloseHandle(jhandle);
+	error_code = 0;
+	return 1;
+}

+ 12 - 0
gm/gm/winapi/Injecter.h

@@ -0,0 +1,12 @@
+#pragma once
+#include "core/optype.h"
+class Injecter
+{
+public:
+	Injecter();
+	~Injecter();
+	static BOOL EnablePrivilege(BOOL enable);
+	// 
+	static long InjectDll(DWORD pid, LPCTSTR dllPath,long& error_code);
+};
+

+ 259 - 0
gm/gm/winapi/MemoryEx.cpp

@@ -0,0 +1,259 @@
+//#include "stdafx.h"
+#include "MemoryEx.h"
+#include "./core/helpfunc.h"
+#define push(s,x)s.push_back(x)
+#define pop(s) s.back();s.pop_back()
+
+int get_op_prior(wchar_t op) {
+	if (op == L'+' || op == L'-')
+		return 0;
+	if (op == L'*' || op == L'/')
+		return 1;
+	return 2;
+}
+
+bool is_op(wchar_t op) {
+	return op == L'+' || op == L'-' || op == L'*' || op == L'/';
+}
+
+int do_op(int a, int b, wchar_t op) {
+	int ans;
+	if (op == L'+')
+		ans = a + b;
+	else if (op == L'-')
+		ans = a - b;
+	else if (op == L'*')
+		ans = a * b;
+	else if (op == L'/')
+		ans = a / b;
+	else
+		ans = 0;
+	return ans;
+}
+//like AA+BB+DD-CC*cc
+int stringcompute(const wchar_t* s) {
+	int ans = 0;
+	if (!s || !*s)
+		return 0;
+	wstring num;
+	int op;
+	vector<int> ns;
+	vector<int> os;
+	while (*s || !os.empty()) {
+		if (is_op(*s) || *s == 0) {
+			int x;
+			swscanf(num.data(), L"%X", &x);
+
+			if (!num.empty()) {
+				push(ns, x); num.clear();
+			}
+
+			if (ns.empty()) { /// 数字栈空,直接压入数据
+				push(os, *s);
+				s++;
+			}
+			else if (!os.empty()) {
+				op = os.back();
+				if (*s == 0 || get_op_prior(op) >= get_op_prior(*s)) { // 进行运算
+					int num2 = pop(ns);
+					int num1 = pop(ns);
+					op = pop(os);
+					ans = do_op(num1, num2, op);
+					push(ns, ans);
+					//push(os, c);
+				}
+				else {   // 将运算压入栈中
+					push(os, *s);
+					s++;
+				}
+			}
+			else {
+				push(os, *s);
+				s++;
+			}
+
+
+		}
+		else {
+			num.push_back(*s);
+			s++;
+		}
+
+	}
+
+	return ns.back();
+}
+
+MemoryEx::MemoryEx()
+{
+}
+
+
+MemoryEx::~MemoryEx()
+{
+}
+
+long MemoryEx::WriteData(HWND hwnd, const wstring& address, const wstring& data, LONG size) {
+	_hwnd = hwnd;
+	if (!checkaddress(address))
+		return 0;
+	vector<uchar> bin;
+	hex2bins(bin, data,size);
+	if (_hwnd) {
+		if (!::IsWindow(hwnd))
+			return 0;
+		DWORD pid;
+		::GetWindowThreadProcessId(hwnd, &pid);
+		auto hr = _proc.Attach(pid);
+		
+		if (hr >= 0) {
+			size_t addr = str2address(address);
+			if (addr == 0)return 0;
+			return mem_write(addr, bin.data(), size);
+			
+		}
+		return 0;
+	}
+	else {
+		size_t addr = str2address(address);
+		if (addr == 0)return 0;
+		return mem_write(addr,bin.data(), size);
+	}
+	
+
+}
+
+wstring MemoryEx::ReadData(HWND hwnd, const wstring& address, LONG size) {
+	_hwnd = hwnd;
+	if (!checkaddress(address))
+		return L"";
+	vector<uchar> bin;
+	bin.resize(size);
+	wstring hex;
+	if (_hwnd) {
+		if (!::IsWindow(hwnd))
+			return L"";
+		DWORD pid;
+		::GetWindowThreadProcessId(hwnd, &pid);
+		auto hr = _proc.Attach(pid);
+
+		if (hr >= 0) {
+			size_t addr = str2address(address);
+			if (addr == 0)return L"";
+			 mem_read(bin.data(), addr, size);
+		}
+	}
+	else {
+		size_t addr = str2address(address);
+		if (addr == 0)return L"";
+		mem_read(bin.data(), addr, size);
+	}
+
+	bin2hexs(bin, hex);
+	return hex;
+
+}
+
+bool MemoryEx::mem_read(void* dst, size_t src, size_t size) {
+	if (_hwnd) {
+		return _proc.memory().Read(src, size, dst) >= 0;
+	}
+	else {
+		::memcpy(dst, (void*)src, size);
+		return true;
+	}
+
+}
+
+bool MemoryEx::mem_write(size_t dst, void* src, size_t size) {
+	if (_hwnd) {
+		return _proc.memory().Write(dst, size, src) >= 0;
+	}
+	else {
+		::memcpy((void*)dst, src, size);
+		return true;
+	}
+}
+
+bool MemoryEx::checkaddress(const wstring& address) {
+	vector<wchar_t> sk;
+	auto p = address.data();
+	while (*p) {
+		if (*p == L'[' || *p == L']') {
+			if (sk.empty())
+				sk.push_back(*p);
+			else if (sk.back() == *p)
+				sk.push_back(*p);
+			else
+				sk.pop_back();
+		}
+		p++;
+	}
+	return sk.empty();
+}
+
+size_t MemoryEx::str2address(const wstring& caddress) {
+	wstring address = caddress;
+	if (!checkaddress(address))
+		return 0;
+
+	vector<int> sk;
+	int idx1 = 0, idx2 = 0;
+	size_t re = 0;
+	idx1 = address.find(L'<');
+	idx2 = address.find(L'>');
+	if (idx1 != -1 && idx2 != -1 && idx1 < idx2) {
+		auto mod_name = address.substr(idx1 + 1, idx2 - idx1 - 1);
+		HMODULE hmod = NULL;
+		if (_hwnd == 0)
+			hmod = ::GetModuleHandleW(mod_name.data());
+		else {
+			auto mptr = _proc.modules().GetModule(mod_name);
+			if (mptr)hmod = (HMODULE)mptr->baseAddress;
+		}
+		if (hmod == NULL)return 0;
+		wchar_t buff[128];
+		wsprintf(buff, L"%X", hmod);
+		address.replace(idx1, idx2 - idx1 + 1, buff);
+	}
+	for (int i = 0; i < address.size();) {
+		if (address[i] == L'[')push(sk, i);
+		if (address[i] == L']') {
+			idx1 = pop(sk);
+			idx2 = i;
+			auto sad = address.substr(idx1 + 1, idx2 - idx1 - 1);
+			size_t src = stringcompute(sad.data());
+			size_t next;
+			if (!mem_read(&next, src, sizeof(size_t)) || next == 0)
+				return 0;
+			wchar_t buff[128];
+			wsprintf(buff, L"%X", next);
+			address.replace(idx1, idx2 - idx1 + 1, buff);
+			i = idx1;
+		}
+		++i;
+	}
+	return stringcompute(address.data());
+}
+
+void MemoryEx::hex2bins(vector<uchar>&bin, const wstring& hex,size_t size) {
+	bin.resize(size);
+	ZeroMemory(bin.data(), bin.size());
+	int low = 1;
+	for (int i = hex.size() - 1; i >= 0; --i) {
+		
+		bin[size - i / 2-1] |= low & 1 ? hex2bin(hex[i]) : hex2bin(hex[i]) << 4;
+		low ^= 1;
+	}
+}
+
+void MemoryEx::bin2hexs(const vector<uchar>&bin, wstring& hex) {
+	//hex.resize(bin.size() * 2);
+	hex.reserve(bin.size() * 2);
+	hex.clear();
+	for (int i = 0; i < bin.size(); ++i) {
+		int ans = bin2hex(bin[i]);
+		hex.push_back(ans >> 8);
+		hex.push_back(ans & 0xff);
+	}
+}

+ 25 - 0
gm/gm/winapi/MemoryEx.h

@@ -0,0 +1,25 @@
+#pragma once
+#ifndef __MEMORYEX_H_
+#define __MEMORYEX_H_
+#include "./core/helpfunc.h"
+#include "BlackBone/Process/Process.h"
+class MemoryEx
+{
+public:
+	MemoryEx();
+	~MemoryEx();
+	long WriteData(HWND hwnd, const wstring& address, const wstring& data, LONG size);
+	wstring ReadData(HWND hwnd, const wstring& address, LONG size);
+	bool checkaddress(const wstring& address);
+	size_t str2address(const wstring& caddress);
+	bool mem_read(void* dst, size_t src, size_t size);
+	bool mem_write(size_t dst, void* src, size_t size);
+	void hex2bins(vector<uchar>&bin, const wstring& hex,size_t size);
+	void bin2hexs(const vector<uchar>&bin, wstring& hex);
+private:
+	blackbone::Process _proc;
+	HWND _hwnd;
+};
+
+
+#endif

+ 2882 - 0
gm/gm/winapi/WinApi.cpp

@@ -0,0 +1,2882 @@
+//#include "stdafx.h"
+#include "WinApi.h"
+
+#include <Tlhelp32.h>
+#include <psapi.h>
+
+#include <memory>
+#pragma comment(lib, "psapi.lib")
+
+WinApi::WinApi(void) {
+  retstringlen = 0;
+  WindowVerion = 0;
+  IsEuemprosuccess = 0;
+  memset(npid, 0, MAX_PATH);
+}
+
+WinApi::~WinApi(void) {}
+
+BOOL WinApi::EnumProcessbyName(DWORD dwPID, LPCWSTR ExeName, LONG type) {
+  if (IsEuemprosuccess == 0) {
+    int nItem = 0;  // 项计数
+    PROCESSENTRY32 pe32 = {sizeof(PROCESSENTRY32)};
+    HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+    if (hProcessSnap == INVALID_HANDLE_VALUE) return FALSE;
+    if (::Process32First(hProcessSnap, &pe32)) {
+      do {
+        if (type == 1) {
+          if (wcsstr(pe32.szExeFile, ExeName) != NULL)  //模糊匹配
+          {
+            npid[nItem] = pe32.th32ProcessID;
+            IsEuemprosuccess++;
+            nItem++;
+          }
+        } else {
+          if (!_wcsicmp(pe32.szExeFile, ExeName)) {
+            npid[nItem] = pe32.th32ProcessID;
+            IsEuemprosuccess++;
+            nItem++;
+          }
+        }
+
+      } while (::Process32Next(hProcessSnap, &pe32));
+    }
+    ::CloseHandle(hProcessSnap);
+    if (IsEuemprosuccess > 0) return TRUE;
+  } else {
+    for (int i = 0; i < IsEuemprosuccess; i++) {
+      if (dwPID == npid[i]) return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+DWORD WinApi::FindChildWnd(HWND hchile, const wchar_t *title,
+                           const wchar_t *classname, wchar_t *retstring,
+                           bool isGW_OWNER, bool isVisible,
+                           const wchar_t *process_name) {
+  hchile = ::GetWindow(hchile, GW_HWNDFIRST);
+  while (hchile != NULL) {
+    if (isGW_OWNER)  //判断是否要匹配所有者窗口为0的窗口,即顶级窗口
+      if (::GetWindow(hchile, GW_OWNER) != 0) {
+        hchile = ::GetWindow(hchile, GW_HWNDNEXT);  //获取下一个窗口
+        continue;
+      }
+
+    if (isVisible)  //判断是否匹配可视窗口
+      if (::IsWindowVisible(hchile) == false) {
+        hchile = ::GetWindow(hchile, GW_HWNDNEXT);  //获取下一个窗口
+        continue;
+      }
+    if (title == NULL && classname == NULL) {
+      if (process_name) {
+        DWORD pid = 0;
+        GetWindowThreadProcessId(hchile, &pid);
+        if (EnumProcessbyName(pid, process_name)) {
+          if (retstring) {
+            if (retstringlen == 0) retstringlen = wcslen(retstring);
+            if (retstringlen > 1)
+              swprintf(retstring, L"%s,%d", retstring, hchile);
+            else
+              swprintf(retstring, L"%d", hchile);
+          } else
+            return (DWORD)hchile;
+        }
+      } else {
+        if (retstring) {
+          int len = wcslen(retstring);
+          if (len > 1)
+            swprintf(retstring, L"%s,%d", retstring, hchile);
+          else
+            swprintf(retstring, L"%d", hchile);
+        } else
+          return (DWORD)hchile;
+      }
+    } else if (title != NULL && classname != NULL) {
+      wchar_t WindowClassName[MAX_PATH] = {0};
+      ::GetClassName(hchile, WindowClassName, MAX_PATH);
+      wchar_t WindowTitle[MAX_PATH] = {0};
+      ::GetWindowText(hchile, WindowTitle, MAX_PATH);
+      if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+        wchar_t *strfindclass = wcsstr(WindowClassName, classname);  //模糊匹配
+        wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+        if (strfindclass && strfindtitle) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(hchile, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (retstring) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, hchile);
+                else
+                  swprintf(retstring, L"%d", hchile);
+              } else
+                return (DWORD)hchile;
+            }
+          } else {
+            if (retstring) {
+              if (retstringlen == 0) retstringlen = wcslen(retstring);
+              if (retstringlen > 1)
+                swprintf(retstring, L"%s,%d", retstring, hchile);
+              else
+                swprintf(retstring, L"%d", hchile);
+            } else
+              return (DWORD)hchile;
+          }
+        }
+      }
+
+    } else if (title != NULL) {
+      wchar_t WindowTitle[MAX_PATH] = {0};
+      ::GetWindowText(hchile, WindowTitle, MAX_PATH);
+      if (wcslen(WindowTitle) > 1) {
+        wchar_t *strfind = wcsstr(WindowTitle, title);  //模糊匹配
+        if (strfind) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(hchile, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (retstring) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, hchile);
+                else
+                  swprintf(retstring, L"%d", hchile);
+              } else
+                return (DWORD)hchile;
+            }
+          } else {
+            if (retstring) {
+              if (retstringlen == 0) retstringlen = wcslen(retstring);
+              if (retstringlen > 1)
+                swprintf(retstring, L"%s,%d", retstring, hchile);
+              else
+                swprintf(retstring, L"%d", hchile);
+            } else
+              return (DWORD)hchile;
+          }
+        }
+      }
+
+    } else if (classname != NULL) {
+      wchar_t WindowClassName[MAX_PATH] = {0};
+      ::GetClassName(hchile, WindowClassName, MAX_PATH);
+      if (wcslen(WindowClassName) > 1) {
+        wchar_t *strfind = wcsstr(WindowClassName, classname);  //模糊匹配
+        if (strfind) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(hchile, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (retstring) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, hchile);
+                else
+                  swprintf(retstring, L"%d", hchile);
+              } else
+                return (DWORD)hchile;
+            }
+          } else {
+            if (retstring) {
+              if (retstringlen == 0) retstringlen = wcslen(retstring);
+              if (retstringlen > 1)
+                swprintf(retstring, L"%s,%d", retstring, hchile);
+              else
+                swprintf(retstring, L"%d", hchile);
+            } else
+              return (DWORD)hchile;
+          }
+        }
+      }
+    }
+
+    HWND hchilechile = ::GetWindow(hchile, GW_CHILD);
+    if (hchilechile != NULL) {
+      DWORD dret = FindChildWnd(hchilechile, title, classname, retstring,
+                                isGW_OWNER, isVisible, process_name);
+      if (dret > 0) break;
+    }
+
+    hchile = ::GetWindow(hchile, GW_HWNDNEXT);  //获取下一个窗口
+  }
+  return 0;
+}
+
+// TSEnumWindow:filter整形数: 取值定义如下
+//
+// 1 : 匹配窗口标题,参数title有效
+//
+// 2 : 匹配窗口类名,参数class_name有效.
+//
+// 4 : 只匹配指定父窗口的第一层孩子窗口
+//
+// 8 : 匹配所有者窗口为0的窗口,即顶级窗口
+//
+// 16 : 匹配可见的窗口
+//
+// 32 : 匹配出的窗口按照窗口打开顺序依次排列
+bool WinApi::EnumWindow(HWND parent, const wchar_t *title,
+                        const wchar_t *class_name, LONG filter,
+                        wchar_t *retstring, const wchar_t *process_name) {
+  bool bret = false;
+  bool bZwindow = false;  //匹配出的窗口按照窗口打开顺序依次排列
+  if (parent == 0) {
+    parent = GetDesktopWindow();
+  }
+  if (filter > 32) {
+    bZwindow = true;  //说明要排序窗口句柄
+    filter = filter - 32;
+  }
+
+  DWORD procpids[MAX_PATH] = {0};
+  int indexpid = 0;
+  if (process_name)  // EnumWindowByProcess
+  {
+    if (wcslen(process_name) < 1) return false;
+    memset(npid, 0, MAX_PATH);
+    IsEuemprosuccess = 0;
+    if (EnumProcessbyName(0, process_name) == false) return false;
+  }
+
+  DWORD processpid = 0;
+  retstringlen = 0;
+  switch (filter) {
+    case 0:  //所有模式
+    {
+      if (process_name)  // EnumWindowByProcess
+      {
+        return false;
+      }
+
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      if (p == NULL) return false;
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (retstringlen == 0) retstringlen = wcslen(retstring);
+        if (retstringlen > 1)
+          swprintf(retstring, L"%s,%d", retstring, p);
+        else
+          swprintf(retstring, L"%d", p);
+        bret = true;
+        HWND hchile = ::GetWindow(p, GW_CHILD);
+        if (hchile != NULL) {
+          FindChildWnd(hchile, NULL, NULL, retstring);
+        }
+
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 1:  // 1 : 匹配窗口标题,参数title有效
+    {
+      if (wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      if (p == NULL) return false;
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        wchar_t WindowTitle[MAX_PATH] = {0};
+        ::GetWindowText(p, WindowTitle, MAX_PATH);
+        if (wcslen(WindowTitle) > 1) {
+          wchar_t *strfind = wcsstr(WindowTitle, title);  //模糊匹配
+          if (strfind) {
+            if (process_name)  // EnumWindowByProcess
+            {
+              DWORD pid = 0;
+              GetWindowThreadProcessId(p, &pid);
+              if (EnumProcessbyName(pid, process_name)) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            } else {
+              if (retstringlen == 0) retstringlen = wcslen(retstring);
+              if (retstringlen > 1)
+                swprintf(retstring, L"%s,%d", retstring, p);
+              else
+                swprintf(retstring, L"%d", p);
+              bret = true;
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, title, NULL, retstring);
+              }
+            }
+          }
+        }
+
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 2:  // 2 : 匹配窗口类名,参数class_name有效.
+    {
+      if (wcslen(class_name) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      if (p == NULL) return false;
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        wchar_t WindowClassName[MAX_PATH] = {0};
+        ::GetClassName(p, WindowClassName, MAX_PATH);
+        if (wcslen(WindowClassName) > 1) {
+          wchar_t *strfind = wcsstr(WindowClassName, class_name);  //模糊匹配
+          if (strfind) {
+            if (process_name)  // EnumWindowByProcess
+            {
+              DWORD pid = 0;
+              GetWindowThreadProcessId(p, &pid);
+              if (EnumProcessbyName(pid, process_name)) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            } else {
+              if (retstringlen == 0) retstringlen = wcslen(retstring);
+              if (retstringlen > 1)
+                swprintf(retstring, L"%s,%d", retstring, p);
+              else
+                swprintf(retstring, L"%d", p);
+              bret = true;
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, NULL, class_name, retstring);
+              }
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 3:  // 1.窗口标题+2.窗口类名
+    {
+      if (wcslen(class_name) < 1 && wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      if (p == NULL) return false;
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        wchar_t WindowClassName[MAX_PATH] = {0};
+        ::GetClassName(p, WindowClassName, MAX_PATH);
+        wchar_t WindowTitle[MAX_PATH] = {0};
+        ::GetWindowText(p, WindowTitle, MAX_PATH);
+        if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+          wchar_t *strfindclass =
+              wcsstr(WindowClassName, class_name);             //模糊匹配
+          wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+          if (strfindclass && strfindtitle) {
+            if (process_name)  // EnumWindowByProcess
+            {
+              DWORD pid = 0;
+              GetWindowThreadProcessId(p, &pid);
+              if (EnumProcessbyName(pid, process_name)) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            } else {
+              if (retstringlen == 0) retstringlen = wcslen(retstring);
+              if (retstringlen > 1)
+                swprintf(retstring, L"%s,%d", retstring, p);
+              else
+                swprintf(retstring, L"%d", p);
+              bret = true;
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, title, class_name, retstring);
+              }
+            }
+          }
+        }
+
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 4:  // 4 : 只匹配指定父窗口的第一层孩子窗口
+    {
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      if (p == NULL) return false;
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (process_name)  // EnumWindowByProcess
+        {
+          DWORD pid = 0;
+          GetWindowThreadProcessId(p, &pid);
+          if (EnumProcessbyName(pid, process_name)) {
+            if (processpid !=
+                pid)  //只匹配指定映像的所对应的第一个进程.
+                      //可能有很多同映像名的进程,只匹配第一个进程的.
+            {
+              if (indexpid < IsEuemprosuccess) {
+                indexpid++;
+                processpid = pid;
+                memset(retstring, 0, retstringlen);  //清空返回字符串
+                retstringlen = 0;
+              }
+            }
+            if (processpid == pid) {
+              if (retstringlen == 0) retstringlen = wcslen(retstring);
+              if (retstringlen > 1)
+                swprintf(retstring, L"%s,%d", retstring, p);
+              else
+                swprintf(retstring, L"%d", p);
+              bret = true;
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, NULL, NULL, retstring, false, false,
+                             process_name);
+              }
+            }
+          }
+        } else {
+          if (retstringlen == 0) retstringlen = wcslen(retstring);
+          if (retstringlen > 1)
+            swprintf(retstring, L"%s,%d", retstring, p);
+          else
+            swprintf(retstring, L"%d", p);
+          bret = true;
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 5:  // 1.匹配窗口标题+//4 : 只匹配指定父窗口的第一层孩子窗口
+    {
+      if (wcslen(title) < 1) return false;
+
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      if (p == NULL) return false;
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (process_name)  // EnumWindowByProcess
+        {
+          DWORD pid = 0;
+          GetWindowThreadProcessId(p, &pid);
+          if (EnumProcessbyName(pid, process_name)) {
+            if (processpid !=
+                pid)  //只匹配指定映像的所对应的第一个进程.
+                      //可能有很多同映像名的进程,只匹配第一个进程的.
+            {
+              if (indexpid < IsEuemprosuccess) {
+                indexpid++;
+                processpid = pid;
+                memset(retstring, 0, retstringlen);  //清空返回字符串
+                retstringlen = 0;
+              }
+            }
+            if (processpid == pid) {
+              wchar_t WindowTitle[MAX_PATH] = {0};
+              ::GetWindowText(p, WindowTitle, MAX_PATH);
+              if (wcslen(WindowTitle) > 1) {
+                if (wcsstr(WindowTitle, title)) {
+                  if (retstringlen == 0) retstringlen = wcslen(retstring);
+                  if (retstringlen > 1)
+                    swprintf(retstring, L"%s,%d", retstring, p);
+                  else
+                    swprintf(retstring, L"%d", p);
+                  bret = true;
+                }
+              }
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, title, NULL, retstring, false, false,
+                             process_name);
+              }
+            }
+          }
+
+        } else {
+          wchar_t WindowTitle[MAX_PATH] = {0};
+          ::GetWindowText(p, WindowTitle, MAX_PATH);
+          if (wcslen(WindowTitle) > 1) {
+            if (wcsstr(WindowTitle, title)) {
+              if (retstringlen == 0) retstringlen = wcslen(retstring);
+              if (retstringlen > 1)
+                swprintf(retstring, L"%s,%d", retstring, p);
+              else
+                swprintf(retstring, L"%d", p);
+              bret = true;
+            }
+          }
+        }
+
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 6:  // 2 : 匹配窗口类名+4 : 只匹配指定父窗口的第一层孩子窗口
+    {
+      if (wcslen(class_name) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      if (p == NULL) return false;
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (process_name)  // EnumWindowByProcess
+        {
+          DWORD pid = 0;
+          GetWindowThreadProcessId(p, &pid);
+          if (EnumProcessbyName(pid, process_name)) {
+            if (indexpid < IsEuemprosuccess) {
+              indexpid++;
+              processpid = pid;
+              memset(retstring, 0, retstringlen);  //清空返回字符串
+              retstringlen = 0;
+            }
+          }
+          if (processpid == pid) {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            if (wcslen(WindowClassName) > 1) {
+              if (wcsstr(WindowClassName, class_name)) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              FindChildWnd(hchile, NULL, class_name, retstring, false, false,
+                           process_name);
+            }
+          }
+        } else {
+          wchar_t WindowClassName[MAX_PATH] = {0};
+          ::GetClassName(p, WindowClassName, MAX_PATH);
+          if (wcslen(WindowClassName) > 1) {
+            if (wcsstr(WindowClassName, class_name)) {
+              if (retstringlen == 0) retstringlen = wcslen(retstring);
+              if (retstringlen > 1)
+                swprintf(retstring, L"%s,%d", retstring, p);
+              else
+                swprintf(retstring, L"%d", p);
+              bret = true;
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 7:  // 1.窗口标题+2.窗口类名+4 : 只匹配指定父窗口的第一层孩子窗口
+    {
+      if (wcslen(class_name) < 1 && wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      if (p == NULL) return false;
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (process_name)  // EnumWindowByProcess
+        {
+          DWORD pid = 0;
+          GetWindowThreadProcessId(p, &pid);
+          if (EnumProcessbyName(pid, process_name)) {
+            if (indexpid < IsEuemprosuccess) {
+              indexpid++;
+              processpid = pid;
+              memset(retstring, 0, retstringlen);  //清空返回字符串
+              retstringlen = 0;
+            }
+          }
+          if (processpid == pid) {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+              wchar_t *strfindclass =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+              if (strfindclass && strfindtitle) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              FindChildWnd(hchile, title, class_name, retstring, false, false,
+                           process_name);
+            }
+          }
+        } else {
+          wchar_t WindowClassName[MAX_PATH] = {0};
+          ::GetClassName(p, WindowClassName, MAX_PATH);
+          wchar_t WindowTitle[MAX_PATH] = {0};
+          ::GetWindowText(p, WindowTitle, MAX_PATH);
+          if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+            wchar_t *strfindclass =
+                wcsstr(WindowClassName, class_name);             //模糊匹配
+            wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+            if (strfindclass && strfindtitle) {
+              if (retstringlen == 0) retstringlen = wcslen(retstring);
+              if (retstringlen > 1)
+                swprintf(retstring, L"%s,%d", retstring, p);
+              else
+                swprintf(retstring, L"%d", p);
+              bret = true;
+            }
+          }
+        }
+
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 8:  // 8 : 匹配所有者窗口为0的窗口,即顶级窗口
+    {
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      if (p == NULL) return false;
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (retstringlen == 0) retstringlen = wcslen(retstring);
+              if (retstringlen > 1)
+                swprintf(retstring, L"%s,%d", retstring, p);
+              else
+                swprintf(retstring, L"%d", p);
+              bret = true;
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, NULL, NULL, retstring, true, false,
+                             process_name);
+              }
+            }
+          } else {
+            if (retstringlen == 0) retstringlen = wcslen(retstring);
+            if (retstringlen > 1)
+              swprintf(retstring, L"%s,%d", retstring, p);
+            else
+              swprintf(retstring, L"%d", p);
+            bret = true;
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              FindChildWnd(hchile, NULL, NULL, retstring, true);
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 9:  // 1.窗口标题+8 : 匹配所有者窗口为0的窗口,即顶级窗口
+    {
+      if (wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      if (p == NULL) return false;
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              wchar_t WindowTitle[MAX_PATH] = {0};
+              ::GetWindowText(p, WindowTitle, MAX_PATH);
+              if (wcslen(WindowTitle) > 1) {
+                wchar_t *strfind = wcsstr(WindowTitle, title);  //模糊匹配
+                if (strfind) {
+                  if (retstringlen == 0) retstringlen = wcslen(retstring);
+                  if (retstringlen > 1)
+                    swprintf(retstring, L"%s,%d", retstring, p);
+                  else
+                    swprintf(retstring, L"%d", p);
+                  bret = true;
+                }
+              }
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, title, NULL, retstring, true, false,
+                             process_name);
+              }
+            }
+          } else {
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowTitle) > 1) {
+              wchar_t *strfind = wcsstr(WindowTitle, title);  //模糊匹配
+              if (strfind) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              FindChildWnd(hchile, title, NULL, retstring, true);
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 10:  // 2.窗口类名+8 : 匹配所有者窗口为0的窗口,即顶级窗口
+    {
+      if (wcslen(class_name) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      if (p == NULL) return false;
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              wchar_t WindowClassName[MAX_PATH] = {0};
+              ::GetClassName(p, WindowClassName, MAX_PATH);
+              if (wcslen(WindowClassName) > 1) {
+                wchar_t *strfind =
+                    wcsstr(WindowClassName, class_name);  //模糊匹配
+                if (strfind) {
+                  if (retstringlen == 0) retstringlen = wcslen(retstring);
+                  if (retstringlen > 1)
+                    swprintf(retstring, L"%s,%d", retstring, p);
+                  else
+                    swprintf(retstring, L"%d", p);
+                  bret = true;
+                }
+              }
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, NULL, class_name, retstring, true, false,
+                             process_name);
+              }
+            }
+          } else {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            if (wcslen(WindowClassName) > 1) {
+              wchar_t *strfind =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              if (strfind) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              FindChildWnd(hchile, NULL, class_name, retstring, true);
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 11:  ////1.窗口标题+2.窗口类名+8 : 匹配所有者窗口为0的窗口,即顶级窗口
+    {
+      if (wcslen(class_name) < 1 && wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      if (p == NULL) return false;
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              wchar_t WindowClassName[MAX_PATH] = {0};
+              ::GetClassName(p, WindowClassName, MAX_PATH);
+              wchar_t WindowTitle[MAX_PATH] = {0};
+              ::GetWindowText(p, WindowTitle, MAX_PATH);
+              if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+                wchar_t *strfindclass =
+                    wcsstr(WindowClassName, class_name);  //模糊匹配
+                wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+                if (strfindclass && strfindtitle) {
+                  if (retstringlen == 0) retstringlen = wcslen(retstring);
+                  if (retstringlen > 1)
+                    swprintf(retstring, L"%s,%d", retstring, p);
+                  else
+                    swprintf(retstring, L"%d", p);
+                  bret = true;
+                }
+              }
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, title, class_name, retstring, true, false,
+                             process_name);
+              }
+            }
+          } else {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+              wchar_t *strfindclass =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+              if (strfindclass && strfindtitle) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              FindChildWnd(hchile, title, class_name, retstring, true);
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 12:  // //4 : 只匹配指定父窗口的第一层孩子窗口+8 :
+              // 匹配所有者窗口为0的窗口,即顶级窗口
+    {
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (processpid !=
+                  pid)  //只匹配指定映像的所对应的第一个进程.
+                        //可能有很多同映像名的进程,只匹配第一个进程的.
+              {
+                if (indexpid < IsEuemprosuccess) {
+                  indexpid++;
+                  processpid = pid;
+                  memset(retstring, 0, retstringlen);  //清空返回字符串
+                  retstringlen = 0;
+                }
+              }
+              if (processpid == pid) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+                HWND hchile = ::GetWindow(p, GW_CHILD);
+                if (hchile != NULL) {
+                  FindChildWnd(hchile, NULL, NULL, retstring, true, false,
+                               process_name);
+                }
+              }
+            }
+          } else {
+            if (retstringlen == 0) retstringlen = wcslen(retstring);
+            if (retstringlen > 1)
+              swprintf(retstring, L"%s,%d", retstring, p);
+            else
+              swprintf(retstring, L"%d", p);
+            bret = true;
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 13:  // 1.窗口标题+4 : 只匹配指定父窗口的第一层孩子窗口+8 :
+              // 匹配所有者窗口为0的窗口,即顶级窗口
+    {
+      if (wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (processpid !=
+                  pid)  //只匹配指定映像的所对应的第一个进程.
+                        //可能有很多同映像名的进程,只匹配第一个进程的.
+              {
+                if (indexpid < IsEuemprosuccess) {
+                  indexpid++;
+                  processpid = pid;
+                  memset(retstring, 0, retstringlen);  //清空返回字符串
+                  retstringlen = 0;
+                }
+              }
+              if (processpid == pid) {
+                wchar_t WindowTitle[MAX_PATH] = {0};
+                ::GetWindowText(p, WindowTitle, MAX_PATH);
+                if (wcslen(WindowTitle) > 1) {
+                  wchar_t *strfind = wcsstr(WindowTitle, title);  //模糊匹配
+                  if (strfind) {
+                    if (retstringlen == 0) retstringlen = wcslen(retstring);
+                    if (retstringlen > 1)
+                      swprintf(retstring, L"%s,%d", retstring, p);
+                    else
+                      swprintf(retstring, L"%d", p);
+                    bret = true;
+                  }
+                }
+                HWND hchile = ::GetWindow(p, GW_CHILD);
+                if (hchile != NULL) {
+                  FindChildWnd(hchile, title, NULL, retstring, true, false,
+                               process_name);
+                }
+              }
+            }
+          } else {
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowTitle) > 1) {
+              wchar_t *strfind = wcsstr(WindowTitle, title);  //模糊匹配
+              if (strfind) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 14:  // 2.窗口类名+4 : 只匹配指定父窗口的第一层孩子窗口+8 :
+              // 匹配所有者窗口为0的窗口,即顶级窗口
+    {
+      if (wcslen(class_name) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (processpid !=
+                  pid)  //只匹配指定映像的所对应的第一个进程.
+                        //可能有很多同映像名的进程,只匹配第一个进程的.
+              {
+                if (indexpid < IsEuemprosuccess) {
+                  indexpid++;
+                  processpid = pid;
+                  memset(retstring, 0, retstringlen);  //清空返回字符串
+                  retstringlen = 0;
+                }
+              }
+              if (processpid == pid) {
+                wchar_t WindowClassName[MAX_PATH] = {0};
+                ::GetClassName(p, WindowClassName, MAX_PATH);
+                if (wcslen(WindowClassName) > 1) {
+                  wchar_t *strfind =
+                      wcsstr(WindowClassName, class_name);  //模糊匹配
+                  if (strfind) {
+                    if (retstringlen == 0) retstringlen = wcslen(retstring);
+                    if (retstringlen > 1)
+                      swprintf(retstring, L"%s,%d", retstring, p);
+                    else
+                      swprintf(retstring, L"%d", p);
+                    bret = true;
+                  }
+                }
+                HWND hchile = ::GetWindow(p, GW_CHILD);
+                if (hchile != NULL) {
+                  FindChildWnd(hchile, NULL, class_name, retstring, true, false,
+                               process_name);
+                }
+              }
+            }
+          } else {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            if (wcslen(WindowClassName) > 1) {
+              wchar_t *strfind =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              if (strfind) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 15:  ////1.窗口标题+2.窗口类名+4 : 只匹配指定父窗口的第一层孩子窗口+8 :
+              ///匹配所有者窗口为0的窗口,即顶级窗口
+    {
+      if (wcslen(class_name) < 1 && wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (processpid !=
+                  pid)  //只匹配指定映像的所对应的第一个进程.
+                        //可能有很多同映像名的进程,只匹配第一个进程的.
+              {
+                if (indexpid < IsEuemprosuccess) {
+                  indexpid++;
+                  processpid = pid;
+                  memset(retstring, 0, retstringlen);  //清空返回字符串
+                  retstringlen = 0;
+                }
+              }
+              if (processpid == pid) {
+                wchar_t WindowClassName[MAX_PATH] = {0};
+                ::GetClassName(p, WindowClassName, MAX_PATH);
+                wchar_t WindowTitle[MAX_PATH] = {0};
+                ::GetWindowText(p, WindowTitle, MAX_PATH);
+                if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+                  wchar_t *strfindclass =
+                      wcsstr(WindowClassName, class_name);  //模糊匹配
+                  wchar_t *strfindtitle =
+                      wcsstr(WindowTitle, title);  //模糊匹配
+                  if (strfindclass && strfindtitle) {
+                    if (retstringlen == 0) retstringlen = wcslen(retstring);
+                    if (retstringlen > 1)
+                      swprintf(retstring, L"%s,%d", retstring, p);
+                    else
+                      swprintf(retstring, L"%d", p);
+                    bret = true;
+                  }
+                }
+                HWND hchile = ::GetWindow(p, GW_CHILD);
+                if (hchile != NULL) {
+                  FindChildWnd(hchile, title, class_name, retstring, true,
+                               false, process_name);
+                }
+              }
+            }
+          } else {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+              wchar_t *strfindclass =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+              if (strfindclass && strfindtitle) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 16:  //匹配可见的窗口
+    {
+      parent = GetDesktopWindow();
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p)) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (retstringlen == 0) retstringlen = wcslen(retstring);
+              if (retstringlen > 1)
+                swprintf(retstring, L"%s,%d", retstring, p);
+              else
+                swprintf(retstring, L"%d", p);
+              bret = true;
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, NULL, NULL, retstring, false, true,
+                             process_name);
+              }
+            }
+          } else {
+            if (retstringlen == 0) retstringlen = wcslen(retstring);
+            if (retstringlen > 1)
+              swprintf(retstring, L"%s,%d", retstring, p);
+            else
+              swprintf(retstring, L"%d", p);
+            bret = true;
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              FindChildWnd(hchile, NULL, NULL, retstring, false, true);
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 17:  // 1.窗口标题+//匹配可见的窗口
+    {
+      if (wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p)) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              wchar_t WindowTitle[MAX_PATH] = {0};
+              ::GetWindowText(p, WindowTitle, MAX_PATH);
+              if (wcslen(WindowTitle) > 1) {
+                wchar_t *strfind = wcsstr(WindowTitle, title);  //模糊匹配
+                if (strfind) {
+                  if (retstringlen == 0) retstringlen = wcslen(retstring);
+                  if (retstringlen > 1)
+                    swprintf(retstring, L"%s,%d", retstring, p);
+                  else
+                    swprintf(retstring, L"%d", p);
+                  bret = true;
+                }
+              }
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, title, NULL, retstring, false, true,
+                             process_name);
+              }
+            }
+          } else {
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowTitle) > 1) {
+              wchar_t *strfind = wcsstr(WindowTitle, title);  //模糊匹配
+              if (strfind) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              FindChildWnd(hchile, title, NULL, retstring, false, true);
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 18:  // 2.窗口类名+//匹配可见的窗口
+    {
+      if (wcslen(class_name) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p)) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              wchar_t WindowClassName[MAX_PATH] = {0};
+              ::GetClassName(p, WindowClassName, MAX_PATH);
+              if (wcslen(WindowClassName) > 1) {
+                wchar_t *strfind =
+                    wcsstr(WindowClassName, class_name);  //模糊匹配
+                if (strfind) {
+                  if (retstringlen == 0) retstringlen = wcslen(retstring);
+                  if (retstringlen > 1)
+                    swprintf(retstring, L"%s,%d", retstring, p);
+                  else
+                    swprintf(retstring, L"%d", p);
+                  bret = true;
+                }
+              }
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, NULL, class_name, retstring, false, true,
+                             process_name);
+              }
+            }
+          } else {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            if (wcslen(WindowClassName) > 1) {
+              wchar_t *strfind =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              if (strfind) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              FindChildWnd(hchile, NULL, class_name, retstring, false, true);
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 19:  ////1.窗口标题+2.窗口类名+匹配可见的窗口
+    {
+      if (wcslen(class_name) < 1 && wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p)) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              wchar_t WindowClassName[MAX_PATH] = {0};
+              ::GetClassName(p, WindowClassName, MAX_PATH);
+              wchar_t WindowTitle[MAX_PATH] = {0};
+              ::GetWindowText(p, WindowTitle, MAX_PATH);
+              if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+                wchar_t *strfindclass =
+                    wcsstr(WindowClassName, class_name);  //模糊匹配
+                wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+                if (strfindclass && strfindtitle) {
+                  if (retstringlen == 0) retstringlen = wcslen(retstring);
+                  if (retstringlen > 1)
+                    swprintf(retstring, L"%s,%d", retstring, p);
+                  else
+                    swprintf(retstring, L"%d", p);
+                  bret = true;
+                }
+              }
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, title, class_name, retstring, false, true,
+                             process_name);
+              }
+            }
+          } else {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+              wchar_t *strfindclass =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+              if (strfindclass && strfindtitle) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              FindChildWnd(hchile, title, class_name, retstring, false, true);
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 20:  // 4 : 只匹配指定父窗口的第一层孩子窗口+匹配可见的窗口
+    {
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p)) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (processpid !=
+                  pid)  //只匹配指定映像的所对应的第一个进程.
+                        //可能有很多同映像名的进程,只匹配第一个进程的.
+              {
+                if (indexpid < IsEuemprosuccess) {
+                  indexpid++;
+                  processpid = pid;
+                  memset(retstring, 0, retstringlen);  //清空返回字符串
+                  retstringlen = 0;
+                }
+              }
+              if (processpid == pid) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+                HWND hchile = ::GetWindow(p, GW_CHILD);
+                if (hchile != NULL) {
+                  FindChildWnd(hchile, NULL, NULL, retstring, false, true,
+                               process_name);
+                }
+              }
+            }
+          } else {
+            if (retstringlen == 0) retstringlen = wcslen(retstring);
+            if (retstringlen > 1)
+              swprintf(retstring, L"%s,%d", retstring, p);
+            else
+              swprintf(retstring, L"%d", p);
+            bret = true;
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 21:  // 1.窗口标题+4 : 只匹配指定父窗口的第一层孩子窗口+匹配可见的窗口
+    {
+      if (wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p)) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (processpid !=
+                  pid)  //只匹配指定映像的所对应的第一个进程.
+                        //可能有很多同映像名的进程,只匹配第一个进程的.
+              {
+                if (indexpid < IsEuemprosuccess) {
+                  indexpid++;
+                  processpid = pid;
+                  memset(retstring, 0, retstringlen);  //清空返回字符串
+                  retstringlen = 0;
+                }
+              }
+              if (processpid == pid) {
+                wchar_t WindowTitle[MAX_PATH] = {0};
+                ::GetWindowText(p, WindowTitle, MAX_PATH);
+                if (wcslen(WindowTitle) > 1) {
+                  wchar_t *strfind = wcsstr(WindowTitle, title);  //模糊匹配
+                  if (strfind) {
+                    if (retstringlen == 0) retstringlen = wcslen(retstring);
+                    if (retstringlen > 1)
+                      swprintf(retstring, L"%s,%d", retstring, p);
+                    else
+                      swprintf(retstring, L"%d", p);
+                    bret = true;
+                  }
+                }
+                HWND hchile = ::GetWindow(p, GW_CHILD);
+                if (hchile != NULL) {
+                  FindChildWnd(hchile, title, NULL, retstring, false, true,
+                               process_name);
+                }
+              }
+            }
+          } else {
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowTitle) > 1) {
+              wchar_t *strfind = wcsstr(WindowTitle, title);  //模糊匹配
+              if (strfind) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 22:  // 2.窗口类名+4 : 只匹配指定父窗口的第一层孩子窗口+匹配可见的窗口
+    {
+      if (wcslen(class_name) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p)) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (processpid !=
+                  pid)  //只匹配指定映像的所对应的第一个进程.
+                        //可能有很多同映像名的进程,只匹配第一个进程的.
+              {
+                if (indexpid < IsEuemprosuccess) {
+                  indexpid++;
+                  processpid = pid;
+                  memset(retstring, 0, retstringlen);  //清空返回字符串
+                  retstringlen = 0;
+                }
+              }
+              if (processpid == pid) {
+                wchar_t WindowClassName[MAX_PATH] = {0};
+                ::GetClassName(p, WindowClassName, MAX_PATH);
+                if (wcslen(WindowClassName) > 1) {
+                  wchar_t *strfind =
+                      wcsstr(WindowClassName, class_name);  //模糊匹配
+                  if (strfind) {
+                    if (retstringlen == 0) retstringlen = wcslen(retstring);
+                    if (retstringlen > 1)
+                      swprintf(retstring, L"%s,%d", retstring, p);
+                    else
+                      swprintf(retstring, L"%d", p);
+                    bret = true;
+                  }
+                }
+                HWND hchile = ::GetWindow(p, GW_CHILD);
+                if (hchile != NULL) {
+                  FindChildWnd(hchile, NULL, class_name, retstring, false, true,
+                               process_name);
+                }
+              }
+            }
+          } else {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            if (wcslen(WindowClassName) > 1) {
+              wchar_t *strfind =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              if (strfind) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 23:  // 1.窗口标题+2.窗口类名+4 :
+              // 只匹配指定父窗口的第一层孩子窗口+匹配可见的窗口
+    {
+      if (wcslen(class_name) < 1 && wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p)) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (processpid !=
+                  pid)  //只匹配指定映像的所对应的第一个进程.
+                        //可能有很多同映像名的进程,只匹配第一个进程的.
+              {
+                if (indexpid < IsEuemprosuccess) {
+                  indexpid++;
+                  processpid = pid;
+                  memset(retstring, 0, retstringlen);  //清空返回字符串
+                  retstringlen = 0;
+                }
+              }
+              if (processpid == pid) {
+                wchar_t WindowClassName[MAX_PATH] = {0};
+                ::GetClassName(p, WindowClassName, MAX_PATH);
+                wchar_t WindowTitle[MAX_PATH] = {0};
+                ::GetWindowText(p, WindowTitle, MAX_PATH);
+                if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+                  wchar_t *strfindclass =
+                      wcsstr(WindowClassName, class_name);  //模糊匹配
+                  wchar_t *strfindtitle =
+                      wcsstr(WindowTitle, title);  //模糊匹配
+                  if (strfindclass && strfindtitle) {
+                    if (retstringlen == 0) retstringlen = wcslen(retstring);
+                    if (retstringlen > 1)
+                      swprintf(retstring, L"%s,%d", retstring, p);
+                    else
+                      swprintf(retstring, L"%d", p);
+                    bret = true;
+                  }
+                }
+                HWND hchile = ::GetWindow(p, GW_CHILD);
+                if (hchile != NULL) {
+                  FindChildWnd(hchile, title, class_name, retstring, false,
+                               true, process_name);
+                }
+              }
+            }
+          } else {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+              wchar_t *strfindclass =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+              if (strfindclass && strfindtitle) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 24:  // 8 : 匹配所有者窗口为0的窗口,即顶级窗口+16.匹配可见的窗口
+    {
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p) && ::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (retstringlen == 0) retstringlen = wcslen(retstring);
+              if (retstringlen > 1)
+                swprintf(retstring, L"%s,%d", retstring, p);
+              else
+                swprintf(retstring, L"%d", p);
+              bret = true;
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, NULL, NULL, retstring, true, true,
+                             process_name);
+              }
+            }
+          } else {
+            if (retstringlen == 0) retstringlen = wcslen(retstring);
+            if (retstringlen > 1)
+              swprintf(retstring, L"%s,%d", retstring, p);
+            else
+              swprintf(retstring, L"%d", p);
+            bret = true;
+
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              FindChildWnd(hchile, NULL, NULL, retstring, true, true);
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 25:  // 1.窗口标题+
+              // 8:匹配所有者窗口为0的窗口,即顶级窗口+16.匹配可见的窗口
+    {
+      if (wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p) && ::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              wchar_t WindowTitle[MAX_PATH] = {0};
+              ::GetWindowText(p, WindowTitle, MAX_PATH);
+              if (wcslen(WindowTitle) > 1) {
+                wchar_t *strfind = wcsstr(WindowTitle, title);  //模糊匹配
+                if (strfind) {
+                  if (retstringlen == 0) retstringlen = wcslen(retstring);
+                  if (retstringlen > 1)
+                    swprintf(retstring, L"%s,%d", retstring, p);
+                  else
+                    swprintf(retstring, L"%d", p);
+                  bret = true;
+                }
+              }
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, title, NULL, retstring, true, true,
+                             process_name);
+              }
+            }
+          } else {
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowTitle) > 1) {
+              wchar_t *strfind = wcsstr(WindowTitle, title);  //模糊匹配
+              if (strfind) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              FindChildWnd(hchile, title, NULL, retstring, true, true);
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 26:  // 2.窗口类名+
+              // 8:匹配所有者窗口为0的窗口,即顶级窗口+16.匹配可见的窗口
+    {
+      if (wcslen(class_name) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p) && ::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              wchar_t WindowClassName[MAX_PATH] = {0};
+              ::GetClassName(p, WindowClassName, MAX_PATH);
+              if (wcslen(WindowClassName) > 1) {
+                wchar_t *strfind =
+                    wcsstr(WindowClassName, class_name);  //模糊匹配
+                if (strfind) {
+                  if (retstringlen == 0) retstringlen = wcslen(retstring);
+                  if (retstringlen > 1)
+                    swprintf(retstring, L"%s,%d", retstring, p);
+                  else
+                    swprintf(retstring, L"%d", p);
+                  bret = true;
+                }
+              }
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, NULL, class_name, retstring, true, true,
+                             process_name);
+              }
+            }
+          } else {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            if (wcslen(WindowClassName) > 1) {
+              wchar_t *strfind =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              if (strfind) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              FindChildWnd(hchile, NULL, class_name, retstring, true, true);
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 27:  // 1.窗口标题+2.窗口类名+8:匹配所有者窗口为0的窗口,即顶级窗口+16.匹配可见的窗口
+    {
+      if (wcslen(class_name) < 1 && wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p) && ::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              wchar_t WindowClassName[MAX_PATH] = {0};
+              ::GetClassName(p, WindowClassName, MAX_PATH);
+              wchar_t WindowTitle[MAX_PATH] = {0};
+              ::GetWindowText(p, WindowTitle, MAX_PATH);
+              if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+                wchar_t *strfindclass =
+                    wcsstr(WindowClassName, class_name);  //模糊匹配
+                wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+                if (strfindclass && strfindtitle) {
+                  if (retstringlen == 0) retstringlen = wcslen(retstring);
+                  if (retstringlen > 1)
+                    swprintf(retstring, L"%s,%d", retstring, p);
+                  else
+                    swprintf(retstring, L"%d", p);
+                  bret = true;
+                }
+              }
+              HWND hchile = ::GetWindow(p, GW_CHILD);
+              if (hchile != NULL) {
+                FindChildWnd(hchile, title, class_name, retstring, true, true,
+                             process_name);
+              }
+            }
+          } else {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+              wchar_t *strfindclass =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+              if (strfindclass && strfindtitle) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              FindChildWnd(hchile, title, class_name, retstring, true, true);
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 28:  // 4 :
+              // 只匹配指定父窗口的第一层孩子窗口+8:匹配所有者窗口为0的窗口,即顶级窗口+16.匹配可见的窗口
+    {
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p) && ::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (processpid !=
+                  pid)  //只匹配指定映像的所对应的第一个进程.
+                        //可能有很多同映像名的进程,只匹配第一个进程的.
+              {
+                if (indexpid < IsEuemprosuccess) {
+                  indexpid++;
+                  processpid = pid;
+                  memset(retstring, 0, retstringlen);  //清空返回字符串
+                  retstringlen = 0;
+                }
+              }
+              if (processpid == pid) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+                HWND hchile = ::GetWindow(p, GW_CHILD);
+                if (hchile != NULL) {
+                  FindChildWnd(hchile, NULL, NULL, retstring, true, true,
+                               process_name);
+                }
+              }
+            }
+          } else {
+            if (retstringlen == 0) retstringlen = wcslen(retstring);
+            if (retstringlen > 1)
+              swprintf(retstring, L"%s,%d", retstring, p);
+            else
+              swprintf(retstring, L"%d", p);
+            bret = true;
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 29:  ////1.窗口标题+4 :
+              ///只匹配指定父窗口的第一层孩子窗口+8:匹配所有者窗口为0的窗口,即顶级窗口+16.匹配可见的窗口
+    {
+      if (wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p) && ::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (processpid !=
+                  pid)  //只匹配指定映像的所对应的第一个进程.
+                        //可能有很多同映像名的进程,只匹配第一个进程的.
+              {
+                if (indexpid < IsEuemprosuccess) {
+                  indexpid++;
+                  processpid = pid;
+                  memset(retstring, 0, retstringlen);  //清空返回字符串
+                  retstringlen = 0;
+                }
+              }
+              if (processpid == pid) {
+                wchar_t WindowTitle[MAX_PATH] = {0};
+                ::GetWindowText(p, WindowTitle, MAX_PATH);
+                if (wcslen(WindowTitle) > 1) {
+                  wchar_t *strfind = wcsstr(WindowTitle, title);  //模糊匹配
+                  if (strfind) {
+                    if (retstringlen == 0) retstringlen = wcslen(retstring);
+                    if (retstringlen > 1)
+                      swprintf(retstring, L"%s,%d", retstring, p);
+                    else
+                      swprintf(retstring, L"%d", p);
+                    bret = true;
+                  }
+                }
+                HWND hchile = ::GetWindow(p, GW_CHILD);
+                if (hchile != NULL) {
+                  FindChildWnd(hchile, title, NULL, retstring, true, true,
+                               process_name);
+                }
+              }
+            }
+          } else {
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowTitle) > 1) {
+              wchar_t *strfind = wcsstr(WindowTitle, title);  //模糊匹配
+              if (strfind) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 30:  // 2.窗口类名+4 :
+              // 只匹配指定父窗口的第一层孩子窗口+8:匹配所有者窗口为0的窗口,即顶级窗口+16.匹配可见的窗口
+    {
+      if (wcslen(class_name) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p) && ::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (processpid !=
+                  pid)  //只匹配指定映像的所对应的第一个进程.
+                        //可能有很多同映像名的进程,只匹配第一个进程的.
+              {
+                if (indexpid < IsEuemprosuccess) {
+                  indexpid++;
+                  processpid = pid;
+                  memset(retstring, 0, retstringlen);  //清空返回字符串
+                  retstringlen = 0;
+                }
+              }
+              if (processpid == pid) {
+                wchar_t WindowClassName[MAX_PATH] = {0};
+                ::GetClassName(p, WindowClassName, MAX_PATH);
+                if (wcslen(WindowClassName) > 1) {
+                  wchar_t *strfind =
+                      wcsstr(WindowClassName, class_name);  //模糊匹配
+                  if (strfind) {
+                    if (retstringlen == 0) retstringlen = wcslen(retstring);
+                    if (retstringlen > 1)
+                      swprintf(retstring, L"%s,%d", retstring, p);
+                    else
+                      swprintf(retstring, L"%d", p);
+                    bret = true;
+                  }
+                }
+                HWND hchile = ::GetWindow(p, GW_CHILD);
+                if (hchile != NULL) {
+                  FindChildWnd(hchile, NULL, class_name, retstring, true, true,
+                               process_name);
+                }
+              }
+            }
+          } else {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            if (wcslen(WindowClassName) > 1) {
+              wchar_t *strfind =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              if (strfind) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    case 31:  // 1.窗口标题+2.窗口类名+4 :
+              // 只匹配指定父窗口的第一层孩子窗口+8:匹配所有者窗口为0的窗口,即顶级窗口+16.匹配可见的窗口
+    {
+      if (wcslen(class_name) < 1 && wcslen(title) < 1) return false;
+      HWND p = ::GetWindow(parent, GW_CHILD);  //获取桌面窗口的子窗口
+      p = ::GetWindow(p, GW_HWNDFIRST);
+      while (p != NULL) {
+        if (::IsWindowVisible(p) && ::GetWindow(p, GW_OWNER) == 0) {
+          if (process_name)  // EnumWindowByProcess
+          {
+            DWORD pid = 0;
+            GetWindowThreadProcessId(p, &pid);
+            if (EnumProcessbyName(pid, process_name)) {
+              if (processpid !=
+                  pid)  //只匹配指定映像的所对应的第一个进程.
+                        //可能有很多同映像名的进程,只匹配第一个进程的.
+              {
+                if (indexpid < IsEuemprosuccess) {
+                  indexpid++;
+                  processpid = pid;
+                  memset(retstring, 0, retstringlen);  //清空返回字符串
+                  retstringlen = 0;
+                }
+              }
+              if (processpid == pid) {
+                wchar_t WindowClassName[MAX_PATH] = {0};
+                ::GetClassName(p, WindowClassName, MAX_PATH);
+                wchar_t WindowTitle[MAX_PATH] = {0};
+                ::GetWindowText(p, WindowTitle, MAX_PATH);
+                if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+                  wchar_t *strfindclass =
+                      wcsstr(WindowClassName, class_name);  //模糊匹配
+                  wchar_t *strfindtitle =
+                      wcsstr(WindowTitle, title);  //模糊匹配
+                  if (strfindclass && strfindtitle) {
+                    if (retstringlen == 0) retstringlen = wcslen(retstring);
+                    if (retstringlen > 1)
+                      swprintf(retstring, L"%s,%d", retstring, p);
+                    else
+                      swprintf(retstring, L"%d", p);
+                    bret = true;
+                  }
+                }
+                HWND hchile = ::GetWindow(p, GW_CHILD);
+                if (hchile != NULL) {
+                  FindChildWnd(hchile, title, class_name, retstring, true, true,
+                               process_name);
+                }
+              }
+            }
+          } else {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+              wchar_t *strfindclass =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+              if (strfindclass && strfindtitle) {
+                if (retstringlen == 0) retstringlen = wcslen(retstring);
+                if (retstringlen > 1)
+                  swprintf(retstring, L"%s,%d", retstring, p);
+                else
+                  swprintf(retstring, L"%d", p);
+                bret = true;
+              }
+            }
+          }
+        }
+        p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+      }
+      break;
+    }
+    default:
+      return bret;
+  }
+
+  return bret;
+}
+
+bool WinApi::EnumWindowSuper(wchar_t *spec1, LONG flag1, LONG type1,
+                             wchar_t *spec2, LONG flag2, LONG type2, LONG sort,
+                             wchar_t *retstring) {
+  bool bret = false;
+  wchar_t findhwnd1[MAX_PATH * 100] = {0};
+  wchar_t findhwnd2[MAX_PATH * 100] = {0};
+  bool bfindhwnd1 = false;
+  bool bfindhwnd2 = false;
+  retstringlen = 0;
+  HWND parent = GetDesktopWindow();
+  HWND p = ::GetWindow(parent, GW_CHILD);
+  p = ::GetWindow(p, GW_HWNDFIRST);
+  while (p != NULL) {
+    if (flag1 == 0)  // 0表示spec1的内容是标题
+    {
+      wchar_t WindowTitle[MAX_PATH] = {0};
+      ::GetWindowText(p, WindowTitle, MAX_PATH);
+      if (wcslen(WindowTitle) > 0) {
+        if (type1 == 0)  // 0精确判断,1模糊判断
+        {
+          if (wcscmp(spec1, WindowTitle) == 0) bfindhwnd1 = true;
+        } else if (type1 == 1) {
+          if (wcsstr(WindowTitle, spec1) != NULL) bfindhwnd1 = true;
+        }
+      }
+    } else if (flag1 == 1)  // 1表示spec1的内容是程序名字
+    {
+      DWORD pid = 0;
+      ::GetWindowThreadProcessId(p, &pid);
+      wchar_t proname[MAX_PATH] = {0};
+      GetProcesspath(pid, proname);
+    } else if (flag1 == 2)  // 2表示spec1的内容是类名
+    {
+      wchar_t WindowClassName[MAX_PATH] = {0};
+      ::GetClassName(p, WindowClassName, MAX_PATH);
+      if (wcslen(WindowClassName) > 0) {
+        if (type1 == 0)  // 0精确判断,1模糊判断
+        {
+          if (wcscmp(spec1, WindowClassName) == 0) bfindhwnd1 = true;
+        } else {
+          if (wcsstr(WindowClassName, spec1) != NULL) bfindhwnd1 = true;
+        }
+      }
+    }
+    if (bfindhwnd1) {
+      if (retstringlen == 0) retstringlen = wcslen(retstring);
+      if (retstringlen > 1)
+        swprintf(retstring, L"%s,%d", retstring, p);
+      else
+        swprintf(retstring, L"%d", p);
+      bfindhwnd1 = false;
+    }
+
+    HWND hchile = ::GetWindow(p, GW_CHILD);
+    if (hchile != NULL) {
+      FindChildWnd(hchile, NULL, NULL, findhwnd1);
+    }
+    p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+  }
+
+  return bret;
+}
+
+bool WinApi::EnumProcess(const wchar_t *name, wchar_t *retstring) {
+  bool bret = false;
+  retstringlen = 0;
+  if (wcslen(name) < 1) return false;
+  IsEuemprosuccess = 0;
+  if (EnumProcessbyName(0, name) == true) {
+    bret = true;
+    for (int i = 0; i < IsEuemprosuccess; i++) {
+      if (retstringlen == 0) retstringlen = wcslen(retstring);
+      if (retstringlen > 1)
+        swprintf(retstring, L"%s,%d", retstring, npid[i]);
+      else
+        swprintf(retstring, L"%d", npid[i]);
+    }
+  }
+  return bret;
+}
+bool WinApi::ClientToScreen(LONG hwnd, LONG &x, LONG &y) {
+  POINT point;
+
+  ::ClientToScreen((HWND)hwnd, &point);
+
+  x = point.x;
+  y = point.y;
+
+  return true;
+}
+long WinApi::FindWindow(const wchar_t *class_name, const wchar_t *title) {
+  if (class_name[0] == L'\0') class_name = nullptr;
+  if (title[0] == L'\0') title = nullptr;
+  return (LONG)::FindWindowW(class_name, title);
+}
+
+long WinApi::FindWindowEx(long parent, const wchar_t *class_name,
+                          const wchar_t *title) {
+  if (class_name[0] == L'\0') class_name = nullptr;
+  if (title[0] == L'\0') title = nullptr;
+  return (long)::FindWindowExW((HWND)parent, NULL, class_name, title);
+}
+
+bool WinApi::FindWindowByProcess(const wchar_t *class_name,
+                                 const wchar_t *title, LONG &rethwnd,
+                                 const wchar_t *process_name, DWORD Pid) {
+  bool bret = false;
+  rethwnd = 0;
+  if (process_name) {
+    if (wcslen(process_name) < 1) return false;
+    memset(npid, 0, MAX_PATH);
+    IsEuemprosuccess = 0;
+    if (EnumProcessbyName(0, process_name) == false) return false;
+
+    HWND p = ::GetWindow(GetDesktopWindow(), GW_CHILD);  //获取桌面窗口的子窗口
+    p = ::GetWindow(p, GW_HWNDFIRST);
+    while (p != NULL) {
+      if (::IsWindowVisible(p) && ::GetWindow(p, GW_OWNER) == 0) {
+        DWORD pid = 0;
+        GetWindowThreadProcessId(p, &pid);
+        if (EnumProcessbyName(pid, process_name)) {
+          if (wcslen(class_name) < 1 && wcslen(title) < 1) {
+            rethwnd = (LONG)p;
+            bret = true;
+            break;
+          } else {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+              wchar_t *strfindclass =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+              if ((wcslen(class_name) >= 1 && strfindclass) ||
+                  (wcslen(title) >= 1 && strfindtitle)) {
+                rethwnd = (LONG)p;
+                bret = true;
+                break;
+              }
+            }
+
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              const wchar_t *classname = NULL;
+              const wchar_t *titles = NULL;
+              if (wcslen(class_name) > 0) classname = class_name;
+              if (wcslen(title) > 0) titles = titles;
+              DWORD dret = FindChildWnd(hchile, titles, classname, NULL, false,
+                                        false, process_name);
+              if (dret > 0) {
+                rethwnd = (LONG)dret;
+                bret = true;
+                break;
+              }
+            }
+          }
+        }
+      }
+      p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+    }
+  } else if (Pid > 0) {
+    HWND p = ::GetWindow(GetDesktopWindow(), GW_CHILD);  //获取桌面窗口的子窗口
+    p = ::GetWindow(p, GW_HWNDFIRST);
+    while (p != NULL) {
+      if (::IsWindowVisible(p) && ::GetWindow(p, GW_OWNER) == 0) {
+        DWORD npid = 0;
+        GetWindowThreadProcessId(p, &npid);
+        if (Pid == npid) {
+          if (wcslen(class_name) < 1 && wcslen(title) < 1) {
+            rethwnd = (LONG)p;
+            bret = true;
+            break;
+          } else {
+            wchar_t WindowClassName[MAX_PATH] = {0};
+            ::GetClassName(p, WindowClassName, MAX_PATH);
+            wchar_t WindowTitle[MAX_PATH] = {0};
+            ::GetWindowText(p, WindowTitle, MAX_PATH);
+            if (wcslen(WindowClassName) > 1 && wcslen(WindowTitle) > 1) {
+              wchar_t *strfindclass =
+                  wcsstr(WindowClassName, class_name);  //模糊匹配
+              wchar_t *strfindtitle = wcsstr(WindowTitle, title);  //模糊匹配
+              if ((wcslen(class_name) >= 1 && strfindclass) ||
+                  (wcslen(title) >= 1 && strfindtitle)) {
+                rethwnd = (LONG)p;
+                bret = true;
+                break;
+              }
+            }
+            HWND hchile = ::GetWindow(p, GW_CHILD);
+            if (hchile != NULL) {
+              const wchar_t *classname = NULL;
+              const wchar_t *titles = NULL;
+              if (wcslen(class_name) > 0) classname = class_name;
+              if (wcslen(title) > 0) titles = titles;
+              DWORD dret = FindChildWnd(hchile, titles, classname, NULL, false,
+                                        false, process_name);
+              if (dret > 0) {
+                rethwnd = (LONG)dret;
+                bret = true;
+                break;
+              }
+            }
+          }
+        }
+      }
+      p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+    }
+  }
+
+  return bret;
+}
+bool WinApi::GetClientRect(LONG hwnd, LONG &x, LONG &y, LONG &x1, LONG &y1) {
+  bool bret = false;
+  RECT clientrect;
+  if (IsWindow((HWND)hwnd)) {
+    ::GetClientRect((HWND)hwnd, &clientrect);
+    POINT point;
+    point.x = clientrect.left;
+    point.y = clientrect.top;
+    ::ClientToScreen((HWND)hwnd, &point);
+    x = point.x;
+    y = point.y;
+    point.x = clientrect.right;
+    point.y = clientrect.bottom;
+    ::ClientToScreen((HWND)hwnd, &point);
+    x1 = point.x;
+    y1 = point.y;
+    bret = true;
+  }
+
+  return bret;
+}
+bool WinApi::GetClientSize(LONG hwnd, LONG &width, LONG &height) {
+  bool bret = false;
+  RECT clientrect;
+  if (IsWindow((HWND)hwnd)) {
+    ::GetClientRect((HWND)hwnd, &clientrect);
+    width = clientrect.right - clientrect.left;
+    height = clientrect.bottom - clientrect.top;
+    bret = true;
+  }
+  return bret;
+}
+bool WinApi::GetMousePointWindow(LONG &rethwnd, LONG x, LONG y) {
+  bool bret = false;
+  rethwnd = 0;
+  POINT point;
+  if ((x != -1 && y != -1)) {
+    point.x = x;
+    point.y = y;
+  } else {
+    ::GetCursorPos(&point);
+  }
+  rethwnd = (DWORD)::WindowFromPoint(point);
+  if (rethwnd == NULL) {
+    HWND p = ::GetWindow(GetDesktopWindow(), GW_CHILD);  //获取桌面窗口的子窗口
+    p = ::GetWindow(p, GW_HWNDFIRST);
+    while (p != NULL) {
+      if (::IsWindowVisible(p) && ::GetWindow(p, GW_OWNER) == 0) {
+        RECT rc;
+        ::GetWindowRect(p, &rc);
+        if ((rc.top <= point.y) && (rc.left <= point.x) &&
+            (rc.right >= (point.x - rc.left)) &&
+            (rc.bottom >= (point.y - rc.top))) {
+          wchar_t WindowClass[MAX_PATH] = {0};
+          ::GetClassName(p, WindowClass, MAX_PATH);
+          // if((windowpoint.x==0||windowpoint.x<rc.left)&&wcscmp(WindowClass,L"CabinetWClass")!=0)
+          // //IE框窗体排除在外
+          if (wcscmp(WindowClass, L"CabinetWClass") != 0)  // IE框窗体排除在外
+          {
+            rethwnd = (DWORD)p;
+            bret = true;
+            break;
+          }
+        }
+      }
+      p = ::GetWindow(p, GW_HWNDNEXT);  //获取下一个窗口
+    }
+  } else
+    bret = true;
+
+  return bret;
+}
+
+int WinApi::GetProcessNumber()  //获取CPU个数
+{
+  SYSTEM_INFO info;
+  GetSystemInfo(&info);
+  return (int)info.dwNumberOfProcessors;
+}
+
+// 时间格式转换
+__int64 WinApi::FileTimeToInt64(const FILETIME &time) {
+  ULARGE_INTEGER tt;
+  tt.LowPart = time.dwLowDateTime;
+  tt.HighPart = time.dwHighDateTime;
+  return (tt.QuadPart);
+}
+
+double WinApi::get_cpu_usage(DWORD ProcessID)  //获取指定进程CPU使用率
+{
+  // cpu数量
+  static int processor_count_ = -1;
+  //上一次的时间
+  static __int64 last_time_ = 0;
+  static __int64 last_system_time_ = 0;
+
+  FILETIME now;
+  FILETIME creation_time;
+  FILETIME exit_time;
+  FILETIME kernel_time;
+  FILETIME user_time;
+  __int64 system_time;
+  __int64 time;
+  // 	__int64 system_time_delta;
+  // 	__int64 time_delta;
+
+  double cpu = -1;
+
+  if (processor_count_ == -1) {
+    processor_count_ = GetProcessNumber();
+  }
+
+  GetSystemTimeAsFileTime(&now);
+
+  // HANDLE hProcess =
+  // OpenProcess(PROCESS_QUERY_INFORMATION/*PROCESS_ALL_ACCESS*/, false,
+  // ProcessID);
+  HANDLE hProcess = NULL;
+
+  hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
+                         ProcessID);
+
+  if (!hProcess) {
+    return -1;
+  }
+  if (!GetProcessTimes(hProcess, &creation_time, &exit_time, &kernel_time,
+                       &user_time)) {
+    return -1;
+  }
+  system_time = (FileTimeToInt64(kernel_time) + FileTimeToInt64(user_time)) /
+                processor_count_;  // CPU使用时间
+  time = FileTimeToInt64(now);     //现在的时间
+
+  last_system_time_ = system_time;
+  last_time_ = time;
+  CloseHandle(hProcess);
+
+  Sleep(1000);
+
+  // hProcess = OpenProcess(PROCESS_QUERY_INFORMATION/*PROCESS_ALL_ACCESS*/,
+  // false, ProcessID);
+
+  hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
+                         ProcessID);
+
+  if (!hProcess) {
+    return -1;
+  }
+  if (!GetProcessTimes(hProcess, &creation_time, &exit_time, &kernel_time,
+                       &user_time)) {
+    return -1;
+  }
+  GetSystemTimeAsFileTime(&now);
+  system_time = (FileTimeToInt64(kernel_time) + FileTimeToInt64(user_time)) /
+                processor_count_;  // CPU使用时间
+  time = FileTimeToInt64(now);     //现在的时间
+
+  CloseHandle(hProcess);
+
+  cpu = ((double)(system_time - last_system_time_) /
+         (double)(time - last_time_)) *
+        100;
+  return cpu;
+}
+
+//或者指定进程内存使用率
+DWORD WinApi::GetMemoryInfo(DWORD ProcessID) {
+  PROCESS_MEMORY_COUNTERS pmc;
+  DWORD memoryInK = 0;
+  HANDLE hProcess = NULL;
+
+  hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
+                         ProcessID);
+
+  if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) {
+    // memoryInK = pmc.WorkingSetSize/1024;		//单位为k
+    memoryInK = pmc.WorkingSetSize;
+  }
+
+  CloseHandle(hProcess);
+  return memoryInK;
+}
+
+bool WinApi::GetProcessInfo(LONG pid, wchar_t *retstring) {
+  bool bret = false;
+  wchar_t process_name[MAX_PATH] = {0};
+  wchar_t process_path[MAX_PATH] = {0};
+  DWORD cpu = 0;
+  DWORD meminfo = 0;
+
+  int nItem = 0;  // 项计数
+  PROCESSENTRY32 pe32 = {sizeof(PROCESSENTRY32)};
+  HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+  if (hProcessSnap == INVALID_HANDLE_VALUE) return FALSE;
+  if (::Process32First(hProcessSnap, &pe32)) {
+    do {
+      if (pe32.th32ProcessID == pid) {
+        wcscpy(process_name, pe32.szExeFile);
+        break;
+      }
+
+    } while (::Process32Next(hProcessSnap, &pe32));
+  }
+  ::CloseHandle(hProcessSnap);
+  if (wcslen(process_name) < 1) return bret;
+
+  // TSRuntime::GetRemoteModulePath(process_name, pid, process_path);
+  cpu = (DWORD)get_cpu_usage(pid);
+  meminfo = (DWORD)GetMemoryInfo(pid);
+
+  swprintf(retstring, L"%s|%s|%d|%d", process_name, process_path, cpu, meminfo);
+
+  return bret;
+}
+bool WinApi::GetProcesspath(DWORD ProcessID, wchar_t *process_path) {
+  HANDLE hProcess = NULL;
+
+  hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
+                         ProcessID);
+
+  HMODULE hMods = NULL;
+  DWORD cbNeededModule = 0;
+  EnumProcessModules(hProcess, &hMods, sizeof(hMods), &cbNeededModule);
+  GetModuleFileNameEx(hProcess, hMods, process_path, MAX_PATH);
+
+  return true;
+}
+bool WinApi::GetWindow(LONG hwnd, LONG flag, LONG &rethwnd) {
+  bool bret = false;
+  rethwnd = 0;
+  HWND wnd = (HWND)hwnd;
+  if (IsWindow(wnd) == false) return bret;
+  DWORD type = -1;
+  if (flag == 0)  // 0:获取父窗口
+    rethwnd = (LONG)::GetParent(wnd);
+  else if (flag == 1)  //获取第一个儿子窗口
+    type = GW_CHILD;
+  else if (flag == 2)  //获取First 窗口
+    type = GW_HWNDFIRST;
+  else if (flag == 3)  //获取Last窗口
+    type = GW_HWNDLAST;
+  else if (flag == 4)  //获取下一个窗口
+    type = GW_HWNDNEXT;
+  else if (flag == 5)  //获取上一个窗口
+    type = GW_HWNDPREV;
+  else if (flag == 6)  //获取拥有者窗口
+    type = GW_OWNER;
+  else if (flag == 7)  //获取顶层窗口
+  {
+    // rethwnd = (LONG)::GetForegroundWindow();
+    HWND next = NULL, current = (HWND)hwnd;
+    while (next = ::GetParent(current)) current = next;
+    rethwnd = (long)current;
+    return ::IsWindow(current);
+  }
+
+  if (type != -1) rethwnd = (LONG)::GetWindow(wnd, (UINT)type);
+
+  if (rethwnd != 0) bret = true;
+
+  return bret;
+}
+
+bool WinApi::GetWindowState(LONG hwnd, LONG flag) {
+  bool bret = false;
+  HWND wnd = (HWND)hwnd;
+  if (flag == 0)  // 0://判断窗口是否存在
+    bret = ::IsWindow(wnd);
+  else if (flag == 1)  //判断窗口是否处于激活
+  {
+    if (::GetActiveWindow() == wnd) bret = true;
+  } else if (flag == 2)  // 2 : 判断窗口是否可见
+    bret = ::IsWindowVisible(wnd);
+  else if (flag == 3)  // 3 : 判断窗口是否最小化
+    bret = ::IsIconic(wnd);
+  else if (flag == 4)  // 4 : 判断窗口是否最大化
+    bret = ::IsZoomed(wnd);
+  else if (flag == 5)  // 5 : 判断窗口是否置顶
+  {
+    if (::GetForegroundWindow() == wnd) bret = true;
+  } else if (flag == 6)  // 6 : 判断窗口是否无响应
+    bret = ::IsHungAppWindow(wnd);
+  else if (flag == 7)  //判断窗口是否可用(灰色为不可用)
+    bret = ::IsWindowEnabled(wnd);
+
+  return bret;
+}
+
+bool WinApi::SendPaste(LONG hwnd) {
+  bool bret = true;
+  HANDLE hClip;
+  char *chBuffer = NULL;
+  if (OpenClipboard(NULL)) {
+    //从剪贴板中取出一个内存的句柄
+    hClip = GetClipboardData(CF_TEXT);
+    //定义字符型指针变量用来保存内存块中的数据
+    //对内存块进行加锁,将内存句柄值转化为一个指针,并将内存块的引用计数器加一,内存中的数据也返回到指针型变量中
+    chBuffer = (char *)GlobalLock(hClip);
+    //将数据保存到字符型变量中
+    //将内存块的引用计数器减一
+    GlobalUnlock(hClip);
+    //关闭剪贴板,释放剪贴板资源的占用权
+    CloseClipboard();
+  }
+  // anscii 转 unicode
+  DWORD num = MultiByteToWideChar(CP_ACP, 0, chBuffer, -1, NULL, 0);
+  wchar_t *wword = new wchar_t[num + 1];          //动态的申请空间存字
+  memset(wword, 0, (num + 1) * sizeof(wchar_t));  //初始化动作
+  MultiByteToWideChar(CP_ACP, 0, chBuffer, -1, wword, num);
+
+  int len = wcslen(wword);
+  // MessageBoxA(NULL,tts,tts,NULL);
+  for (int i = 0; i < len; i++) {
+    ::SendMessage((HWND)hwnd, WM_CHAR, (WPARAM)wword[i], (LPARAM)1);
+    Sleep(10);
+  }
+  delete[] wword;
+
+  return bret;
+}
+
+bool WinApi::SetWindowSize(LONG hwnd, LONG width, LONG hight, int type) {
+  bool bret = false;
+  if (type == 0)  // SetClientSize
+  {
+    RECT rectProgram, rectClient;
+    HWND hWnd = (HWND)hwnd;
+    ::GetWindowRect(hWnd, &rectProgram);  //获得程序窗口位于屏幕坐标
+    ::GetClientRect(hWnd, &rectClient);   //获得客户区坐标
+    //非客户区宽,高
+    int nWidth = rectProgram.right - rectProgram.left -
+                 (rectClient.right - rectClient.left);
+    int nHeiht = rectProgram.bottom - rectProgram.top -
+                 (rectClient.bottom - rectClient.top);
+    nWidth += width;
+    nHeiht += hight;
+    rectProgram.right = nWidth;
+    rectProgram.bottom = nHeiht;
+    int showToScreenx =
+        GetSystemMetrics(SM_CXSCREEN) / 2 - nWidth / 2;  //居中处理
+    int showToScreeny = GetSystemMetrics(SM_CYSCREEN) / 2 - nHeiht / 2;
+    bret = ::MoveWindow(hWnd, showToScreenx, showToScreeny, rectProgram.right,
+                        rectProgram.bottom, false);
+  } else  // SetWindowSize
+  {
+    RECT rectClient;
+    HWND hWnd = (HWND)hwnd;
+    ::GetWindowRect(hWnd, &rectClient);  //获得程序窗口位于屏幕坐标
+    bret = ::MoveWindow(hWnd, rectClient.left, rectClient.top, width, hight,
+                        false);
+  }
+  return bret;
+}
+
+bool WinApi::SetWindowState(LONG hwnd, LONG flag, LONG rethwnd) {
+  bool bret = false;
+  HWND hWnd = (HWND)hwnd;
+  if (IsWindow(hWnd) == false) return bret;
+  int type = -1;
+  type = flag;
+  if (flag == 0)  //关闭指定窗口
+    ::SendMessage(hWnd, WM_CLOSE, 0, 0);
+  else if (flag == 1)  //激活指定窗口
+  {
+    ::ShowWindow(hWnd, SW_SHOW);
+    ::SetForegroundWindow(hWnd);
+  } else if (flag == 2)  //最小化指定窗口,但不激活
+    ::ShowWindow(hWnd, SW_SHOWMINNOACTIVE);
+  else if (flag == 3)  //最小化指定窗口,并释放内存,但同时也会激活窗口
+    ::ShowWindow(hWnd, SW_SHOWMINIMIZED);
+  else if (flag == 4)  //最大化指定窗口,同时激活窗口.
+    ::ShowWindow(hWnd, SW_SHOWMAXIMIZED);
+  else if (flag == 5)  //恢复指定窗口 ,但不激活
+    ::ShowWindow(hWnd, SW_SHOWNOACTIVATE);
+  else if (flag == 6)  //隐藏指定窗口
+    ::ShowWindow(hWnd, SW_HIDE);
+  else if (flag == 7)  //显示指定窗口
+  {
+    ::ShowWindow(hWnd, SW_SHOW);
+    ::SetForegroundWindow(hWnd);
+  } else if (flag == 8)  //置顶指定窗口
+    ::SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,
+                   SWP_NOMOVE | SWP_NOSIZE);  //窗口置顶
+  else if (flag == 9)                         // 9 : 取消置顶指定窗口
+    ::SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+  else if (flag == 10)  //禁止指定窗口
+    ::EnableWindow(hWnd, false);
+  else if (flag == 11)  //取消禁止指定窗口
+    ::EnableWindow(hWnd, true);
+  else if (flag == 12)  // 12 : 恢复并激活指定窗口
+    ::ShowWindow(hWnd, SW_RESTORE);
+  else if (flag == 13)  // 13 : 强制结束窗口所在进程.
+  {
+    DWORD pid = 0;
+    ::GetWindowThreadProcessId(hWnd, &pid);
+    // TSRuntime::EnablePrivilege(L"SeDebugPrivilege", true);
+    HANDLE hprocess = NULL;
+
+    hprocess = ::OpenProcess(PROCESS_ALL_ACCESS, false, pid);
+
+    ::TerminateProcess(hprocess, 0);
+  } else if (flag == 14)  // 14 : 闪烁指定的窗口
+  {
+    FLASHWINFO fInfo;
+    fInfo.cbSize = sizeof(FLASHWINFO);
+    fInfo.dwFlags =
+        FLASHW_ALL |
+        FLASHW_TIMERNOFG;  //这里是闪动窗标题和任务栏按钮,直到用户激活窗体
+    fInfo.dwTimeout = 0;
+    fInfo.hwnd = hWnd;
+    fInfo.uCount = 0xffffff;
+    FlashWindowEx(&fInfo);
+  } else if (flag == 15)  //使指定的窗口获取输入焦点
+  {
+    ::ShowWindow(hWnd, SW_SHOW);
+    ::SetFocus(hWnd);
+  }
+
+  if (type >= 0 && type < 16) bret = true;
+
+  return bret;
+}
+
+bool WinApi::SetWindowTransparent(LONG hwnd, LONG trans) {
+  bool bret = false;
+
+  COLORREF crKey = NULL;
+  DWORD dwFlags = 0;
+  BYTE bAlpha = 0;
+  if (trans < 0) trans = 0;
+  if (trans > 255) trans = 255;
+  //...
+  /*typedef bool(__stdcall  *  mySetLayeredWindowAttributes)(
+          HWND hwnd,
+          COLORREF pcrKey,
+          BYTE pbAlpha,
+          DWORD pdwFlags);
+  mySetLayeredWindowAttributes obj_SetLayeredWindowAttributes = NULL;
+  HINSTANCE hlibrary;
+  hlibrary = LoadLibrary(_T("user32.dll"));
+  obj_SetLayeredWindowAttributes =
+  (mySetLayeredWindowAttributes)GetProcAddress(hlibrary,
+  "SetLayeredWindowAttributes");*/
+
+  SetWindowLong((HWND)hwnd, GWL_EXSTYLE, 0x80001);
+  bret = SetLayeredWindowAttributes((HWND)hwnd, crKey, trans, 2);
+
+  return bret;
+}
+
+bool WinApi::SetClipboard(wchar_t *values) {
+  bool bret = false;
+  int n = ::WideCharToMultiByte(CP_ACP, 0, values, -1, NULL, 0, NULL, NULL);
+  char *chcontent = new char[n + 1];
+  memset(chcontent, 0, sizeof(char) * n + 1);
+  WideCharToMultiByte(CP_ACP, 0, values, -1, chcontent, n, NULL, NULL);
+
+  if (OpenClipboard(NULL)) {
+    //将剪贴板内容清空
+    EmptyClipboard();
+    //字节长度
+    int leng = strlen(chcontent) + 1;
+    //在堆上分配可移动的内存块,程序返回一个内存句柄
+    HANDLE hClip = GlobalAlloc(GHND | GMEM_SHARE, leng);
+    //定义指向字符型的指针变量
+    char *buff;
+    //对分配的内存块进行加锁,将内存块句柄转化成一个指针,并将相应的引用计数器加一
+    buff = (char *)GlobalLock(hClip);
+    //将用户输入的数据拷贝到指针变量中,实际上就是拷贝到分配的内存块中
+    memcpy(buff, chcontent, leng);
+    buff[leng - 1] = 0;
+    //数据写入完毕,进行解锁操作,并将引用计数器数字减一
+    GlobalUnlock(hClip);
+    //将存放有数据的内存块放入剪贴板的资源管理中
+    HANDLE help = SetClipboardData(CF_TEXT, hClip);
+    //关闭剪贴板,释放剪贴板资源的占用权
+    CloseClipboard();
+    // MessageBox(0,L"已将数据存入剪贴板",L"剪切扳",0);
+    if (help != NULL) {
+      bret = true;
+    } else {
+      bret = false;
+    }
+  }
+  delete[] chcontent;
+  return bret;
+}
+
+bool WinApi::GetClipboard(wchar_t *retstr) {
+  bool bret = false;
+  HANDLE hClip;
+  char *chBuffer = NULL;
+  if (OpenClipboard(NULL)) {
+    //从剪贴板中取出一个内存的句柄
+    hClip = GetClipboardData(CF_TEXT);
+    //定义字符型指针变量用来保存内存块中的数据
+
+    //对内存块进行加锁,将内存句柄值转化为一个指针,并将内存块的引用计数器加一,内存中的数据也返回到指针型变量中
+    chBuffer = (char *)GlobalLock(hClip);
+
+    //将数据保存到字符型变量中
+    //将内存块的引用计数器减一
+    GlobalUnlock(hClip);
+    //关闭剪贴板,释放剪贴板资源的占用权
+    CloseClipboard();
+  }
+
+  DWORD num = MultiByteToWideChar(CP_ACP, 0, chBuffer, -1, NULL, 0);
+  wchar_t *wword = new wchar_t[num + 1];          //动态的申请空间存字
+  memset(wword, 0, (num + 1) * sizeof(wchar_t));  //初始化动作
+  MultiByteToWideChar(CP_ACP, 0, chBuffer, -1, wword, num);
+
+  if (num < MAX_PATH * 4 - 1) wcscpy(retstr, wword);
+
+  delete[] wword;
+
+  return bret;
+}
+
+long WinApi::SendString(HWND hwnd, const wstring &s) {
+  if (::IsWindow(hwnd)) {
+    auto p = s.data();
+    for (int i = 0; i < s.length(); ++i) {
+      ::PostMessageW(hwnd, WM_CHAR, p[i], 0);
+      ::Sleep(5);
+    }
+    return 1;
+  }
+  return 0;
+}
+
+long WinApi::SendStringIme(HWND hwnd, const wstring &s) {
+  if (::IsWindow(hwnd)) {
+    auto p = s.data();
+    for (int i = 0; i < s.length(); ++i) {
+      ::PostMessage(hwnd, WM_IME_CHAR, p[i], 0);
+      ::Sleep(5);
+    }
+    return 1;
+  }
+  return 0;
+}
+
+long WinApi::RunApp(const wstring &cmd, long mode) {
+  std::unique_ptr<wchar_t> cmdptr(new wchar_t[cmd.length()]);
+  memcpy(cmdptr.get(), cmd.data(), cmd.length() * sizeof(wchar_t));
+  /*SECURITY_ATTRIBUTES SA;
+  SA.bInheritHandle = NULL;
+  SA.*/
+  STARTUPINFO si;
+  PROCESS_INFORMATION pi;
+  ZeroMemory(&si, sizeof(si));
+  ZeroMemory(&pi, sizeof(pi));
+  int bret;
+  wstring curr_dir;
+  if (mode == 1) {
+    // find
+    size_t pos;
+    pos = cmd.find(L".exe");
+    if (pos != wstring::npos && pos != 0) {
+      for (int i = pos - 1; i >= 1; --i) {
+        if (cmd[i] == L'\\' || cmd[i] == L'/') {
+          pos = i;
+          break;
+        }
+      }
+      if (pos > 0) {
+        curr_dir = cmd.substr(0, pos);
+      }
+    }
+    // setlog(curr_dir.c_str());
+  }
+  bret = ::CreateProcessW(
+      nullptr,       //// 应用程序名称
+      cmdptr.get(),  // 命令行字符串
+      NULL,          // 进程的安全属性
+      NULL,          // 线程的安全属性
+      false,         // 是否继承父进程的属性
+      0,             // 创建标志
+      nullptr,       // 指向新的环境块的指针
+      mode == 1 && !curr_dir.empty() ? curr_dir.c_str()
+                                     : nullptr,  // 指向当前目录名的指针
+      &si,                                       // 传递给新进程的信息
+      &pi                                        // 新进程返回的信息
+  );
+  if (bret) {
+    CloseHandle(pi.hProcess);
+    CloseHandle(pi.hThread);
+  }
+
+  return bret;
+}
+
+HWND WinApi::GetTopWindowSp(HWND hwnd) {
+  HWND i = hwnd, temp;
+
+  while (GetWindowLongA(i, GWL_STYLE) >= 0) {
+    temp = GetParent(i);
+    if (!temp) break;
+  }
+  return i;
+}

+ 58 - 0
gm/gm/winapi/WinApi.h

@@ -0,0 +1,58 @@
+#pragma once
+#ifndef __WINAPI_H_
+#define __WINAPI_JH_
+#include "../core/optype.h"
+#undef FindWindow
+#undef FindWindowEx
+class WinApi
+{
+public:
+	WinApi(void);
+	~WinApi(void);
+
+
+public:
+	int retstringlen;
+	DWORD WindowVerion;
+	DWORD IsEuemprosuccess;
+	DWORD npid[MAX_PATH];
+	bool EnumWindow(HWND parent, const wchar_t *title, const wchar_t *class_name, LONG filter, wchar_t *retstring, const wchar_t  *process_name = NULL);
+	bool EnumWindowSuper(wchar_t *spec1, LONG flag1, LONG type1, wchar_t *spec2, LONG flag2, LONG type2, LONG sort, wchar_t *retstring = NULL);
+	bool EnumProcess(const wchar_t *name, wchar_t *retstring);
+	bool ClientToScreen(LONG hwnd, LONG &x, LONG &y);
+	long FindWindow(const wchar_t *class_name, const wchar_t*title);
+	long FindWindowEx(long parent, const wchar_t *class_name, const wchar_t*title);
+	bool FindWindowByProcess(const wchar_t *class_name, const wchar_t *titl, LONG &rethwnd, const wchar_t *process_name = NULL, DWORD Pid = 0);
+	bool GetClientRect(LONG hwnd, LONG &x, LONG &y, LONG &x1, LONG &y1);
+	bool GetClientSize(LONG hwnd, LONG &width, LONG &height);
+	bool GetMousePointWindow(LONG &rethwnd, LONG x = -1, LONG y = -1);
+	bool GetProcessInfo(LONG pid, wchar_t *retstring);
+	bool GetWindow(LONG hwnd, LONG flag, LONG &rethwnd);
+	bool GetProcesspath(DWORD ProcessID, wchar_t* process_path);
+	bool GetWindowState(LONG hwnd, LONG flag);
+	bool SendPaste(LONG hwnd);
+	bool SetWindowSize(LONG hwnd, LONG width, LONG hight, int type = 0);
+	bool SetWindowState(LONG hwnd, LONG flag, LONG rethwnd = 0);
+	bool SetWindowTransparent(LONG hwnd, LONG trans);
+	bool SetClipboard(wchar_t *values);
+	bool GetClipboard(wchar_t *retstr);
+	//2019.1
+	long SendString(HWND hwnd, const wstring& str);
+	long SendStringIme(HWND hwnd, const wstring& str);
+	//2019.3
+	long RunApp(const wstring& cmd, long mode);
+	static HWND GetTopWindowSp(HWND hwnd);
+private:
+	DWORD  FindChildWnd(HWND hchile, const wchar_t *title, const wchar_t *classname, wchar_t *retstring, bool isGW_OWNER = false, bool isVisible = false, const wchar_t  *process_name = NULL);
+	BOOL   EnumProcessbyName(DWORD   dwPID, LPCWSTR   ExeName, LONG type = 0);
+	int GetProcessNumber();//获取CPU个数
+	// 时间格式转换
+	__int64 FileTimeToInt64(const FILETIME& time);
+	double get_cpu_usage(DWORD ProcessID);	 //获取指定进程CPU使用率
+	DWORD GetMemoryInfo(DWORD ProcessID);  //或者指定进程内存使用率
+
+
+};
+
+
+#endif

+ 22 - 0
gm/gm/winapi/query_api.cpp

@@ -0,0 +1,22 @@
+//#include "stdafx.h"
+#include "core/optype.h"
+#include "query_api.h"
+
+
+void* query_api(const char* mod_name, const char* func_name) {
+	auto hdll = ::GetModuleHandleA(mod_name);
+	if (!hdll) {
+		//_error_code = -1;
+		return NULL;
+	}
+	void* paddress = (void*)::GetProcAddress(hdll, func_name);
+	if (!paddress) {
+		//_error_code = -2;
+		return NULL;
+	}
+	//_error_code = 0;
+	return paddress;
+
+}
+
+

+ 5 - 0
gm/gm/winapi/query_api.h

@@ -0,0 +1,5 @@
+#pragma once
+
+void* query_api(const char* mod_name, const char* func_name);
+
+