fork(1) download
  1. // main.cppだけ
  2. #pragma comment(lib, "Gdi32.lib")
  3. #pragma comment(lib, "GlU32.Lib")
  4. #pragma comment(lib, "OpenGL32.Lib")
  5. #pragma comment(lib, "User32.lib")
  6.  
  7. #include "detour_hook.h"
  8. #include "file_mapping_view.h"
  9. #include "file_pointer.h"
  10. #include "find_window_by_process_id.h"
  11. #include "glrc_handle.h"
  12. #include "handle.h"
  13. #include "logger.h"
  14. #include "pixmap.h"
  15. #include "sprintf2.h"
  16. #include <windows.h>
  17. #include <gl/GL.h>
  18. #include <gl/GLU.h>
  19. #include <cstdio>
  20. #include <string>
  21. #include <vector>
  22.  
  23. using namespace std;
  24.  
  25. typedef struct {
  26. bool aborted;
  27. SP<DetourHook> detourHook;
  28. SP<Handle> doneEvent;
  29. SP<GlrcHandle> glrch;
  30. SP<Pixmap> pixmap;
  31. SP<Handle> requestEvent;
  32. } CAPTGL_CONTEXT;
  33.  
  34. static void cleanup();
  35. static bool capturePixmap(const HDC& hdc);
  36. extern BOOL WINAPI detourSwapBuffers(HDC hdc);
  37. static bool setup(const HINSTANCE& hinstDLL);
  38. static string getModuleName(const HMODULE& hmod);
  39.  
  40. static CAPTGL_CONTEXT context;
  41. static BOOL (WINAPI * const realSwapBuffers)(HDC hdc) = SwapBuffers;
  42.  
  43. BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID) {
  44. SP<FilePointer> logFilePointer;
  45. switch (dwReason) {
  46. case DLL_PROCESS_ATTACH:
  47. if (!setup(hinstDLL)) {
  48. context.aborted = true;
  49. return FALSE;
  50. }
  51. break;
  52. case DLL_PROCESS_DETACH:
  53. cleanup();
  54. break;
  55. }
  56. return TRUE;
  57. }
  58.  
  59. void cleanup() {
  60. Logger::getInstance()->put("キャプチャを終了します。", "INF");
  61. }
  62.  
  63. bool capturePixmap(const HDC& hdc) {
  64. if (!context.glrch.get()) {
  65. context.glrch = GlrcHandle::create(hdc);
  66. if (!context.glrch.get()) {
  67. return false;
  68. }
  69. }
  70. switch (WaitForSingleObject(context.requestEvent->get(), 0)) {
  71. case WAIT_ABANDONED: case WAIT_FAILED:
  72. return false;
  73. case WAIT_TIMEOUT:
  74. return true;
  75. }
  76. SP<GlrcCurrent> glrcc = new GlrcCurrent(hdc, context.glrch->get());
  77. glGetError();
  78. glReadBuffer(GL_BACK);
  79. if (GLint glError = glGetError()) {
  80. Logger::getInstance()->put(sprintf2("予期せぬエラーが発生しました。(%s:%d:%s)", "glReadBuffer", glError, gluErrorString(glError)), "CRI");
  81. return false;
  82. }
  83. glReadPixels(0, 0, context.pixmap->getWidth(), context.pixmap->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, context.pixmap->getBits());
  84. if (GLint glError = glGetError()) {
  85. Logger::getInstance()->put(sprintf2("予期せぬエラーが発生しました。(%s:%d:%s)", "glReadPixels", glError, gluErrorString(glError)), "CRI");
  86. return false;
  87. }
  88. SetEvent(context.doneEvent->get());
  89. return true;
  90. }
  91.  
  92. BOOL WINAPI detourSwapBuffers(HDC hdc) {
  93. if (!context.aborted) {
  94. if (!capturePixmap(hdc)) {
  95. context.aborted = true;
  96. }
  97. }
  98. return realSwapBuffers(hdc);
  99. }
  100.  
  101. string getModuleName(const HMODULE& hmod) {
  102. char path[MAX_PATH];
  103. GetModuleFileName(hmod, path, MAX_PATH);
  104. char fullPath[MAX_PATH];
  105. char* name;
  106. GetFullPathName(path, MAX_PATH, fullPath, &name);
  107. return string(name);
  108. }
  109.  
  110. bool setup(const HINSTANCE& hinstDLL) {
  111. context.aborted = false;
  112. string exeName = getModuleName(NULL);
  113. string dllName = getModuleName((HMODULE)hinstDLL);
  114. SP<FilePointer> logFilePointer = new FilePointer(fopen(sprintf2("%s_%s.log", dllName.c_str(), exeName.c_str()).c_str(), "a"));
  115. if (logFilePointer->get()) {
  116. Logger::getInstance()->setFilePointer(logFilePointer);
  117. }
  118. Logger::getInstance()->put("キャプチャを開始します。", "INF");
  119. HWND hwnd = findWindowByProcessId(GetCurrentProcessId());
  120. if (hwnd == NULL) {
  121. Logger::getInstance()->put("ウィンドウが見つかりませんでした。", "CRI");
  122. return false;
  123. }
  124. RECT client;
  125. GetClientRect(hwnd, &client);
  126. string pixmapViewName = sprintf2("%s_%s_%s_%s", dllName.c_str(), exeName.c_str(), "pixmap", "view");
  127. DWORD pixmapViewSize = sizeof(DWORD) + sizeof(DWORD) + 4 * client.right * client.bottom;
  128. SP<Handle> pixmapViewHandle = new Handle(CreateFileMapping((HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, pixmapViewSize, pixmapViewName.c_str()));
  129. if (!pixmapViewHandle || GetLastError() == ERROR_ALREADY_EXISTS) {
  130. Logger::getInstance()->put(sprintf2("予期せぬエラーが発生しました。(%s:%d)", "CreateFileMapping", GetLastError()), "CRI");
  131. return false;
  132. }
  133. SP<FileMappingView> pixmapView = FileMappingView::map(pixmapViewHandle, FILE_MAP_WRITE, 0, 0);
  134. if (!pixmapView.get()) {
  135. return false;
  136. }
  137. context.pixmap = new Pixmap(pixmapView, client.right, client.bottom);
  138. SP<vector<DETOUR_PAIR> > detourPairs = new vector<DETOUR_PAIR>();
  139. detourPairs->push_back(newDetourPair(&(PVOID&)realSwapBuffers, detourSwapBuffers));
  140. context.detourHook = DetourHook::hook(detourPairs);
  141. if (!context.detourHook.get()) {
  142. return false;
  143. }
  144. string requestEventName = sprintf2("%s_%s_%s_%s", dllName.c_str(), exeName.c_str(), "request", "event");
  145. context.requestEvent = new Handle(CreateEvent(NULL, FALSE, FALSE, requestEventName.c_str()));
  146. if (!context.requestEvent || GetLastError() == ERROR_ALREADY_EXISTS) {
  147. Logger::getInstance()->put(sprintf2("予期せぬエラーが発生しました。(%s:%d)", "CreateEvent", GetLastError()), "CRI");
  148. return false;
  149. }
  150. string doneEventName = sprintf2("%s_%s_%s_%s", dllName.c_str(), exeName.c_str(), "done", "event");
  151. context.doneEvent = new Handle(CreateEvent(NULL, FALSE, FALSE, doneEventName.c_str()));
  152. if (!context.doneEvent || GetLastError() == ERROR_ALREADY_EXISTS) {
  153. Logger::getInstance()->put(sprintf2("予期せぬエラーが発生しました。(%s:%d)", "CreateEvent", GetLastError()), "CRI");
  154. return false;
  155. }
  156. return true;
  157. }
  158.  
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty