Help cast Mask GetPrivateProfileString from Kernel32

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • alag20
    New Member
    • Apr 2007
    • 84

    Help cast Mask GetPrivateProfileString from Kernel32

    Hi Guys,
    I need some urgent help with this as I am becoming clueless now.

    I have 2 DllImport as below from Kernel32

    Code:
    [DllImport("kernel32")]
    private static extern int GetPrivateProfileString(string section, int key, string defaultValue, [MarshalAs(UnmanagedType.LPArray)] byte[] result, int size, string fileName);
    
    [DllImport("kernel32")]
    private static extern int GetPrivateProfileString(string section, string key, string defaultValue, StringBuilder result, int size, string fileName);
    Now, I have made my DLL called CustomDLL.DLL which maps the second one properly. However, I am trying to use this and convert one above aswell and this is where i am not sure what to do.

    ***this doesnt work*******
    Code:
    private static int GetPrivateProfileString(string section, int key, string defaultValue, [MarshalAs(UnmanagedType.LPArray)] byte[] result, int size, string fileName)
            {
                StringBuilder res = new StringBuilder(Encoding.ASCII.GetString(result));
                int ret = IniFile.GetPrivateProfileString(section, key.ToString(), defaultValue, res, size, fileName);
    
                result = Encoding.ASCII.GetBytes(res.ToString());
                
                return ret;
            }
    ****this works fine*********** *
    Code:
    private static int GetPrivateProfileString(string section, string key, string defaultValue, StringBuilder result, int size, string fileName)
            {
                return IniFile.GetPrivateProfileString(section, key, defaultValue, result, size, fileName);
            }


    Please help, how do i make the not working bit working here. Any help will be appreciated as this is very very urgent!
  • nukefusion
    Recognized Expert New Member
    • Mar 2008
    • 221

    #2
    Hi There,
    Should you not be passing a char array instead of a byte array? Like this:

    Code:
    [DllImport("kernel32.dll")]
    static extern uint GetPrivateProfileString(
       string lpAppName, 
       string lpKeyName,
       string lpDefault, 
       [In, Out] char[] lpReturnedString, 
       uint nSize,
       string lpFileName);
    Also, please try to use code tags when posting code samples, as it makes it easier for us to read.

    Comment

    • vekipeki
      Recognized Expert New Member
      • Nov 2007
      • 229

      #3
      If I understood well, you want to create a .Net assembly (CustomDLL.DLL) which wraps Kernel32 imports?

      1. If CustomDLL.DLL is going to be called from managed code only, you shouldn't add the MarshalAs() attribute. If it is not being marshalled, this only makes it confusing later.

      2. When you say "it doesn't work", what does that actually mean? One thing that surely does not work is changing your "result" parameter's reference in line:

      Code:
      result = Encoding.ASCII.GetBytes(res.ToString());
      Since "result" is passed by value, you cannot expect it to change outside your method. Here is what I'm talking about:

      Code:
      private static void DoSomething(int x)
      {
          x = 5;
      }
      
      private static void Main()
      {
            int x = 4;
            DoSomething(x);
            Console.WriteLine(x); // x is 4
      }
      But the actual remark is: if you are wrapping DllImports, you don't need to stick to the original function signature in your managed code; you are free to pass any parameters and return any object from your method (returning int in managed code for error handling is usually avoided), so it's best to create a method that is simple to use from managed code, and then hide the messy DllImport stuff inside.

      Comment

      • alag20
        New Member
        • Apr 2007
        • 84

        #4
        Hi nuke,
        Thanks for you help.

        The way the application stands, I am being forced to used byte array.

        I cant go changing the who app so i need to make the switch at this level, i.e. map my dll there so that it can take that byte array. instead of StringBuilder etc.

        Please help

        Comment

        • alag20
          New Member
          • Apr 2007
          • 84

          #5
          hi vekipeki

          I tried the following :-

          Code:
          private static int GetPrivateProfileString(int section, string key, string defaultValue,[MarshalAs(UnmanagedType.LPArray)] byte[] result, int size, string fileName)
          {
             StringBuilder res = new StringBuilder(Encoding.ASCII.GetString(result));
             int ret = IniFile.GetPrivateProfileString(section.ToString(), key, defaultValue, res, size, fileName);
          
                      result = Encoding.ASCII.GetBytes(res.ToString());
          
                      return ret;
                  }

          Doesnt work either - i should have mentioned that i already tried that:(


          As i mentioned, the CustomDll is in C++ which has been done for one reason only - that filename can be changed on the fly and this has been done by an external company and i have no access to its source code:(

          Comment

          • nukefusion
            Recognized Expert New Member
            • Mar 2008
            • 221

            #6
            I'm not sure I understand entirely what it is you are trying to do. You simply cannot use a byte array in your call to the Kernel32 method because it's not available as a parameter in the signature exposed.
            If needs be, you'll need to do some sort of type conversion within your custom dll, but you can't pass a byte array if the method doesn't accept it.

            Comment

            • vekipeki
              Recognized Expert New Member
              • Nov 2007
              • 229

              #7
              I am also not sure I understand what's going on, but here is what I am talking about (that is at least one of the problems).

              This will never work, because result will point to a different object, so after the method ends the original byte[] array will not be changed:
              Code:
              result = Encoding.ASCII.GetBytes(res.ToString());
              If you want the result to be changed, you can either:

              1. Add the ref keyword to pass it by reference:
              Code:
              ref byte[] result
              2. Or, if your method signature must stay the same, use Array.Copy to actually copy the elements into your array:
              Code:
              byte[] data = Encoding.ASCII.GetBytes("000");
              Array.Copy(data, result, data.Length);
              Note that the last line will throw an exception if result is not large enough, so it must be preallocated to the right size. You cannot allocate it or resize it in this method, because it is not passed by reference.

              Comment

              Working...