2008-10-13 3 views
5

C#에서 opengl을 사용하려고합니다. 실패wglCreateContext C#에서 실패하지만 관리되는 C++이 아닙니다.

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] 
public static extern IntPtr GetDC(IntPtr hWnd); 

[StructLayout(LayoutKind.Sequential)] 
    public struct PIXELFORMATDESCRIPTOR 
    { 
     public void Init() 
     { 
      nSize = (ushort) Marshal.SizeOf(typeof (PIXELFORMATDESCRIPTOR)); 
      nVersion = 1; 
      dwFlags = PFD_FLAGS.PFD_DRAW_TO_WINDOW | PFD_FLAGS.PFD_SUPPORT_OPENGL | PFD_FLAGS.PFD_DOUBLEBUFFER | PFD_FLAGS.PFD_SUPPORT_COMPOSITION; 
      iPixelType = PFD_PIXEL_TYPE.PFD_TYPE_RGBA; 
      cColorBits = 24; 
      cRedBits = cRedShift = cGreenBits = cGreenShift = cBlueBits = cBlueShift = 0; 
      cAlphaBits = cAlphaShift = 0; 
      cAccumBits = cAccumRedBits = cAccumGreenBits = cAccumBlueBits = cAccumAlphaBits = 0; 
      cDepthBits = 32; 
      cStencilBits = cAuxBuffers = 0; 
      iLayerType = PFD_LAYER_TYPES.PFD_MAIN_PLANE; 
      bReserved = 0; 
      dwLayerMask = dwVisibleMask = dwDamageMask = 0; 
     } 
     ushort nSize; 
     ushort nVersion; 
     PFD_FLAGS dwFlags; 
     PFD_PIXEL_TYPE iPixelType; 
     byte cColorBits; 
     byte cRedBits; 
     byte cRedShift; 
     byte cGreenBits; 
     byte cGreenShift; 
     byte cBlueBits; 
     byte cBlueShift; 
     byte cAlphaBits; 
     byte cAlphaShift; 
     byte cAccumBits; 
     byte cAccumRedBits; 
     byte cAccumGreenBits; 
     byte cAccumBlueBits; 
     byte cAccumAlphaBits; 
     byte cDepthBits; 
     byte cStencilBits; 
     byte cAuxBuffers; 
     PFD_LAYER_TYPES iLayerType; 
     byte bReserved; 
     uint dwLayerMask; 
     uint dwVisibleMask; 
     uint dwDamageMask; 
    } 

    [Flags] 
    public enum PFD_FLAGS : uint 
    { 
     PFD_DOUBLEBUFFER = 0x00000001, 
     PFD_STEREO = 0x00000002, 
     PFD_DRAW_TO_WINDOW = 0x00000004, 
     PFD_DRAW_TO_BITMAP = 0x00000008, 
     PFD_SUPPORT_GDI = 0x00000010, 
     PFD_SUPPORT_OPENGL = 0x00000020, 
     PFD_GENERIC_FORMAT = 0x00000040, 
     PFD_NEED_PALETTE = 0x00000080, 
     PFD_NEED_SYSTEM_PALETTE = 0x00000100, 
     PFD_SWAP_EXCHANGE = 0x00000200, 
     PFD_SWAP_COPY = 0x00000400, 
     PFD_SWAP_LAYER_BUFFERS = 0x00000800, 
     PFD_GENERIC_ACCELERATED = 0x00001000, 
     PFD_SUPPORT_DIRECTDRAW = 0x00002000, 
     PFD_DIRECT3D_ACCELERATED = 0x00004000, 
     PFD_SUPPORT_COMPOSITION = 0x00008000, 
     PFD_DEPTH_DONTCARE = 0x20000000, 
     PFD_DOUBLEBUFFER_DONTCARE = 0x40000000, 
     PFD_STEREO_DONTCARE = 0x80000000 
    } 

    public enum PFD_LAYER_TYPES : byte 
    { 
     PFD_MAIN_PLANE = 0, 
     PFD_OVERLAY_PLANE = 1, 
     PFD_UNDERLAY_PLANE = 255 
    } 

    public enum PFD_PIXEL_TYPE : byte 
    { 
     PFD_TYPE_RGBA = 0, 
     PFD_TYPE_COLORINDEX = 1 
    } 

    [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] 
    public static extern int ChoosePixelFormat(IntPtr hdc, [In] ref PIXELFORMATDESCRIPTOR ppfd); 

    [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] 
    public static extern bool SetPixelFormat(IntPtr hdc, int iPixelFormat, ref PIXELFORMATDESCRIPTOR ppfd); 
