opengl32.dll зависает на SetPixelFormat Как заменить или подключить пользовательскую функцию

#c #assembly #opengl #native-code

Вопрос:

У меня есть сценарий, в котором в некоторых случаях, когда вызывается opengl32.SetPixelFormat, затем вызывается _wglDescribePixelFormat ( который является экспортируемой функцией), который затем вызывает далее в стеке вызовов ComputeBitsFromMasks и, наконец, _MaskToBitsAndShift. Функция _MaskToBitsAndShift остается в цикле и никогда не завершается, что приводит к зависанию всего приложения. Стек вызовов-это введите описание изображения здесь

 opengl32.dll!_MaskToBitsAndShift@12
opengl32.dll!ComputeBitsFromMasks
opengl32.dll!___wglGetBitfieldColorFormat@16
opengl32.dll!_InternalDescribePixelFormat@40
opengl32.dll!_wglDescribePixelFormat@16
opengl32.dll!_wglSetPixelFormat@12
gdi32full.dll!_SetPixelFormat@12
Unmanaged.dll!CGLContext::CreateOffScreenContext
Unmanaged.dll!Shared::Generate3DImages
 

Декодирование метода _MaskToBitsAndShift из asm в c становится таким.

Код Asm

 opengl32!MaskToBitsAndShift:
6da7d6f2 8bff            mov     edi,edi
6da7d6f4 55              push    ebp
6da7d6f5 8bec            mov     ebp,esp
6da7d6f7 56              push    esi
6da7d6f8 8b7508          mov     esi,dword ptr [ebp 8]
6da7d6fb 33c0            xor     eax,eax
6da7d6fd 40              inc     eax – initialize eax to 1, used to find highest set bit in the mask
6da7d6fe c60200          mov     byte ptr [edx],0
6da7d701 c60600          mov     byte ptr [esi],0
6da7d704 84c8            test    al,cl
6da7d706 7508            jne     opengl32!MaskToBitsAndShift 0x1e (6da7d710)
6da7d708 03c0            add     eax,eax – shifts eax (the bit) left 
6da7d70a fe06            inc     byte ptr [esi] – increases shift count
6da7d70c 85c1            test    ecx,eax – ecx is the mask, first param to this function apparently
– and this is the problem. if ecx or mask is 0, test ecx,eax will never set the flag for je to fail, hence infinite loop
6da7d70e 74f8            je      opengl32!MaskToBitsAndShift 0x16 (6da7d708)
6da7d710 5e              pop     esi
6da7d711 eb04            jmp     opengl32!MaskToBitsAndShift 0x25 (6da7d717)
6da7d713 03c0            add     eax,eax
6da7d715 fe02            inc     byte ptr [edx]
6da7d717 85c1            test    ecx,eax
6da7d719 75f8            jne     opengl32!MaskToBitsAndShift 0x21 (6da7d713)
6da7d71b 5d              pop     ebp
6da7d71c c20400          ret     4
 

Equivalant c code

 void stdcall MaskToBitsAndShift(DWORD mask, BYTE* shiftCount, BYTE* bitCount)
{
// literal translation from asm; could be safer using bittest intrinsics or counted bits but no big deal
DWORD bit = 1;
*shiftCount = 0;
*bitCount = 0;

while (!(mask amp; bit))

{ *shiftCount  = 1; bit <<= 1; }
while (mask amp; bit)

{ *bitCount  = 1; bit <<= 1; }
}
 

Если мы заметим маску, если 0, цикл никогда не закончится.
Я не могу подключить эту функцию, потому что она не экспортируется.

Есть идеи, как это обойти ? или переписать метод _wglDescribePixelFormat, который экспортируется, но я понятия не имею, как это перевести.

Начальный вызов SetPixelFormat-это

 bool CGLContext::CreateOffScreenContext(int nWidth, int nHeight, CString* pstrLog /*=NULL*/)
{
    if(pstrLog)
        pstrLog->Append("Creating Off Screen Contextrn");

    m_eContextType = CONTEXT_TYPE_OFFSCREEN;

    // Create a new Device Context
    m_pDC = new CDC;
    m_pDC->CreateCompatibleDC(NULL);

    // Initialize all of the compenents used to select a pixel format
    memset(amp;m_PixelFormatDescriptor, 0, sizeof(m_PixelFormatDescriptor));
    m_PixelFormatDescriptor.nSize = sizeof(PIXELFORMATDESCRIPTOR);
    m_PixelFormatDescriptor.nVersion = 1;
    m_PixelFormatDescriptor.dwFlags = PFD_DRAW_TO_BITMAP|PFD_SUPPORT_OPENGL|PFD_SUPPORT_GDI;
    m_PixelFormatDescriptor.iPixelType = PFD_TYPE_RGBA;
    m_PixelFormatDescriptor.cColorBits = 0;
    m_PixelFormatDescriptor.cDepthBits = 0;
    m_PixelFormatDescriptor.cAccumBits = 0;
    m_PixelFormatDescriptor.cStencilBits = 0;
    m_PixelFormatDescriptor.cAuxBuffers = 0;
    m_PixelFormatDescriptor.iLayerType = PFD_MAIN_PLANE;

    m_hDC = m_pDC->m_hDC;
    
    int nPixelFormat = ChoosePixelFormat(m_hDC, amp;m_PixelFormatDescriptor);

    if(nPixelFormat == 0) {
        if(pstrLog)
        {
            CString str;
            str.Format("Unable to Choose Pixel Format: %lirn", nPixelFormat);
            pstrLog->Append(str);
            pstrLog->Append(DescribePFD(m_PixelFormatDescriptor));
            return false;
        }
        else
        {   
            ThrowException("Unable to Choose Pixel Format");
        }
    }.....
 

Комментарии:

1. По — видимому, вы передаете неверные данные SetPixelFormat .

2. @1201ProgramAlarm я отредактировал вопрос, чтобы также добавить первоначальный вызов.

3. @1201ProgramAlarm В идеале это не должно быть из-за данных, потому что PixelFormatDescriptor, о котором они сказали в своем документе, не действует, а DC просто новый.

4. У вас есть memset(amp;m_PixelFormatDescriptor, 0, sizeof(m_PixelFormatDescriptor)); , а затем не устанавливайте для этого элемента ненулевое значение. Таким образом, он остается равным нулю.

5. Ну, это в вашем собственном коде, который вы разместили в этом вопросе: m_PixelFormatDescriptor.cColorBits = 0; . Все описание формата пикселей, используемое там, действительно абсурдно. Интересно, какой смысл запрашивать программный растризатор Microsoft GDI OpenGL 1.1 в формате буфера кадров, который не может содержать никаких данных.