2008-10-13 34 views
5

我想在C#中使用opengl。我有以下代碼失敗,錯誤2000 ERROR_INVALID_PIXEL_FORMAT
首先定義: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); 

我已經用VITIAL 64位ATI顯卡和Windows XP 32位Nvidia在兩種情況下都使用了相同的結果。
另外我想提一下,我不想使用任何已經寫好的框架。

任何人都可以告訴我哪裏是導致異常的C#代碼中的錯誤?

回答

14

找到解決方案。
問題非常奇怪難看,真的很難找到。在互聯網上的Somwhere,我發現當你在編譯C++應用程序時連接opengl32.lib時,它必須放在gdi32.lib之前。原因是(據推測)opengl32.dll覆蓋ChoosePixelFormat和SetPixelFormat函數(可能更多:-)。正如我在我的C++版本中發現的那樣,意外情況是這樣。
嘿,而是如何做它在C#
搜索後,我發現了幾天,在tao framework他們解決它使用kernel32.dll中調用LoadLibrary()函數和加載OPENGL32.DLL調用SetPixelFormat

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

所以之前我們知道opengl32.dll必須在gdi32.dll之前加載,是否有其他方式來做到這一點。之後,我認爲我們可以從opengl32.dll中調用一些NOP函數來加載它。例如:

[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我用這個:

GL.glGetString(0); 

兩種方式解決這個問題。

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