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 }