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.