2015-06-22 3 views
0

У меня небольшая проблема. Я хотел бы сделать снимок экрана из Genymotion. Поскольку это не так просто и требует OpenGL Hooking, у меня есть DLL, которая вводится через Easyhook.Снимок экрана с подключенным приложением OpenGL

Теперь DLL перехватывает метод wglSwapBuffers() для обработки буфера, снимает скриншот, а затем возвращает буфер обратно в genymotion. Проблема в том, что он сбрасывает приложение (Kernelbase.dll) и/или mscorlib, как только он пытается использовать любые методы OpenGL.

Удаление этих и просто печать текста при вызове SwapBuffers_Hooked работает хорошо.

Вот длл, который вводится в процесс

public class Main : EasyHook.IEntryPoint 
{ 



    GlMon.GlMonInterface Interface; 
    Stack<String> Queue = new Stack<String>(); 
    public LocalHook CreateBufferHook = null; 
    Bitmap bitmap = null; 

    public Main(
     RemoteHooking.IContext InContext, 
     String InChannelName) 
    { 


     // connect to host... 
     Interface = RemoteHooking.IpcConnectClient<GlMon.GlMonInterface>(InChannelName); 

     Interface.Ping(); 
    } 

    public void Run(
     RemoteHooking.IContext InContext, 
     String InChannelName) 
    { 
     // install hook... 
     try 
     { 

      CreateBufferHook = LocalHook.Create(LocalHook.GetProcAddress("opengl32.dll", "wglSwapBuffers"), new DwglSwapBuffers(SwapBuffers_Hooked), this); 

      CreateBufferHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 }); 
     } 
     catch (Exception ExtInfo) 
     { 
      Interface.ReportException(ExtInfo); 

      return; 
     } 

     Interface.IsInstalled(RemoteHooking.GetCurrentProcessId()); 

     RemoteHooking.WakeUpProcess(); 
     try 
     { 
      while (true) 
      { 
       Thread.Sleep(500); 

       // transmit newly monitored file accesses... 
       if (this.bitmap != null) 
       { 

        Interface.onSwapBuffer(RemoteHooking.GetCurrentProcessId(), "bitmap received. size=" + bitmap.Size); 
        this.bitmap = null; 
       } 
       else 
       { 
        Interface.onSwapBuffer(RemoteHooking.GetCurrentProcessId(), "ping.."); 

        Interface.Ping(); 
       } 
      } 
     } 
     catch 
     { 
      // Ping() will raise an exception if host is unreachable 
     } 
     // wait for host process termination... 

    } 

    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] 
    delegate IntPtr DwglSwapBuffers(IntPtr hdc); 



    [DllImport("opengl32.dll", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)] 
    static extern IntPtr wglSwapBuffers(IntPtr hdc); 


    // this is where we are intercepting all file accesses! 
    static IntPtr SwapBuffers_Hooked(IntPtr hdc) 
    { 

     Main This = (Main)HookRuntimeInfo.Callback; 

     try 
     { 

      /** apitrace dump is 
      *          
       11288 wglSwapBuffers(hdc = 0xb0013e0a) = TRUE 
       11289 glFlush() 
       11290 wglMakeCurrent(hdc = 0xf601374b, hglrc = 0x10004) = TRUE 
       11291 glDisable(cap = GL_SCISSOR_TEST) 
       11292 glClear(mask = GL_COLOR_BUFFER_BIT) 
       11293 glEnable(cap = GL_SCISSOR_TEST) 
       11294 glDisable(cap = GL_BLEND) 
       11295 glBindTexture(target = GL_TEXTURE_2D, texture = 20) 
       11296 glPushClientAttrib(mask = GL_CLIENT_VERTEX_ARRAY_BIT) 
       11297 glPushAttrib(mask = GL_TRANSFORM_BIT) 
       11298 glMatrixMode(mode = GL_PROJECTION) 
       11299 glPushMatrix() 
       11300 glLoadIdentity() 
       11301 glGetIntegerv(pname = GL_VIEWPORT, params = {0, 0, 860, 720}) 
       11302 glOrtho(left = 0, right = 860, bottom = 0, top = 720, zNear = 0, zFar = -1) 
       11303 glMatrixMode(mode = GL_TEXTURE) 
       11304 glPushMatrix() 
       11305 glLoadIdentity() 
       11306 glMatrixMode(mode = GL_MODELVIEW) 
       11307 glPushMatrix()          * **/ 
       Bitmap bitmap = new Bitmap(860, 720); 
      Rectangle bounds = new Rectangle(0, 0, 860, 720); 
      BitmapData bmpData = bitmap.LockBits(bounds, ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb); 

      wgl.glReadBuffer((uint)wgl.DrawBufferMode.GL_FRONT_AND_BACK); 
      wgl.glReadPixels(0, 0, bounds.Width, bounds.Height, (uint)wgl.PixelFormat.GL_RGB, (uint)wgl.DataType.GL_UNSIGNED_BYTE, bmpData.Scan0); 
      bitmap.UnlockBits(bmpData); 
      bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); 

      int i = 0; 
      while (File.Exists("images/test_" + i + ".png")) 
      { 
       i++; 
      } 
      bitmap.Save("images/test_" + i + ".png"); 
     return wgl.SwapBuffers(hdc); 


     } 
     catch 
     { 
     } 
     // call original API... 
     return wglSwapBuffers(hdc); 
    } 

