Marshaling Structure

  • Thread starter Thread starter Kevin Hutchison
  • Start date Start date
K

Kevin Hutchison

Is my understanding here correct?

When an extern function prototype requires a structure to be passed by
reference, the marshaler creates a copy of structure in unmanaged memory and
pushes a pointer to the memory location on the call stack. Upon return from
the call, the marshaller frees the unmanaged memory allocated just prior to
the call.

For two unmanged functions declared as:

BOOL ConfigStart( START_DATA *psData );
void Start();

If "Start" attempts to use a reference to psData stored in "ConfigStart",
it may fail because the memory had already been freed.

- K.
 
I'm somewhat confused by the question, but I think the answer is no.

If you have this:

void foo()
{
START_DATA sd;
sd.data1 = 1;
sd.data2 = 3;

ConfigStart(&sd);
Start(&sd);
}

sd can be used as long as it's in scope, so in Start it's fine.

Again, the question isn't clear, and if you could post some code that would
help clarify.

-Chris
 
Sorry for any confusion, I hope this is clearer:

struct START_DATA {
public int int1;
public int int2;
}

[DLLImport("start.dll")]
public static extern bool ConfigStart( ref STARTDATA psData );

[DLLImport("start.dll")]
public static extern void Start( );

....

void foo()
{
START_DATA sd;
sd.data1 = 1;
sd.data2 = 3;

if ( ConfigStart( ref sd ) )
{
Start();
}
}

From the API side, is the address passed to ConfigStart for "sd" still valid
when start is called?

- K.
 
Ah, now I see. The answer is "don't count on it". Since the object isn't
pinned, the GC is free to move it where it wishes, so the address may stay
the swame or it may not. Pinning it is the only way to ensure the address
stays the same (or call LocalAlloc or use unsafe code).

-Chris

Kevin Hutchison said:
Sorry for any confusion, I hope this is clearer:

struct START_DATA {
public int int1;
public int int2;
}

[DLLImport("start.dll")]
public static extern bool ConfigStart( ref STARTDATA psData );

[DLLImport("start.dll")]
public static extern void Start( );

...

void foo()
{
START_DATA sd;
sd.data1 = 1;
sd.data2 = 3;

if ( ConfigStart( ref sd ) )
{
Start();
}
}

From the API side, is the address passed to ConfigStart for "sd" still valid
when start is called?

- K.




Chris Tacke said:
I'm somewhat confused by the question, but I think the answer is no.

If you have this:

void foo()
{
START_DATA sd;
sd.data1 = 1;
sd.data2 = 3;

ConfigStart(&sd);
Start(&sd);
}

sd can be used as long as it's in scope, so in Start it's fine.

Again, the question isn't clear, and if you could post some code that would
help clarify.

-Chris



memory
and return
from prior
to
 
Tx Chris. ... The short term solution is going to be unsafe code, but long
term we cannot have unsafe blocks. Busy weekend ahead!

- K.


Chris Tacke said:
Ah, now I see. The answer is "don't count on it". Since the object isn't
pinned, the GC is free to move it where it wishes, so the address may stay
the swame or it may not. Pinning it is the only way to ensure the address
stays the same (or call LocalAlloc or use unsafe code).

-Chris

Kevin Hutchison said:
Sorry for any confusion, I hope this is clearer:

struct START_DATA {
public int int1;
public int int2;
}

[DLLImport("start.dll")]
public static extern bool ConfigStart( ref STARTDATA psData );

[DLLImport("start.dll")]
public static extern void Start( );

...

void foo()
{
START_DATA sd;
sd.data1 = 1;
sd.data2 = 3;

if ( ConfigStart( ref sd ) )
{
Start();
}
}

From the API side, is the address passed to ConfigStart for "sd" still valid
when start is called?

- K.




Chris Tacke said:
I'm somewhat confused by the question, but I think the answer is no.

If you have this:

void foo()
{
START_DATA sd;
sd.data1 = 1;
sd.data2 = 3;

ConfigStart(&sd);
Start(&sd);
}

sd can be used as long as it's in scope, so in Start it's fine.

Again, the question isn't clear, and if you could post some code that would
help clarify.

-Chris



Is my understanding here correct?

