Clicky

Experts,

I am attempting to learn a little more on unsafe code within C# and are running into a problem with converting a char pointer to a string.  To give a little background on what I am doing is reading in a file with a specific structure into a void pointer.  I then cast my struct pointers from the void pointer.  All of that works great with no problems.  However, on one of them, there is a char pointer with a variable size that is causing errors.  In typical managed code I would simply read in the value starting at the specified offset and going until I reach the passed in length.

I have tried several methods but here is how it is declared in C/C++

 struct key {   short len_name;   short len_classnam;   char  keyname[1]; };                             
1: 2: 3: 4: 5: 

Select allOpen in new window



I have tried using an IntPtr, char*, byte*, void* and using Marshal functions like copy and allocate.  Also attempted to use the new string(char*) method but all of them either give a access violation error or return an empty string.  The keyname is a null-terminated ASCII string.

Thanks

asked 12/06/2011 02:09

jabullard's gravatar image

jabullard ♦♦


9 Answers:
The string constructor has an overload to accept a char*. Have you tried that?

1:
2:
char* data = ...
string s = new string(data);
link

answered

kaufmed's gravatar image

kaufmed

Never mind...  Sometimes I type before I completely read  : \
link

answered 2011-12-06 at 10:19:25

kaufmed's gravatar image

kaufmed

It should be something like this usually there would be a maximum key name constant defined in this example it's set to 64 characters
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
private const int MAX_KEYNAMELENGTH = 64;

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        private struct Key
        {
            public short lenName;
            public short lenClassName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_KEYNAMELENGTH)]
            public string KeyName;
        }
link

answered 2011-12-06 at 10:19:53

egl1044's gravatar image

egl1044

keyname[1] actually if I can remember is ANYSIZE_ARRAY in that case it may need to be changed to LPStr if it doesn't have a maximum length defined for KeyName member.
1:
[MarshalAs(UnmanagedType.LPStr)]
link

answered 2011-12-06 at 10:28:59

egl1044's gravatar image

egl1044

egl1044,

I have tried marshalling it as you showed; however, since I am using an usafe pointer

1:
key* _k = (key*)(_ptr + offset);


you can't use a string.  It will throw an error about not being able to get the size of, address of, etc of a managed type.
link

answered 2011-12-06 at 10:46:21

jabullard's gravatar image

jabullard

Alright, so I have gotten the string to actually be marshalled but I'm not a fan of the solution.  So here is what I have so far:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Auto, Pack = 1)]
internal unsafe struct key
{
[FieldOffset(0x4C)]
public short name_length;

[FieldOffset(0x4E)]
public short class_name_length;

[FieldOffset(0x50)]
public char* name;
}


And here is what I have to do in order to get the name:

1:
2:
3:
byte[] b = new byte[_nk->name_length];
Marshal.Copy(new IntPtr(_ptr + _CellOffset + 0x50), b, 0x0, _nk->name_length);
MessageBox.Show(System.Text.Encoding.ASCII.GetString(b));


So if you have any ideas on how to actually make this solution better please let me know.  I am thinking that using two methods GetName and SetName(name) is how I am going to accomplish it temporarily.
link

answered 2011-12-06 at 11:31:34

jabullard's gravatar image

jabullard

Well, I have attempted pretty much everything that I know of to get that one character pointer to work.  Though the above script works, you have to know the pointer location in order to copy the bytes and then return the string.

To me, the character pointer (name) is jacked up.  In C++, it will return the character array being pointed to; however, in C#, I have to do pointer arithmetic in order to get the value.  Doesn't make sense why that is.

I'll leave this open for a few more days just in case anyone else might have an idea.
link

answered 2011-12-06 at 11:56:26

jabullard's gravatar image

jabullard

So I finally got my solution to work.  In the end, what you have to do is use this:

1:
public fixed char name[1];


Once you have read in your unsafe struct, you simply Marshal it PtrToStringAnsi with the length of the passed in value (name_length);
link

answered 2011-12-07 at 09:29:54

jabullard's gravatar image

jabullard

It is the only solution that worked.

link

answered 2011-12-12 at 14:50:25

jabullard's gravatar image

jabullard

Your answer
[hide preview]

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Tags:

×156
×1
×3
×1

Asked: 12/06/2011 02:09

Seen: 296 times

Last updated: 12/16/2011 05:20