Погрешность Крэш

Problemereignisname: APPCRASH 
Anwendungsname: player.exe 
Anwendungsversion: 0.0.0.0 
Anwendungszeitstempel: 54edc8da 
Fehlermodulname: KERNELBASE.dll 
Fehlermodulversion: 6.3.9600.17415 

Другой Исключение отображается отладчик является System.FileNotFoundexception, но я не могу понять, какой файл не найден.

Обновление: я обновил код. Этот код работает в большинстве случаев, и изображения хранятся. Во всяком случае, у них есть раздражающие цвета. Похоже, что некоторые цвета отсутствуют и/или имеют меньший красный цвет. Что может вызвать эту проблему? если я выберу другой PixelFormat, он снова сработает. То же самое с GL_RGB. RGBA, похоже, падает. Если я увеличиваю DataType, он также сработает. Любая идея, почему цвета переполнены?

ответ

0

Код фрагмент

IntPtr hglrc = wgl.GetCurrentDC(); 
[...] 
wgl.MakeCurrent(hdc, hglrc); 

, конечно, не будет работать (и может быть причиной аварии). wglGetCurrentDC() возвращает контекст устройства, а не дескриптор Контекст GL. Вы можете запросить контекст GL на glGetCurrentContext(). Howerver, поскольку единственная операция, которая вам нужна, по-видимому, нуждается в дескрипторе контекста GL, похоже, который устанавливает текущий контекст, это не поможет вам вообще. Либо приложение оставляет привязку к контексту, то ваша операция не является обязательной, либо она отталкивает ее или использует несколько разных контекстов - тогда вам нужно подключиться к wglMakeCurrent и фактически отслеживать, какой контекст будет отображаться для того, что DC, поэтому вы можете узнать, какой контекст вам нужен, чтобы захватить данные буфера с помощью специального вызова SwapBuffers.

У вашего кода есть еще одна проблема: вы меняете буфер дважды: один раз, прежде чем читать данные и один раз после этого. После буфера swao содержимое заднего буфера становится неопределенным. Таким образом, есть две стратегии, которые вы можете следовать:

  1. захватить содержание заднего буфера, а затем поменять местами, ИЛИ
  2. подкачки и захватить содержимое переднего буфера

, но никогда не подкачки дважды.

+0

спасибо. Я хочу обновить код. Я до сих пор работаю, но цвета все еще повреждены. Любая идея почему? –

+0

Растровые изображения используют формат BGR, а не RGB.также убедитесь, что все правила выравнивания выполнены – derhass

0

Я думаю, что причиной проблемы GRB является то, что данные Genymotion являются Big-endian, а ваш hookprogram - малолитражным. Вы должны поменять массив байтов.

+0

Это может быть правильный ответ, но в его нынешнем виде он больше похож на комментарий. Вы должны добавить более подробную информацию. Краткие ответы вроде этого, как правило, снижаются - проголосовали и/или удалены. –

Смежные вопросы