[.net] Marshalling string[] to char**

Started by
6 comments, last by mutex 17 years, 9 months ago
Ok, I'm working on an OpenGL wrapper for C# (because Tao doesn't play well with x64 if you want to use it to its fullest -- I know you can force a .NET app to run as 32 bit anyway, but I, and many other x64 users, want to actually use the hardware they bought, not sit there running things that are starting to become outdated). So now I'm trying to implement the ability to start using shaders in it. thus far, I have something along the lines of this going:
public static void AttachShader(uint ProgramID, uint ShaderID) {
            m_AttachShader.DynamicInvoke(new object[] { ProgramID, ShaderID });
        }
        public static void CompileShader(uint ShaderID) {
            m_CompileShader.DynamicInvoke(new object[] { ShaderID });
        }
        public static uint CreateProgram() {
            return (uint)m_CreateProgram.DynamicInvoke(null);
        }
        public static uint CreateShader(glShader Type) {
            return (uint)m_CreateShader.DynamicInvoke(new object[] { Type });
        }
        public static void DeleteProgram(uint ProgramID) {
            m_DeleteProgram.DynamicInvoke(new object[] { ProgramID });
        }
        public static void DeleteShader(uint ShaderID) {
            m_DeleteShader.DynamicInvoke(new object[] { ShaderID });
        }
        public static void DetachShader(uint ProgramID, uint ShaderID) {
            m_DetachShader.DynamicInvoke(new object[] { ProgramID, ShaderID });
        }
        public static void GetProgramInfoLog(uint ShaderID, int LogSize, ref int LengthOut, ref StringBuilder LogOut) {
            m_GetProgramInfoLog.DynamicInvoke(new object[] { ShaderID, LogSize, LengthOut, LogOut });
        }
        public static void GetShaderInfoLog(uint ShaderID, int LogSize, ref int LengthOut, ref StringBuilder LogOut) {
            m_GetShaderInfoLog.DynamicInvoke(new object[] { ShaderID, LogSize, LengthOut, LogOut });
        }
        public static int GetUniformLocation(uint ProgramID, string Name) {
            return (int)m_GetUniformLocation.DynamicInvoke(new object[] { ProgramID, Name });
        }
        public static void LinkProgram(uint ProgramID) {
            m_LinkProgram.DynamicInvoke(new object[] { ProgramID });
        }
        public static void ShaderSource(uint ShaderID, int Count, string[] Sources, int[] SourceSizes) {
            m_ShaderSource.DynamicInvoke(new object[] { ShaderID, Count, Sources, SourceSizes });
        }
        public static void Uniform1(int Location, int Count, float[] Values) {
            m_Uniform1f.DynamicInvoke(new object[] { Location, Count, Values });
        }
        public static void Uniform2(int Location, int Count, float[] Values) {
            m_Uniform2f.DynamicInvoke(new object[] { Location, Count, Values });
        }
        public static void Uniform3(int Location, int Count, float[] Values) {
            m_Uniform3f.DynamicInvoke(new object[] { Location, Count, Values });
        }
        public static void Uniform4(int Location, int Count, float[] Values) {
            m_Uniform4f.DynamicInvoke(new object[] { Location, Count, Values });
        }
        public static void Uniform1(int Location, int Count, int[] Values) {
            m_Uniform1i.DynamicInvoke(new object[] { Location, Count, Values });
        }
        public static void Uniform2(int Location, int Count, int[] Values) {
            m_Uniform2i.DynamicInvoke(new object[] { Location, Count, Values });
        }
        public static void Uniform3(int Location, int Count, int[] Values) {
            m_Uniform3i.DynamicInvoke(new object[] { Location, Count, Values });
        }
        public static void Uniform4(int Location, int Count, int[] Values) {
            m_Uniform4i.DynamicInvoke(new object[] { Location, Count, Values });
        }
        public static void UseProgram(uint ProgramID) {
            m_UseProgram.DynamicInvoke(new object[] { ProgramID });
        }

        public static void EnableShaders() {
            m_AttachShader = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glAttachShader"), typeof(delattachshader));

            m_CompileShader = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glCompileShader"), typeof(delcompile));
            m_CreateProgram = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glCreateProgram"), typeof(delcreateprog));
            m_CreateShader = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glCreateProgram"), typeof(delcreateshader));

            m_DeleteProgram = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glDeleteProgram"), typeof(deldelshader));
            m_DeleteShader = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glDeleteShader"), typeof(deldelshader));
            m_DetachShader = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glDetachShader"), typeof(deldetachshader));


            m_GetProgramInfoLog = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glGetProgramInfoLog"), typeof(dellog));
            m_GetShaderInfoLog = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glGetShaderInfoLog"), typeof(dellog));
            m_GetUniformLocation = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glGetUniformLocation"), typeof(deluniloc));

            m_LinkProgram = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glLinkProgram"), typeof(dellink));

            m_ShaderSource = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glShaderSource"), typeof(delshadersource));

            m_Uniform1f = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glUniform1fv"), typeof(deluniformf));
            m_Uniform2f = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glUniform2fv"), typeof(deluniformf));
            m_Uniform3f = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glUniform3fv"), typeof(deluniformf));
            m_Uniform4f = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glUniform4fv"), typeof(deluniformf));

            m_Uniform1i = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glUniform1iv"), typeof(deluniformi));
            m_Uniform2i = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glUniform2iv"), typeof(deluniformi));
            m_Uniform3i = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glUniform3iv"), typeof(deluniformi));
            m_Uniform4i = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glUniform4iv"), typeof(deluniformi));

            m_UseProgram = Marshal.GetDelegateForFunctionPointer(wgl.GetProcAddress("glUseProgram"), typeof(deluseprogram));
        }

        private static Delegate m_AttachShader;
        private static Delegate m_CompileShader;
        private static Delegate m_CreateProgram;
        private static Delegate m_CreateShader;
        private static Delegate m_DeleteProgram;
        private static Delegate m_DeleteShader;
        private static Delegate m_DetachShader;
        private static Delegate m_GetProgramInfoLog;
        private static Delegate m_GetShaderInfoLog;
        private static Delegate m_GetUniformLocation;
        private static Delegate m_LinkProgram;
        private static Delegate m_ShaderSource;
        private static Delegate m_Uniform1f;
        private static Delegate m_Uniform2f;
        private static Delegate m_Uniform3f;
        private static Delegate m_Uniform4f;
        private static Delegate m_Uniform1i;
        private static Delegate m_Uniform2i;
        private static Delegate m_Uniform3i;
        private static Delegate m_Uniform4i;
        private static Delegate m_UseProgram;

        private delegate void delattachshader(uint prog, uint shader);
        private delegate void delcompile(uint shader);
        private delegate uint delcreateprog();
        private delegate uint delcreateshader(glShader type);
        private delegate void deldelshader(uint id);
        private delegate void deldetachshader(uint prog, uint shader);
        private delegate void dellink(uint prog);
        private delegate void dellog(uint ShaderID, int LogSize, ref int LengthOut, [Out] StringBuilder LogOut);
        private delegate void delshadersource(uint shader, int count, ref string[] sources, ref int[] size);
        private delegate void deluniformf(int loc, int count, float[] vals);
        private delegate void deluniformi(int loc, int count, int[] vals);
        private delegate int deluniloc(uint prog, string[] name);
        private delegate void deluseprogram(uint prog);


