Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

300 lines
7.2 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Example of how to connect to a debugger server and execute
  4. // a command when the server is broken in.
  5. //
  6. // Copyright (C) Microsoft Corporation, 2002.
  7. //
  8. //----------------------------------------------------------------------------
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <stdarg.h>
  12. #include <windows.h>
  13. #include <dbgeng.h>
  14. BOOL g_ForceBreak;
  15. PSTR g_Connect;
  16. PSTR g_Command = ".echo Broken in";
  17. IDebugClient* g_Client;
  18. IDebugClient* g_ExitDispatchClient;
  19. IDebugControl* g_Control;
  20. ULONG g_ExecStatus;
  21. //----------------------------------------------------------------------------
  22. //
  23. // Event callbacks.
  24. //
  25. //----------------------------------------------------------------------------
  26. class EventCallbacks : public DebugBaseEventCallbacks
  27. {
  28. public:
  29. // IUnknown.
  30. STDMETHOD_(ULONG, AddRef)(
  31. THIS
  32. );
  33. STDMETHOD_(ULONG, Release)(
  34. THIS
  35. );
  36. // IDebugEventCallbacks.
  37. STDMETHOD(GetInterestMask)(
  38. THIS_
  39. OUT PULONG Mask
  40. );
  41. STDMETHOD(ChangeEngineState)(
  42. THIS_
  43. IN ULONG Flags,
  44. IN ULONG64 Argument
  45. );
  46. };
  47. STDMETHODIMP_(ULONG)
  48. EventCallbacks::AddRef(
  49. THIS
  50. )
  51. {
  52. // This class is designed to be static so
  53. // there's no true refcount.
  54. return 1;
  55. }
  56. STDMETHODIMP_(ULONG)
  57. EventCallbacks::Release(
  58. THIS
  59. )
  60. {
  61. // This class is designed to be static so
  62. // there's no true refcount.
  63. return 0;
  64. }
  65. STDMETHODIMP
  66. EventCallbacks::GetInterestMask(
  67. THIS_
  68. OUT PULONG Mask
  69. )
  70. {
  71. *Mask = DEBUG_EVENT_CHANGE_ENGINE_STATE;
  72. return S_OK;
  73. }
  74. STDMETHODIMP
  75. EventCallbacks::ChangeEngineState(
  76. THIS_
  77. IN ULONG Flags,
  78. IN ULONG64 Argument
  79. )
  80. {
  81. if (Flags & DEBUG_CES_EXECUTION_STATUS)
  82. {
  83. g_ExecStatus = (ULONG)Argument;
  84. // If this notification came from a wait completing
  85. // we want to wake up the input thread so that new
  86. // commands can be processed. If it came from inside
  87. // a wait we don't want to ask for input as the engine
  88. // may go back to running at any time.
  89. if (!(Argument & DEBUG_STATUS_INSIDE_WAIT))
  90. {
  91. // Wake up the wait loop.
  92. g_ExitDispatchClient->ExitDispatch(g_Client);
  93. }
  94. }
  95. return S_OK;
  96. }
  97. EventCallbacks g_EventCb;
  98. //----------------------------------------------------------------------------
  99. //
  100. // Functions.
  101. //
  102. //----------------------------------------------------------------------------
  103. void
  104. Exit(int Code, PCSTR Format, ...)
  105. {
  106. // Clean up any resources.
  107. if (g_Control != NULL)
  108. {
  109. g_Control->Release();
  110. }
  111. if (g_ExitDispatchClient != NULL)
  112. {
  113. g_ExitDispatchClient->Release();
  114. }
  115. if (g_Client != NULL)
  116. {
  117. g_Client->EndSession(DEBUG_END_DISCONNECT);
  118. g_Client->Release();
  119. }
  120. // Output an error message if given.
  121. if (Format != NULL)
  122. {
  123. va_list Args;
  124. va_start(Args, Format);
  125. vfprintf(stderr, Format, Args);
  126. va_end(Args);
  127. }
  128. exit(Code);
  129. }
  130. void
  131. CreateInterfaces(void)
  132. {
  133. HRESULT Status;
  134. // Start things off by getting an initial interface from
  135. // the engine. This can be any engine interface but is
  136. // generally IDebugClient as the client interface is
  137. // where sessions are started.
  138. if ((Status = DebugConnect(g_Connect,
  139. __uuidof(IDebugClient),
  140. (void**)&g_Client)) != S_OK)
  141. {
  142. Exit(1, "DebugConnect(%s) failed, 0x%X\n",
  143. g_Connect, Status);
  144. }
  145. // Query for some other interfaces that we'll need.
  146. if ((Status = g_Client->QueryInterface(__uuidof(IDebugControl),
  147. (void**)&g_Control)) != S_OK)
  148. {
  149. Exit(1, "QueryInterface failed, 0x%X\n", Status);
  150. }
  151. if ((Status = g_Client->SetEventCallbacks(&g_EventCb)) != S_OK)
  152. {
  153. Exit(1, "SetEventCallbacks failed, 0x%X\n", Status);
  154. }
  155. //
  156. // This app may wait inside of a DispatchCallbacks
  157. // while it's waiting for the server to break in.
  158. // We'll need to be able to exit that dispatch so
  159. // we need another connection to the server to
  160. // send the exit request.
  161. //
  162. // This could all be avoided by simply doing a polling
  163. // loop when waiting, but the intent of this sample
  164. // is to show some of the more advanced callback-driven
  165. // techniques.
  166. //
  167. if ((Status = DebugConnect(g_Connect,
  168. __uuidof(IDebugClient),
  169. (void**)&g_ExitDispatchClient)) != S_OK)
  170. {
  171. Exit(1, "DebugConnect(%s) failed, 0x%X\n",
  172. g_Connect, Status);
  173. }
  174. }
  175. void
  176. ParseCommandLine(int Argc, char** Argv)
  177. {
  178. while (--Argc > 0)
  179. {
  180. Argv++;
  181. if (!strcmp(*Argv, "-b"))
  182. {
  183. g_ForceBreak = TRUE;
  184. }
  185. else if (!strcmp(*Argv, "-cmd"))
  186. {
  187. if (Argc < 2)
  188. {
  189. Exit(1, "-cmd missing argument\n");
  190. }
  191. Argv++;
  192. Argc--;
  193. g_Command = *Argv;
  194. }
  195. else if (!strcmp(*Argv, "-remote"))
  196. {
  197. if (Argc < 2)
  198. {
  199. Exit(1, "-remote missing argument\n");
  200. }
  201. Argv++;
  202. Argc--;
  203. g_Connect = *Argv;
  204. }
  205. else
  206. {
  207. Exit(1, "Unknown command line argument '%s'\n", *Argv);
  208. }
  209. }
  210. if (!g_Connect)
  211. {
  212. Exit(1, "No connection string specified, use -remote <options>\n");
  213. }
  214. }
  215. void
  216. WaitForBreakIn(void)
  217. {
  218. HRESULT Status;
  219. // If we're forcing a break in request one.
  220. if (g_ForceBreak)
  221. {
  222. if ((Status = g_Control->SetInterrupt(DEBUG_INTERRUPT_ACTIVE)) != S_OK)
  223. {
  224. Exit(1, "SetInterrupt failed, 0x%X\n", Status);
  225. }
  226. }
  227. // Check on the current state as the server may be broken in.
  228. if ((Status = g_Control->GetExecutionStatus(&g_ExecStatus)) != S_OK)
  229. {
  230. Exit(1, "GetExecutionStatus failed, 0x%X\n", Status);
  231. }
  232. printf("Waiting for break-in...\n");
  233. while (g_ExecStatus != DEBUG_STATUS_BREAK)
  234. {
  235. // Wait for the server to enter the break-in state.
  236. // When this happens our event callbacks will get called
  237. // to update g_ExecStatus and wake up this wait.
  238. if ((Status = g_Client->DispatchCallbacks(INFINITE)) != S_OK)
  239. {
  240. Exit(1, "DispatchCallbacks failed, 0x%X\n", Status);
  241. }
  242. }
  243. // The server is broken in. Another user can immediately resume
  244. // it but we'll assume that we're not competing with
  245. // other server users.
  246. }
  247. void __cdecl
  248. main(int Argc, char** Argv)
  249. {
  250. ParseCommandLine(Argc, Argv);
  251. CreateInterfaces();
  252. WaitForBreakIn();
  253. printf("Executing '%s' on server\n", g_Command);
  254. g_Control->Execute(DEBUG_OUTCTL_ALL_CLIENTS,
  255. g_Command, DEBUG_EXECUTE_DEFAULT);
  256. Exit(0, NULL);
  257. }