2008-10-13 6 views
5

Ich versuche, OpenGL in C# zu verwenden. Ich habe folgende Code, der mit dem Fehler 2000 ERROR_INVALID_PIXEL_FORMAT
Erste Definitionen fehlschlägt:wglCreateContext in C# fehlgeschlagen, aber nicht in verwaltetem 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); 

Und nun der Code, der fehlschlägt:

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 

den gleichen Code in verwaltetem C++ arbeitet

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); 

Ich habe es auf VIsta 64-Bit mit ATI-Grafikkarte und auf Windows XP 32-Bit mit Nvidia mit dem gleichen Ergebnis in beiden Fällen versucht.
Auch möchte ich erwähnen, dass ich kein bereits geschriebenes Framework dafür verwenden möchte.

Kann mir jemand zeigen, wo ist der Fehler in C# -Code, der die Ausnahme verursacht?

Antwort

14

gefunden Lösung.
Problem ist sehr seltsam hässlich und wirklich schwer zu finden. Irgendwo im Internet fand ich, dass wenn Sie opengl32.lib während der Kompilierung von C++ - Anwendung verknüpfen, es vor gdi32.lib platziert werden muss. Der Grund dafür ist, dass (angeblich) opengl32.dll die Funktionen ChoosePixelFormat und SetPixelFormat überschreibt (und wahrscheinlich mehr :-). Wie ich in meiner C++ Version gefunden habe, war es aus Versehen der Fall.
Heh, aber wie es zu tun in C#
Nach einigen Tagen des Suchens fand ich, dass in tao framework sie es mit kernel32.dll Loadlibrary() Funktion und Laden opengl32.dll gelöst vor SetPixelFormat

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

So rufen wir wissen, dass opengl32.dll vor gdi32.dll geladen werden muss, gibt es eine andere Möglichkeit, dies zu tun. Nachher dachte ich, dass wir eine NOP-Funktion von opengl32.dll aufrufen können, um sie zu laden. Zum Beispiel:

[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 
} 

und über den Beginn der Anwendung vor jedem Aufruf Gdi32.dll Ich benutze diese:

GL.glGetString(0); 

Beiden Möglichkeiten, das Problem löst.

0

Ich kann das jetzt nicht testen, aber mein erster Verdacht wäre die Struktur Verpackung. Haben Sie versucht, das Attribut StructLayout auf 1 zu setzen? Zum Beispiel:

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

Cheers, Brian

0

Das zweimalige Aufrufen von wglCreateContext hilft auch.

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()); 
} 
Verwandte Themen