PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/pipes.d

http://github.com/AndrejMitrovic/DWinProgramming
D | 225 lines | 162 code | 38 blank | 25 comment | 14 complexity | ab6daf8ec2113b38065a971df88d3c2a MD5 | raw file
  1. module pipes;
  2. pragma(lib, "gdi32.lib");
  3. import core.memory;
  4. import core.runtime;
  5. import core.thread;
  6. import core.stdc.string;
  7. import std.conv;
  8. import std.math;
  9. import std.range;
  10. import std.string;
  11. import std.utf;
  12. import win32.windef;
  13. import win32.winuser;
  14. import win32.wingdi;
  15. import win32.winbase;
  16. import std.algorithm;
  17. import std.array;
  18. import std.stdio;
  19. import std.conv;
  20. import std.typetuple;
  21. import std.typecons;
  22. import std.traits;
  23. enum BUFSIZE = 4096;
  24. wstring fromUTF16z(const wchar* s)
  25. {
  26. if (s is null) return null;
  27. wchar* ptr;
  28. for (ptr = cast(wchar*)s; *ptr; ++ptr) {}
  29. return to!wstring(s[0..ptr-s]);
  30. }
  31. auto toUTF16z(S)(S s)
  32. {
  33. return toUTFz!(const(wchar)*)(s);
  34. }
  35. struct ProcessInfo
  36. {
  37. HANDLE procHandle;
  38. string procName;
  39. HANDLE childStdinRead;
  40. HANDLE childStdinWrite;
  41. HANDLE childStdoutRead;
  42. HANDLE childStdoutWrite;
  43. }
  44. int getReturnCode(ref ProcessInfo procInfo)
  45. {
  46. WaitForSingleObject(procInfo.procHandle, INFINITE);
  47. DWORD exitCode = 0;
  48. if (GetExitCodeProcess(procInfo.procHandle, &exitCode))
  49. {
  50. // successfully retrieved exit code
  51. return exitCode;
  52. }
  53. else
  54. {
  55. writeln("failed to get return code.");
  56. //~ ErrorExit("CreateProcess");
  57. }
  58. CloseHandle(procInfo.procHandle);
  59. return exitCode;
  60. }
  61. ProcessInfo createProcessPipes()
  62. {
  63. ProcessInfo pi;
  64. createProcessPipes(pi);
  65. return pi;
  66. }
  67. void createProcessPipes(ref ProcessInfo procInfo)
  68. {
  69. SECURITY_ATTRIBUTES saAttr;
  70. // Set the bInheritHandle flag so pipe handles are inherited.
  71. saAttr.nLength = SECURITY_ATTRIBUTES.sizeof;
  72. saAttr.bInheritHandle = true;
  73. with (procInfo)
  74. {
  75. // Create a pipe for the child process's STDOUT.
  76. if (!CreatePipe(/* out */ &childStdoutRead, /* out */ &childStdoutWrite, &saAttr, 0) )
  77. ErrorExit(("StdoutRd CreatePipe"));
  78. // Ensure the read handle to the pipe for STDOUT is not inherited (sets to 0)
  79. if (!SetHandleInformation(childStdoutRead, HANDLE_FLAG_INHERIT, 0) )
  80. ErrorExit(("Stdout SetHandleInformation"));
  81. // Create a pipe for the child process's STDIN.
  82. if (!CreatePipe(&childStdinRead, &childStdinWrite, &saAttr, 0))
  83. ErrorExit(("Stdin CreatePipe"));
  84. // Ensure the write handle to the pipe for STDIN is not inherited. (sets to 0)
  85. if (!SetHandleInformation(childStdinWrite, HANDLE_FLAG_INHERIT, 0) )
  86. ErrorExit(("Stdin SetHandleInformation"));
  87. }
  88. }
  89. string readProcessPipeString(ProcessInfo procInfo)
  90. {
  91. // Read output from the child process's pipe for STDOUT
  92. // and write to the parent process's pipe for STDOUT.
  93. // Stop when there is no more data.
  94. DWORD dwRead, dwWritten;
  95. CHAR[BUFSIZE] chBuf;
  96. BOOL bSuccess = false;
  97. HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
  98. string buffer;
  99. buffer.reserve(4096 * 16);
  100. // Close the write end of the pipe before reading from the
  101. // read end of the pipe, to control child process execution.
  102. // The pipe is assumed to have enough buffer space to hold the
  103. // data the child process has already written to it.
  104. if (!CloseHandle(procInfo.childStdoutWrite))
  105. ErrorExit(("StdOutWr CloseHandle"));
  106. while (1)
  107. {
  108. bSuccess = ReadFile(procInfo.childStdoutRead, chBuf.ptr, BUFSIZE, &dwRead, NULL);
  109. if (!bSuccess || dwRead == 0)
  110. break;
  111. buffer ~= chBuf[0..dwRead];
  112. }
  113. return buffer;
  114. }
  115. // Create a child process that uses the previously created pipes for STDIN and STDOUT.
  116. void runProcess(string command, ref ProcessInfo procInfo)
  117. {
  118. auto szCmdline = toUTFz!(wchar*)(command);
  119. PROCESS_INFORMATION piProcInfo;
  120. STARTUPINFO siStartInfo;
  121. BOOL bSuccess = false;
  122. // Set up members of the STARTUPINFO structure.
  123. // This structure specifies the STDIN and STDOUT handles for redirection.
  124. siStartInfo.cb = STARTUPINFO.sizeof;
  125. siStartInfo.hStdError = procInfo.childStdoutWrite; // we should replace this
  126. siStartInfo.hStdOutput = procInfo.childStdoutWrite;
  127. siStartInfo.hStdInput = procInfo.childStdinRead;
  128. siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
  129. if (CreateProcess(NULL,
  130. szCmdline, // command line
  131. NULL, // process security attributes
  132. NULL, // primary thread security attributes
  133. true, // handles are inherited
  134. 0, // creation flags
  135. NULL, // use parent's environment
  136. NULL, // use parent's current directory
  137. &siStartInfo, // STARTUPINFO pointer
  138. &piProcInfo) == 0) // receives PROCESS_INFORMATION
  139. {
  140. ErrorExit("CreateProcess");
  141. }
  142. else
  143. {
  144. procInfo.procHandle = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, piProcInfo.dwProcessId);
  145. }
  146. }
  147. Tuple!(int, "status", string, "output") execute(string command)
  148. {
  149. auto procInfo = createProcessPipes();
  150. runProcess(command, procInfo);
  151. typeof(return) r;
  152. r.output = readProcessPipeString(procInfo);
  153. r.status = getReturnCode(procInfo);
  154. return r;
  155. }
  156. void ErrorExit(string lpszFunction)
  157. {
  158. // Format a readable error message, display a message box,
  159. // and exit from the application.
  160. LPVOID lpMsgBuf;
  161. LPVOID lpDisplayBuf;
  162. DWORD dw = GetLastError();
  163. FormatMessage(
  164. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  165. FORMAT_MESSAGE_FROM_SYSTEM |
  166. FORMAT_MESSAGE_IGNORE_INSERTS,
  167. NULL,
  168. dw,
  169. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  170. cast(LPTSTR)&lpMsgBuf,
  171. 0, NULL);
  172. lpDisplayBuf = cast(LPVOID)LocalAlloc(LMEM_ZEROINIT,
  173. (lstrlen(cast(LPCTSTR)lpMsgBuf) + lstrlen(cast(LPCTSTR)lpszFunction) + 40) * (TCHAR.sizeof));
  174. auto str = format("%s failed with error %s: %s",
  175. lpszFunction,
  176. dw,
  177. fromUTF16z(cast(wchar*)lpMsgBuf)
  178. );
  179. writeln(str);
  180. ExitProcess(1);
  181. }
  182. //~ void main(string[] args)
  183. //~ {
  184. //~ auto pc = execute("dmd test.d");
  185. //~ writeln("status: ", pc.status);
  186. //~ writeln(pc.output);
  187. //~ }