473,396 Members | 2,098 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

marshaling a structure by value from managed to unmanaged

Hi All,

********************** My Situation **********************
I am working on project that involves passing a structure to unmanaged
code from .Net world (well using C#). Perhaps an example will prove
useful.

structure MyStruct
{
// this is a complicated struct declaration in the sense
that it includes other structures
// (thankfully they are not variable sized) and also a
large array of char
SomeStruct1 member1
SomeStruct2 member2
char bigArray[7664];
};
void foo_get_struct_by_value( MyStruct valStruc );

in managed world I wrote all the required declaration for MyStruct,
SomeStruct1, SomeStruct2 and p-invoke signature of
foo_get_struct_by_value().

let this be the declaration in C#(appended Cs against each type, Cs
stands for well, C# )

structure CsMyStruct
{
CsSomeStruct1 member1
CsSomeStruct2 member2
char bigArray[7664];
};
void cs_foo_get_struct_by_value( MyStruct valStruc );

********************** My Problem **********************
if I try calling cs_foo_get_struct_by_value() MarshalDirectiveException
is being thrown with this message "Internal limitation: structure is
too complex or too large."

********************** My Solution (that didn't work, hence this
post) **********************
Hence I tried using unconventional means to achieve my goal. I cannot
modify the legacy code, it is important to achieve in managed code else
I will have to run around begging for permission to modify the legacy
code.
The idea is to present legacy code with a 'lump' of memory. The legacy
code will interpret it as a valid structure instance. Here is the code
illustrating what I am mean. For this I modified the p-invoke signature
of cs_foo_get_struct_by_value() to as below

cs_foo_get_struct_by_value( byte[] lumpOfMemory );

// allocate a structure and do something with it, fill it with data
etc.
CsMyStruct myStruct = new CsMyStruct();

// save the size, we will need it again
int structSize = Marshal.SizeOf( myStruct );

// allocate memory in unmanaged area
IntPtr ptr = Marshal.AllocHGlobal( structSize );
// get the address of managed structure
Marshal.StructureToPtr( myStruct, ptr, false );

// copy the managed structure contents in 'lump of memory'
byte[] lumpOfMemory = new byte[structSize];
Marshal.Copy( ptr, lumpOfMemory, 0, structSize );
Marshal.FreeHGlobal( ptr );

// let the unmanaged function do its job
cs_foo_get_struct_by_value( lumpOfMemory );

Nov 23 '06 #1
6 5871
>structure CsMyStruct
>{
CsSomeStruct1 member1
CsSomeStruct2 member2
char bigArray[7664];
};
It would help if you could post valid C# code that actually compiles.

>void cs_foo_get_struct_by_value( MyStruct valStruc );
Are you sure the struct should be passed by value and not by
reference. It's unusual to push such a large structure on the stack.

Mattias

--
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Nov 23 '06 #2
Hi

thanks for your interest, and sorry for my late reply, I have been busy
since late.
yes its unusual to push such large data to stack but as already told,
this is a legacy library, now I have made changes in legacy code to
take reference(pointer) to this structure and was able to marshal the
reference using IntPtr.

but am still interested in this problem. I will provide a working code
soon

regards,
Aston

Mattias Sjögren wrote:
structure CsMyStruct
{
CsSomeStruct1 member1
CsSomeStruct2 member2
char bigArray[7664];
};

It would help if you could post valid C# code that actually compiles.

void cs_foo_get_struct_by_value( MyStruct valStruc );

Are you sure the struct should be passed by value and not by
reference. It's unusual to push such a large structure on the stack.

Mattias

--
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Nov 28 '06 #3
below is the C# file

using System;
using System.Runtime.InteropServices;

namespace managed
{
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
struct CsSomeStruct1
{
internal int day;
internal int month;
internal int year;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
struct CsMyStruct
{
internal CsSomeStruct1 member1;
internal CsSomeStruct1 member2;

[MarshalAs(UnmanagedType.ByValArray,
SizeConst=TestClass.BLOB_SIZE)]
internal byte[] bigArray;
}

/// <summary>
/// Summary description for Class1.
/// </summary>
class TestClass
{
public const int BLOB_SIZE = 75 * 1024;

/***************************** NOT-WORKING, BY VALUE
*****************************/
// Entry in unmanaged via value-taking-function.
// Calling this will cause MarshalDirectiveException to be
thrown
[DllImport("unmanaged.dll",
EntryPoint="foo_get_struct_by_value" ,CharSet=CharSet.Unicode)]
extern static void cs_foo_get_struct_by_value( CsMyStruct
valStruc );
/***************************** WORKING TRICK, BY REFERENCE
*****************************/
// Entry in unmanaged via reference-taking-function.
// This will work, but this is at the cost of introducing
// foo_get_struct_by_reference( MyStruct* pStruc ) from
unmanaged code.
[DllImport("unmanaged.dll",
EntryPoint="foo_get_struct_by_reference" ,CharSet=CharSet.Unicode)]
extern static void internal_cs_foo_get_struct_by_reference(
IntPtr pStruc );

// This will 'sheild' rest of code knowing about marshalling
and make
// them feel as if they are making a direct extern call.
static void cs_foo_get_struct_by_reference( CsMyStruct mystruc
)
{
IntPtr ptr = Marshal.AllocHGlobal( Marshal.SizeOf(
mystruc.GetType() ) );
Marshal.StructureToPtr( mystruc, ptr, false );
internal_cs_foo_get_struct_by_reference( ptr );
Marshal.FreeHGlobal( ptr );
}
/***************************** NOT-WORKING, BY BLOB
*****************************/
// Entry in unmanaged via value-taking-function, but we shall
present
// unmanaged code with a blob from managed code.
// This will not work, had this worked I would have continued
without
// changing legacy code.
[DllImport("unmanaged.dll",
EntryPoint="foo_get_struct_by_value" ,CharSet=CharSet.Unicode)]
extern static void internal_cs_foo_get_struct_by_blob( [In]
byte[] pBuffer );

// The idea is to present unamanged code with a blob from
managed memory
// which it shall treat as structure
// what i will do is take the pointer of managed structure and
copy the
// contents to an byte[] array and pass it to unmanaged code
static void cs_foo_get_struct_as_blob( CsMyStruct mystruc )
{
// allocate an array to pass to unmanaged code
int struct_native_size = Marshal.SizeOf( mystruc.GetType()
);
byte[] blob = new byte[struct_native_size];

// take the address of structure instance to pass
IntPtr ptr = Marshal.AllocHGlobal( struct_native_size );
Marshal.StructureToPtr( mystruc, ptr, false );

// copy the structure contents into that byte[] array
Marshal.Copy( ptr, blob, 0, struct_native_size );

// pass on to unmanaged code
internal_cs_foo_get_struct_by_blob( blob );

// free the memory to avoid memory-leaks
Marshal.FreeHGlobal( ptr );
}

/// <summary>
/// The main entry point for the a pplication.
/// </summary>
[STAThread]
static void Main(string[] args)
{
try
{
CsMyStruct mystruct = new CsMyStruct();
mystruct.bigArray = new byte[TestClass.BLOB_SIZE];
for( int i=0; i<BLOB_SIZE; i++ )
{
mystruct.bigArray[i] = 10;
}

// the call below will throw a
MarshalDirectiveException
// cs_foo_get_struct_by_value( mystruct );

// this is passing a strucuture via blob, not working
// this will take to you unmanaged code but with
unexpected
// and potentially garbage data
cs_foo_get_struct_as_blob( mystruct );

// this call can take you to unamanaged code,
succesfully!
// cs_foo_get_struct_by_reference( mystruct );

}
// swallow all errors
catch( Exception error )
{
Console.WriteLine( error.Message );
}
}
}
}

and here is the unmanaged code

#include<tchar.h>

#define BLOB_SIZE 75 * 1024

struct SomeStruct1
{
int day;
int month;
int year;
};

struct MyStruct
{
// this is a complicated struct declaration in the sense
// that it includes other structures
// (thankfully they are not variable sized) and also a large array
of char
SomeStruct1 member1;
SomeStruct1 member2;
char bigArray[BLOB_SIZE];
};

// this function cannot be used since it wants structure by value
extern "C" __declspec(dllexport) void foo_get_struct_by_value( MyStruct
valStruc )
{
for( int i=0; i<BLOB_SIZE; i++ )
_tprintf( _T("%d"), valStruc.bigArray[i] );
}

// this function cannot be used since it wants structure by reference
// suppose this code is part of a large legacy library and you somehow
// have to manage by calling the above value-taking function
extern "C" __declspec(dllexport) void foo_get_struct_by_reference(
MyStruct* pStruc )
{
foo_get_struct_by_value( *pStruc );
}

for this who are willing I can provide a working MS Studio solution
file with projects ofcourse

On Nov 28, 4:27 pm, "Aston Martin" <masoom.sha...@gmail.comwrote:
Hi

thanks for your interest, and sorry for my late reply, I have been busy
since late.
yes its unusual to push such large data to stack but as already told,
this is a legacy library, now I have made changes in legacy code to
take reference(pointer) to this structure and was able to marshal the
reference using IntPtr.

but am still interested in this problem. I will provide a working code
soon

regards,
Aston

Mattias Sjögren wrote:
>structure CsMyStruct
>{
CsSomeStruct1 member1
CsSomeStruct2 member2
char bigArray[7664];
>};
It would help if you could post valid C# code that actually compiles.
>void cs_foo_get_struct_by_value( MyStruct valStruc );
Are you sure the struct should be passed by value and not by
reference. It's unusual to push such a large structure on the stack.
Mattias
--
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/|http://www.dotnetinterop.com
Please reply only to the newsgroup.
Nov 30 '06 #4
"Aston Martin" <ma***********@gmail.comwrote in message
news:11*********************@f1g2000cwa.googlegrou ps.com...
below is the C# file
....
for this who are willing I can provide a working MS Studio solution
file with projects ofcourse
The largest blob you can pass by value must be < 32KB, this is a CLR imposed interop
restriction (un-documented), anything larger must be passed by reference, or be passed
through a C++ managed wrapper.

Following is a working sample based on your code, but now using a fixed byte buffer (compile
with /unsafe). But as noted by Mattias, you should try avoid to pass such large blobs by
value between managed and unmanaged code.
using System;
using System.Runtime.InteropServices;

namespace managed
{
[StructLayout(LayoutKind.Sequential)]
struct CsSomeStruct1
{
internal int day;
internal int month;
internal int year;
}

[StructLayout(LayoutKind.Sequential)]
unsafe struct CsMyStruct
{
internal CsSomeStruct1 member1;
internal CsSomeStruct1 member2;
internal fixed byte bigArray[TestClass.BLOB_SIZE];
}
class TestClass
{
public const int BLOB_SIZE = 31 * 1024;

/***************************** NOT-WORKING, BY VALUE *****************************/
// Entry in unmanaged via value-taking-function.
// Calling this will cause MarshalDirectiveException to be thrown
[DllImport("passblobcpp.dll",EntryPoint="foo_get_st ruct_by_value" )]
extern static void cs_foo_get_struct_by_value( CsMyStruct valStruc );
/// <summary>
/// The main entry point for the a pplication.
/// </summary>
[STAThread]
static void Main(string[] args)
{
try
{
CsMyStruct mystruct = new CsMyStruct();
unsafe
{
for (int i = 0; i < BLOB_SIZE; i++)
{
mystruct.bigArray[i] = 10;
}
}
// the call below will throw a MarshalDirectiveException
cs_foo_get_struct_by_value( mystruct );
}
// swallow all errors
catch( Exception error )
{
Console.WriteLine( error.Message );
}
}
}
}

Nov 30 '06 #5
thanks to both of you Mattias as well as Willy for taking time to look
in this issue.

Willy,
what you told did work but only figures are different. In my case I
could carry upto 64K data through to unmanaged code. ( 63 * 1024 ). But
I did not understand the meaning of adding unsafe keyword, since it
worked for me without using it ?

regards,
Aston Martin

On Nov 30, 9:22 pm, "Willy Denoyette [MVP]"
<willy.denoye...@telenet.bewrote:
"Aston Martin" <masoom.sha...@gmail.comwrote in messagenews:11*********************@f1g2000cwa.goo glegroups.com...
below is the C# file
...
for this who are willing I can provide a working MS Studio solution
file with projects ofcourse

The largest blob you can pass by value must be < 32KB, this is a CLR imposed interop
restriction (un-documented), anything larger must be passed by reference, or be passed
through a C++ managed wrapper.

Following is a working sample based on your code, but now using a fixed byte buffer (compile
with /unsafe). But as noted by Mattias, you should try avoid to pass such large blobs by
value between managed and unmanaged code.

using System;
using System.Runtime.InteropServices;

namespace managed
{
[StructLayout(LayoutKind.Sequential)]
struct CsSomeStruct1
{
internal int day;
internal int month;
internal int year;
}

[StructLayout(LayoutKind.Sequential)]
unsafe struct CsMyStruct
{
internal CsSomeStruct1 member1;
internal CsSomeStruct1 member2;
internal fixed byte bigArray[TestClass.BLOB_SIZE];
}
class TestClass
{
public const int BLOB_SIZE = 31 * 1024;

/***************************** NOT-WORKING, BY VALUE *****************************/
// Entry in unmanaged via value-taking-function.
// Calling this will cause MarshalDirectiveException to be thrown
[DllImport("passblobcpp.dll",EntryPoint="foo_get_st ruct_by_value" )]
extern static void cs_foo_get_struct_by_value( CsMyStruct valStruc );
/// <summary>
/// The main entry point for the a pplication.
/// </summary>
[STAThread]
static void Main(string[] args)
{
try
{
CsMyStruct mystruct = new CsMyStruct();
unsafe
{
for (int i = 0; i < BLOB_SIZE; i++)
{
mystruct.bigArray[i] = 10;
}
}
// the call below will throw a MarshalDirectiveException
cs_foo_get_struct_by_value( mystruct );
}
// swallow all errors
catch( Exception error )
{
Console.WriteLine( error.Message );
}
}
}

}
Dec 1 '06 #6
"Aston Martin" <ma***********@gmail.comwrote in message
news:11*********************@73g2000cwn.googlegrou ps.com...
thanks to both of you Mattias as well as Willy for taking time to look
in this issue.

Willy,
what you told did work but only figures are different. In my case I
could carry upto 64K data through to unmanaged code. ( 63 * 1024 ). But
I did not understand the meaning of adding unsafe keyword, since it
worked for me without using it ?
Don't know exactly which unsafe keyword you are referring to, but I can compile the sample
posted without any of them.
Also, I can't get above 32 KB either, this all running on V2 of the framework with VS2005
SP1 (Beta1) installed, that means using version 8.00.50727.312 of the compiler.

Willy.

Dec 1 '06 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Nikolay Petrov | last post by:
Guys, please help. I am trying to make this work from at least 4 months. I am new to programming and some things are difficult to me, but I really need to make my project work. I can't find...
3
by: Webdiyer | last post by:
I want to integrate SecurID two-factor authentication system of the RSASecurity.inc into our asp.net application,but I get into trouble when trying to call the API functions of the ACE Agent,I got...
5
by: VM | last post by:
What's marshalling? I've had to use it extensively for a project but I don't know what it means. I tried to look for a definition in the Internet but I couldn't find anything that would explain...
1
by: Nadav | last post by:
Hi I am about to write a performance crutial system, I am considering writing this system based on native COM or unmanaged C++ exposed as CLI, Now, I Wonder... does exposing a native code through...
2
by: mirek | last post by:
Hi, I'm trying to import my old code to the .NET using managed wrappers. I've read "Managed Extensions for C++ Migration Guide" document and was trying to do what it stated in it. For example if...
3
by: zhphust | last post by:
I want to convert a object of a managed class to a unmanaged structure that has the same member with that managed class. Can anybody tell me how i can do it? Thanks in advance. -- zhphust...
1
by: Lee Crabtree | last post by:
I have several unmanaged struct types that I've created equivalent managed struct types for. How do I marshal the managed structs into their unmanaged versions and vice versa? Here's a quick...
0
by: tomwolfstein | last post by:
Hi. I am trying to write a wrapper for the standard VC1 decoder, and I need to resolve a "TypeLoadException" The decoder comes an an executable which I've turned into a .dll. This decoder has about...
0
by: swts | last post by:
hi, the following marshaling code gives me an errror of "type packet cannot be marshaled as an unmanaged structure; no meaningful size or offset can be managed". public static byte...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.