When an extern function prototype requires a structure to be passed by
reference, the marshaler creates a copy of structure in unmanaged memory
and
pushes a pointer to the memory location on the call stack. Upon return
from
the call, the marshaller frees the unmanaged memory allocated just prior
to
the call.

For two unmanged functions declared as:

BOOL ConfigStart( START_DATA *psData );
void Start();

If "Start" attempts to use a reference to psData stored in "ConfigStart",
it may fail because the memory had already been freed.

- K.
 
Interesting. Is it a company policy against unsafe blocks? Is there a
specific reason, or simply becasue it's called "unsafe"? You're not the
only person I've heard say that you can't use them and I'm just wondering
what the rationale behind it is. Personally I like unsafe for some things,
but I'm just curios how many devs out there are forces to not use it. Do
you have limitations on creating unmanaged DLLs and calling them?

-Chris


Kevin Hutchison said:
Tx Chris. ... The short term solution is going to be unsafe code, but long
term we cannot have unsafe blocks. Busy weekend ahead!

- K.


Chris Tacke said:
Ah, now I see. The answer is "don't count on it". Since the object isn't
pinned, the GC is free to move it where it wishes, so the address may stay
the swame or it may not. Pinning it is the only way to ensure the address
stays the same (or call LocalAlloc or use unsafe code).

-Chris

Kevin Hutchison said:
Sorry for any confusion, I hope this is clearer:

struct START_DATA {
public int int1;
public int int2;
}

[DLLImport("start.dll")]
public static extern bool ConfigStart( ref STARTDATA psData );

[DLLImport("start.dll")]
public static extern void Start( );

...

void foo()
{
START_DATA sd;
sd.data1 = 1;
sd.data2 = 3;

if ( ConfigStart( ref sd ) )
{
Start();
}
}

From the API side, is the address passed to ConfigStart for "sd" still valid
when start is called?

- K.




"Chris Tacke, eMVP" <ctacke[at]Open_NET_CF[dot]org> wrote in message
I'm somewhat confused by the question, but I think the answer is no.

If you have this:

void foo()
{
START_DATA sd;
sd.data1 = 1;
sd.data2 = 3;

ConfigStart(&sd);
Start(&sd);
}

sd can be used as long as it's in scope, so in Start it's fine.

Again, the question isn't clear, and if you could post some code that
would
help clarify.

-Chris



Is my understanding here correct?

When an extern function prototype requires a structure to be
passed
 
The strong preference is not to use unsafe blocks and manual memory
allocation. If they are to be used, they must be in a separate assembly
with additional unit tests ensuring that they are handled well. I tend to
misstate it as, "we can't use unsafe blocks" which really isn't accurate. I
am using an unsafe block for handling buffer manipulation and I doubt I will
change that.
Do you have limitations on creating unmanaged DLLs and calling them?
Nope. The API I am working with will work on the desktop and PPC, so
sticking to C# helps speed development time.

- K.

Chris Tacke said:
Interesting. Is it a company policy against unsafe blocks? Is there a
specific reason, or simply becasue it's called "unsafe"? You're not the
only person I've heard say that you can't use them and I'm just wondering
what the rationale behind it is. Personally I like unsafe for some things,
but I'm just curios how many devs out there are forces to not use it. Do
you have limitations on creating unmanaged DLLs and calling them?

-Chris


Kevin Hutchison said:
Tx Chris. ... The short term solution is going to be unsafe code, but long
term we cannot have unsafe blocks. Busy weekend ahead!

- K.


Chris Tacke said:
Ah, now I see. The answer is "don't count on it". Since the object isn't
pinned, the GC is free to move it where it wishes, so the address may stay
the swame or it may not. Pinning it is the only way to ensure the address
stays the same (or call LocalAlloc or use unsafe code).

-Chris

Sorry for any confusion, I hope this is clearer:

struct START_DATA {
public int int1;
public int int2;
}

[DLLImport("start.dll")]
public static extern bool ConfigStart( ref STARTDATA psData );

[DLLImport("start.dll")]
public static extern void Start( );

...

void foo()
{
START_DATA sd;
sd.data1 = 1;
sd.data2 = 3;

if ( ConfigStart( ref sd ) )
{
Start();
}
}

From the API side, is the address passed to ConfigStart for "sd" still
valid
when start is called?

- K.




