By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,776 Members | 1,302 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,776 IT Pros & Developers. It's quick & easy.

Help cast Mask GetPrivateProfileString from Kernel32

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

I have 2 DllImport as below from Kernel32

Expand|Select|Wrap|Line Numbers
  1. [DllImport("kernel32")]
  2. private static extern int GetPrivateProfileString(string section, int key, string defaultValue, [MarshalAs(UnmanagedType.LPArray)] byte[] result, int size, string fileName);
  3.  
  4. [DllImport("kernel32")]
  5. 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*******
Expand|Select|Wrap|Line Numbers
  1. private static int GetPrivateProfileString(string section, int key, string defaultValue, [MarshalAs(UnmanagedType.LPArray)] byte[] result, int size, string fileName)
  2.         {
  3.             StringBuilder res = new StringBuilder(Encoding.ASCII.GetString(result));
  4.             int ret = IniFile.GetPrivateProfileString(section, key.ToString(), defaultValue, res, size, fileName);
  5.  
  6.             result = Encoding.ASCII.GetBytes(res.ToString());
  7.  
  8.             return ret;
  9.         }
  10.  
****this works fine************
Expand|Select|Wrap|Line Numbers
  1. private static int GetPrivateProfileString(string section, string key, string defaultValue, StringBuilder result, int size, string fileName)
  2.         {
  3.             return IniFile.GetPrivateProfileString(section, key, defaultValue, result, size, fileName);
  4.         }


Please help, how do i make the not working bit working here. Any help will be appreciated as this is very very urgent!
Jan 16 '09 #1
Share this Question
Share on Google+
6 Replies


nukefusion
Expert 100+
P: 221
Hi There,
Should you not be passing a char array instead of a byte array? Like this:

Expand|Select|Wrap|Line Numbers
  1. [DllImport("kernel32.dll")]
  2. static extern uint GetPrivateProfileString(
  3.    string lpAppName, 
  4.    string lpKeyName,
  5.    string lpDefault, 
  6.    [In, Out] char[] lpReturnedString, 
  7.    uint nSize,
  8.    string lpFileName);
  9.  
Also, please try to use code tags when posting code samples, as it makes it easier for us to read.
Jan 16 '09 #2

vekipeki
Expert 100+
P: 229
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:

Expand|Select|Wrap|Line Numbers
  1. 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:

Expand|Select|Wrap|Line Numbers
  1. private static void DoSomething(int x)
  2. {
  3.     x = 5;
  4. }
  5.  
  6. private static void Main()
  7. {
  8.       int x = 4;
  9.       DoSomething(x);
  10.       Console.WriteLine(x); // x is 4
  11. }
  12.  
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.
Jan 16 '09 #3

P: 84
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
Jan 16 '09 #4

P: 84
hi vekipeki

I tried the following :-

Expand|Select|Wrap|Line Numbers
  1. private static int GetPrivateProfileString(int section, string key, string defaultValue,[MarshalAs(UnmanagedType.LPArray)] byte[] result, int size, string fileName)
  2. {
  3.    StringBuilder res = new StringBuilder(Encoding.ASCII.GetString(result));
  4.    int ret = IniFile.GetPrivateProfileString(section.ToString(), key, defaultValue, res, size, fileName);
  5.  
  6.             result = Encoding.ASCII.GetBytes(res.ToString());
  7.  
  8.             return ret;
  9.         }
  10.  

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:(
Jan 16 '09 #5

nukefusion
Expert 100+
P: 221
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.
Jan 16 '09 #6

vekipeki
Expert 100+
P: 229
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:
Expand|Select|Wrap|Line Numbers
  1. 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:
Expand|Select|Wrap|Line Numbers
  1. ref byte[] result
2. Or, if your method signature must stay the same, use Array.Copy to actually copy the elements into your array:
Expand|Select|Wrap|Line Numbers
  1. byte[] data = Encoding.ASCII.GetBytes("000");
  2. Array.Copy(data, result, data.Length);
  3.  
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.
Jan 16 '09 #7

Post your reply

Sign in to post your reply or Sign up for a free account.