struct -> null

  • Thread starter Thread starter Juan Gabriel Del Cid
  • Start date Start date
J

Juan Gabriel Del Cid

Structs are value types (in C++ and in C#), so NULL would be incompatible
with any struct type. Now, if you want to pass NULL for a reference type,
for example if yourfunction was declared like:

open (struct struct1 *str, struct struct1 *str2) { ... }

you would do so with IntPtr.Zero (that is NULL).

Hope that helps,
-JG
 
Hello,

if I have a P/Invoke method: open(STRUCT1 str, STRUCT2 str2);

is there a way to pass <null> for a struct in C#?
How can I solve this?

thx
 
Create two DllImports for the same api. The second one will be overloaded
with something like "object flag" on the STRUCT2 parm. Now you can pass a
STRUCT2 or a null ref. Example:

[DllImport("kernel32.dll")]
public static extern uint GetFileSize(
IntPtr hFile, //[in] Handle to the file for size.
ref uint fileSizeHigh); //[out] Pointer to var where high-order word is
returned.

[DllImport("kernel32.dll")]
public static extern uint GetFileSize(
IntPtr hFile, //[in] Handle to the file for size.
object flag); //[out] Overloaded to allow passing null.
 
From the help on IntPtr.Zero: "The value of this field is not equivalent to
a null reference..."
Wouldn't you be passing a ptr to the IntPtr struct that contains a zero? Or
does pInvoke change this to a null ref?
 
is there a way to pass <null> for a struct in C#?
How can I solve this?

In addition to what the other suggested, another way is to use unsafe
code and a real pointer type

STRUCT1* str

And yet another option is to change the parameter type to an array

STRUCT1[] str

and then either pass in a single-element array or null.



Mattias
 
From the help on IntPtr.Zero: "The value of this field is not
equivalent to a null reference..."

Of course it's not a null reference, it's a value type. In the past there
was no distinction between a value type and a reference type. You could cast
data to whatever you wanted and back. For example, a pointer is really
nothing more than an integer (4 bytes on a 32 bit processor). In this case,
NULL is just 4 bytes all set to zero (just like IntPtr.Zero).

So, in C/C++ you have:

if ((int)NULL == 0) {
// this is always true
}

and in C# you have:

if ((int)null == 0) {
// this will never compile because you can't convert
// null (or any other reference type)
// to an int (or any other value type)
}

if ((int)IntPtr.Zero == 0) {
// this is always true
}

Hope that clears it up for you,
-JG
 
In terms of the OP question, IntPtr does not help him. Assume the exported
function is something like:
BOOL DoSomething(SOMESTRUCT * struct1);

And the managed struct and/or class is:
// Declares a managed structure for the unmanaged structure.
[ StructLayout( LayoutKind.Sequential )]
public struct MyStruct
{
public int one = 1;
public long two =2;
}
// Declares a managed class for the unmanaged structure.
[ StructLayout( LayoutKind.Sequential )]
public class MyClass
{
public int one = 1;
public long two = 2;
}

Then his exports might be something like (among others):
// Because MyStruct is a value type, you cannot pass null as a
// parameter. Instead, declare an overloaded method.
[ DllImport( "Kernel32.dll" )]
public static extern bool DoSomething(
ref MyStruct myStruct );

[ DllImport( "Kernel32.dll" )]
public static extern bool DoSomething(
int flag ); // Declares an int instead of a structure reference so you
can pass a zero.

// Because MyClass is a class, you can also pass null as parameter.
// No overloading is needed.
[ DllImport( "Kernel32.dll", EntryPoint="DoSomething" )]
public static extern bool DoSomething2(
MyClass myClass );

Then he can call "DoSomething" like:
MyStruct ms;
MyClass mc = new MyClass();
bool b = DoSomething(ref ms); //Call using ref to struct.
bool b = DoSomething(0); //Call passing zero. You could pass
(int)IntPtr.Zero here, but why?
bool b = DoSomething2(mc); //Call using ref to class.
bool b = DoSomething2(null); //Call passing null.

In none of those cases does IntPtr help.
 
Back
Top