[DllImport("opengl32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] 
    public static extern IntPtr wglCreateContext(IntPtr hDC); 

그리고 지금 코드 :

IntPtr dc = Win.GetDC(hwnd); 

var pixelformatdescriptor = new GL.PIXELFORMATDESCRIPTOR(); 
pixelformatdescriptor.Init(); 

var pixelFormat = GL.ChoosePixelFormat(dc, ref pixelformatdescriptor); 
if(!GL.SetPixelFormat(dc, pixelFormat, ref pixelformatdescriptor)) 
    throw new Win32Exception(Marshal.GetLastWin32Error()); 
IntPtr hglrc; 
if((hglrc = GL.wglCreateContext(dc)) == IntPtr.Zero) 
    throw new Win32Exception(Marshal.GetLastWin32Error()); //<----- here I have exception 

관리 C++에서 동일한 코드가 작동

HDC dc = GetDC(hWnd); 

PIXELFORMATDESCRIPTOR pf; 
pf.nSize = sizeof(PIXELFORMATDESCRIPTOR); 
pf.nVersion = 1; 
pf.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SUPPORT_COMPOSITION; 
pf.cColorBits = 24; 
pf.cRedBits = pf.cRedShift = pf.cGreenBits = pf.cGreenShift = pf.cBlueBits = pf.cBlueShift = 0; 
pf.cAlphaBits = pf.cAlphaShift = 0; 
pf.cAccumBits = pf.cAccumRedBits = pf.cAccumGreenBits = pf.cAccumBlueBits = pf.cAccumAlphaBits = 0; 
pf.cDepthBits = 32; 
pf.cStencilBits = pf.cAuxBuffers = 0; 
pf.iLayerType = PFD_MAIN_PLANE; 
pf.bReserved = 0; 
pf.dwLayerMask = pf.dwVisibleMask = pf.dwDamageMask = 0; 

int ipf = ChoosePixelFormat(dc, &pf); 
SetPixelFormat(dc, ipf, &pf); 

HGLRC hglrc = wglCreateContext(dc); 
나는
먼저 정의 오류 2000 ERROR_INVALID_PIXEL_FORMAT 실패 코드를 다음 한

나는 ATI 그래픽 카드가있는 VIsta 64 비트와 Nvidia가 설치된 Windows XP 32 비트에서이 두 가지 방법으로 같은 결과를 얻으려고했습니다.
또한 이미 작성한 프레임 워크를 사용하고 싶지는 않습니다.

누구나 예외를 일으키는 C# 코드의 버그가 어디에 있습니까?

답변

14

발견.
문제는 매우 이상하고보기가 어렵습니다. 인터넷에서 Somwhere 나는 C++ 응용 프로그램을 컴파일하는 동안 opengl32.lib를 연결할 때 gdi32.lib 앞에 놓여 있어야한다는 것을 알았습니다. 그 이유는 (아마도) opengl32.dll이 ChoosePixelFormat 및 SetPixelFormat 함수를 덮어 쓰고 있기 때문입니다. 내 C++ 버전에서 발견했듯이 우발적 인 경우였습니다.
훗,하지만 tao framework 그들이 KERNEL32.DLL에서 LoadLibrary를 사용하여 해결하는 것이 내가 찾은 검색의 몇 일 후 C#
그것을에서 수행하는 방법() 함수와로드 OPENGL32.DLL

public static bool SetPixelFormat(IntPtr deviceContext, int pixelFormat, ref PIXELFORMATDESCRIPTOR pixelFormatDescriptor) { 
     Kernel.LoadLibrary("opengl32.dll"); 
     return _SetPixelFormat(deviceContext, pixelFormat, ref pixelFormatDescriptor); 
    } 

그래서 SetPixelFormat 호출하기 전에 우리는 gdi32.dll 전에 opengl32.dll을로드해야한다는 것을 알고 있습니다. 다른 방법이 있습니다. 후에 나는 그것을로드하기 위해 opengl32.dll에서 어떤 NOP 함수를 호출 할 수 있다고 생각했다. 예를 들어 :

GL.glGetString(0); 

두 가지 방법으로 문제를 해결 :

[DllImport("opengl32.dll", EntryPoint = "glGetString", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] 
static extern IntPtr _glGetString(StringName name); 
public static string glGetString(StringName name) 
{ 
    return Marshal.PtrToStringAnsi(_glGetString(name)); 
} 
public enum StringName : uint 
{ 
    GL_VENDOR = 0x1F00, 
    GL_RENDERER = 0x1F01, 
    GL_VERSION = 0x1F02, 
    GL_EXTENSIONS = 0x1F03 
} 

및 응용 프로그램의 시작에

은 어떤 호출하기 전에이 사용 gdi32.dll에 있습니다.

0

지금은 테스트 할 수 없지만 첫 번째 의심은 구조체 패킹입니다. StructLayout 속성에서 패킹을 1로 설정해 보았습니까? 예를 들어 :

[StructLayout(LayoutKind.Sequential, Pack=1)] 

건배, 솔루션을 브라이언

0

wglCreateContext를 두 번 호출하면 도움이됩니다.

if (SetPixelFormat(DC, iPixelformat, ref pfd) == false) 
    throw new Win32Exception(Marshal.GetLastWin32Error()); 

RC = wglCreateContext(DC); 
if (RC == HGLRC.Zero) 
{ 
    if (SetPixelFormat(DC, iPixelformat, ref pfd) == false) 
     throw new Win32Exception(Marshal.GetLastWin32Error()); 
    RC = wglCreateContext(DC); 
    if (RC == HGLRC.Zero) 
     throw new Win32Exception(Marshal.GetLastWin32Error()); 
} 
관련 문제