PInvoke. Passing void* instance.

  • Thread starter Thread starter promko
  • Start date Start date
P

promko

Hi!
I need to call the following unmanged method:
HFCI __cdecl FCICreate( void FAR* pv)

I have written the next managed declaration:
[ DllImport( "cabinet.dll" ) ]
public static extern IntPtr FCICreate(
[ In, Out, MarshalAs( UnmanagedType.LPStruct ) ]
IntPtr pv
);

Now suppore I have class called some_class.
How to pass the instance of that class as pv paramter?

Thanks.

*-----------------------*
Posted at:
www.GroupSrv.com
*-----------------------*
 
[ DllImport( "cabinet.dll" ) ]

You should add CallingConvention=CallingConvention.CDecl to the
attribute.

public static extern IntPtr FCICreate(
[ In, Out, MarshalAs( UnmanagedType.LPStruct ) ]
IntPtr pv

You can remove all of the attributes on the parameter.

How to pass the instance of that class as pv paramter?

What will the function do with the parameter? You may be able to use
the GCHandle type for this.



Mattias
 
Thank you for your reply.
I have done that, but as result I retrieve the exception:
PInvoke restrictions: can not return variants.
Any ideas?

[ DllImport( "cabinet.dll", CallingConvention =
CallingConvention.Cdecl ) ]
public static extern IntPtr FCICreate(
IntPtr pv );

client_state cs = new client_state();
GCHandle gch = GCHandle.Alloc( cs );
FciAPI.FCICreate(
(IntPtr)gch );
gch.Free();

*-----------------------*
Posted at:
www.GroupSrv.com
*-----------------------*
 
trying next code doen't help too:
IntPtr buffer = Marshal.AllocHGlobal( Marshal.SizeOf( cs ) );
FciCreate( buffer );

*-----------------------*
Posted at:
www.GroupSrv.com
*-----------------------*
 
ok. maybe I was dismissed that the problem is in the last parameter.
The whole code I try:

[ DllImport( "cabinet.dll", CallingConvention =
CallingConvention.Cdecl ) ]
public static extern IntPtr FCICreate(
[ In, Out, MarshalAs( UnmanagedType.LPStruct ) ]
ERF perf,
PFNFCIFILEPLACED pfnfcifp,
PFNFCIALLOC pfna,
PFNFCIFREE pfnf,
PFNFCIOPEN pfnopen,
PFNFCIREAD pfnread,
PFNFCIWRITE pfnwrite,
PFNFCICLOSE pfnclose,
PFNFCISEEK pfnseek,
PFNFCIDELETE pfndelete,
PFNFCIGETTEMPFILE pfnfcigtf,
[ In, Out, MarshalAs( UnmanagedType.LPStruct ) ]
CCAB pccab,
IntPtr pv );

, where PFNF*** - delegates are.

FciAPI.FCICreate(
erf,
new PFNFCIFILEPLACED( file_placed ),
new PFNFCIALLOC( mem_alloc ),
new PFNFCIFREE( mem_free ),
new PFNFCIOPEN( fci_open ),
new PFNFCIREAD( fci_read ),
new PFNFCIWRITE( fci_write ),
new PFNFCICLOSE( fci_close ),
new PFNFCISEEK( fci_seek ),
new PFNFCIDELETE( fci_delete ),
new PFNFCIGETTEMPFILE( get_temp_file ),
cab_parameters,
(IntPtr)gch
);

HFCI __cdecl FCICreate( PERF perf,
PFNFCIFILEPLACED pfnfcifp,
PFNFCIALLOC pfna,
PFNFCIFREE pfnf,
PFNFCIOPEN pfnopen,
PFNFCIREAD pfnread,
PFNFCIWRITE pfnwrite,
PFNFCICLOSE pfnclose,
PFNFCISEEK pfnseek,
PFNFCIDELETE pfndelete,
PFNFCIGETTEMPFILE pfnfcigtf,
PCCAB pccab,
void FAR * pv
);

*-----------------------*
Posted at:
www.GroupSrv.com
*-----------------------*
 
The Cabinet API was designed to be used from C language and expects the File
IO callbacks to use C runtime library semantics.
That means:
- The CAB API callbacks are declared to use cdecl calling convention, while
the calling convention emitted by the C# compiler for the delegates is
stdcall.
To solve this you'll have to modify the IL code generated.
- The IO callback's return file handles as integers, and expect the file
attributes, open mode, shared mode, file dates etc...
You will have to translate these to .NET Stream attributes.
- You also need to implement the memory allocation/de-allocation delegates
(unmanaged memory) and carefully handle Cabinet API errors.
This is a lot of work, and IMHO a much better option would be to create a
wrapper in Managed C++.

Here is the correct signature for FCICreate, however I don't know if this
will help you any further, as there are a lot of API's and data structures
to be defined as well.

[ DllImport( "cabinet.dll", CallingConvention =
CallingConvention.Cdecl ) ]
public static extern IntPtr FCICreate(
ref ERF perf,
PFNFCIFILEPLACED pfnfcifp,
PFNFCIALLOC pfna,
PFNFCIFREE pfnf,
PFNFCIOPEN pfnopen,
PFNFCIREAD pfnread,
PFNFCIWRITE pfnwrite,
PFNFCICLOSE pfnclose,
PFNFCISEEK pfnseek,
PFNFCIDELETE pfndelete,
PFNFCIGETTEMPFILE pfnfcigtf,
ref CCAB pccab,
IntPtr pv );


Willy.

promko said:
ok. maybe I was dismissed that the problem is in the last parameter.
The whole code I try:

[ DllImport( "cabinet.dll", CallingConvention =
CallingConvention.Cdecl ) ]
public static extern IntPtr FCICreate(
[ In, Out, MarshalAs( UnmanagedType.LPStruct ) ]
ERF perf,
PFNFCIFILEPLACED pfnfcifp,
PFNFCIALLOC pfna,
PFNFCIFREE pfnf,
PFNFCIOPEN pfnopen,
PFNFCIREAD pfnread,
PFNFCIWRITE pfnwrite,
PFNFCICLOSE pfnclose,
PFNFCISEEK pfnseek,
PFNFCIDELETE pfndelete,
PFNFCIGETTEMPFILE pfnfcigtf,
[ In, Out, MarshalAs( UnmanagedType.LPStruct ) ]
CCAB pccab,
IntPtr pv );

, where PFNF*** - delegates are.

FciAPI.FCICreate(
erf,
new PFNFCIFILEPLACED( file_placed ),
new PFNFCIALLOC( mem_alloc ),
new PFNFCIFREE( mem_free ),
new PFNFCIOPEN( fci_open ),
new PFNFCIREAD( fci_read ),
new PFNFCIWRITE( fci_write ),
new PFNFCICLOSE( fci_close ),
new PFNFCISEEK( fci_seek ),
new PFNFCIDELETE( fci_delete ),
new PFNFCIGETTEMPFILE( get_temp_file ),
cab_parameters,
(IntPtr)gch
);

HFCI __cdecl FCICreate( PERF perf,
PFNFCIFILEPLACED pfnfcifp,
PFNFCIALLOC pfna,
PFNFCIFREE pfnf,
PFNFCIOPEN pfnopen,
PFNFCIREAD pfnread,
PFNFCIWRITE pfnwrite,
PFNFCICLOSE pfnclose,
PFNFCISEEK pfnseek,
PFNFCIDELETE pfndelete,
PFNFCIGETTEMPFILE pfnfcigtf,
PCCAB pccab,
void FAR * pv
);

*-----------------------*
Posted at:
www.GroupSrv.com
*-----------------------*
 
- You also need to implement the memory allocation/de-allocation
delegates
(unmanaged memory) and carefully handle Cabinet API errors.
Something like that?:
public object mem_alloc( ulong cb )
{
}
public void mem_free( IntPtr memory )
{
}
This is a lot of work, and IMHO a much better option would be to
create a
wrapper in Managed C++.
I must to do using C#. Would be easier the following scenario:
wrapper in Managed C++ and than use it from C# code ?

Here is the correct signature for FCICreate, however I don't know if
this
will help you any further, as there are a lot of API's and data
structures
to be defined as well.
doesn't help.
I think the problem can be in that delegates ?!

*-----------------------*
Posted at:
www.GroupSrv.com
*-----------------------*
 
Inline ***

promko said:
- You also need to implement the memory allocation/de-allocation
delegates
(unmanaged memory) and carefully handle Cabinet API errors.
Something like that?:
public object mem_alloc( ulong cb )
{
}
***
Nope,
// return a pointer to unmanaged memory
public IntPtr mem_alloc(int cb)
{
return Marshal.AllocHGlobal(cb);
}

// and the delegate (!!! needs Cdecl calling convention - you have to modify
the IL !!! )
public delegate IntPtr YourMemAlloc(int cb);

public void mem_free( IntPtr memory )
{
}
This is a lot of work, and IMHO a much better option would be to
create a
wrapper in Managed C++.
I must to do using C#. Would be easier the following scenario:
wrapper in Managed C++ and than use it from C# code ?

Here is the correct signature for FCICreate, however I don't know if
this
will help you any further, as there are a lot of API's and data
structures
to be defined as well.
doesn't help.
I think the problem can be in that delegates ?!
***
It certainly is.

Willy.
 
Back
Top