├── .gitattributes ├── .gitignore ├── Common ├── ipc.h ├── utils.h └── wm.h ├── D3DRecorder.sln ├── D3DRecorder ├── D3DRecorder.cpp ├── D3DRecorder.h ├── D3DRecorder.rc ├── D3DRecorder.vcxproj ├── D3DRecorder.vcxproj.filters ├── D3DRecorderDlg.cpp ├── D3DRecorderDlg.h ├── HookEngine.cpp ├── HookEngine.h ├── PipeServer.cpp ├── PipeServer.h ├── SpyMgrEventSink.cpp ├── SpyMgrEventSink.h ├── res │ ├── D3DRecorder.ico │ └── D3DRecorder.rc2 ├── resource.h ├── stdafx.cpp ├── stdafx.h └── targetver.h ├── D3DRecorderPlugin ├── AVIVideo.cpp ├── AVIVideo.h ├── CommandQueue.cpp ├── CommandQueue.h ├── Console.cpp ├── Console.h ├── D3DRecorderPlugin.cpp ├── D3DRecorderPlugin.h ├── D3DRecorderPlugin.vcxproj ├── D3DRecorderPlugin.vcxproj.filters ├── Exports.Def ├── KeyboardHook.cpp ├── KeyboardHook.h ├── ParamHelper.cpp ├── ParamHelper.h ├── ReadMe.txt ├── RecorderEngine.cpp ├── RecorderEngine.h ├── dllmain.cpp ├── stdafx.cpp ├── stdafx.h └── targetver.h ├── README.md └── dll └── README!!!!.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | -------------------------------------------------------------------------------- /Common/ipc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define D3DRECORDER_PIPENAME L"\\\\.\\pipe\\D3DRECORDER_PIPE" 4 | 5 | #define MSG_NULL 0 6 | #define MSG_METHODADDR_DIRECT3D_CREATEDEVICE 1 7 | #define MSG_METHODADDR_DIRECT3DDEVICE_ENDSCENE 2 8 | 9 | // 1k messages 10 | 11 | struct IPCMESSAGE 12 | { 13 | int msgType; 14 | 15 | union 16 | { 17 | DWORD_PTR address; 18 | }; 19 | }; 20 | 21 | #define IPCMESSAGESIZE sizeof(IPCMESSAGE) -------------------------------------------------------------------------------- /Common/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define MAX_STRING_CCH 1024 4 | 5 | template 6 | inline void SafeDelete(T* p) 7 | { 8 | delete p; 9 | p = NULL; 10 | } 11 | 12 | static void d_printf(const wchar_t* szFormat, ...) 13 | { 14 | wchar_t wBuf[MAX_STRING_CCH]; 15 | va_list va; 16 | 17 | va_start(va, szFormat); 18 | vswprintf (wBuf, MAX_STRING_CCH, szFormat, va); 19 | va_end(va); 20 | 21 | OutputDebugString(wBuf); 22 | } 23 | 24 | static void DumpDIBHeader(BITMAPINFOHEADER* bih) 25 | { 26 | d_printf(L"Dump of BITMAPINFOHEADER at 0x%p", bih); 27 | d_printf(L" biBitCount: %d\n", bih->biBitCount); 28 | d_printf(L" biClrUsed: %d\n", bih->biClrUsed); 29 | d_printf(L" biHeight: %d\n", bih->biHeight); 30 | d_printf(L" biWidth: %d\n", bih->biWidth); 31 | d_printf(L" biSizeImage: %d\n", bih->biSizeImage); 32 | d_printf(L" biPlanes: %d\n", bih->biPlanes); 33 | } 34 | 35 | 36 | __inline UINT_PTR CoGetMethodAddress(LPVOID pVT, UINT index) 37 | { 38 | UINT_PTR *pdwVirtualTable; 39 | pdwVirtualTable = (UINT_PTR*)*(UINT_PTR*)pVT; 40 | return pdwVirtualTable[index]; 41 | } 42 | 43 | static void GetOutputDir( wchar_t* szDir, DWORD cchBuf) 44 | { 45 | DWORD cBytes = cchBuf*sizeof(WCHAR); 46 | 47 | SHRegGetUSValue(L"Software\\Nektra\\D3DRecorder\\Configuration", 48 | L"OutputFolder", NULL, szDir, &cBytes, FALSE, 0, 0); 49 | } 50 | 51 | ////////////////////////////////////////////////////////////////////////////// 52 | // 53 | // VTABLE Function Indices for Core Audio interfaces 54 | // 55 | ////////////////////////////////////////////////////////////////////////////// 56 | 57 | struct VTI_IAudioRenderClient 58 | { 59 | static const int QueryInterface =0; 60 | static const int AddRef = 1; 61 | static const int Release = 2; 62 | static const int GetBuffer = 3; 63 | static const int ReleaseBuffer = 4; 64 | }; 65 | 66 | struct VTI_IAudioCaptureClient 67 | { 68 | static const int QueryInterface =0; 69 | static const int AddRef = 1; 70 | static const int Release = 2; 71 | static const int GetBuffer = 3; 72 | static const int ReleaseBuffer = 4; 73 | }; 74 | 75 | struct VTI_IAudioClient 76 | { 77 | static const int QueryInterface =0; 78 | static const int AddRef = 1; 79 | static const int Release = 2; 80 | static const int Initialize = 3; 81 | static const int Start = 10; 82 | static const int Stop = 11; 83 | static const int Reset = 12; 84 | static const int GetService = 14; 85 | }; 86 | 87 | ////////////////////////////////////////////////////////////////////////////// 88 | // 89 | // Struct for Core Audio Interface pointers 90 | // 91 | ////////////////////////////////////////////////////////////////////////////// 92 | 93 | interface IAudioRenderClient; 94 | interface IAudioCaptureClient; 95 | interface IAudioClient; 96 | 97 | struct COREAUDIO_VTABLE_PTR 98 | { 99 | DWORD_PTR pvt_IAudioRenderClient; 100 | DWORD_PTR pvt_IAudioCaptureClient; 101 | DWORD_PTR pvt_IAudioClient; 102 | }; 103 | 104 | ////////////////////////////////////////////////////////////////////////////// 105 | // 106 | // VTABLE Function Indices for Direct3D 9.0 Interfaces 107 | // 108 | ////////////////////////////////////////////////////////////////////////////// 109 | 110 | struct VTI_IDirect3D9 111 | { 112 | static const int QueryInterface =0; 113 | static const int AddRef = 1; 114 | static const int Release = 2; 115 | 116 | //... 117 | 118 | static const int CreateDevice = 16; 119 | }; 120 | 121 | struct VTI_IDirect3D9Device 122 | { 123 | static const int Queryinterface = 0; 124 | static const int AddRef = 1; 125 | static const int Release = 2; 126 | static const int TestCooperativeLevel = 3; 127 | static const int GetAvailableTextureMem = 4; 128 | static const int EvictManagedResources = 5; 129 | static const int GetDirect3D = 6; 130 | static const int GetDeviceCaps = 7; 131 | static const int GetDisplayMode = 8; 132 | static const int GetCreationParameters = 9; 133 | static const int SetCursorProperties = 10; 134 | static const int SetCursorPosition = 11; 135 | static const int ShowCursor = 12; 136 | static const int CreateAdditionalSwapChain = 13; 137 | static const int GetSwapChain = 14; 138 | static const int GetNumberOfSwapChains = 15; 139 | static const int Reset = 16; 140 | static const int Present = 17; 141 | static const int GetBackBuffer = 18; 142 | static const int GetRasterStatus = 19; 143 | static const int SetDialogBoxMode = 20; 144 | static const int SetGammaRamp = 21; 145 | static const int GetGammaRamp = 22; 146 | static const int CreateTexture = 23; 147 | static const int CreateVolumeTexture = 24; 148 | static const int CreateCubeTexture = 25; 149 | static const int CreateVertexBuffer = 26; 150 | static const int CreateIndexBuffer = 27; 151 | static const int CreateRenderTarget = 28; 152 | static const int CreateDepthStencilSurface = 29; 153 | static const int UpdateSurface = 30; 154 | static const int UpdateTexture = 31; 155 | static const int GetRenderTargetData = 32; 156 | static const int GetFrontBufferData = 33; 157 | static const int StretchRect = 34; 158 | static const int ColorFill = 35; 159 | static const int CreateOffscreenPlainSurface = 36; 160 | static const int SetRenderTarget = 37; 161 | static const int GetRenderTarget = 38; 162 | static const int SetDepthStencilSurface = 39; 163 | static const int GetDepthStencilSurface = 40; 164 | static const int BeginScene = 41; 165 | static const int EndScene = 42; 166 | static const int Clear = 43; 167 | static const int SetTransform = 44; 168 | static const int GetTransform = 45; 169 | static const int MultiplyTransform = 46; 170 | static const int SetViewport = 47; 171 | static const int GetViewport = 48; 172 | static const int SetMaterial = 49; 173 | static const int GetMaterial = 50; 174 | static const int SetLight = 51; 175 | static const int GetLight = 52; 176 | static const int LightEnable = 53; 177 | static const int GetLightEnable = 54; 178 | static const int SetClipPlane = 55; 179 | static const int GetClipPlane = 56; 180 | static const int SetRenderState = 57; 181 | static const int GetRenderState = 58; 182 | static const int CreateStateBlock = 59; 183 | static const int BeginStateBlock = 60; 184 | static const int EndStateBlock = 61; 185 | static const int SetClipStatus = 62; 186 | static const int GetClipStatus = 63; 187 | static const int GetTexture = 64; 188 | static const int SetTexture = 65; 189 | static const int GetTextureStageState = 66; 190 | static const int SetTextureStageState = 67; 191 | static const int GetSamplerState = 68; 192 | static const int SetSamplerState = 69; 193 | static const int ValidateDevice = 70; 194 | static const int SetPaletteEntries = 71; 195 | static const int GetPaletteEntries = 72; 196 | static const int SetCurrentTexturePalette = 73; 197 | static const int GetCurrentTexturePalette = 74; 198 | static const int SetScissorRect = 75; 199 | static const int GetScissorRect = 76; 200 | static const int SetSoftwareVertexProcessing = 77; 201 | static const int GetSoftwareVertexProcessing = 78; 202 | static const int SetNPatchMode = 79; 203 | static const int GetNPatchMode = 80; 204 | static const int DrawPrimitive = 81; 205 | static const int DrawIndexedPrimitive = 82; 206 | static const int DrawPrimitiveUP = 83; 207 | static const int DrawIndexedPrimitiveUP = 84; 208 | static const int ProcessVertices = 85; 209 | static const int CreateVertexDeclaration = 86; 210 | static const int SetVertexDeclaration = 87; 211 | static const int GetVertexDeclaration = 88; 212 | static const int SetFVF = 89; 213 | static const int GetFVF = 90; 214 | static const int CreateVertexShader = 91; 215 | static const int SetVertexShader = 92; 216 | static const int GetVertexShader = 93; 217 | static const int SetVertexShaderConstantF = 94; 218 | static const int GetVertexShaderConstantF = 95; 219 | static const int SetVertexShaderConstantI = 96; 220 | static const int GetVertexShaderConstantI = 97; 221 | static const int SetVertexShaderConstantB = 98; 222 | static const int GetVertexShaderConstantB = 99; 223 | static const int SetStreamSource = 100; 224 | static const int GetStreamSource = 101; 225 | static const int SetStreamSourceFreq = 102; 226 | static const int GetStreamSourceFreq = 103; 227 | static const int SetIndices = 104; 228 | static const int GetIndices = 105; 229 | static const int CreatePixelShader = 106; 230 | static const int SetPixelShader = 107; 231 | static const int GetPixelShader = 108; 232 | static const int SetPixelShaderConstantF = 109; 233 | static const int GetPixelShaderConstantF = 110; 234 | static const int SetPixelShaderConstantI = 111; 235 | static const int GetPixelShaderConstantI = 112; 236 | static const int SetPixelShaderConstantB = 113; 237 | static const int GetPixelShaderConstantB = 114; 238 | static const int DrawRectPatch = 115; 239 | static const int DrawTriPatch = 116; 240 | static const int DeletePatch = 117; 241 | static const int CreateQuery = 118; 242 | static const int NumberOfFunctions = 118; 243 | }; 244 | 245 | // -------------------------------------------------------------------------------- /Common/wm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define WM_IPCMESSAGE (WM_APP+1) 3 | #define WM_PROCESSTERMINATED (WM_APP+2) -------------------------------------------------------------------------------- /D3DRecorder.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3DRecorder", "D3DRecorder\D3DRecorder.vcxproj", "{CB1F9258-7424-4797-9A61-5AF2825262A2}" 5 | ProjectSection(ProjectDependencies) = postProject 6 | {340CB5F8-A80B-47A1-90D9-EC1700963CB6} = {340CB5F8-A80B-47A1-90D9-EC1700963CB6} 7 | EndProjectSection 8 | EndProject 9 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3DRecorderPlugin", "D3DRecorderPlugin\D3DRecorderPlugin.vcxproj", "{340CB5F8-A80B-47A1-90D9-EC1700963CB6}" 10 | EndProject 11 | Global 12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 13 | Debug|Win32 = Debug|Win32 14 | Debug|x64 = Debug|x64 15 | Release|Win32 = Release|Win32 16 | Release|x64 = Release|x64 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {CB1F9258-7424-4797-9A61-5AF2825262A2}.Debug|Win32.ActiveCfg = Debug|Win32 20 | {CB1F9258-7424-4797-9A61-5AF2825262A2}.Debug|Win32.Build.0 = Debug|Win32 21 | {CB1F9258-7424-4797-9A61-5AF2825262A2}.Debug|x64.ActiveCfg = Debug|x64 22 | {CB1F9258-7424-4797-9A61-5AF2825262A2}.Debug|x64.Build.0 = Debug|x64 23 | {CB1F9258-7424-4797-9A61-5AF2825262A2}.Release|Win32.ActiveCfg = Release|Win32 24 | {CB1F9258-7424-4797-9A61-5AF2825262A2}.Release|Win32.Build.0 = Release|Win32 25 | {CB1F9258-7424-4797-9A61-5AF2825262A2}.Release|x64.ActiveCfg = Release|x64 26 | {CB1F9258-7424-4797-9A61-5AF2825262A2}.Release|x64.Build.0 = Release|x64 27 | {340CB5F8-A80B-47A1-90D9-EC1700963CB6}.Debug|Win32.ActiveCfg = Debug|Win32 28 | {340CB5F8-A80B-47A1-90D9-EC1700963CB6}.Debug|Win32.Build.0 = Debug|Win32 29 | {340CB5F8-A80B-47A1-90D9-EC1700963CB6}.Debug|x64.ActiveCfg = Debug|x64 30 | {340CB5F8-A80B-47A1-90D9-EC1700963CB6}.Debug|x64.Build.0 = Debug|x64 31 | {340CB5F8-A80B-47A1-90D9-EC1700963CB6}.Release|Win32.ActiveCfg = Release|Win32 32 | {340CB5F8-A80B-47A1-90D9-EC1700963CB6}.Release|Win32.Build.0 = Release|Win32 33 | {340CB5F8-A80B-47A1-90D9-EC1700963CB6}.Release|x64.ActiveCfg = Release|x64 34 | {340CB5F8-A80B-47A1-90D9-EC1700963CB6}.Release|x64.Build.0 = Release|x64 35 | EndGlobalSection 36 | GlobalSection(SolutionProperties) = preSolution 37 | HideSolutionNode = FALSE 38 | EndGlobalSection 39 | EndGlobal 40 | -------------------------------------------------------------------------------- /D3DRecorder/D3DRecorder.cpp: -------------------------------------------------------------------------------- 1 | 2 | // D3DRecorder.cpp : Defines the class behaviors for the application. 3 | // 4 | 5 | #include "stdafx.h" 6 | #include "D3DRecorder.h" 7 | #include "D3DRecorderDlg.h" 8 | #include "HookEngine.h" 9 | 10 | using namespace Deviare2; 11 | 12 | #ifdef _DEBUG 13 | #define new DEBUG_NEW 14 | #endif 15 | 16 | 17 | // CD3DRecorderApp 18 | 19 | BEGIN_MESSAGE_MAP(CD3DRecorderApp, CWinApp) 20 | ON_COMMAND(ID_HELP, &CWinApp::OnHelp) 21 | END_MESSAGE_MAP() 22 | 23 | 24 | // CD3DRecorderApp construction 25 | 26 | CD3DRecorderApp::CD3DRecorderApp() 27 | { 28 | 29 | } 30 | 31 | 32 | // The one and only CD3DRecorderApp object 33 | 34 | CD3DRecorderApp theApp; 35 | 36 | 37 | // CD3DRecorderApp initialization 38 | 39 | BOOL CD3DRecorderApp::InitInstance() 40 | { 41 | CoInitializeEx(0,COINIT_MULTITHREADED); 42 | 43 | m_pHookEngine = new CHookEngine; 44 | 45 | if (m_pHookEngine->Initialize()) 46 | { 47 | INITCOMMONCONTROLSEX InitCtrls; 48 | InitCtrls.dwSize = sizeof(InitCtrls); 49 | InitCtrls.dwICC = ICC_WIN95_CLASSES; 50 | InitCommonControlsEx(&InitCtrls); 51 | 52 | CWinApp::InitInstance(); 53 | 54 | CShellManager *pShellManager = new CShellManager; 55 | 56 | CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows)); 57 | 58 | SetRegistryKey(_T("Nektra")); 59 | 60 | CD3DRecorderDlg dlg; 61 | m_pMainWnd = &dlg; 62 | INT_PTR nResponse = dlg.DoModal(); 63 | if (nResponse == IDOK) 64 | { 65 | // TODO: Place code here to handle when the dialog is 66 | // dismissed with OK 67 | } 68 | else if (nResponse == IDCANCEL) 69 | { 70 | // TODO: Place code here to handle when the dialog is 71 | // dismissed with Cancel 72 | } 73 | else if (nResponse == -1) 74 | { 75 | TRACE(traceAppMsg, 0, "Warning: dialog creation failed, so application is terminating unexpectedly.\n"); 76 | TRACE(traceAppMsg, 0, "Warning: if you are using MFC controls on the dialog, you cannot #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS.\n"); 77 | } 78 | 79 | // Delete the shell manager created above. 80 | if (pShellManager != NULL) 81 | { 82 | delete pShellManager; 83 | } 84 | 85 | } 86 | else 87 | TRACE("Initialization Failed, exiting...\n"); 88 | 89 | // Since the dialog has been closed, return FALSE so that we exit the 90 | // application, rather than start the application's message pump. 91 | 92 | if (m_pHookEngine) 93 | { 94 | delete m_pHookEngine; 95 | } 96 | 97 | CoUninitialize(); 98 | 99 | return FALSE; 100 | } 101 | 102 | -------------------------------------------------------------------------------- /D3DRecorder/D3DRecorder.h: -------------------------------------------------------------------------------- 1 | 2 | // D3DRecorder.h : main header file for the PROJECT_NAME application 3 | // 4 | 5 | #pragma once 6 | 7 | #ifndef __AFXWIN_H__ 8 | #error "include 'stdafx.h' before including this file for PCH" 9 | #endif 10 | 11 | #include "resource.h" // main symbols 12 | 13 | class CHookEngine; 14 | 15 | // CD3DRecorderApp: 16 | // See D3DRecorder.cpp for the implementation of this class 17 | // 18 | 19 | #include "../Common/wm.h" 20 | class CD3DRecorderApp : public CWinApp 21 | { 22 | public: 23 | CD3DRecorderApp(); 24 | 25 | // Overrides 26 | public: 27 | virtual BOOL InitInstance(); 28 | 29 | CHookEngine* GetHookEngine() const { return m_pHookEngine; } 30 | 31 | // Implementation 32 | 33 | DECLARE_MESSAGE_MAP() 34 | private: 35 | CHookEngine* m_pHookEngine; 36 | }; 37 | 38 | extern CD3DRecorderApp theApp; -------------------------------------------------------------------------------- /D3DRecorder/D3DRecorder.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nektra/AVRecorderTool/ab52af635403646167b1e64d3160537fb8d52c58/D3DRecorder/D3DRecorder.rc -------------------------------------------------------------------------------- /D3DRecorder/D3DRecorder.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {CB1F9258-7424-4797-9A61-5AF2825262A2} 23 | D3DRecorder 24 | MFCProj 25 | 26 | 27 | 28 | Application 29 | true 30 | v110 31 | Unicode 32 | Static 33 | 34 | 35 | Application 36 | true 37 | v110 38 | Unicode 39 | Static 40 | 41 | 42 | Application 43 | false 44 | v110 45 | true 46 | Unicode 47 | Static 48 | 49 | 50 | Application 51 | false 52 | v110 53 | true 54 | Unicode 55 | Static 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Use 88 | Level3 89 | Disabled 90 | WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) 91 | true 92 | 93 | 94 | Windows 95 | true 96 | 97 | 98 | false 99 | true 100 | _DEBUG;%(PreprocessorDefinitions) 101 | 102 | 103 | 0x0409 104 | _DEBUG;%(PreprocessorDefinitions) 105 | $(IntDir);%(AdditionalIncludeDirectories) 106 | 107 | 108 | 109 | 110 | Use 111 | Level3 112 | Disabled 113 | WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) 114 | true 115 | 116 | 117 | Windows 118 | true 119 | 120 | 121 | false 122 | _DEBUG;%(PreprocessorDefinitions) 123 | 124 | 125 | 0x0409 126 | _DEBUG;%(PreprocessorDefinitions) 127 | $(IntDir);%(AdditionalIncludeDirectories) 128 | 129 | 130 | 131 | 132 | Level3 133 | Use 134 | MaxSpeed 135 | true 136 | true 137 | WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) 138 | true 139 | 140 | 141 | Windows 142 | true 143 | true 144 | true 145 | 146 | 147 | false 148 | true 149 | NDEBUG;%(PreprocessorDefinitions) 150 | 151 | 152 | 0x0409 153 | NDEBUG;%(PreprocessorDefinitions) 154 | $(IntDir);%(AdditionalIncludeDirectories) 155 | 156 | 157 | 158 | 159 | Level3 160 | Use 161 | MaxSpeed 162 | true 163 | true 164 | WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) 165 | true 166 | 167 | 168 | Windows 169 | true 170 | true 171 | true 172 | 173 | 174 | false 175 | NDEBUG;%(PreprocessorDefinitions) 176 | 177 | 178 | 0x0409 179 | NDEBUG;%(PreprocessorDefinitions) 180 | $(IntDir);%(AdditionalIncludeDirectories) 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | Create 201 | Create 202 | Create 203 | Create 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | -------------------------------------------------------------------------------- /D3DRecorder/D3DRecorder.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | 64 | 65 | Resource Files 66 | 67 | 68 | 69 | 70 | Resource Files 71 | 72 | 73 | 74 | 75 | Resource Files 76 | 77 | 78 | -------------------------------------------------------------------------------- /D3DRecorder/D3DRecorderDlg.cpp: -------------------------------------------------------------------------------- 1 | 2 | // D3DRecorderDlg.cpp : implementation file 3 | // 4 | 5 | #include "stdafx.h" 6 | #include "HookEngine.h" 7 | #include "D3DRecorder.h" 8 | #include "D3DRecorderDlg.h" 9 | #include "afxdialogex.h" 10 | #include "../Common/ipc.h" 11 | 12 | #ifdef _DEBUG 13 | #define new DEBUG_NEW 14 | #endif 15 | 16 | 17 | // CAboutDlg dialog used for App About 18 | 19 | class CAboutDlg : public CDialogEx 20 | { 21 | public: 22 | CAboutDlg(); 23 | 24 | // Dialog Data 25 | enum { IDD = IDD_ABOUTBOX }; 26 | 27 | protected: 28 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support 29 | 30 | // Implementation 31 | protected: 32 | DECLARE_MESSAGE_MAP() 33 | }; 34 | 35 | CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD) 36 | { 37 | } 38 | 39 | void CAboutDlg::DoDataExchange(CDataExchange* pDX) 40 | { 41 | CDialogEx::DoDataExchange(pDX); 42 | } 43 | 44 | BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) 45 | END_MESSAGE_MAP() 46 | 47 | 48 | // CD3DRecorderDlg dialog 49 | 50 | 51 | 52 | CD3DRecorderDlg::CD3DRecorderDlg(CWnd* pParent /*=NULL*/) 53 | : CDialogEx(CD3DRecorderDlg::IDD, pParent) 54 | { 55 | m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 56 | } 57 | 58 | void CD3DRecorderDlg::DoDataExchange(CDataExchange* pDX) 59 | { 60 | CDialogEx::DoDataExchange(pDX); 61 | DDX_Control(pDX, IDC_TARGETBINARYFILE, m_browseCtrl); 62 | DDX_Control(pDX, IDC_TARGETFOLDER, m_browseFolder); 63 | DDX_Control(pDX, IDC_LAUNCH, m_btnLaunch); 64 | // DDX_Text(pDX, IDC_STATUSTEXT, m_statusText); 65 | DDX_Control(pDX, IDC_STATUSTEXT, m_statusText); 66 | } 67 | 68 | BEGIN_MESSAGE_MAP(CD3DRecorderDlg, CDialogEx) 69 | ON_WM_SYSCOMMAND() 70 | ON_WM_PAINT() 71 | ON_WM_QUERYDRAGICON() 72 | ON_BN_CLICKED(IDC_LAUNCH, &CD3DRecorderDlg::OnBnClickedLaunch) 73 | ON_MESSAGE(WM_IPCMESSAGE, OnIPCMessage) 74 | ON_MESSAGE(WM_PROCESSTERMINATED, OnProcessTerminated) 75 | END_MESSAGE_MAP() 76 | 77 | 78 | // CD3DRecorderDlg message handlers 79 | 80 | BOOL CD3DRecorderDlg::OnInitDialog() 81 | { 82 | CDialogEx::OnInitDialog(); 83 | 84 | // Add "About..." menu item to system menu. 85 | 86 | // IDM_ABOUTBOX must be in the system command range. 87 | ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 88 | ASSERT(IDM_ABOUTBOX < 0xF000); 89 | 90 | CMenu* pSysMenu = GetSystemMenu(FALSE); 91 | if (pSysMenu != NULL) 92 | { 93 | BOOL bNameValid; 94 | CString strAboutMenu; 95 | bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); 96 | ASSERT(bNameValid); 97 | if (!strAboutMenu.IsEmpty()) 98 | { 99 | pSysMenu->AppendMenu(MF_SEPARATOR); 100 | pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 101 | } 102 | } 103 | 104 | // Set the icon for this dialog. The framework does this automatically 105 | // when the application's main window is not a dialog 106 | SetIcon(m_hIcon, TRUE); // Set big icon 107 | SetIcon(m_hIcon, FALSE); // Set small icon 108 | 109 | m_browseCtrl.EnableFileBrowseButton(L".exe", L"Executable files (*.exe)|*.exe"); 110 | 111 | m_browseCtrl.SetWindowText(theApp.GetProfileString(L"Configuration", L"LastLaunch")); 112 | m_browseFolder.SetWindowTextW(theApp.GetProfileString(L"Configuration", L"OutputFolder")); 113 | 114 | m_statusText.SetWindowText(L"Stopped"); 115 | 116 | 117 | return TRUE; // return TRUE unless you set the focus to a control 118 | } 119 | 120 | void CD3DRecorderDlg::OnSysCommand(UINT nID, LPARAM lParam) 121 | { 122 | if ((nID & 0xFFF0) == IDM_ABOUTBOX) 123 | { 124 | CAboutDlg dlgAbout; 125 | dlgAbout.DoModal(); 126 | } 127 | else 128 | { 129 | CDialogEx::OnSysCommand(nID, lParam); 130 | } 131 | } 132 | 133 | // If you add a minimize button to your dialog, you will need the code below 134 | // to draw the icon. For MFC applications using the document/view model, 135 | // this is automatically done for you by the framework. 136 | 137 | void CD3DRecorderDlg::OnPaint() 138 | { 139 | if (IsIconic()) 140 | { 141 | CPaintDC dc(this); // device context for painting 142 | 143 | SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); 144 | 145 | // Center icon in client rectangle 146 | int cxIcon = GetSystemMetrics(SM_CXICON); 147 | int cyIcon = GetSystemMetrics(SM_CYICON); 148 | CRect rect; 149 | GetClientRect(&rect); 150 | int x = (rect.Width() - cxIcon + 1) / 2; 151 | int y = (rect.Height() - cyIcon + 1) / 2; 152 | 153 | // Draw the icon 154 | dc.DrawIcon(x, y, m_hIcon); 155 | } 156 | else 157 | { 158 | CDialogEx::OnPaint(); 159 | } 160 | } 161 | 162 | // The system calls this function to obtain the cursor to display while the user drags 163 | // the minimized window. 164 | HCURSOR CD3DRecorderDlg::OnQueryDragIcon() 165 | { 166 | return static_cast(m_hIcon); 167 | } 168 | 169 | void CD3DRecorderDlg::OnBnClickedLaunch() 170 | { 171 | CString strFilename, strFolder; 172 | m_browseCtrl.GetWindowText(strFilename); 173 | m_browseFolder.GetWindowText(strFolder); 174 | 175 | CFileStatus fs; 176 | 177 | if (!CFile::GetStatus(strFilename.GetBuffer(), fs)) 178 | { 179 | ::AfxMessageBox(L"Cannot open target executable file", MB_ICONERROR); 180 | return; 181 | } 182 | 183 | if (!CFile::GetStatus(strFolder.GetBuffer(), fs)) 184 | { 185 | ::AfxMessageBox(L"Cannot open target folder for capture data", MB_ICONERROR); 186 | return; 187 | } 188 | 189 | theApp.WriteProfileString(L"Configuration", L"LastLaunch", strFilename); 190 | theApp.WriteProfileString(L"Configuration", L"OutputFolder", strFolder); 191 | 192 | // Try to launch this process thorugh SpyMgr. 193 | 194 | CHookEngine* pHookEngine = theApp.GetHookEngine(); 195 | 196 | if (pHookEngine->CreatePipeServer(GetSafeHwnd())) // Pass this HWND for interthread messaging 197 | { 198 | if (pHookEngine->LaunchProcess(strFilename)) 199 | { 200 | pHookEngine->SetParentDialog(this->GetSafeHwnd()); 201 | m_btnLaunch.EnableWindow(0); 202 | m_statusText.SetWindowTextW(L"Process is running..."); 203 | pHookEngine->HookD3D9Creation(); 204 | pHookEngine->ResumeProcess(); 205 | } 206 | } 207 | } 208 | 209 | LRESULT CD3DRecorderDlg::OnIPCMessage(WPARAM wParam,LPARAM) 210 | { 211 | IPCMESSAGE* pMsg = (IPCMESSAGE*)wParam; 212 | ASSERT(pMsg); 213 | 214 | TRACE("Unknown IPC message!"); 215 | 216 | delete pMsg; 217 | pMsg = NULL; 218 | return 0L; 219 | } 220 | 221 | LRESULT CD3DRecorderDlg::OnProcessTerminated(WPARAM,LPARAM) 222 | { 223 | 224 | m_statusText.SetWindowText(L"Stopped."); 225 | m_btnLaunch.EnableWindow(1); 226 | return 0L; 227 | } -------------------------------------------------------------------------------- /D3DRecorder/D3DRecorderDlg.h: -------------------------------------------------------------------------------- 1 | 2 | // D3DRecorderDlg.h : header file 3 | // 4 | 5 | #pragma once 6 | #include "afxeditbrowsectrl.h" 7 | #include "afxwin.h" 8 | 9 | struct IPCMESSAGE; 10 | 11 | // CD3DRecorderDlg dialog 12 | class CD3DRecorderDlg : public CDialogEx 13 | { 14 | // Construction 15 | public: 16 | CD3DRecorderDlg(CWnd* pParent = NULL); // standard constructor 17 | 18 | // Dialog Data 19 | enum { IDD = IDD_D3DRECORDER_DIALOG }; 20 | 21 | protected: 22 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support 23 | 24 | 25 | // Implementation 26 | protected: 27 | HICON m_hIcon; 28 | 29 | // Generated message map functions 30 | virtual BOOL OnInitDialog(); 31 | afx_msg void OnSysCommand(UINT nID, LPARAM lParam); 32 | afx_msg void OnPaint(); 33 | afx_msg HCURSOR OnQueryDragIcon(); 34 | DECLARE_MESSAGE_MAP() 35 | public: 36 | CMFCEditBrowseCtrl m_browseCtrl; 37 | afx_msg void OnBnClickedLaunch(); 38 | afx_msg LRESULT OnIPCMessage(WPARAM,LPARAM); 39 | afx_msg void OnEnChangeTargetfolder(); 40 | afx_msg LRESULT OnProcessTerminated(WPARAM,LPARAM); 41 | CMFCEditBrowseCtrl m_browseFolder; 42 | CButton m_btnLaunch; 43 | // CString m_statusText; 44 | CStatic m_statusText; 45 | }; 46 | -------------------------------------------------------------------------------- /D3DRecorder/HookEngine.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "SpyMgrEventSink.h" 3 | #include "HookEngine.h" 4 | #include "PipeServer.h" 5 | #include "../Common/utils.h" 6 | #include "../Common/wm.h" 7 | 8 | using namespace Deviare2; 9 | 10 | CHookEngine::CHookEngine(HWND hDlg) : m_hParent(hDlg), 11 | m_dwCookie(0), 12 | m_pTargetProc(0), 13 | m_pipeThread(NULL), 14 | m_createDeviceHookReady(false) 15 | { 16 | } 17 | 18 | BOOL CHookEngine::LoadLicenseKey(char** ppLicenseBuf) 19 | { 20 | wchar_t dir[MAX_PATH]; 21 | GetCurrentDirectory(MAX_PATH, dir); 22 | 23 | try 24 | { 25 | CFile licenseFile(L"license.txt", CFile::modeRead); 26 | const ULONGLONG cch = licenseFile.GetLength(); 27 | 28 | *ppLicenseBuf = new char[(UINT)cch+1]; 29 | 30 | licenseFile.Read(*ppLicenseBuf, (UINT)cch+1); 31 | return TRUE; 32 | } 33 | catch (CFileException* e) 34 | { 35 | wchar_t errData[400]; 36 | e->GetErrorMessage(errData, 400, 0); 37 | d_printf(L"%s Exception loading license file: %s\\%s \n", __FUNCTIONW__,dir, errData); 38 | return FALSE; 39 | } 40 | 41 | } 42 | 43 | BOOL CHookEngine::Initialize() 44 | { 45 | HRESULT hr; 46 | 47 | if (SUCCEEDED(hr = m_pSpyMgr.CreateInstance(__uuidof(NktSpyMgr)))) 48 | { 49 | char* szLicense; 50 | BOOL b = LoadLicenseKey(&szLicense); 51 | 52 | if (!b) 53 | { 54 | d_printf(L"Cannot open license file, loading without Deviare license.\n"); 55 | } 56 | else 57 | { 58 | d_printf(L"Using license from file\n"); 59 | m_pSpyMgr->put_LicenseKey(_bstr_t(szLicense)); 60 | delete[] szLicense; 61 | } 62 | 63 | long ret; 64 | hr = m_pSpyMgr->Initialize(&ret); 65 | if (SUCCEEDED(hr) && ret == 0) 66 | { 67 | m_pSink = new CSpyMgrEventSink(this); 68 | 69 | TRACE("HookEngine successfully initialized.\n"); 70 | return TRUE; 71 | } 72 | else 73 | { 74 | TRACE("HookEngine initialization error. HR=0x%08x RC=%d\n", hr, ret); 75 | } 76 | } 77 | else 78 | { 79 | TRACE("Cannot instance SpyMgr. HR=0x%08x\n",hr); 80 | } 81 | 82 | return FALSE; 83 | } 84 | BOOL CHookEngine::CreatePipeServer(HWND hwndParentNotify) 85 | { 86 | InterlockedExchange(&g_killServer, 0); 87 | m_pipeThread = AfxBeginThread(CPipeServer::threadProc, (LPVOID) hwndParentNotify); 88 | return (m_pipeThread != NULL); 89 | } 90 | 91 | void CHookEngine::TerminatePipeServer() 92 | { 93 | InterlockedExchange(&g_killServer, 1); 94 | 95 | if (m_pipeThread) 96 | { 97 | WaitForSingleObject(m_pipeThread->m_hThread, INFINITE); 98 | } 99 | } 100 | 101 | BOOL CHookEngine::LaunchProcess(const CString& fn) 102 | { 103 | ASSERT(m_pSpyMgr); 104 | 105 | wchar_t szDir[MAX_PATH]; 106 | StringCchCopy(szDir, MAX_PATH, fn); 107 | PathRemoveFileSpec(szDir); 108 | 109 | wchar_t szCurDir[MAX_PATH]; 110 | 111 | GetCurrentDirectory(MAX_PATH, szCurDir); 112 | SetCurrentDirectory(szDir); 113 | 114 | HRESULT hr = m_pSpyMgr->__CreateProcess(_bstr_t(fn), VARIANT_TRUE, 115 | &m_vaContinueEvent, &m_pTargetProc); 116 | 117 | if (FAILED(hr)) 118 | { 119 | TRACE("Process Launch failed for target binary: %s. HR=0x%08x\n",fn, hr); 120 | } 121 | else 122 | { 123 | // Keep informaed for events 124 | // 125 | SetCurrentDirectory(szCurDir); 126 | 127 | ASSERT(m_pSink); 128 | 129 | if (!m_dwCookie) 130 | { 131 | AfxConnectionAdvise(m_pSpyMgr, DIID_DNktSpyMgrEvents, m_pSink->GetIDispatch(FALSE), FALSE, &m_dwCookie); 132 | } 133 | } 134 | 135 | return SUCCEEDED(hr); 136 | } 137 | 138 | void CHookEngine::GetDllHandlerName(wchar_t* buf, size_t cchBuf) 139 | { 140 | GetModuleFileName(AfxGetInstanceHandle(), buf, (DWORD) cchBuf); 141 | PathRemoveFileSpec(buf); 142 | StringCchCat(buf, cchBuf, PLUGIN_DLLNAME); 143 | } 144 | 145 | void CHookEngine::ResumeProcess() 146 | { 147 | m_pSpyMgr->ResumeProcess(m_pTargetProc, m_vaContinueEvent); 148 | } 149 | 150 | BOOL CHookEngine::HookD3D9Creation() 151 | { 152 | INktHookPtr pD3DCreate9Hook; 153 | 154 | if (SUCCEEDED(m_pSpyMgr->CreateHook(_variant_t("d3d9.dll!Direct3DCreate9"), eNktHookFlags::flgOnlyPostCall, 155 | &pD3DCreate9Hook))) 156 | { 157 | long PID; 158 | m_pTargetProc->get_Id(&PID); 159 | pD3DCreate9Hook->Attach(_variant_t(PID), FALSE); 160 | pD3DCreate9Hook->Hook(FALSE); 161 | 162 | m_hookSet.insert(pD3DCreate9Hook); 163 | 164 | return TRUE; 165 | } 166 | 167 | return FALSE; 168 | } 169 | 170 | void CHookEngine::OnCall_Direct3DCreate9(__in Deviare2::INktHook *Hook, __in Deviare2::INktProcess *proc, 171 | __in Deviare2::INktHookCallInfo *callInfo) 172 | { 173 | d_printf(L"%s\n",__FUNCTIONW__); 174 | 175 | DEVIAREPTR pVal; 176 | 177 | INktParamPtr pResult; 178 | callInfo->Result(&pResult); 179 | pResult->get_PointerVal(&pVal); 180 | 181 | // We got a IDirect3D9 ptr. Now hook CreateDevice by Indexing vtable. 182 | // 183 | 184 | INktProcessMemoryPtr pMem; 185 | proc->Memory(&pMem); 186 | 187 | DEVIAREPTR lpD3D9_VT; 188 | pMem->get_SSizeTVal(pVal, &lpD3D9_VT); 189 | 190 | if (lpD3D9_VT) 191 | { 192 | DEVIAREPTR lpMethodAddr; 193 | pMem->get_SSizeTVal((DEVIAREPTR) 194 | (lpD3D9_VT + VTI_IDirect3D9::CreateDevice * sizeof(DEVIAREPTR)), &lpMethodAddr); 195 | 196 | if (lpMethodAddr) 197 | { 198 | INktHookPtr pHook; 199 | 200 | m_pSpyMgr->CreateHookForAddress(lpMethodAddr, 201 | _bstr_t(L"IDirect3D9::CreateDevice"), 202 | eNktHookFlags::flgOnlyPostCall, 203 | &pHook); 204 | 205 | long PID; 206 | proc->get_Id(&PID); 207 | _variant_t vPID(PID); 208 | 209 | wchar_t handlerDllName[MAX_PATH]; 210 | GetDllHandlerName(handlerDllName, MAX_PATH); 211 | 212 | // Add a remote handler for initialization. 213 | pHook->AddCustomHandler(handlerDllName, eNktHookCustomHandlerFlags::flgChDisableExceptionChecks, L""); 214 | 215 | pHook->Hook(TRUE); 216 | pHook->Attach(vPID, TRUE); 217 | 218 | m_hookSet.insert(pHook); 219 | } 220 | } 221 | } 222 | 223 | void CHookEngine::OnCall_IDirect3D9_CreateDevice(__in Deviare2::INktHook *Hook, __in Deviare2::INktProcess *proc, 224 | __in Deviare2::INktHookCallInfo *callInfo) 225 | { 226 | d_printf(L"%s\n",__FUNCTIONW__); 227 | 228 | 229 | 230 | INktParamsEnumPtr pParams; 231 | callInfo->Params(&pParams); 232 | 233 | // 234 | // Ensure hooking for hardware-rasterizer ONLY 235 | // 236 | 237 | INktParamPtr pParamDevType; 238 | pParams->GetAt(2, &pParamDevType); 239 | long devType; 240 | pParamDevType->get_LongVal(&devType); 241 | 242 | if (devType != D3DDEVTYPE_HAL) 243 | { 244 | d_printf(L"WARNING! %s: Ignoring hooks for device type D3DDEVTYPE=%d\n",__FUNCTIONW__,devType); 245 | return; 246 | } 247 | 248 | // 249 | // Get IDirect3DDevice9 ptr and hook Reset/EndScene/Present by Indexing vtable. 250 | // 251 | INktParamPtr pParamD3DDevice; 252 | pParams->GetAt(6, &pParamD3DDevice); 253 | pParamD3DDevice->Evaluate(&pParamD3DDevice); 254 | 255 | DEVIAREPTR pD3DDevice; 256 | pParamD3DDevice->get_PointerVal(&pD3DDevice); 257 | 258 | INktProcessMemoryPtr pMem; 259 | proc->Memory(&pMem); 260 | 261 | DEVIAREPTR lpD3DDevice9_VT; 262 | pMem->get_SSizeTVal(pD3DDevice, &lpD3DDevice9_VT); 263 | 264 | // 265 | // Ensure we hook this VTable addresses once 266 | // 267 | 268 | if (!m_createDeviceHookReady) 269 | { 270 | if (lpD3DDevice9_VT) 271 | { 272 | wchar_t handlerDllName[MAX_PATH]; 273 | GetDllHandlerName(handlerDllName, MAX_PATH); 274 | HookInterfaceMethod(proc, lpD3DDevice9_VT, VTI_IDirect3D9Device::Release, L"IDirect3DDevice9::Release", handlerDllName); 275 | HookInterfaceMethod(proc, lpD3DDevice9_VT, VTI_IDirect3D9Device::EndScene, L"IDirect3DDevice9::EndScene", handlerDllName); 276 | HookInterfaceMethod(proc, lpD3DDevice9_VT, VTI_IDirect3D9Device::Present, L"IDirect3DDevice9::Present", handlerDllName); 277 | HookInterfaceMethod(proc, lpD3DDevice9_VT, VTI_IDirect3D9Device::Reset, L"IDirect3DDevice9::Reset", handlerDllName); 278 | 279 | m_createDeviceHookReady = true; 280 | } 281 | } 282 | else 283 | { 284 | d_printf(L"Already hooked IDirect3DDevice9 method addresses.\n"); 285 | } 286 | } 287 | 288 | BOOL CHookEngine::HookInterfaceMethod(Deviare2::INktProcessPtr proc, 289 | DEVIAREPTR pIF, 290 | int idx, 291 | const wchar_t* fqname, 292 | const wchar_t* handlerDll) 293 | { 294 | INktProcessMemoryPtr pMem; 295 | proc->Memory(&pMem); 296 | 297 | DEVIAREPTR lpMethodAddr; 298 | HRESULT hr = E_FAIL; 299 | 300 | pMem->get_SSizeTVal((DEVIAREPTR)(pIF + idx * sizeof(DEVIAREPTR)), &lpMethodAddr); 301 | 302 | if (lpMethodAddr) 303 | { 304 | INktHookPtr pHook; 305 | 306 | if (SUCCEEDED(hr = m_pSpyMgr->CreateHookForAddress(lpMethodAddr, _bstr_t(fqname), 0, &pHook))) 307 | { 308 | if (handlerDll) 309 | { 310 | pHook->AddCustomHandler(_bstr_t(handlerDll), 311 | eNktHookCustomHandlerFlags::flgChDisableExceptionChecks, L""); 312 | } 313 | 314 | long vPID; 315 | proc->get_Id(&vPID); 316 | 317 | pHook->Hook(TRUE); 318 | pHook->Attach(_variant_t(vPID), TRUE); 319 | 320 | m_hookSet.insert(pHook); 321 | } 322 | else 323 | { 324 | d_printf(L"CreateHookForAddress for method %s failed HR=0x%08x.", fqname, hr); 325 | } 326 | } 327 | 328 | return SUCCEEDED(hr); 329 | } 330 | 331 | void CHookEngine::UnhookAll() 332 | { 333 | if (m_pTargetProc) 334 | { 335 | long pid; 336 | m_pTargetProc->get_Id(&pid); 337 | 338 | for (auto it = m_hookSet.begin(); it != m_hookSet.end(); it++) 339 | { 340 | CComBSTR fName; 341 | (*it)->get_FunctionName(&fName); 342 | 343 | d_printf(L"UnhookAll> Unhooking function %s...\n", fName); 344 | 345 | (*it)->Detach(_variant_t(pid), TRUE); 346 | (*it)->Unhook(TRUE); 347 | m_pSpyMgr->DestroyHook(*it); 348 | } 349 | 350 | m_hookSet.clear(); 351 | } 352 | } 353 | 354 | CHookEngine::~CHookEngine(void) 355 | { 356 | TerminatePipeServer(); 357 | UnhookAll(); 358 | 359 | AfxConnectionUnadvise(m_pSpyMgr, DIID_DNktSpyMgrEvents, m_pSink->GetIDispatch(FALSE), FALSE, m_dwCookie); 360 | m_dwCookie = 0; 361 | delete m_pSink; 362 | } 363 | 364 | void CHookEngine::OnProcessTerminated(Deviare2::INktProcess* proc) 365 | { 366 | long thisPID, runningPID; 367 | 368 | proc->get_Id(&thisPID); 369 | m_pTargetProc->get_Id(&runningPID); 370 | 371 | if (thisPID == runningPID) 372 | { 373 | TerminatePipeServer(); 374 | UnhookAll(); 375 | m_createDeviceHookReady = false; 376 | 377 | SendMessage(m_hParent, WM_PROCESSTERMINATED, 0 ,0); 378 | 379 | 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /D3DRecorder/HookEngine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.h" 3 | 4 | #ifdef _M_IX86 5 | #define PLUGIN_DLLNAME L"\\D3DRecorderPlugin.dll" 6 | #define AUDIOSESSHOST_DLLNAME L"\\AudioSessionHost.dll" 7 | #define DEVIAREPTR long 8 | #elif defined _M_X64 9 | #define PLUGIN_DLLNAME L"\\D3DRecorderPlugin64.dll" 10 | #define AUDIOSESSHOST_DLLNAME L"\\AudioSessionHost64.dll" 11 | #define DEVIAREPTR __int64 12 | #endif 13 | 14 | class CSpyMgrEventSink; 15 | 16 | class CHookEngine 17 | { 18 | Deviare2::INktSpyMgrPtr m_pSpyMgr; 19 | Deviare2::INktProcessPtr m_pTargetProc; 20 | DWORD m_dwCookie; 21 | _variant_t m_vaContinueEvent; 22 | CSpyMgrEventSink* m_pSink; 23 | HWND m_hParent; 24 | CWinThread* m_pipeThread; 25 | 26 | bool m_createDeviceHookReady; 27 | 28 | std::map m_methodAddrMap; 29 | std::set m_hookSet; 30 | 31 | void GetDllHandlerName(wchar_t* buf, size_t cchBuf); 32 | void GetAudioSessionHostDllName(wchar_t* buf, size_t cchBuf); 33 | 34 | BOOL HookInterfaceMethod(Deviare2::INktProcessPtr proc, 35 | DEVIAREPTR pIF, 36 | int idx, 37 | const wchar_t* fqname, 38 | const wchar_t* handlerDll); 39 | 40 | public: 41 | CHookEngine(HWND hDlg = NULL); 42 | ~CHookEngine(void); 43 | 44 | BOOL Initialize(); 45 | BOOL LoadLicenseKey(char**); 46 | BOOL LaunchProcess(const CString& fn); 47 | BOOL CreatePipeServer(HWND hwndParentNotify); 48 | void TerminatePipeServer(); 49 | BOOL LoadCustomDll(); 50 | BOOL HookD3D9Creation(); 51 | BOOL HookAudioSession(); 52 | void ResumeProcess(); 53 | void UnhookAll(); 54 | void HookRemoteMethodAddress(const CString&, DWORD_PTR pAddr); 55 | void SetParentDialog (HWND hWnd) { m_hParent = hWnd; } 56 | 57 | // Received from event sink 58 | 59 | void OnCall_Direct3DCreate9(__in Deviare2::INktHook *Hook, __in Deviare2::INktProcess *proc, 60 | __in Deviare2::INktHookCallInfo *callInfo); 61 | 62 | void OnCall_IDirect3D9_CreateDevice(__in Deviare2::INktHook *Hook, __in Deviare2::INktProcess *proc, 63 | __in Deviare2::INktHookCallInfo *callInfo); 64 | 65 | void OnProcessTerminated(Deviare2::INktProcess* p); 66 | }; 67 | 68 | -------------------------------------------------------------------------------- /D3DRecorder/PipeServer.cpp: -------------------------------------------------------------------------------- 1 | // PipeServer.cpp : implementation file 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "D3DRecorder.h" 6 | #include "PipeServer.h" 7 | 8 | HANDLE CPipeServer::_hPipe = NULL; 9 | 10 | volatile LONG g_killServer; 11 | 12 | CPipeServer::CPipeServer() 13 | { 14 | 15 | } 16 | 17 | CPipeServer::~CPipeServer() 18 | { 19 | if (_hPipe) 20 | CloseHandle(_hPipe); 21 | } 22 | 23 | UINT CPipeServer::threadProc(LPVOID lParam) 24 | { 25 | _hPipe = CreateNamedPipe(D3DRECORDER_PIPENAME, 26 | PIPE_ACCESS_DUPLEX, 27 | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 28 | PIPE_UNLIMITED_INSTANCES | PIPE_WAIT, 29 | IPCMESSAGESIZE*2, 30 | IPCMESSAGESIZE*2, 31 | NMPWAIT_WAIT_FOREVER, 32 | NULL); 33 | 34 | if (_hPipe != INVALID_HANDLE_VALUE) 35 | { 36 | TRACE("Named Pipe Creation successful. Waiting for connection...\n"); 37 | 38 | ConnectNamedPipe(_hPipe, NULL); 39 | 40 | IPCMESSAGE msg; 41 | DWORD dwRead; 42 | 43 | while (g_killServer == 0) 44 | { 45 | Sleep(100); // enough to yield CPU to scheduler 46 | 47 | if (ReadFile(_hPipe, &msg, IPCMESSAGESIZE, &dwRead, NULL)) 48 | { 49 | IPCMESSAGE* pMsg = new IPCMESSAGE; 50 | RtlCopyMemory((LPVOID)pMsg, &msg, sizeof(IPCMESSAGE)); 51 | 52 | SendMessage((HWND) lParam, WM_IPCMESSAGE, (WPARAM) pMsg, 0); 53 | } 54 | } 55 | } 56 | else 57 | { 58 | TRACE("Named Pipe Creation failed. Last Error is %d\n", GetLastError()); 59 | } 60 | 61 | return TRUE; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /D3DRecorder/PipeServer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Common/ipc.h" 3 | 4 | // CPipeServer 5 | 6 | extern volatile LONG g_killServer; 7 | 8 | class CPipeServer 9 | { 10 | CPipeServer(); 11 | virtual ~CPipeServer(); 12 | 13 | public: 14 | static UINT threadProc( LPVOID pParam ); 15 | static HANDLE _hPipe; 16 | }; 17 | 18 | 19 | -------------------------------------------------------------------------------- /D3DRecorder/SpyMgrEventSink.cpp: -------------------------------------------------------------------------------- 1 | // SpyMgrEventSink.cpp : implementation file 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "D3DRecorder.h" 6 | #include "SpyMgrEventSink.h" 7 | #include "HookEngine.h" 8 | 9 | // CSpyMgrEventSink 10 | 11 | IMPLEMENT_DYNAMIC(CSpyMgrEventSink, CCmdTarget) 12 | 13 | 14 | CSpyMgrEventSink::CSpyMgrEventSink(CHookEngine* pHookEng) 15 | { 16 | ASSERT(pHookEng); 17 | 18 | m_pHookEng = pHookEng; 19 | 20 | EnableAutomation(); 21 | } 22 | 23 | CSpyMgrEventSink::~CSpyMgrEventSink() 24 | { 25 | } 26 | 27 | 28 | void CSpyMgrEventSink::OnFinalRelease() 29 | { 30 | CCmdTarget::OnFinalRelease(); 31 | } 32 | 33 | 34 | BEGIN_MESSAGE_MAP(CSpyMgrEventSink, CCmdTarget) 35 | END_MESSAGE_MAP() 36 | 37 | BEGIN_DISPATCH_MAP(CSpyMgrEventSink, CCmdTarget) 38 | DISP_FUNCTION_ID(CSpyMgrEventSink,"OnFunctionCalled",dispidNktSpyMgrEventsOnFunctionCalled,OnFunctionCalled,VT_EMPTY,VTS_UNKNOWN VTS_UNKNOWN VTS_UNKNOWN) 39 | DISP_FUNCTION_ID(CSpyMgrEventSink,"OnProcessTerminated",dispidNktSpyMgrEventsOnProcessTerminated,OnProcessTerminated,VT_EMPTY,VTS_UNKNOWN) 40 | END_DISPATCH_MAP() 41 | 42 | BEGIN_INTERFACE_MAP(CSpyMgrEventSink, CCmdTarget) 43 | INTERFACE_PART(CSpyMgrEventSink, Deviare2::DIID_DNktSpyMgrEvents, Dispatch) 44 | END_INTERFACE_MAP() 45 | 46 | 47 | // CSpyMgrEventSink message handlers 48 | 49 | void CSpyMgrEventSink::OnFunctionCalled (__in Deviare2::INktHook *Hook, __in Deviare2::INktProcess *proc, 50 | __in Deviare2::INktHookCallInfo *callInfo) 51 | { 52 | BSTR fnName; 53 | Hook->get_FunctionName(&fnName); 54 | 55 | if (_wcsicmp(fnName, L"d3d9.dll!Direct3DCreate9") == 0) 56 | { 57 | m_pHookEng->OnCall_Direct3DCreate9(Hook, proc, callInfo); 58 | } 59 | else if (_wcsicmp(fnName, L"IDirect3D9::CreateDevice") == 0) 60 | { 61 | m_pHookEng->OnCall_IDirect3D9_CreateDevice(Hook, proc, callInfo); 62 | } 63 | } 64 | 65 | void CSpyMgrEventSink::OnProcessTerminated(__in Deviare2::INktProcess* p) 66 | { 67 | m_pHookEng->OnProcessTerminated(p); 68 | } 69 | -------------------------------------------------------------------------------- /D3DRecorder/SpyMgrEventSink.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | class CHookEngine; 5 | 6 | typedef enum { 7 | dispidNktSpyMgrEventsOnCustomDllLoad = 1, 8 | dispidNktSpyMgrEventsOnCustomDllUnload, 9 | dispidNktSpyMgrEventsOnCustomApiCall, 10 | dispidNktSpyMgrEventsOnHookStateChanged, 11 | dispidNktSpyMgrEventsOnFunctionCalled, 12 | dispidNktSpyMgrEventsOnCreateProcessCall, 13 | dispidNktSpyMgrEventsOnLoadLibraryCall, 14 | dispidNktSpyMgrEventsOnFreeLibraryCall, 15 | dispidNktSpyMgrEventsOnProcessStarted, 16 | dispidNktSpyMgrEventsOnProcessTerminated, 17 | dispidNktSpyMgrEventsOnAgentLoad, 18 | dispidNktSpyMgrEventsOnAgentUnload, 19 | } eDispidNktSpyMgrEvents; 20 | 21 | 22 | // CSpyMgrEventSink command target 23 | 24 | class CSpyMgrEventSink : public CCmdTarget 25 | { 26 | DECLARE_DYNAMIC(CSpyMgrEventSink) 27 | 28 | public: 29 | CSpyMgrEventSink(CHookEngine*); 30 | virtual ~CSpyMgrEventSink(); 31 | 32 | virtual void OnFinalRelease(); 33 | 34 | protected: 35 | DECLARE_MESSAGE_MAP() 36 | DECLARE_DISPATCH_MAP() 37 | DECLARE_INTERFACE_MAP() 38 | 39 | private: 40 | 41 | CHookEngine* m_pHookEng; 42 | 43 | void OnFunctionCalled (__in Deviare2::INktHook *Hook, __in Deviare2::INktProcess *proc, __in Deviare2::INktHookCallInfo *callInfo); 44 | void OnProcessTerminated(Deviare2::INktProcess*); 45 | }; 46 | 47 | 48 | -------------------------------------------------------------------------------- /D3DRecorder/res/D3DRecorder.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nektra/AVRecorderTool/ab52af635403646167b1e64d3160537fb8d52c58/D3DRecorder/res/D3DRecorder.ico -------------------------------------------------------------------------------- /D3DRecorder/res/D3DRecorder.rc2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nektra/AVRecorderTool/ab52af635403646167b1e64d3160537fb8d52c58/D3DRecorder/res/D3DRecorder.rc2 -------------------------------------------------------------------------------- /D3DRecorder/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nektra/AVRecorderTool/ab52af635403646167b1e64d3160537fb8d52c58/D3DRecorder/resource.h -------------------------------------------------------------------------------- /D3DRecorder/stdafx.cpp: -------------------------------------------------------------------------------- 1 | 2 | // stdafx.cpp : source file that includes just the standard includes 3 | // D3DRecorder.pch will be the pre-compiled header 4 | // stdafx.obj will contain the pre-compiled type information 5 | 6 | #include "stdafx.h" 7 | 8 | 9 | -------------------------------------------------------------------------------- /D3DRecorder/stdafx.h: -------------------------------------------------------------------------------- 1 | 2 | // stdafx.h : include file for standard system include files, 3 | // or project specific include files that are used frequently, 4 | // but are changed infrequently 5 | 6 | #pragma once 7 | 8 | #ifndef VC_EXTRALEAN 9 | #define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers 10 | #endif 11 | 12 | #include "targetver.h" 13 | 14 | 15 | 16 | #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit 17 | 18 | // turns off MFC's hiding of some common and often safely ignored warning messages 19 | #define _AFX_ALL_WARNINGS 20 | 21 | #include // MFC core and standard components 22 | #include // MFC extensions 23 | #include 24 | 25 | #ifndef _AFX_NO_OLE_SUPPORT 26 | #include // MFC support for Internet Explorer 4 Common Controls 27 | #endif 28 | #ifndef _AFX_NO_AFXCMN_SUPPORT 29 | #include // MFC support for Windows Common Controls 30 | #endif // _AFX_NO_AFXCMN_SUPPORT 31 | 32 | #include // MFC support for ribbons and control bars 33 | 34 | // Copy Deviare COM DLLs there... 35 | // 36 | #ifdef _M_IX86 37 | #import "../dll/deviarecom.dll" raw_interfaces_only, named_guids, raw_dispinterfaces, auto_rename 38 | #elif defined _M_X64 39 | #import "../dll/deviareCom64.dll" raw_interfaces_only, named_guids, raw_dispinterfaces, auto_rename 40 | #else 41 | #error "Unsupported system architecture" 42 | #endif 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #define MAX_CCH_LICENSE_STRING 8192 50 | 51 | #ifdef _UNICODE 52 | #if defined _M_IX86 53 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") 54 | #elif defined _M_X64 55 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") 56 | #else 57 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 58 | #endif 59 | #endif 60 | 61 | 62 | -------------------------------------------------------------------------------- /D3DRecorder/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | 10 | #define _WIN32_WINNT 0x0502 11 | 12 | #include 13 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/AVIVideo.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "AVIVideo.h" 3 | #include "../Common/utils.h" 4 | 5 | #pragma comment(lib, "winmm.lib") 6 | #pragma comment(lib,"vfw32.lib") 7 | 8 | CAVIVideo::CAVIVideo(void) : 9 | _pIAVIFile(0) 10 | { 11 | AVIFileInit(); 12 | ZeroMemory(&_aviData, sizeof(AVIDATA)); 13 | } 14 | 15 | CAVIVideo::~CAVIVideo(void) 16 | { 17 | Close(); 18 | AVIFileExit(); 19 | } 20 | 21 | HRESULT CAVIVideo::Create(wchar_t* fname) 22 | { 23 | if (_pIAVIFile) 24 | { 25 | d_printf(L"%s: Still with OpenFile ref count >1, close file first.\n",__FUNCTIONW__); 26 | return AVIERR_ERROR; 27 | } 28 | else 29 | { 30 | _aviData.nFrames = 0; 31 | return AVIFileOpen(&_pIAVIFile, fname, OF_WRITE | OF_CREATE, NULL); 32 | } 33 | } 34 | 35 | void CAVIVideo::SetVideoOptions(const char codec[4], FRAMESIZE *fsz, int fps) 36 | { 37 | ZeroMemory(&_aviData.vidStreamInfo,sizeof(AVISTREAMINFO)); 38 | 39 | RECT rcFrame; 40 | SetRect(&rcFrame, 0, 0, fsz->width, fsz->height); 41 | 42 | _aviData.fourCC = mmioFOURCC(codec[0],codec[1],codec[2],codec[3]); // or 0?? 43 | 44 | _aviData.vidStreamInfo.fccType = streamtypeVIDEO; 45 | _aviData.vidStreamInfo.fccHandler = 0; 46 | _aviData.vidStreamInfo.dwScale = 1; 47 | _aviData.vidStreamInfo.dwRate = fps; 48 | _aviData.vidStreamInfo.dwSuggestedBufferSize = fsz->height * fsz->width * 4; 49 | _aviData.vidStreamInfo.dwQuality = (DWORD)-1; 50 | _aviData.vidStreamInfo.rcFrame = rcFrame; 51 | StringCchCopy(_aviData.vidStreamInfo.szName, 64, L"Nektra D3DRECORDER Video Stream"); 52 | } 53 | 54 | HRESULT CAVIVideo::GrabFrame(LPVOID pDIBFile) 55 | { 56 | if (!pDIBFile) 57 | return E_POINTER; 58 | 59 | if (!_pIAVIFile) 60 | { 61 | d_printf(L"_pIAVIFile==0\n"); 62 | return E_UNEXPECTED; 63 | } 64 | 65 | // Skip past BITMAPFILEHEADER (but check at least signature...) 66 | 67 | BITMAPFILEHEADER* pHdr = (BITMAPFILEHEADER*)pDIBFile; 68 | 69 | if (pHdr->bfType != 0x4D42) 70 | { 71 | d_printf(L"%s ERROR File header not 0x4D42\n", __FUNCTIONW__); 72 | return E_INVALIDARG; 73 | } 74 | 75 | BITMAPINFO* pBitmapInfo = (BITMAPINFO*) ((BYTE*)pDIBFile + sizeof(BITMAPFILEHEADER)); 76 | BITMAPINFOHEADER* pDibHdr = &pBitmapInfo->bmiHeader; 77 | 78 | HRESULT hr; 79 | 80 | 81 | if (_aviData.nFrames == 0) 82 | { 83 | // Create a video stream 84 | 85 | if (SUCCEEDED(hr = AVIFileCreateStream(_pIAVIFile, 86 | &_aviData.pVidStream, 87 | &_aviData.vidStreamInfo))) 88 | { 89 | AVICOMPRESSOPTIONS copt; 90 | ZeroMemory(&copt,sizeof(AVICOMPRESSOPTIONS)); 91 | 92 | AVICOMPRESSOPTIONS* pOpt[1]; 93 | pOpt[0] = &copt; 94 | 95 | //// Get default compressor options 96 | 97 | INT_PTR r = AVISaveOptions(GetDesktopWindow(), 0, 1, &_aviData.pVidStream, pOpt); 98 | 99 | if (r) 100 | { 101 | if (SUCCEEDED(hr = AVIMakeCompressedStream(&_aviData.pCompVidStream, 102 | _aviData.pVidStream, 103 | pOpt[0], 104 | NULL))) 105 | { 106 | 107 | if (FAILED(hr = AVIStreamSetFormat(_aviData.pCompVidStream, 108 | 0, 109 | pDibHdr, 110 | sizeof(BITMAPINFOHEADER)))) 111 | { 112 | d_printf(L"AVISetStreamFormat failed. HR = 0x%08x\n", hr); 113 | 114 | DumpDIBHeader(pDibHdr); 115 | 116 | return hr; 117 | } 118 | 119 | AVISaveOptionsFree(1, pOpt); 120 | } 121 | else 122 | { 123 | d_printf(L"AVIMakeCompressedStream failed. HR = 0x%08x\n", hr); 124 | DumpDIBHeader(pDibHdr); 125 | } 126 | } 127 | else 128 | { 129 | d_printf(L"user cancelled video options, or error ocurred (0x%08x)\n", r); 130 | } 131 | } 132 | else 133 | { 134 | d_printf(L"AVIFileCreateStream failed. HR = 0x%08x\n", hr); 135 | DumpDIBHeader(pDibHdr); 136 | } 137 | } 138 | 139 | // 140 | // Write to stream 141 | // 142 | 143 | LONG lBytesWritten = 0; 144 | 145 | if (FAILED(hr = AVIStreamWrite(_aviData.pCompVidStream, 146 | _aviData.nFrames, 147 | 1, 148 | ((BYTE*)pHdr + pHdr->bfOffBits), 149 | pDibHdr->biWidth * pDibHdr->biHeight * (pDibHdr->biBitCount >> 3), 150 | AVIIF_KEYFRAME, 151 | 0, 152 | &lBytesWritten))) 153 | { 154 | d_printf(L"AVIStreamWrite failed. HR = 0x%08x\n", hr); 155 | } 156 | else 157 | { 158 | d_printf(L"AVIStreamWrite commited %d bytes to AVI stream\n", lBytesWritten); 159 | } 160 | 161 | _aviData.nFrames++; 162 | 163 | return hr; 164 | } 165 | 166 | void CAVIVideo::SetAudioOptions() 167 | { 168 | _aviData.audStreamOpt.fccType = streamtypeAUDIO; 169 | } 170 | 171 | void CAVIVideo::Close() 172 | { 173 | d_printf(__FUNCTIONW__); 174 | 175 | if (_pIAVIFile) 176 | { 177 | AVIFileRelease(_pIAVIFile); 178 | 179 | if (_aviData.pVidStream) 180 | { 181 | AVIStreamRelease(_aviData.pVidStream); 182 | _aviData.pVidStream = NULL; 183 | } 184 | if (_aviData.pCompVidStream) 185 | { 186 | AVIStreamRelease(_aviData.pCompVidStream); 187 | _aviData.pCompVidStream = NULL; 188 | } 189 | 190 | if (_aviData.pAudStream) 191 | { 192 | AVIStreamRelease(_aviData.pAudStream); 193 | _aviData.pAudStream = NULL; 194 | } 195 | if (_aviData.pCompAudStream) 196 | { 197 | AVIStreamRelease(_aviData.pCompAudStream); 198 | _aviData.pCompAudStream = NULL; 199 | } 200 | 201 | _pIAVIFile = NULL; 202 | } 203 | else 204 | { 205 | d_printf(L"%s: WARNING Called without file references.\n",__FUNCTIONW__); 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/AVIVideo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // 5 | 6 | struct FRAMESIZE 7 | { 8 | unsigned int height; 9 | unsigned int width; 10 | }; 11 | 12 | struct AVIDATA 13 | { 14 | AVICOMPRESSOPTIONS vidStreamOpt; 15 | AVICOMPRESSOPTIONS audStreamOpt; 16 | AVISTREAMINFO vidStreamInfo; 17 | IAVIStream* pVidStream; 18 | IAVIStream* pCompVidStream; 19 | IAVIStream* pAudStream; 20 | IAVIStream* pCompAudStream; 21 | FRAMESIZE size; 22 | int fps; 23 | int nFrames; 24 | DWORD fourCC; 25 | bool fActive; 26 | }; 27 | 28 | class CAVIVideo 29 | { 30 | IAVIFile* _pIAVIFile; 31 | AVIDATA _aviData; 32 | 33 | public: 34 | CAVIVideo(void); 35 | ~CAVIVideo(void); 36 | 37 | HRESULT Create(wchar_t* szAviFile); 38 | void Close(); 39 | 40 | void SetVideoOptions(const char vCodec[4], FRAMESIZE *size, int fps); 41 | void SetAudioOptions(); 42 | HRESULT StartRecord(); 43 | HRESULT GrabFrame(LPVOID pDIBFile); 44 | int GetFrameCount() const { return _aviData.nFrames; } 45 | void StopRecord(); 46 | }; 47 | 48 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/CommandQueue.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CommandQueue.h" 3 | #include "../Common/utils.h" 4 | 5 | CCommandQueue::CCommandQueue(void) 6 | { 7 | try 8 | { 9 | InitializeCriticalSection(&_cs); 10 | } 11 | catch (...) 12 | { 13 | d_printf(L"%s: InitializeCriticalSection exception.",__FUNCTIONW__); 14 | } 15 | } 16 | 17 | bool CCommandQueue::IsEmpty() 18 | { 19 | EnterCriticalSection(&_cs); 20 | bool r = _q.empty(); 21 | LeaveCriticalSection(&_cs); 22 | 23 | return r; 24 | } 25 | 26 | CCommand CCommandQueue::_peek(bool fRemove) 27 | { 28 | CCommand c; 29 | memset(&c,0,sizeof(CCommand)); 30 | 31 | if (!IsEmpty()) 32 | { 33 | EnterCriticalSection(&_cs); 34 | c = _q.front(); 35 | 36 | if (fRemove) 37 | { 38 | _q.pop(); 39 | } 40 | 41 | LeaveCriticalSection(&_cs); 42 | } 43 | 44 | return c; 45 | } 46 | 47 | CCommand CCommandQueue::Peek() 48 | { 49 | return _peek(); 50 | } 51 | 52 | void CCommandQueue::Enqueue(const CCommand& c) 53 | { 54 | EnterCriticalSection(&_cs); 55 | _q.push(c); 56 | LeaveCriticalSection(&_cs); 57 | } 58 | 59 | CCommand CCommandQueue::Dequeue() 60 | { 61 | return _peek(true); 62 | } 63 | 64 | CCommandQueue::~CCommandQueue(void) 65 | { 66 | DeleteCriticalSection(&_cs); 67 | } 68 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/CommandQueue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.h" 3 | 4 | enum COMMANDID 5 | { 6 | CMD_NULL, 7 | CMD_VIDEORECORD_START, 8 | CMD_VIDEORECORD_STOP, 9 | CMD_TAKE_SCREENSHOT 10 | }; 11 | 12 | class CCommand 13 | { 14 | public: 15 | COMMANDID id; 16 | }; 17 | 18 | class CCommandQueue 19 | { 20 | CRITICAL_SECTION _cs; 21 | std::queue _q; 22 | 23 | CCommand _peek(bool fRemove = false); 24 | 25 | public: 26 | CCommandQueue(void); 27 | ~CCommandQueue(void); 28 | 29 | void Enqueue(const CCommand& cc); 30 | CCommand Dequeue(); 31 | CCommand Peek(); 32 | bool IsEmpty(); 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/Console.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Console.h" 3 | #include "..\Common\utils.h" 4 | 5 | CConsole::CConsole(IDirect3DDevice9* pD3DDev9, 6 | int x, 7 | int y, 8 | int lines /*= 1*/, 9 | bool fShowTime /*= false*/, 10 | bool fShowLineNumber /*= false*/, 11 | bool fShowFPSCount /*= true */) 12 | 13 | { 14 | _pD3DDev9 = pD3DDev9; 15 | _pConsoleFont = NULL; 16 | _pConsoleSprite = NULL; 17 | _currentFps = 0.0f; 18 | 19 | _cst.pos.x = x; 20 | _cst.pos.y = y; 21 | 22 | _cst.cLines = lines; 23 | _cst.fShowLineNumber = fShowLineNumber; 24 | _cst.fShowTime = fShowTime; 25 | _cst.fShowFps = fShowFPSCount; 26 | 27 | _cst.fDirty = true; 28 | 29 | CreateResources(); 30 | } 31 | 32 | CConsole::CConsole(IDirect3DDevice9* pD3DDev9, const CConsoleState& prevState) 33 | { 34 | _pD3DDev9 = pD3DDev9; 35 | _pConsoleFont = NULL; 36 | _pConsoleSprite = NULL; 37 | 38 | _cst = prevState; 39 | 40 | CreateResources(); 41 | } 42 | 43 | 44 | BOOL CConsole::CreateResources() 45 | { 46 | d_printf(__FUNCTIONW__); 47 | 48 | HRESULT hr; 49 | 50 | HDC hDC = GetDC( NULL ); 51 | 52 | if (!hDC) 53 | { 54 | d_printf(L"%s: Cannot get global DC! Lasterr is %d\n", __FUNCTIONW__, GetLastError()); 55 | return FALSE; 56 | } 57 | 58 | // Get backbuffer desc 59 | 60 | IDirect3DSurface9* pBackBuf; 61 | if (SUCCEEDED(hr = _pD3DDev9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuf))) 62 | { 63 | pBackBuf->GetDesc(&_backbuf_sd); 64 | pBackBuf->Release(); 65 | } 66 | else 67 | { 68 | d_printf(L"%s: Cannot get device backbuffer. HR is 0x08%x\n", __FUNCTIONW__, hr); 69 | return FALSE; 70 | } 71 | 72 | // cache to avoid further MUL operations 73 | 74 | _fontHeight = -MulDiv (CONSOLE_FONTSIZE, GetDeviceCaps (hDC, LOGPIXELSY), 72); 75 | ReleaseDC(NULL, hDC); 76 | 77 | hr = D3DXCreateFont(_pD3DDev9, _fontHeight,0 , FW_NORMAL, 1, 78 | FALSE, DEFAULT_CHARSET, 79 | OUT_DEFAULT_PRECIS, 80 | DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 81 | CONSOLE_FONTFACE, 82 | &_pConsoleFont); 83 | 84 | if (FAILED(hr)) 85 | { 86 | d_printf(L"%s: Font creation failed. HR is 0x08%x\n", __FUNCTIONW__, hr); 87 | return FALSE; 88 | } 89 | 90 | hr = D3DXCreateSprite(_pD3DDev9, &_pConsoleSprite); 91 | 92 | if (FAILED(hr)) 93 | { 94 | d_printf(L"%s: Sprite creation failed. HR is 0x08%x\n", __FUNCTIONW__, hr); 95 | return FALSE; 96 | } 97 | 98 | return TRUE; 99 | } 100 | 101 | void CConsole::DestroyResources() 102 | { 103 | _pConsoleFont->Release(); 104 | _pConsoleSprite->Release(); 105 | Clear(); 106 | } 107 | 108 | CConsole::~CConsole(void) 109 | { 110 | DestroyResources(); 111 | } 112 | 113 | void CConsole::OnResetDevice() 114 | { 115 | _pConsoleFont->OnResetDevice(); 116 | _pConsoleSprite->OnResetDevice(); 117 | } 118 | 119 | void CConsole::OnLostDevice() 120 | { 121 | _pConsoleFont->OnLostDevice(); 122 | _pConsoleSprite->OnLostDevice(); 123 | } 124 | 125 | void CConsole::Update() 126 | { 127 | HRESULT hr; 128 | 129 | if (SUCCEEDED(hr = _pConsoleSprite->Begin(D3DXSPRITE_SORT_TEXTURE | D3DXSPRITE_ALPHABLEND))) 130 | { 131 | static wchar_t* buf; 132 | 133 | if (_cst.fDirty) 134 | { 135 | GenerateOutputBuffer(&buf); 136 | } 137 | 138 | RECT rc; 139 | rc.top = rc.left = 1; 140 | rc.right = _backbuf_sd.Width; 141 | rc.bottom = _backbuf_sd.Height; 142 | 143 | if (_pConsoleFont->DrawTextW(_pConsoleSprite, 144 | buf, 145 | -1, 146 | &rc, DT_TOP | DT_NOCLIP | DT_WORDBREAK | DT_LEFT, 147 | D3DCOLOR_RGBA(0,0,0,255)) == 0) 148 | { 149 | d_printf(L"IDXD3Sprite::DrawTextW FAILED\n"); 150 | } 151 | 152 | // Draw shadow 153 | 154 | rc.top = rc.left = 0; 155 | 156 | if (_pConsoleFont->DrawTextW(_pConsoleSprite, 157 | buf, 158 | -1, 159 | &rc, DT_TOP | DT_NOCLIP | DT_WORDBREAK | DT_LEFT, 160 | D3DCOLOR_RGBA(0,255,0,255)) == 0) 161 | { 162 | d_printf(L"IDXD3Sprite::DrawTextW FAILED\n"); 163 | } 164 | 165 | // If enabled, draw FPS counter 166 | // 167 | 168 | if (_cst.fShowFps) 169 | { 170 | static const size_t FPS_STRLEN = 20; 171 | wchar_t wszFps[FPS_STRLEN]; 172 | 173 | StringCchPrintfEx(wszFps, FPS_STRLEN, 0, 0, 0, L"FPS: %d", (int) max(0,_currentFps)); 174 | 175 | if (_pConsoleFont->DrawTextW(_pConsoleSprite, 176 | wszFps, 177 | -1, 178 | &rc, DT_TOP | DT_RIGHT | DT_NOCLIP, D3DCOLOR_RGBA(64,255,0,255)) == 0) 179 | { 180 | d_printf(L"IDXD3Sprite::DrawTextW FAILED\n"); 181 | } 182 | } 183 | 184 | _pConsoleSprite->End(); 185 | 186 | if (_cst.fDirty) 187 | { 188 | delete [] buf; 189 | } 190 | } 191 | else 192 | { 193 | d_printf(L"IDXD3Sprite::Begin FAILED. HR = 0x%08x\n", hr); 194 | } 195 | } 196 | 197 | void CConsole::AddLine(wchar_t* wszText) 198 | { 199 | if (_lineBuffer.size() == _cst.cLines) 200 | { 201 | assert( *(_lineBuffer.begin())); 202 | delete[] (* (_lineBuffer.begin())); 203 | _lineBuffer.erase(_lineBuffer.begin()); 204 | } 205 | 206 | wchar_t* newStr = new wchar_t[MAX_STRING_CCH]; 207 | memset(newStr, 0, MAX_STRING_CCH * sizeof(wchar_t)); 208 | 209 | if (_cst.fShowTime) 210 | { 211 | SYSTEMTIME tm; 212 | GetLocalTime(&tm); 213 | 214 | StringCchPrintf(newStr, MAX_STRING_CCH, L"[%d:%d:%d.%d] ", 215 | tm.wHour, tm.wMinute, tm.wSecond, tm.wMilliseconds); 216 | } 217 | 218 | StringCchCat(newStr, MAX_STRING_CCH, wszText); 219 | 220 | _lineBuffer.push_back(newStr); 221 | _cst.fDirty = true; 222 | } 223 | 224 | void CConsole::Clear() 225 | { 226 | for (auto it = _lineBuffer.begin(); it != _lineBuffer.end(); ++it) 227 | delete [] (*it); 228 | 229 | _lineBuffer.clear(); 230 | _cst.fDirty = true; 231 | } 232 | 233 | void CConsole::GenerateOutputBuffer(wchar_t** ppOutBuffer) 234 | { 235 | const size_t bufSize = (MAX_STRING_CCH + sizeof(wchar_t)) * sizeof(wchar_t) * _cst.cLines; 236 | *ppOutBuffer = new wchar_t[bufSize]; 237 | memset(*ppOutBuffer, 0, bufSize * sizeof(wchar_t)); 238 | 239 | for (auto it = _lineBuffer.begin(); 240 | it != _lineBuffer.end(); 241 | ++it) 242 | { 243 | // Add trailing '\n' 244 | wchar_t* pEnd = NULL; 245 | StringCchCatEx(*ppOutBuffer, bufSize, *it, (STRSAFE_LPWSTR*) &pEnd, NULL, NULL); 246 | *pEnd = L'\n'; 247 | } 248 | 249 | _cst.fDirty = false; 250 | } 251 | 252 | const CConsoleState CConsole::SaveConsoleState() const 253 | { 254 | return _cst; 255 | } 256 | 257 | void CConsole::RestoreConsoleState(const CConsoleState& cs) 258 | { 259 | _cst = cs; 260 | } 261 | 262 | 263 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/Console.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.h" 3 | 4 | #define CONSOLE_FONTFACE L"System" 5 | #define CONSOLE_FONTSIZE 12 6 | 7 | struct CConsoleState 8 | { 9 | POINT pos; 10 | bool fShowLineNumber; 11 | bool fShowTime; 12 | bool fShowFps; 13 | int cLines; 14 | bool fDirty; 15 | bool fOnResetOrLost; 16 | }; 17 | 18 | class CConsole 19 | { 20 | IDirect3DDevice9* _pD3DDev9; 21 | LPD3DXFONT _pConsoleFont; 22 | LPD3DXSPRITE _pConsoleSprite; 23 | int _fontHeight; 24 | D3DSURFACE_DESC _backbuf_sd; 25 | 26 | CConsoleState _cst; 27 | 28 | double _currentFps; 29 | 30 | typedef std::vector StringBuffer_t; 31 | StringBuffer_t _lineBuffer; 32 | 33 | ////////////////////////////////////////////////////////////////////////// 34 | 35 | void GenerateOutputBuffer(wchar_t** ppOutBuffer); 36 | 37 | public: 38 | CConsole(IDirect3DDevice9* pDev9, 39 | int x, 40 | int y, 41 | int lines = 1, 42 | bool fShowTime = false, 43 | bool fShowLineNumber = false, 44 | bool fShowFpsCounter = true); 45 | 46 | CConsole(IDirect3DDevice9* pDev9, const CConsoleState& prevState); 47 | 48 | ~CConsole(void); 49 | 50 | BOOL CreateResources(); 51 | void DestroyResources(); 52 | 53 | void Show(); 54 | void Hide(); 55 | void Clear(); 56 | void AddLine(wchar_t* wszText); 57 | void Update(); 58 | 59 | void OnResetDevice(); 60 | void OnLostDevice(); 61 | 62 | void SetShowLineNumber(bool f) { _cst.fShowLineNumber = f; } 63 | void SetShowTime(bool f) { _cst.fShowTime = f; } 64 | 65 | const CConsoleState SaveConsoleState() const; 66 | void RestoreConsoleState(const CConsoleState&); 67 | 68 | void SetCurrentFps(double f) { _currentFps = f; } 69 | }; 70 | 71 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/D3DRecorderPlugin.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "D3DRecorderPlugin.h" 3 | #include "RecorderEngine.h" 4 | #include "../Common/utils.h" 5 | #include "../Common/ipc.h" 6 | #include "ParamHelper.h" 7 | #include "KeyboardHook.h" 8 | #include "CommandQueue.h" 9 | 10 | using namespace Deviare2; 11 | 12 | #pragma comment ( lib, "d3dx9.lib" ) 13 | 14 | // Global 15 | // 16 | 17 | ULONG g_resourceRefCount = 0; 18 | CRecorderEngine * g_pRecEng = NULL; 19 | CKeyboardHook * g_pKeybHook = NULL; 20 | CCommandQueue * g_pCmdQueue = NULL; 21 | WNDPROC g_oldWndProc = NULL; 22 | HWND g_subclassWnd = NULL; 23 | 24 | double t0 = 0.0f; 25 | 26 | // 27 | // Subclassed Window procedure 28 | // 29 | LRESULT CALLBACK D3DWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 30 | { 31 | switch (msg) 32 | { 33 | case WM_CLOSE: 34 | 35 | d_printf(L"D3DWindowProc WM_CLOSE\n"); 36 | g_pRecEng->DetachFromDevice(); 37 | break; 38 | 39 | case WM_NCDESTROY: 40 | 41 | d_printf(L"D3DWindowProc WM_NCDESTROY\n"); 42 | SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)g_oldWndProc); 43 | break; 44 | } 45 | 46 | return CallWindowProc(g_oldWndProc, hwnd, msg, wparam, lparam); 47 | } 48 | 49 | /////////////////////////////////////////////////////////////////////////////// 50 | 51 | HRESULT WINAPI OnLoad() 52 | { 53 | d_printf(__FUNCTIONW__); 54 | 55 | g_pRecEng = new CRecorderEngine(); 56 | g_pCmdQueue = new CCommandQueue; 57 | g_pKeybHook = new CKeyboardHook(g_pCmdQueue); 58 | 59 | return (g_pRecEng->InitIPC() ? S_OK : E_FAIL); 60 | } 61 | 62 | VOID WINAPI OnUnload() 63 | { 64 | d_printf(__FUNCTIONW__); 65 | 66 | if (g_pRecEng != NULL) 67 | delete g_pRecEng; 68 | 69 | if (g_pCmdQueue != NULL) 70 | delete g_pCmdQueue; 71 | 72 | if (g_pKeybHook != NULL) 73 | delete g_pKeybHook; 74 | } 75 | 76 | HRESULT WINAPI OnHookAdded(__in Deviare2::INktHookInfo *lpHookInfo, __in DWORD dwChainIndex, 77 | __in LPCWSTR szParametersW) 78 | { 79 | CComBSTR fnName; 80 | lpHookInfo->get_FunctionName(&fnName); 81 | d_printf(L"D3DRecorderPlugin.dll: OnHookAdded for: %s\n", fnName); 82 | return S_OK; 83 | } 84 | 85 | VOID WINAPI OnHookRemoved(__in INktHookInfo *lpHookInfo, __in DWORD dwChainIndex) 86 | { 87 | CComBSTR fnName; 88 | lpHookInfo->get_FunctionName(&fnName); 89 | d_printf(L"D3DRecorderPlugin.dll: OnHookRemoved for: %s\n", fnName); 90 | } 91 | 92 | HRESULT WINAPI OnFunctionCall(__in INktHookInfo *lpHookInfo, __in DWORD dwChainIndex, 93 | __in INktHookCallInfoPlugin *lpHookCallInfoPlugin) 94 | { 95 | CComBSTR fnName; 96 | lpHookInfo->get_FunctionName(&fnName); 97 | 98 | VARIANT_BOOL bIsPre; 99 | lpHookCallInfoPlugin->get_IsPreCall(&bIsPre); 100 | 101 | //d_printf(L"D3DRecorderPlugin.dll: OnFunctionCall for: %s (%s) \n", fnName, bIsPre ? L"PRE" : L"POST"); 102 | 103 | if (fnName == "IDirect3D9::CreateDevice") 104 | { 105 | DWORD dt = GetLongParam(lpHookCallInfoPlugin, 2); 106 | HWND hWndFocus = static_cast(GetHandleParam(lpHookCallInfoPlugin, 3)); 107 | D3DPRESENT_PARAMETERS* pPresentParams = static_cast(GetPointerParam(lpHookCallInfoPlugin, 5)); 108 | 109 | if (dt == D3DDEVTYPE_HAL) // We care only about hardware rasterizers. 110 | { 111 | IDirect3DDevice9* pD3DDev9 = GetDeviceFromParamInfo(lpHookCallInfoPlugin, 6, true); 112 | 113 | d_printf(L"IDirect3D9::CreateDevice successfully returned interface ptr = 0x%p\n", pD3DDev9); 114 | 115 | if (pD3DDev9) 116 | { 117 | HWND hSubclass = pPresentParams->hDeviceWindow == NULL ? hWndFocus : pPresentParams->hDeviceWindow; 118 | 119 | if (!hSubclass) 120 | { 121 | d_printf(L"Cannot determine device window handle!!!! -- skipping subclass\n"); 122 | } 123 | else 124 | { 125 | if (g_subclassWnd != hSubclass) 126 | { 127 | g_subclassWnd = hSubclass; 128 | d_printf(L"Subclassing window HWND=%d\n", hSubclass); 129 | g_oldWndProc = (WNDPROC) SetWindowLongPtr(hSubclass, GWLP_WNDPROC, (LONG_PTR) D3DWindowProc); 130 | } 131 | } 132 | 133 | Handle_IDirect3D9_CreateDevice(pD3DDev9); 134 | } 135 | else 136 | { 137 | d_printf(L"IDirect3D9::CreateDevice returned NULL interface pointer!\n"); 138 | } 139 | } 140 | else 141 | { 142 | d_printf(L"WARNING!! Ignoring IDirect3D9::CreateDevice handler for D3DDEVTYPE = %d\n", dt); 143 | } 144 | } 145 | else 146 | { 147 | // 148 | // Filter out those function calls 149 | // 150 | lpHookCallInfoPlugin->FilterSpyMgrEvent(); 151 | 152 | if (fnName == "IDirect3DDevice9::Release") 153 | { 154 | if (bIsPre == VARIANT_TRUE) 155 | { 156 | //... 157 | } 158 | else 159 | { 160 | Handle_IDirect3DDevice9_Release_POST(GetUlongRetVal(lpHookCallInfoPlugin), 161 | GetDeviceFromParamInfo(lpHookCallInfoPlugin)); 162 | } 163 | 164 | return S_OK; 165 | } 166 | else 167 | if (fnName == "IDirect3DDevice9::EndScene") 168 | { 169 | if (bIsPre == VARIANT_TRUE) 170 | { 171 | Handle_IDirect3DDevice9_EndScene_PRE(GetDeviceFromParamInfo(lpHookCallInfoPlugin)); 172 | } 173 | else 174 | { 175 | Handle_IDirect3DDevice9_EndScene_POST(GetDeviceFromParamInfo(lpHookCallInfoPlugin)); 176 | } 177 | } 178 | else if (fnName == "IDirect3DDevice9::Present") 179 | { 180 | if (bIsPre == VARIANT_TRUE) 181 | { 182 | Handle_IDirect3DDevice9_Present_PRE(GetDeviceFromParamInfo(lpHookCallInfoPlugin)); 183 | } 184 | else 185 | { 186 | Handle_IDirect3DDevice9_Present_POST(GetDeviceFromParamInfo(lpHookCallInfoPlugin)); 187 | } 188 | } 189 | else if (fnName == "IDirect3DDevice9::Reset") 190 | { 191 | if (bIsPre == VARIANT_TRUE) 192 | { 193 | Handle_IDirect3DDevice9_Reset_PRE(GetDeviceFromParamInfo(lpHookCallInfoPlugin)); 194 | } 195 | else 196 | { 197 | Handle_IDirect3DDevice9_Reset_POST(GetSizeTRetVal(lpHookCallInfoPlugin), 198 | GetDeviceFromParamInfo(lpHookCallInfoPlugin)); 199 | } 200 | } 201 | else 202 | { 203 | d_printf(L"d3dRecorderPlugin Error: I dont know to handle call for %s\n -- returning E_FAIL", fnName); 204 | return E_FAIL; 205 | } 206 | } 207 | 208 | return S_OK; 209 | } 210 | 211 | 212 | void Handle_IDirect3D9_CreateDevice(IDirect3DDevice9* pID3DDev9) 213 | { 214 | 215 | if (g_pRecEng->IsDeviceAttached()) 216 | { 217 | d_printf(L"Already hooked another D3D device, releasing..."); 218 | g_pRecEng->DetachFromDevice(); 219 | } 220 | 221 | // Check number of refs we're adding up. 222 | // 223 | 224 | d_printf(L"%s\n",__FUNCTIONW__); 225 | 226 | pID3DDev9->AddRef(); 227 | ULONG rc0 = pID3DDev9->Release(); 228 | 229 | g_pKeybHook->Initialize(pID3DDev9); 230 | g_pRecEng->AttachToDevice(pID3DDev9); 231 | g_pRecEng->InitResources(); 232 | 233 | pID3DDev9->AddRef(); 234 | ULONG rc1 = pID3DDev9->Release(); 235 | 236 | d_printf(L"Before CreateDevice RC=%d, after RC=%d\n", rc0, rc1); 237 | 238 | g_resourceRefCount = rc1-rc0; 239 | 240 | g_pRecEng->ConsoleWriteLine(L"Nektra D3D Tool Ready."); 241 | } 242 | 243 | void Handle_IDirect3DDevice9_Present_POST(IDirect3DDevice9* pID3DDev9) 244 | { 245 | UNREFERENCED_PARAMETER(pID3DDev9); 246 | } 247 | 248 | void Handle_IDirect3DDevice9_Present_PRE(IDirect3DDevice9* pID3DDev9) 249 | { 250 | assert(g_pRecEng); 251 | 252 | if (g_pRecEng->IsDeviceAttached()) 253 | { 254 | CCommand cmd = g_pCmdQueue->Peek(); 255 | 256 | switch (cmd.id) 257 | { 258 | case CMD_TAKE_SCREENSHOT: 259 | 260 | g_pCmdQueue->Dequeue(); 261 | 262 | { 263 | wchar_t fname[MAX_PATH]; 264 | wchar_t outputDir[MAX_PATH]; 265 | GetOutputDir(outputDir,MAX_PATH); 266 | 267 | g_pRecEng->MakeSequentialFilename(outputDir, L"PIC", fname, MAX_PATH); 268 | StringCchCat(fname, MAX_PATH, L".bmp"); 269 | 270 | g_pRecEng->TakeScreenshot(fname, IMAGEFORMAT_BMP); 271 | 272 | g_pRecEng->ConsoleWriteLine(L"Screenshot saved to: %s", fname); 273 | } 274 | 275 | break; 276 | 277 | case CMD_VIDEORECORD_START: 278 | g_pCmdQueue->Dequeue(); 279 | 280 | if (!g_pRecEng->IsVideoRecording()) 281 | { 282 | wchar_t fname[MAX_PATH]; 283 | wchar_t outputDir[MAX_PATH]; 284 | GetOutputDir(outputDir,MAX_PATH); 285 | 286 | g_pRecEng->MakeSequentialFilename(outputDir, L"VID", fname, MAX_PATH); 287 | StringCchCat(fname, MAX_PATH, L".avi"); 288 | 289 | g_pRecEng->VideoRecorderInit(fname); 290 | g_pRecEng->ConsoleWriteLine(L"Video recording started to: %s", fname); 291 | } 292 | else 293 | { 294 | g_pRecEng->ConsoleWriteLine(L"Video already recording ... "); 295 | 296 | } 297 | break; 298 | 299 | case CMD_VIDEORECORD_STOP: 300 | 301 | g_pCmdQueue->Dequeue(); 302 | 303 | if (g_pRecEng->IsVideoRecording()) 304 | { 305 | int cFrames = g_pRecEng->VideoCurrentFrameCount(); 306 | g_pCmdQueue->Dequeue(); 307 | g_pRecEng->VideoRecorderStop(); 308 | 309 | g_pRecEng->ConsoleWriteLine(L"Video recording stopped. Frame count: ", cFrames); 310 | } 311 | else 312 | { 313 | g_pRecEng->ConsoleWriteLine(L"Can't stop. Video is not recording."); 314 | } 315 | 316 | break; 317 | } 318 | 319 | // If recording, grab current frame. 320 | // 321 | if (g_pRecEng->IsVideoRecording()) 322 | { 323 | if (g_pRecEng->VideoGrabFrame() == FALSE) 324 | { 325 | g_pRecEng->ConsoleWriteLine(L"(!) Video recording stopped due to error."); 326 | g_pRecEng->VideoRecorderStop(); 327 | } 328 | } 329 | 330 | // Update fps 331 | // 332 | 333 | g_pRecEng->UpdateFrameRate(); 334 | } 335 | 336 | } 337 | 338 | void Handle_IDirect3DDevice9_EndScene_PRE(IDirect3DDevice9* pID3DDev9) 339 | { 340 | assert(g_pRecEng); 341 | 342 | if (g_pRecEng->IsDeviceAttached()) 343 | { 344 | if (pID3DDev9->TestCooperativeLevel() == D3D_OK) 345 | { 346 | g_pRecEng->Update(); 347 | } 348 | } 349 | } 350 | 351 | void Handle_IDirect3DDevice9_EndScene_POST(IDirect3DDevice9* pID3DDev9) 352 | { 353 | UNREFERENCED_PARAMETER(pID3DDev9); 354 | 355 | /*assert(g_pRecEng); 356 | assert(pID3DDev9);*/ 357 | } 358 | 359 | void Handle_IDirect3DDevice9_Reset_PRE(IDirect3DDevice9* pID3DDev9) 360 | { 361 | d_printf(L"%s\n",__FUNCTIONW__); 362 | 363 | assert(g_pRecEng); 364 | 365 | if (g_pRecEng->IsDeviceAttached()) 366 | { 367 | if (pID3DDev9) 368 | { 369 | if (g_pRecEng->IsVideoRecording()) 370 | { 371 | g_pRecEng->ConsoleWriteLine(L"(!) Video recording stopped due to device reset."); 372 | g_pRecEng->VideoRecorderStop(); 373 | } 374 | 375 | g_pRecEng->OnDeviceReset(); 376 | } 377 | } 378 | } 379 | 380 | void Handle_IDirect3DDevice9_Reset_POST(DEVIARERETVAL rv, IDirect3DDevice9* pID3DDev9) 381 | { 382 | d_printf(L"%s\n",__FUNCTIONW__); 383 | 384 | assert(g_pRecEng); 385 | 386 | if (g_pRecEng->IsDeviceAttached()) 387 | { 388 | 389 | //Check for lost device 390 | // 391 | 392 | if (pID3DDev9) 393 | { 394 | if (g_pRecEng->IsVideoRecording()) 395 | { 396 | g_pRecEng->ConsoleWriteLine(L"(!) Video recording stopped due to device reset."); 397 | g_pRecEng->VideoRecorderStop(); 398 | } 399 | 400 | if (rv == D3D_OK) 401 | { 402 | // Reset succeeded. 403 | g_pRecEng->AttachToDevice(pID3DDev9); 404 | g_pRecEng->InitResources(); 405 | } 406 | 407 | else if (rv == D3DERR_DEVICELOST) 408 | { 409 | g_pRecEng->OnDeviceLost(); 410 | } 411 | } 412 | } 413 | } 414 | 415 | void Handle_IDirect3DDevice9_Release_PRE(ULONG rv, IDirect3DDevice9* pID3DDev9) 416 | { 417 | // dummy. 418 | } 419 | 420 | void Handle_IDirect3DDevice9_Release_POST(ULONG rv, IDirect3DDevice9* pID3DDev9) 421 | { 422 | // dummy. 423 | } 424 | 425 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/D3DRecorderPlugin.h: -------------------------------------------------------------------------------- 1 | #ifndef D3DRECORDERPLUGIN_H 2 | #define D3DRECORDERPLUGIN_H 3 | #include "ParamHelper.h" 4 | 5 | #ifdef D3DRECORDERPLUGIN_EXPORTS 6 | #define D3DRECORDERPLUGIN_API extern "C" __declspec(dllexport) 7 | #else 8 | #define D3DRECORDERPLUGIN_API extern "C" __declspec(dllimport) 9 | #endif 10 | 11 | void Handle_IDirect3D9_CreateDevice(IDirect3DDevice9* pID3DDev9); 12 | void Handle_IDirect3DDevice9_EndScene_PRE(IDirect3DDevice9* pID3DDev9); 13 | void Handle_IDirect3DDevice9_EndScene_POST(IDirect3DDevice9* pID3DDev9); 14 | void Handle_IDirect3DDevice9_Reset_PRE(IDirect3DDevice9* pID3DDev9); 15 | void Handle_IDirect3DDevice9_Reset_POST(DEVIARERETVAL rv, IDirect3DDevice9* pID3DDev9); 16 | void Handle_IDirect3DDevice9_Present_POST(IDirect3DDevice9* pID3DDev9); 17 | void Handle_IDirect3DDevice9_Present_PRE(IDirect3DDevice9* pID3DDev9); 18 | void Handle_IDirect3DDevice9_Release_PRE(ULONG rv, IDirect3DDevice9* pID3DDev9); 19 | void Handle_IDirect3DDevice9_Release_POST(ULONG rv, IDirect3DDevice9* pID3DDev9); 20 | 21 | #endif //D3DRECORDERPLUGIN_H 22 | 23 | 24 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/D3DRecorderPlugin.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {340CB5F8-A80B-47A1-90D9-EC1700963CB6} 23 | Win32Proj 24 | D3DRecorderPlugin 25 | 26 | 27 | 28 | DynamicLibrary 29 | true 30 | v110 31 | Unicode 32 | Static 33 | 34 | 35 | DynamicLibrary 36 | true 37 | v110 38 | Unicode 39 | Static 40 | 41 | 42 | DynamicLibrary 43 | false 44 | v110 45 | true 46 | Unicode 47 | 48 | 49 | DynamicLibrary 50 | false 51 | v110 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | true 73 | $(DXSDK_DIR)\Include;$(IncludePath) 74 | $(DXSDK_DIR)\Lib\X86;$(LibraryPath) 75 | 76 | 77 | true 78 | $(DXSDK_DIR)\Include;$(IncludePath) 79 | $(DXSDK_DIR)\Lib\X64;$(LibraryPath) 80 | $(ProjectName)64 81 | 82 | 83 | false 84 | $(DXSDK_DIR)\Include;$(IncludePath) 85 | $(DXSDK_DIR)\lib\x86;$(LibraryPath) 86 | 87 | 88 | false 89 | $(DXSDK_DIR)\Include;$(IncludePath) 90 | $(DXSDK_DIR)\lib\x64;$(LibraryPath) 91 | $(ProjectName)64 92 | 93 | 94 | 95 | Use 96 | Level3 97 | Disabled 98 | WIN32;_DEBUG;_WINDOWS;_USRDLL;D3DRECORDERPLUGIN_EXPORTS;%(PreprocessorDefinitions) 99 | true 100 | 101 | 102 | Windows 103 | true 104 | exports.def 105 | 106 | 107 | 108 | 109 | Use 110 | Level3 111 | Disabled 112 | WIN32;_DEBUG;_WINDOWS;_USRDLL;D3DRECORDERPLUGIN_EXPORTS;%(PreprocessorDefinitions) 113 | true 114 | 115 | 116 | Windows 117 | true 118 | exports.def 119 | 120 | 121 | 122 | 123 | Level3 124 | Use 125 | MaxSpeed 126 | true 127 | true 128 | WIN32;NDEBUG;_WINDOWS;_USRDLL;D3DRECORDERPLUGIN_EXPORTS;%(PreprocessorDefinitions) 129 | true 130 | StreamingSIMDExtensions2 131 | Fast 132 | 133 | 134 | Windows 135 | true 136 | true 137 | true 138 | EXPORTS.DEF 139 | 140 | 141 | 142 | 143 | Level3 144 | Use 145 | MaxSpeed 146 | true 147 | true 148 | WIN32;NDEBUG;_WINDOWS;_USRDLL;D3DRECORDERPLUGIN_EXPORTS;%(PreprocessorDefinitions) 149 | true 150 | 151 | 152 | Windows 153 | true 154 | true 155 | true 156 | EXPORTS.DEF 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | false 177 | false 178 | 179 | 180 | 181 | 182 | false 183 | false 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | Create 194 | Create 195 | Create 196 | Create 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/D3DRecorderPlugin.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | Source Files 64 | 65 | 66 | Source Files 67 | 68 | 69 | Source Files 70 | 71 | 72 | Source Files 73 | 74 | 75 | 76 | 77 | Source Files 78 | 79 | 80 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/Exports.Def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | OnLoad @1 3 | OnUnload @2 4 | OnHookAdded @3 5 | OnHookRemoved @4 6 | OnFunctionCall @5 -------------------------------------------------------------------------------- /D3DRecorderPlugin/KeyboardHook.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CommandQueue.h" 3 | #include "KeyboardHook.h" 4 | #include "../Common/utils.h" 5 | 6 | HHOOK CKeyboardHook::_hHook = NULL; 7 | CCommandQueue* CKeyboardHook::_pCmdQueue = NULL; 8 | 9 | CKeyboardHook::CKeyboardHook(CCommandQueue* pCmdQ) 10 | { 11 | _pCmdQueue = pCmdQ; 12 | assert(pCmdQ); 13 | } 14 | 15 | BOOL CKeyboardHook::Initialize(IDirect3DDevice9* pID3DDev9) 16 | { 17 | D3DDEVICE_CREATION_PARAMETERS cp; 18 | if (SUCCEEDED(pID3DDev9->GetCreationParameters(&cp))) 19 | { 20 | _hHook = SetWindowsHookEx(WH_KEYBOARD, 21 | KeyboardProc, 22 | NULL, 23 | GetWindowThreadProcessId(cp.hFocusWindow, 0)); 24 | 25 | if (_hHook) 26 | { 27 | d_printf(L"d3dRecorderPlugin: Keyboard hook installed.\n"); 28 | return TRUE; 29 | } 30 | else 31 | { 32 | d_printf(L"d3dRecorderPlugin: Keyboard hook installed.\n"); 33 | return FALSE; 34 | } 35 | } 36 | 37 | return FALSE; 38 | } 39 | 40 | 41 | CKeyboardHook::~CKeyboardHook(void) 42 | { 43 | d_printf(__FUNCTIONW__); 44 | UnhookWindowsHookEx(_hHook); 45 | } 46 | 47 | LRESULT CALLBACK CKeyboardHook::KeyboardProc(int code, WPARAM wparam, LPARAM lparam) 48 | { 49 | assert(_pCmdQueue); 50 | 51 | if (code == HC_ACTION ) 52 | { 53 | UINT msg = (lparam & 0x80000000) ? WM_KEYUP : WM_KEYDOWN; 54 | 55 | CCommand cmd; 56 | 57 | if (msg == WM_KEYUP) 58 | { 59 | d_printf(L"%s WM_KEYUP vk=%d\n",__FUNCTIONW__, wparam); 60 | 61 | switch (wparam) 62 | { 63 | case VK_DELETE: 64 | cmd.id = CMD_TAKE_SCREENSHOT; 65 | _pCmdQueue->Enqueue(cmd); 66 | break; 67 | 68 | case VK_F11: 69 | cmd.id = CMD_VIDEORECORD_START; 70 | _pCmdQueue->Enqueue(cmd); 71 | break; 72 | 73 | case VK_F12: 74 | cmd.id = CMD_VIDEORECORD_STOP; 75 | _pCmdQueue->Enqueue(cmd); 76 | break; 77 | } 78 | } 79 | else if (msg == WM_KEYDOWN) 80 | { 81 | //d_printf(L"%s WM_KEYDOWN vk=%d\n",__FUNCTIONW__, wparam); 82 | } 83 | 84 | } 85 | 86 | return CallNextHookEx(0, code, wparam, lparam); 87 | } -------------------------------------------------------------------------------- /D3DRecorderPlugin/KeyboardHook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.h" 3 | 4 | class CCommandQueue; 5 | 6 | class CKeyboardHook 7 | { 8 | static CCommandQueue* _pCmdQueue; 9 | static HHOOK _hHook; 10 | 11 | static LRESULT CALLBACK CKeyboardHook::KeyboardProc(int code, WPARAM wparam, LPARAM lparam); 12 | 13 | 14 | public: 15 | BOOL Initialize(IDirect3DDevice9* pID3DDev9); 16 | CKeyboardHook(CCommandQueue*); 17 | ~CKeyboardHook(void); 18 | 19 | void Start(); 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/ParamHelper.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "ParamHelper.h" 3 | 4 | using namespace Deviare2; 5 | 6 | IDirect3DDevice9* GetDeviceFromParamInfo(INktHookCallInfoPlugin* lpHookCallInfoPlugin, int index, bool derefPtr) 7 | { 8 | INktParamsEnumPtr params; 9 | lpHookCallInfoPlugin->Params(¶ms); 10 | 11 | INktParamPtr pParam; 12 | params->GetAt(index, &pParam); 13 | 14 | if (derefPtr) 15 | { 16 | pParam->Evaluate(&pParam); 17 | } 18 | 19 | DEVIAREPTR pAddr; 20 | pParam->get_PointerVal(&pAddr); 21 | 22 | return reinterpret_cast(pAddr); 23 | } 24 | 25 | DEVIARERETVAL GetSizeTRetVal(INktHookCallInfoPlugin* lpHookCallInfoPlugin) 26 | { 27 | INktParamPtr pRV; 28 | lpHookCallInfoPlugin->Result(&pRV); 29 | 30 | DEVIARERETVAL rv = 0; 31 | pRV->get_SSizeTVal(&rv); 32 | return rv; 33 | } 34 | 35 | ULONG GetUlongRetVal(INktHookCallInfoPlugin* lpHookCallInfoPlugin) 36 | { 37 | INktParamPtr pRV; 38 | lpHookCallInfoPlugin->Result(&pRV); 39 | 40 | ULONG rv = 0; 41 | pRV->get_ULongVal(&rv); 42 | return rv; 43 | } 44 | 45 | long GetLongParam(INktHookCallInfoPlugin* lpHookCallInfoPlugin, int idx) 46 | { 47 | INktParamsEnumPtr params; 48 | lpHookCallInfoPlugin->Params(¶ms); 49 | 50 | INktParamPtr pp; 51 | params->GetAt(idx, &pp); 52 | 53 | long ret; 54 | pp->get_LongVal(&ret); 55 | 56 | return ret; 57 | } 58 | 59 | HANDLE GetHandleParam(INktHookCallInfoPlugin* lpHookCallInfoPlugin, int idx) 60 | { 61 | INktParamsEnumPtr params; 62 | lpHookCallInfoPlugin->Params(¶ms); 63 | 64 | INktParamPtr pp; 65 | params->GetAt(idx, &pp); 66 | 67 | SIZETVAL ret; 68 | pp->get_SizeTVal(&ret); 69 | 70 | return (HANDLE) ret; 71 | } 72 | 73 | void* GetPointerParam(INktHookCallInfoPlugin* lpHookCallInfoPlugin, int idx) 74 | { 75 | INktParamsEnumPtr params; 76 | lpHookCallInfoPlugin->Params(¶ms); 77 | 78 | INktParamPtr pp; 79 | params->GetAt(idx, &pp); 80 | 81 | DEVIAREPTR ret; 82 | pp->get_PointerVal(&ret); 83 | 84 | return (void*) ret; 85 | } 86 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/ParamHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.h" 3 | 4 | #ifdef _M_IX86 5 | #define SIZETVAL unsigned long 6 | #define REGSIZE long 7 | #define DEVIAREPTR long 8 | #elif defined _M_X64 9 | #define SIZETVAL unsigned long long 10 | #define REGSIZE __int64 11 | #define DEVIAREPTR __int64 12 | #endif 13 | #define DEVIARERETVAL REGSIZE 14 | 15 | IDirect3DDevice9* GetDeviceFromParamInfo(Deviare2::INktHookCallInfoPlugin* lpHookCallInfoPlugin, 16 | int index = 0, 17 | bool deref = false); 18 | 19 | DEVIARERETVAL GetSizeTRetVal(Deviare2::INktHookCallInfoPlugin* lpHookCallInfoPlugin); 20 | ULONG GetUlongRetVal(Deviare2::INktHookCallInfoPlugin* lpHookCallInfoPlugin); 21 | 22 | long GetLongParam(Deviare2::INktHookCallInfoPlugin* lpHookCallInfoPlugin, int idx); 23 | HANDLE GetHandleParam(Deviare2::INktHookCallInfoPlugin* lpHookCallInfoPlugin, int idx); 24 | void* GetPointerParam(Deviare2::INktHookCallInfoPlugin* lpHookCallInfoPlugin, int idx); 25 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | DYNAMIC LINK LIBRARY : D3DRecorderPlugin Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this D3DRecorderPlugin DLL for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your D3DRecorderPlugin application. 9 | 10 | 11 | D3DRecorderPlugin.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | D3DRecorderPlugin.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | D3DRecorderPlugin.cpp 25 | This is the main DLL source file. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other standard files: 29 | 30 | StdAfx.h, StdAfx.cpp 31 | These files are used to build a precompiled header (PCH) file 32 | named D3DRecorderPlugin.pch and a precompiled types file named StdAfx.obj. 33 | 34 | ///////////////////////////////////////////////////////////////////////////// 35 | Other notes: 36 | 37 | AppWizard uses "TODO:" comments to indicate parts of the source code you 38 | should add to or customize. 39 | 40 | ///////////////////////////////////////////////////////////////////////////// 41 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/RecorderEngine.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "AVIVideo.h" 3 | #include "../Common/utils.h" 4 | #include "../Common/ipc.h" 5 | #include "RecorderEngine.h" 6 | #include "Console.h" 7 | 8 | CRecorderEngine::CRecorderEngine() : 9 | _hPipe(NULL), 10 | _pD3DDev9(0), 11 | _pD3DSurf9(0), 12 | _bIsRecording(false), 13 | _fShowConsole (false) , 14 | _videoRate(0), 15 | _iFileSequence(0), 16 | _t0(0.0f), 17 | _curFpsSample(0) 18 | { 19 | ZeroMemory( &_lastConsoleState, sizeof(CConsoleState)); 20 | 21 | _pAVIVideo = new CAVIVideo; 22 | } 23 | 24 | CRecorderEngine::~CRecorderEngine() 25 | { 26 | d_printf(__FUNCTIONW__); 27 | 28 | delete _pAVIVideo; 29 | 30 | if (_hPipe) 31 | CloseHandle(_hPipe); 32 | } 33 | 34 | BOOL CRecorderEngine::InitIPC() 35 | { 36 | d_printf(__FUNCTIONW__); 37 | 38 | _hPipe = CreateFile(D3DRECORDER_PIPENAME, 39 | GENERIC_READ|GENERIC_WRITE, 40 | 0, 41 | NULL, 42 | OPEN_EXISTING, 43 | 0, 44 | NULL); 45 | 46 | if (_hPipe == INVALID_HANDLE_VALUE) 47 | { 48 | d_printf(L"Cannot connect to named pipe %s. Lasterr = 0x%x\n", D3DRECORDER_PIPENAME, GetLastError()); 49 | return FALSE; 50 | } 51 | else 52 | { 53 | d_printf(L"Connected to named pipe %s.\n",D3DRECORDER_PIPENAME); 54 | return TRUE; 55 | } 56 | } 57 | 58 | BOOL CRecorderEngine::AttachToDevice(IDirect3DDevice9* pD3DDev) 59 | { 60 | d_printf(__FUNCTIONW__); 61 | 62 | _pD3DDev9 = pD3DDev; 63 | 64 | return pD3DDev !=NULL; 65 | } 66 | 67 | void CRecorderEngine::DetachFromDevice() 68 | { 69 | ReleaseOffScreenSurface(); 70 | LostConsoleResources(); 71 | ReleaseConsoleResources(); 72 | 73 | _pD3DDev9 = NULL; 74 | 75 | } 76 | 77 | BOOL CRecorderEngine::InitResources() 78 | { 79 | return CreateOffScreenSurface() && CreateConsoleResources(); 80 | } 81 | 82 | BOOL CRecorderEngine::IsDeviceAttached() const 83 | { 84 | return _pD3DDev9 != NULL; 85 | } 86 | 87 | BOOL CRecorderEngine::CreateConsoleResources() 88 | { 89 | if(!_pConsole) 90 | { 91 | if (_lastConsoleState.fOnResetOrLost) 92 | { 93 | _pConsole = new CConsole(_pD3DDev9, _lastConsoleState); 94 | _lastConsoleState.fOnResetOrLost = false; 95 | } 96 | else 97 | { 98 | _pConsole = new CConsole(_pD3DDev9, 0, 0, 4, true); 99 | } 100 | } 101 | 102 | return (_pConsole != NULL); 103 | } 104 | 105 | void CRecorderEngine::ReleaseConsoleResources() 106 | { 107 | d_printf(__FUNCTIONW__); 108 | assert(_pConsole); 109 | 110 | delete _pConsole; 111 | _pConsole = NULL; 112 | } 113 | 114 | void CRecorderEngine::ResetConsoleResources() 115 | { 116 | d_printf(__FUNCTIONW__); 117 | assert(_pConsole); 118 | 119 | _pConsole->OnResetDevice(); 120 | } 121 | 122 | void CRecorderEngine::LostConsoleResources() 123 | { 124 | d_printf(__FUNCTIONW__); 125 | assert(_pConsole); 126 | 127 | _pConsole->OnLostDevice(); 128 | } 129 | 130 | void CRecorderEngine::Update() 131 | { 132 | _pConsole->Update(); 133 | } 134 | 135 | void CRecorderEngine::UpdateFrameRate() 136 | { 137 | double t = (double) timeGetTime(); 138 | double dt = (t - _t0); 139 | _t0 = t; 140 | 141 | double cFt = 1000 / dt; 142 | 143 | _fpsSample[++_curFpsSample % MAX_FPS_SAMPLE_COUNT] = cFt; 144 | 145 | double fps = 0; 146 | 147 | for (int i = 0; i < MAX_FPS_SAMPLE_COUNT; i++) 148 | { 149 | fps += _fpsSample[i]; 150 | } 151 | 152 | fps /= (double) MAX_FPS_SAMPLE_COUNT; 153 | _pConsole->SetCurrentFps(fps); 154 | } 155 | 156 | void CRecorderEngine::ConsoleWriteLine(const wchar_t* wszFormat, ...) 157 | { 158 | wchar_t wBuf[MAX_STRING_CCH]; 159 | va_list va; 160 | 161 | va_start(va, wszFormat); 162 | StringCchVPrintf(wBuf, MAX_STRING_CCH, wszFormat, va); 163 | va_end(va); 164 | 165 | _pConsole->AddLine(wBuf); 166 | } 167 | 168 | BOOL CRecorderEngine::CreateOffScreenSurface() 169 | { 170 | d_printf(__FUNCTIONW__); 171 | 172 | assert(_pD3DDev9); 173 | 174 | HRESULT hr; 175 | 176 | CComPtr pBackBuf; 177 | if (SUCCEEDED(hr = _pD3DDev9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuf))) 178 | { 179 | D3DSURFACE_DESC sd; 180 | pBackBuf->GetDesc(&sd); 181 | 182 | if (FAILED(hr = _pD3DDev9->CreateOffscreenPlainSurface(sd.Width, 183 | sd.Height, 184 | sd.Format, 185 | D3DPOOL_SYSTEMMEM, 186 | &_pD3DSurf9, NULL))) 187 | { 188 | d_printf(L"Cannot create OffScreenPlainSurface. HR is 0x%08x\n", hr); 189 | } 190 | } 191 | 192 | return SUCCEEDED(hr); 193 | } 194 | 195 | void CRecorderEngine::ReleaseOffScreenSurface() 196 | { 197 | d_printf(__FUNCTIONW__); 198 | 199 | if (_pD3DSurf9) 200 | { 201 | _pD3DSurf9->Release(); 202 | _pD3DSurf9 = NULL; 203 | } 204 | } 205 | 206 | void CRecorderEngine::OnDeviceReset() 207 | { 208 | d_printf(__FUNCTIONW__); 209 | 210 | _lastConsoleState = _pConsole->SaveConsoleState(); 211 | _lastConsoleState.fOnResetOrLost = true; 212 | 213 | ResetConsoleResources(); 214 | ReleaseConsoleResources(); 215 | ReleaseOffScreenSurface(); 216 | } 217 | 218 | void CRecorderEngine::OnDeviceLost() 219 | { 220 | d_printf(__FUNCTIONW__); 221 | 222 | _lastConsoleState = _pConsole->SaveConsoleState(); 223 | _lastConsoleState.fOnResetOrLost = true; 224 | 225 | LostConsoleResources(); 226 | ReleaseOffScreenSurface(); 227 | } 228 | 229 | BOOL CRecorderEngine::CaptureBackBuffer(IDirect3DSurface9** pBackBuf) 230 | { 231 | d_printf(__FUNCTIONW__); 232 | assert(_pD3DDev9); 233 | assert(_pD3DSurf9); 234 | 235 | HRESULT hr; 236 | 237 | if (SUCCEEDED(hr = _pD3DDev9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, pBackBuf))) 238 | { 239 | if (FAILED(hr = _pD3DDev9->GetRenderTargetData(*pBackBuf, _pD3DSurf9))) 240 | { 241 | d_printf(L"%s Cannot get data from backbuffer. HR is 0x%08x\n", __FUNCTIONW__, hr); 242 | } 243 | } 244 | else 245 | { 246 | d_printf(L"%s Cannot get backbuffer data HR is 0x%08x",__FUNCTIONW__,hr); 247 | } 248 | 249 | return SUCCEEDED(hr); 250 | } 251 | 252 | BOOL CRecorderEngine::SaveBackBufferToMemDIB(LPD3DXBUFFER* ppD3DBuffer) 253 | { 254 | d_printf(__FUNCTIONW__); 255 | HRESULT hr; 256 | if (FAILED(hr = D3DXSaveSurfaceToFileInMemory(ppD3DBuffer, D3DXIFF_DIB, _pD3DSurf9, NULL, NULL))) 257 | { 258 | d_printf(L"%s: Error saving buffer HR is 0x%08x\n",__FUNCTIONW__,hr); 259 | } 260 | 261 | return SUCCEEDED(hr); 262 | } 263 | 264 | BOOL CRecorderEngine::SaveBackBufferToFile(const wchar_t* wszFileName, D3DXIMAGE_FILEFORMAT format) 265 | { 266 | d_printf(__FUNCTIONW__); 267 | HRESULT hr; 268 | if (FAILED(hr = D3DXSaveSurfaceToFile(wszFileName, format, _pD3DSurf9, NULL, NULL))) 269 | { 270 | d_printf(L"%s: Error saving file HR is 0x%08x\n",__FUNCTIONW__,hr); 271 | } 272 | 273 | return SUCCEEDED(hr); 274 | } 275 | 276 | void CRecorderEngine::MakeSequentialFilename(const wchar_t* szPath, 277 | const wchar_t* szPrefix, 278 | wchar_t* szOutName, 279 | size_t cch) 280 | { 281 | const size_t COUNTBUF = 10; 282 | wchar_t szFSeq[COUNTBUF]; 283 | 284 | assert(szOutName); 285 | ZeroMemory(szOutName, cch * sizeof(wchar_t)); 286 | 287 | wchar_t szFileName[MAX_PATH]; 288 | GetModuleFileName(NULL, szFileName, MAX_PATH); 289 | PathStripPath(szFileName); 290 | 291 | if (szPath) 292 | { 293 | StringCchCat(szOutName, cch, szPath); 294 | StringCchCat(szOutName, cch, L"\\"); 295 | } 296 | 297 | if (szPrefix && lstrlen(szPrefix) > 0) 298 | { 299 | StringCchCat(szOutName, cch, szPrefix); 300 | StringCchCat(szOutName, cch, L"-"); 301 | } 302 | 303 | StringCchCat(szOutName, cch, szFileName); 304 | StringCchCat(szOutName, cch, L"-"); 305 | StringCchPrintf(szFSeq, COUNTBUF, L"%08d", _iFileSequence); 306 | StringCchCat(szOutName, cch, szFSeq); 307 | 308 | _iFileSequence++; 309 | } 310 | 311 | void CRecorderEngine::ExtensionFromImageFormat(IMAGEFORMAT f, wchar_t out[5]) 312 | { 313 | switch (f) 314 | { 315 | case IMAGEFORMAT_BMP: 316 | StringCchCopy(out, 5, L".BMP"); 317 | break; 318 | 319 | case IMAGEFORMAT_DIB: 320 | StringCchCopy(out, 5, L".DIB"); 321 | break; 322 | } 323 | } 324 | 325 | void CRecorderEngine::TakeScreenshot(const wchar_t* fname, IMAGEFORMAT f) 326 | { 327 | d_printf(L"%s Saving screenshot to %s...\n", __FUNCTIONW__, fname); 328 | 329 | IDirect3DSurface9* pBackBuf = NULL; 330 | 331 | if (CaptureBackBuffer(&pBackBuf)) 332 | { 333 | SaveBackBufferToFile(fname, (D3DXIMAGE_FILEFORMAT) f); 334 | pBackBuf->Release(); 335 | } 336 | } 337 | 338 | BOOL CRecorderEngine::VideoRecorderInit(wchar_t* fname, int w, int h, int fps) 339 | { 340 | HRESULT hr; 341 | assert(_pAVIVideo); 342 | 343 | if (SUCCEEDED(hr = _pAVIVideo->Create(fname))) 344 | { 345 | FRAMESIZE fs; 346 | 347 | if (w == USEDEFAULT || h == USEDEFAULT) 348 | { 349 | D3DSURFACE_DESC sd; 350 | _pD3DSurf9->GetDesc(&sd); 351 | 352 | fs.height = sd.Height; 353 | fs.width = sd.Width; 354 | } 355 | else 356 | { 357 | fs.height = h; 358 | fs.width = w; 359 | } 360 | 361 | if (fps == USEDEFAULT) 362 | { 363 | fps = 15; 364 | } 365 | 366 | _pAVIVideo->SetVideoOptions("", &fs, fps); 367 | _videoRate = fps; 368 | _bIsRecording = true; 369 | 370 | _lastFrameTime = timeGetTime(); 371 | _elapsedTime = 0; 372 | 373 | return TRUE; 374 | } 375 | else 376 | { 377 | d_printf(L"%s CAviVideo::Create failed, HR is 0x%08x\n", __FUNCTIONW__, hr); 378 | 379 | } 380 | 381 | return FALSE; 382 | } 383 | 384 | BOOL CRecorderEngine::IsFrameTimeAvailable() 385 | { 386 | const int MS_LIMIT = 8000; 387 | 388 | DWORD now = timeGetTime(); 389 | 390 | DWORD elpTime = (now > _lastFrameTime) ? (now - _lastFrameTime) : 1; 391 | _lastFrameTime = now; 392 | 393 | _elapsedTime += (elpTime * _videoRate); 394 | 395 | if (_elapsedTime >= 1000 + _videoRate) 396 | { 397 | if (_elapsedTime >= MS_LIMIT) 398 | _elapsedTime = MS_LIMIT; 399 | 400 | _elapsedTime -= 1000 + _videoRate; 401 | 402 | return TRUE; 403 | } 404 | 405 | return FALSE; 406 | } 407 | 408 | BOOL CRecorderEngine::VideoGrabFrame() 409 | { 410 | assert(_pAVIVideo); 411 | 412 | IDirect3DSurface9* pBackBuf; 413 | HRESULT hr; 414 | 415 | // Collect only at fixed sample rate 416 | // 417 | 418 | if (IsFrameTimeAvailable()) 419 | { 420 | if (CaptureBackBuffer(&pBackBuf)) 421 | { 422 | LPD3DXBUFFER pD3DXBuf; 423 | 424 | if (SaveBackBufferToMemDIB(&pD3DXBuf)) 425 | { 426 | if (FAILED(hr = _pAVIVideo->GrabFrame(pD3DXBuf->GetBufferPointer()))) 427 | { 428 | d_printf(L"%s : AVIVIdeo::GrabFrame FAILED. HR=0x%08x\n",__FUNCTIONW__, hr); 429 | 430 | ConsoleWriteLine(L"GrabFrame FAIL HR=0x%08x. Check codec framebuffer format support/choose another codec", hr); 431 | return FALSE; 432 | } 433 | 434 | pD3DXBuf->Release(); 435 | } 436 | 437 | pBackBuf->Release(); 438 | } 439 | } 440 | 441 | return TRUE; 442 | } 443 | 444 | void CRecorderEngine::VideoRecorderStop() 445 | { 446 | assert(_pAVIVideo); 447 | 448 | if (_bIsRecording) 449 | { 450 | _pAVIVideo->Close(); 451 | _bIsRecording = false; 452 | _elapsedTime = 0; 453 | } 454 | } 455 | 456 | int CRecorderEngine::VideoCurrentFrameCount() const 457 | { 458 | return _pAVIVideo->GetFrameCount(); 459 | } -------------------------------------------------------------------------------- /D3DRecorderPlugin/RecorderEngine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Console.h" 3 | 4 | // Must do OOP! to handle various dx versions. 5 | 6 | // font props? 7 | 8 | #define USEDEFAULT 0 9 | #define CONSOLE_LINES 2 10 | #define MAX_LINE_LEN 80 11 | 12 | class CAVIVideo; 13 | 14 | #define MAX_FPS_SAMPLE_COUNT 100 15 | 16 | enum IMAGEFORMAT 17 | { 18 | IMAGEFORMAT_BMP = D3DXIFF_BMP, 19 | IMAGEFORMAT_DIB = D3DXIFF_DIB 20 | }; 21 | 22 | class CRecorderEngine 23 | { 24 | CAVIVideo* _pAVIVideo; 25 | CConsole* _pConsole; 26 | CConsoleState _lastConsoleState; 27 | 28 | HANDLE _hPipe; 29 | 30 | // Direct3D9 Resources 31 | 32 | IDirect3DDevice9* _pD3DDev9; 33 | IDirect3DSurface9* _pD3DSurf9; 34 | 35 | bool _fShowConsole; 36 | bool _bIsRecording; 37 | DWORD _videoRate; 38 | double _t0; 39 | DWORD _lastFrameTime, _elapsedTime; 40 | int _iFileSequence; 41 | double _fpsSample[MAX_FPS_SAMPLE_COUNT]; 42 | int _curFpsSample; 43 | 44 | 45 | // functions 46 | 47 | BOOL CreateOffScreenSurface(); 48 | void ReleaseOffScreenSurface(); 49 | 50 | BOOL CreateConsoleResources(); 51 | void ResetConsoleResources(); 52 | void LostConsoleResources(); 53 | void ReleaseConsoleResources(); 54 | 55 | BOOL CaptureBackBuffer(IDirect3DSurface9**); 56 | BOOL SaveBackBufferToFile(const wchar_t* wszFileName, D3DXIMAGE_FILEFORMAT format); 57 | BOOL SaveBackBufferToMemDIB(LPD3DXBUFFER* ppDestBuf); 58 | 59 | void ExtensionFromImageFormat(IMAGEFORMAT f, wchar_t ext[5]); 60 | 61 | BOOL IsFrameTimeAvailable(); 62 | 63 | public: 64 | CRecorderEngine(); 65 | ~CRecorderEngine(); 66 | 67 | BOOL InitIPC(); 68 | BOOL AttachToDevice(IDirect3DDevice9* pD3DDev); 69 | void DetachFromDevice(); 70 | BOOL IsDeviceAttached() const; 71 | BOOL InitResources(); 72 | void OnDeviceReset(); 73 | void OnDeviceLost(); 74 | void Update(); 75 | void UpdateFrameRate(); 76 | 77 | void ConsoleWriteLine(const wchar_t* wszFormat,...); 78 | 79 | // Screenshot 80 | 81 | void MakeSequentialFilename( 82 | const wchar_t* szTargetPath, 83 | const wchar_t* szPrefix, 84 | wchar_t* szOut_fname, 85 | size_t cch); 86 | 87 | void TakeScreenshot(const wchar_t* fname, IMAGEFORMAT f); 88 | 89 | // AVI Video 90 | 91 | BOOL VideoRecorderInit(wchar_t* fname, int w = USEDEFAULT, int h = USEDEFAULT, int fps = USEDEFAULT); 92 | BOOL IsVideoRecording() const { return _bIsRecording; } 93 | int VideoCurrentFrameCount() const; 94 | BOOL VideoGrabFrame(); 95 | void VideoRecorderStop(); 96 | 97 | }; -------------------------------------------------------------------------------- /D3DRecorderPlugin/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | #pragma comment ( lib, "d3d9.lib") 4 | 5 | BOOL APIENTRY DllMain( HMODULE hModule, 6 | DWORD ul_reason_for_call, 7 | LPVOID lpReserved 8 | ) 9 | { 10 | switch (ul_reason_for_call) 11 | { 12 | case DLL_PROCESS_ATTACH: 13 | case DLL_THREAD_ATTACH: 14 | case DLL_THREAD_DETACH: 15 | case DLL_PROCESS_DETACH: 16 | break; 17 | } 18 | return TRUE; 19 | } 20 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // D3DRecorderPlugin.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "targetver.h" 4 | 5 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 6 | // Windows Header Files: 7 | #include 8 | 9 | #include 10 | 11 | #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | // C++ headers 20 | // 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | // D3D 27 | 28 | #include 29 | #include 30 | 31 | #ifdef _M_IX86 32 | #import "../dll/deviarecom.dll" raw_interfaces_only, named_guids, raw_dispinterfaces, auto_rename 33 | #elif defined _M_X64 34 | #import "../dll/deviareCom64.dll" raw_interfaces_only, named_guids, raw_dispinterfaces, auto_rename 35 | #else 36 | #error "Unsupported system architecture" 37 | #endif 38 | -------------------------------------------------------------------------------- /D3DRecorderPlugin/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | #define _WIN32_WINNT 0x0502 10 | #include 11 | 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AVRecorderTool 2 | ============== 3 | 4 | DirectX video recording and frames per second counter 5 | 6 | This code instruments Direct3D 9 applications to calculate frames per second and capture video. It produces an AVI container using the video codec of your choice. It is also possible to capture game screenshots in the 32-bit BMP format by pressing “delete”. The shortcuts for starting and stopping video recording are “F11” and “F12”. 7 | 8 | [Original article](http://blog.nektra.com/main/2013/07/23/instrumenting-direct3d-applications-to-capture-video-and-calculate-frames-per-second/) 9 | -------------------------------------------------------------------------------- /dll/README!!!!.txt: -------------------------------------------------------------------------------- 1 | Put Deviare system DLLs and database here. 2 | 3 | Deviare32.db 4 | Deviare64.db 5 | DeviareCOM.dll 6 | DeviareCom64.dll 7 | DvAgent.dll 8 | DvAgent64.dll 9 | 10 | --------------------------------------------------------------------------------