tags:

views:

127

answers:

3

I need to get the address of an integer and assign it to an IntPtr to use in an API. How?

Dim my_integer as Integer
Dim ptr as new IntPtr

' This fails because AddressOf can only be used for functions.
ptr = AddressOf my_integer

APICall(ptr)

What do I do?

+2  A: 

Short answer: you can't and you don't need to. (Although there is a way to do so in C#.)

But there are other ways to do this. When you declare the external function APICall, you need to declare its parameter ByRef, and then just use it. The CLR will take care of getting the address.

I'm a C# guy and don't remember VB.NET's syntax for this, so my apologies. Here's the declaration and use of APICall in C#. Something very closely similar would have to be done in VB.NET:

[DllImport("FooBar.dll")]
static extern APICall(ref int param);

int x = 3;
APICall(ref x);

In sum, whether it's C# or VB.NET, it's all about how you declare APICall, not about getting the address of the integer.

Gregory Higley
The problem with this is, the API is written so that this particular function could send anything. It uses a void pointer. It needs to stay that way otherwise I can't use the function for any other types of access.EdsError EDSAPI EdsGetPropertyData(EdsBaseRef inRef,EdsPropertyID inPropertyID,EdsInt32 inParam,EdsUInt32 inPropertySize,EdsVoid *outPropertyData )Note the last parameter. Depending on inPropertyID, outPropertyData could point to anything. In my one case it is an integer.
superjoe30
+1. I suggest you to change your short answer to "you don't need that". The correct import of unmanaged function is a right way both in C# and VB.NET.
Dmitriy Matveev
Dmitriy: Good suggestion. Done.
Gregory Higley
@superjoe30: You will have to create overloads for each type you want to pass. There is no equivalent of `void*` in C# or VB.NET, as far as I know.
Gregory Higley
See my answer, you can use the Marshall class. It is incorrect to say "You can't"
superjoe30
@superjoe30: You may find C# a better choice of language for this sort of thing. It has features that VB.NET entirely lacks, like the `unsafe` keyword and direct use of pointers in some circumstances. If you want the rest of your project to remain in VB.NET, just do these functions in C# in a separate library, and reference them in your VB.NET project.
Gregory Higley
@superjoe30: Actually, it is correct to say you can't: You can't directly take the address of an integer in VB.NET in the way you had wanted. Although `Marshal` may work, it's not directly equivalent, and I don't really recommend it anyway.
Gregory Higley
The equivalent of `void*` in C# is `void*` :) and I second the call to do this sort of thing in C# - it has `unsafe` for a reason.
Pavel Minaev
I stand corrected by Pavel. There is `void*` in C#, as long as you're inside of an unsafe block. (I believe you can also use it with a `static extern unsafe` method as well.)
Gregory Higley
Greg, you are correct in that usually, in almost every case, it's best to avoid doing this. However, *in this one case* it makes the most sense to do what I'm doing. The question doesn't have enough details for you to see this though, so you are completely correct in your answer. Maybe if I posted the API details you would see that, yeah, okay, maybe this one time using Marshal is the correct solution.
superjoe30
I saw the API. You posted it above. I've been writing C, C++ and so on for a long time, so I know the sort of API call it is. If you _must_ do this in VB.NET, you're stuck with Marshal. However, in C#, you could actually declare it `void*` and use an `unsafe` block, which would be a bit cleaner and easier. (Thanks to Pavel for reminding me that `void*` exists in C#.) Bottom line: it looks like Marshal is the correct solution for your particular set of criteria.
Gregory Higley
+2  A: 

The Marshal class is probably what you need. This article (may be getting a bit out of date now) provides some good examples.

However, I would read the other answer by Gregory that talks about declaring the external function and try to do it that way first. Using Marshal should be a last resort.

Ash
A: 
Imports System.Runtime.InteropServices

Dim my_integer as Integer = 0
Dim ptr as IntPtr = Marshal.AllocHGlobal(4)

Marshal.WriteInt32(my_integer)

APICall(ptr)

my_integer = Marshal.ReadInt32(ptr)

Marshal.FreeHGlobal(ptr)
superjoe30
Don't forget to free the memory you allocated with `AllocHGlobal`.
Gregory Higley
@superjoe30, Did you magically just realise this, or is it from the link I provided you?
Ash
Ash, I upvoted your answer and then dug up the *actual source code* answer to my question and posted it, which I think provides value to the page.
superjoe30