1

I have a function which I can't alter because of protection and abstraction, and it is declared like this:

GetDeviceLongInfo(int, int, ref int);

In which the "ref int" argument to be passed is said to give back 6400 bytes of information.

My question is, how can I get this information in a variable if the only choice I have is to give the function an Int32? Can I allocate more memory for that Int32? Is this even possible to achieve in some way?

EDIT: I can tell you that the function uses the ref int to dump values in it, the int size (size of the information) is not fixed, depends on the option chosed in the second parameter. I can't even look at the function to see how it uses that ref.

Tiago Cachinho
  • 323
  • 1
  • 4
  • 15
  • 1
    I assume that is really a pointer to memory? Marshal.Copy first would be guess: http://stackoverflow.com/questions/9732625/can-intptr-be-cast-into-a-byte-array-without-doing-a-marshal-copy – rene Nov 19 '14 at 10:57
  • How would you make that work? Remember I can only pass an int. – Tiago Cachinho Nov 19 '14 at 11:09
  • This question is a little pointless until you show the unmanaged function's declaration and sample unmanaged code that calls it. – David Heffernan Nov 19 '14 at 12:47
  • It is from SBXPC.OCX, which has little to no information about it online what so ever... The only thing I find online is a buch of questions about it being a possible threat to the computer, which is not the case... If anyone recognizes this ocx and worked with it, please help me! – Tiago Cachinho Nov 19 '14 at 15:45

3 Answers3

1

You can allocate an int[] and pass that to the function. This is a hack but I don't see why it should not be safe.

var array = new int[6400 / sizeof(int)];
GetDevice(..., ref array[0]);

The array is pinned by the CLR for the duration of the call.

Note, that ref is a so called managed pointer to the CLR. It is marshaled by passing it as a pointer and pinning the object it points to. An int[] would be passed in almost the same way (a pointer to the first element is passed).

usr
  • 168,620
  • 35
  • 240
  • 369
0

Can I allocate more memory for that Int32? No

Is this even possible to achieve in some way? Changing the signature or using the int as a reference to the data are both options

Kaido
  • 3,383
  • 24
  • 34
  • Looks like it... but how should I use the int as a reference? – Tiago Cachinho Nov 19 '14 at 11:16
  • Depends where the data is kept. If it is in unmanaged memory, then you have no choice but to Marshal it. I don't know exactly how to do this, but adding attributes as atlaste suggests would break the signature from a compilation point of view but not an interop point of view and seems the best approach. – Kaido Nov 19 '14 at 11:25
  • I made a Marshal ptr, like so: `var values = Marshal.AllocHGlobal(6400).ToInt32();` but it crashes... maybe I'm doing it wrong... – Tiago Cachinho Nov 19 '14 at 11:29
  • @TiagoCachinho: That should work. Also make sure you are compiling for 32-bit. – leppie Nov 19 '14 at 11:57
  • @leppie the project can only compile via x86, but unfortunately, it crashes still. I'm running out of option, sad story... – Tiago Cachinho Nov 19 '14 at 12:07
0

You're attempting to marshal an array (which is a native pointer to data) to an integer. C# will have no problem with that, but processing it is another story. Also note that depending on your architecture you will have different pointer sizes, which means using a 32-bit int isn't the way to go.

See also: http://msdn.microsoft.com/en-us/library/z6cfh6e6(v=vs.110).aspx

I cannot remember the details from the top of my head, but basically you want to use the MarshalAs to tell .NET that it's a pointer to an array. IIRC it was something like this (1600 = 6400/4):

void GetDeviceLongInfo(int, int, [MarshalAs(UnmanagedType.LPArray, SizeConst=1600)] int[] ar );

update

I noticed the questions on how this works, so here it is... How this signature will work: signature in C is probably (long, long, long*) which means the third argument should be a pointer to int. The underlying buffer will be filled with the GetDeviceLongInfo by means of a strncpy or something similar. Things that can go wrong is passing a buffer that's too small (that's checked running it in Debug mode in VS), using the wrong processor architecture, incorrectly passing the integer instead of a pointer (you can try casting the address of your AllocHGlobal to int and see if that works -- that does mean you will have to run on x86 though) and basically a whole lot of other things :-)

Apparently you cannot change anything to the signature. What you're basically attempting to do then is allocate a buffer, cast it to an int* and then process it. Since the approach of usr isn't working, I'd try Marshal.AllocHGlobal to create the buffer, and then pass it to the function (if needed, use unsafe code).

atlaste
  • 30,418
  • 3
  • 57
  • 87