everything seems to be working except the functions involving string and StringBuilder (glShaderSource and glGetUniformLocation being the most important). My only guess as to why these don't work would be that it does like converting the string to char[] when using Delegate.DynamicInvoke, but I don't really know of another way to use the function pointers as functions. If that is the reason, could someone please tell me an alternate way of doing it? I'm thinking it doesn't like Marshalling the string[] to the char** that OpenGL is expecting. (If I try making the delegate have char[][] in place of string[] it won't work because Marshalling can't be done on nested arrays) As a side note: I've already tried looking at the Tao source code but all I can really find is massive numbers of overloads that throw an exception when they are called. Thanks. [Edited by - amnesiasoft on June 25, 2006 3:53:34 AM]
Advertisement
Ah, at last, someone who is writing his own OpenGL bindings for C#!

I have come across the same problem while writing my own OpenGL bindings. While I haven't written the wrappers for the shader functions yet, if I remember correctly char**s should be marshalled as ref strings (or ref StringBuilders) by default, not as string[]s. As I said, I haven't tried this yet, but I'm positive that a reference to a StringBuilder will work ok (well, there's nothing to lose anyway!)

About the exceptions in Tao.OpenGL, they are actually postprocessed into real code by some kind of custom IL tool (because of a limitation of the 1.1 specification or something along these lines.) The 2.0 Tao branch does not suffer from these problems.

How are you loading the OpenGL extensions? I am using the 2.0 function GetDelegateFromFunctionPointer which works very nicely, but I was wondering if there is some other way.

[OpenTK: C# OpenGL 4.4, OpenGL ES 3.0 and OpenAL 1.1. Now with Linux/KMS support!]

Alright, thanks, I'll give it a try.

And while I know Tao does some post processing to the dll's, the reason it won't work on x64 is because x64 programs can't load x86 dll's, and vice versa.

And I'm using that same method to load GL Extensions, I can't think of another way to do it.

EDIT: Well, it didn't work, I guess I'll have to find another way. But thanks for at least trying to help me.
Quote:Original post by Fiddler
The 2.0 Tao branch does not suffer from these problems.



Where do you find the 2.0 branch of tao? I haven't had any luck compiling tao with .net 2.0, only 1.1, so this would help me a lot (I need signed dlls, so I need to compile them myself).
Well, for those interested, I figured out the problem...I was making the CreateShader delegate call CreateProgram. The lesson of this story is: Copy and Paste is a powerful tool, but it must be used carefully :P
Glad you figured it out! The correct parameter was "string[]" or "ref string"?

RipTorn, I read about the 2.0 branch in the developer forums, though I do not know if it has been checked in yet.

[OpenTK: C# OpenGL 4.4, OpenGL ES 3.0 and OpenAL 1.1. Now with Linux/KMS support!]

both string[] and ref string will work.
Just FYI DynamicInvoke is pretty slow, so you might want to do some benchmarking to see how it compares with P/Invoke before you spend a lot of time wrapping OpenGL. See Calling Code Dynamically and Dodge Common Performance Pitfalls to Craft Speedy Applications.

Why not design your wrapper like this (the p/invoke definitions may be incorrect):
public class OpenGL{  public static void AttachShader(uint programID, uint shaderID)  {    glAttachShader(program, shader);  }  [DllImport("opengl32.dll"), CallingConvention=CallingConvention.Winapi)]  private static extern bool glAttachShader(uint program, uint shader);}

This topic is closed to new replies.

Advertisement