"Chris Tacke, eMVP" <ctacke[at]Open_NET_CF[dot]org> wrote in message
I'm somewhat confused by the question, but I think the answer is no.

If you have this:

void foo()
{
START_DATA sd;
sd.data1 = 1;
sd.data2 = 3;

ConfigStart(&sd);
Start(&sd);
}

sd can be used as long as it's in scope, so in Start it's fine.

Again, the question isn't clear, and if you could post some code that
would
help clarify.

-Chris



Is my understanding here correct?

When an extern function prototype requires a structure to be
passed
by
reference, the marshaler creates a copy of structure in unmanaged
memory
and
pushes a pointer to the memory location on the call stack. Upon
return
from
the call, the marshaller frees the unmanaged memory allocated just
prior
to
the call.

For two unmanged functions declared as:

BOOL ConfigStart( START_DATA *psData );
void Start();

If "Start" attempts to use a reference to psData stored in
"ConfigStart",
it may fail because the memory had already been freed.

- K.
 
Thanks for the feedback. I'm just trying to get a feel for how the
industry/community views unsafe code.

--
Chris Tacke, eMVP
Co-Founder and Advisory Board Member
www.OpenNETCF.org
---
Windows CE Product Manager
Applied Data Systems
www.applieddata.net


Kevin Hutchison said:
The strong preference is not to use unsafe blocks and manual memory
allocation. If they are to be used, they must be in a separate assembly
with additional unit tests ensuring that they are handled well. I tend to
misstate it as, "we can't use unsafe blocks" which really isn't accurate. I
am using an unsafe block for handling buffer manipulation and I doubt I will
change that.
Do you have limitations on creating unmanaged DLLs and calling them?
Nope. The API I am working with will work on the desktop and PPC, so
sticking to C# helps speed development time.

- K.

Chris Tacke said:
Interesting. Is it a company policy against unsafe blocks? Is there a
specific reason, or simply becasue it's called "unsafe"? You're not the
only person I've heard say that you can't use them and I'm just wondering
what the rationale behind it is. Personally I like unsafe for some things,
but I'm just curios how many devs out there are forces to not use it. Do
you have limitations on creating unmanaged DLLs and calling them?

-Chris


Kevin Hutchison said:
Tx Chris. ... The short term solution is going to be unsafe code,
but
long
term we cannot have unsafe blocks. Busy weekend ahead!

- K.


"Chris Tacke, eMVP" <ctacke[at]Open_NET_CF[dot]org> wrote in message
Ah, now I see. The answer is "don't count on it". Since the object isn't
pinned, the GC is free to move it where it wishes, so the address
may
stay
the swame or it may not. Pinning it is the only way to ensure the address
stays the same (or call LocalAlloc or use unsafe code).

-Chris

Sorry for any confusion, I hope this is clearer:

struct START_DATA {
public int int1;
public int int2;
}

[DLLImport("start.dll")]
public static extern bool ConfigStart( ref STARTDATA psData );

[DLLImport("start.dll")]
public static extern void Start( );

...

void foo()
{
START_DATA sd;
sd.data1 = 1;
sd.data2 = 3;

if ( ConfigStart( ref sd ) )
{
Start();
}
}

From the API side, is the address passed to ConfigStart for "sd" still
valid
when start is called?

- K.




"Chris Tacke, eMVP" <ctacke[at]Open_NET_CF[dot]org> wrote in message
I'm somewhat confused by the question, but I think the answer is no.

If you have this:

void foo()
{
START_DATA sd;
sd.data1 = 1;
sd.data2 = 3;

ConfigStart(&sd);
Start(&sd);
}

sd can be used as long as it's in scope, so in Start it's fine.

Again, the question isn't clear, and if you could post some code that
would
help clarify.

-Chris



Is my understanding here correct?

When an extern function prototype requires a structure to be passed
by
reference, the marshaler creates a copy of structure in unmanaged
memory
and
pushes a pointer to the memory location on the call stack. Upon
return
from
the call, the marshaller frees the unmanaged memory allocated just
prior
to
the call.

For two unmanged functions declared as:

BOOL ConfigStart( START_DATA *psData );
void Start();

If "Start" attempts to use a reference to psData stored in
"ConfigStart",
it may fail because the memory had already been freed.

- K.
 
Back
Top