1 module ddebug.windows.mago; 2 version(Windows): 3 version(USE_MAGO): 4 5 import ddebug.windows.msdbg; 6 import dlangui.core.logger; 7 import core.atomic; 8 import std.string; 9 10 //const GUID CLSID_MAGO = {0xE348A53A, 0x470A, 0x4A70, [0x9B, 0x55, 0x1E, 0x02, 0xF3, 0x52, 0x79, 0x0D]}; 11 const GUID IID_MAGO_NATIVE_ENGINE = {0x97348AC0, 0x2B6B, 0x4B99, [0xA2, 0x45, 0x4C, 0x7E, 0x2C, 0x09, 0xD4, 0x03]}; 12 //const GUID CLSID_PORT_SUPPLIER = {0x3484EFB2, 0x0A52, 0x4EB2, [0x86, 0x9C, 0x1F, 0x7E, 0x66, 0x8E, 0x1B, 0x87]}; 13 //const GUID CLSID_PORT_SUPPLIER = {0x3B476D38, 0xA401, 0x11D2, [0xAA, 0xD4, 0x00, 0xC0, 0x4F, 0x99, 0x01, 0x71]}; //3B476D38-A401-11D2-AAD4-00C04F990171 14 const GUID CLSID_PORT_SUPPLIER = {0x708C1ECA, 0xFF48, 0x11D2, [0x90, 0x4F, 0x00, 0xC0, 0x4F, 0xA3, 0x02, 0xA1]}; //{708C1ECA-FF48-11D2-904F-00C04FA302A1} 15 //const GUID CLSID_PORT_SUPPLIER = {0xF561BF8D, 0xBFBA, 0x4FC6, [0xAE, 0xA7, 0x24, 0x45, 0xD0, 0xEA, 0xC1, 0xC5]}; 16 //const GUID CLSID_PORT_SUPPLIER = {0x708C1ECA, 0xFF48, 0x11D2, [0x90, 0x4F, 0x00, 0x04, 0xA3, 0x2, 0xA1]}; 17 18 class ComObject : IUnknown 19 { 20 extern (Windows): 21 HRESULT QueryInterface(GUID* riid, void** ppv) 22 { 23 if (*riid == IID_IUnknown) 24 { 25 *ppv = cast(void*)cast(IUnknown)this; 26 AddRef(); 27 return S_OK; 28 } 29 else 30 { *ppv = null; 31 return E_NOINTERFACE; 32 } 33 } 34 35 ULONG AddRef() 36 { 37 return atomicOp!"+="(*cast(shared)&count, 1); 38 } 39 40 ULONG Release() 41 { 42 LONG lRef = atomicOp!"-="(*cast(shared)&count, 1); 43 if (lRef == 0) 44 { 45 // free object 46 47 // If we delete this object, then the postinvariant called upon 48 // return from Release() will fail. 49 // Just let the GC reap it. 50 //delete this; 51 52 return 0; 53 } 54 return cast(ULONG)lRef; 55 } 56 57 LONG count = 0; // object reference count 58 } 59 60 class DebugCallback : ComObject, IDebugEventCallback2 { 61 62 override HRESULT Event( 63 /+[in]+/ IDebugEngine2 pEngine, 64 /+[in]+/ IDebugProcess2 pProcess, 65 /+[in]+/ IDebugProgram2 pProgram, 66 /+[in]+/ IDebugThread2 pThread, 67 /+[in]+/ IDebugEvent2 pEvent, 68 in IID* riidEvent, 69 in DWORD dwAttrib) { 70 // 71 Log.d("debug event"); 72 return 0; 73 } 74 75 } 76 77 string formatHResult(HRESULT hr) { 78 switch(hr) { 79 case S_OK: return "S_OK"; 80 case S_FALSE: return "S_FALSE"; 81 case E_NOTIMPL: return "E_NOTIMPL"; 82 case E_NOINTERFACE: return "E_NOINTERFACE"; 83 case E_FAIL: return "E_FAIL"; 84 case E_HANDLE: return "E_HANDLE"; 85 case 0x80040154: return "REGDB_E_CLASSNOTREG"; 86 default: 87 return format("%08x", hr); 88 } 89 } 90 91 IDebugPortSupplier2 createPortSupplier() { 92 HRESULT hr; 93 IDebugPortSupplier2 portSupplier = null; 94 LPOLESTR str; 95 StringFromCLSID(&CLSID_PORT_SUPPLIER, &str); 96 hr = CoCreateInstance(&CLSID_PORT_SUPPLIER, //CLSID_MAGO, 97 null, 98 CLSCTX_INPROC, //CLSCTX_ALL, 99 &IID_IDebugPortSupplier2, //IID_MAGO_NATIVE_ENGINE, 100 cast(void**)&portSupplier); //piUnknown); 101 if (FAILED(hr) || !portSupplier) { 102 Log.e("Failed to create port supplier ", formatHResult(hr)); 103 return null; 104 } 105 Log.i("Port supplier is created"); 106 return portSupplier; 107 } 108 109 class DebugPortRequest : ComObject, IDebugPortRequest2 { 110 static const wchar[] portName = "magoDebuggerPort\0"; 111 HRESULT GetPortName(/+[out]+/ BSTR* pbstrPortName) { 112 pbstrPortName = cast(BSTR*)portName.ptr; 113 return S_OK; 114 } 115 } 116 117 void testMago() { 118 HRESULT hr; 119 IUnknown* piUnknown; 120 IDebugEngine2 debugEngine = null; 121 IDebugEngineLaunch2 debugEngineLaunch = null; 122 hr=CoInitialize(null); // Initialize OLE 123 if (FAILED(hr)) { 124 Log.e("OLE 2 failed to initialize", formatHResult(hr)); 125 return; 126 } 127 128 IDebugPortSupplier2 portSupplier = createPortSupplier(); 129 if (!portSupplier) { 130 Log.e("Failed to create port supplier"); 131 return; 132 } 133 if (portSupplier.CanAddPort() != S_OK) { 134 Log.e("Cannot add debug port ", portSupplier.CanAddPort()); 135 return; 136 } 137 IDebugPort2 debugPort = null; 138 DebugPortRequest debugPortRequest = new DebugPortRequest(); 139 // Add a port 140 hr = portSupplier.AddPort( 141 /+[in]+/ debugPortRequest, 142 /+[out]+/ &debugPort); 143 if (FAILED(hr) || !debugPort) { 144 Log.e("Failed to create debub port ", formatHResult(hr)); 145 return; 146 } 147 148 149 //hr = CoCreateInstance(&CLSID_MAGO, null, CLSCTX_ALL, &IID_IDebugEngine2, cast(void**)&piUnknown); 150 hr = CoCreateInstance(&IID_MAGO_NATIVE_ENGINE, //CLSID_MAGO, 151 null, 152 CLSCTX_INPROC, //CLSCTX_ALL, 153 &IID_IDebugEngine2, //IID_MAGO_NATIVE_ENGINE, 154 cast(void**)&debugEngine); //piUnknown); 155 if (debugEngine) { 156 Log.d("Debug interface is not null"); 157 } 158 if (FAILED(hr) || !debugEngine) { 159 Log.e("Failed to create MAGO interface instance ", formatHResult(hr)); 160 return; 161 } 162 163 Log.d("Debug interface initialized ok"); 164 GUID eid; 165 debugEngine.GetEngineId(&eid); 166 Log.d("Engine id: ", eid); 167 168 hr = debugEngine.QueryInterface(cast(GUID*)&IID_IDebugEngineLaunch2, cast(void**)&debugEngineLaunch); 169 if (FAILED(hr) || !debugEngineLaunch) { 170 Log.e("Failed to get IID_IDebugEngineLaunch2 interface ", formatHResult(hr)); 171 return; 172 } 173 174 IDebugProcess2 process = null; 175 DebugCallback callback = new DebugCallback(); 176 177 wchar[] exe = `D:\projects\d\dlangide\workspaces\tetris\bin\tetris.exe`w.dup; 178 wchar[] args; 179 wchar[] dir = `D:\projects\d\dlangide\workspaces\tetris\bin`w.dup; 180 wchar[] envblock; 181 wchar[] opts; 182 exe ~= 0; 183 args ~= 0; 184 dir ~= 0; 185 envblock ~= 0; 186 opts ~= 0; 187 188 IDebugPort2 port; 189 hr = debugEngineLaunch.LaunchSuspended ( 190 null, 191 port, 192 exe.ptr,//LPCOLESTR 193 args.ptr, 194 dir.ptr, 195 envblock.ptr, 196 opts.ptr, 197 LAUNCH_DEBUG, //LAUNCH_NODEBUG 198 0, 199 0, 200 0, 201 callback, 202 &process 203 ); 204 205 if (FAILED(hr) || !process) { 206 Log.e("Failed to run process ", formatHResult(hr)); 207 return; 208 } 209 Log.d("LaunchSuspended executed ok"); 210 }