I have been struggling 2nd day with the task how to pass a structure, containing array of byte to c++ dll. Namely, I don't know how to marshal C# structure. Here is my code:
in C++ dll:
struct Image
{
int Width;
int Height;
int Depth;
uchar *Data;
};
.....
__declspec(dllexport) void DirectTransform(Image *InImage, Image*DestImage)
{
...Implementation...
}
in C# program:
[StructLayout(LayoutKind.Sequential)]
struct ImageData
{
public int Width;
public int Height;
public int Depth;
[MarshalAs(UnmanagedType.LPArray)]
public byte[] Data;
}
[DllImport("MyDll.dll",CallingConvention=CallingConvention.Cdecl)]
public static extern void DirectTransform(ImageData Src, ImageData Dest);
//Fill out both structures..
DirectTransform(Image, DestImage);
Exception throws at calling of DirectTransform and says that:
Cannot marshal field 'Data' of type'ImageData': Invalid managed/unmanaged
type combination (Array fields must be paired with ByValArray or
SafeArray).
When I change LPArray to ByValArray and point the size of array(in this case 202500) it also doesn't work, because the size is too large. When SafeArray is used, the program fails inside DLL with the message :
Attempted to read or write protected memory. This is often an
indication that other memory is corrupt.
And data in structures are erroneous.
Could anyone help me?
Look at this question
You can try passing a pointer to your array and, for example an integer length field.
Doing that, you'll need to manually allocate unmanaged memory using Marshal.AllocHGlobal, call your function and after that in finally block - clear after yourself with Marshal.FreeHGlobal
With Marshal.Copy method you are copying your data into allocated memory.
Related
I am developing an COM library that uses the IStream interface to read and write data. My MIDL code looks like this:
interface IParser : IUnknown
{
HRESULT Load([in] IStream* stream, [out, retval] IParsable** pVal);
};
Since IStream and it's base interface ISequentialStream are not defined inside a type library, they get defined in mine. So far so good. However, when I view my type library with OLEView, ISequentialStream only defines the members RemoteRead and RemoteWrite, while I expected Read and Write, since they are what I am actually calling. Even more strange is, that the the MSDN lists those two members (additionally to the original ones), but states they are not supported.
The question
So what are those members and how do I use them from a client (e.g. a managed application to create a managed Stream wrapper for IStream)?
The long story
I want to implement a wrapper on the client side, that forwards IStream calls to .NET streams, like System.IO.FileStream. This wrapper could inherit from IStream like so:
public class Stream : Lib.IStream
{
public System.IO.Stream BaseStream { get; private set; }
public Stream(System.IO.Stream stream)
{
this.BaseStream = stream;
}
// All IStream members in here...
public void Read(byte[] buffer, int bufferSize, IntPtr bytesReadPtr)
{
// further implementation...
this.BaseStream.Read();
}
}
And then, I want to call my server with this wrapper:
var wrapper = new Stream(baseStream);
var parsable = parser.Load(wrapper);
The problem is, that Lib.Stream in the previous example only provides RemoteRead and RemoteWrite, so that server calls to stream->Read() would end up in no mans land. As far as I understood, there is System.Runtime.InteropServices.ComTypes.IStream for managed COM servers, but in my example I have a unmanaged COM server and a managed client that should provide IStream instances.
Actually, there is no RemoteRead and RemoteWrite in ISequentialStream v-table layout. They exist only in ObjIdl.Idl, as an aid for RPC proxy/stub code generator. Have a look at ObjIdl.h from SDK:
MIDL_INTERFACE("0c733a30-2a1c-11ce-ade5-00aa0044773d")
ISequentialStream : public IUnknown
{
public:
virtual /* [local] */ HRESULT STDMETHODCALLTYPE Read(
/* [annotation] */
__out_bcount_part(cb, *pcbRead) void *pv,
/* [in] */ ULONG cb,
/* [annotation] */
__out_opt ULONG *pcbRead) = 0;
virtual /* [local] */ HRESULT STDMETHODCALLTYPE Write(
/* [annotation] */
__in_bcount(cb) const void *pv,
/* [in] */ ULONG cb,
/* [annotation] */
__out_opt ULONG *pcbWritten) = 0;
};
It's hard to guess why your type library ends up with RemoteRead/RemoteWrite names, instead of Read/Write. You may want to upload your IDL somewhere and post a link to it, if you need help with that.
However, as long as the v-table layout, the method signatures and the GUID of the interfaces from your typelib match those of ISequentialStream and IStream from ObjIdl.h, the method names do not matter.
Anyway, I would do as Igor suggested in his comment. Do not expose IStream at all in the type library. Use IUnknown in the IDL, and just cast it to System.Runtime.InteropServices.ComTypes.IStream inside the C# client's method implementation, when you actually do read/write, i.e.:
IDL:
interface IParser : IUnknown
{
HRESULT Load([in] IUnknown* stream, [out, retval] IParsable** pVal);
};
C#:
IParsable Load(object stream)
{
// ...
var comStream = (System.Runtime.InteropServices.ComTypes.IStream)stream;
comStream.Read(...);
// ...
}
[UPDATE] I guess I see what's going on with the method names. Your situation is exactly like this:
https://groups.google.com/forum/#!topic/microsoft.public.vc.atl/e-qj0xwoVzg/discussion
Once more, I suggest to not drag non-automation compatible interfaces into the type library, and I'm not alone here with this advice. You actually drag a lot more unneeded stuff into your typlib, which projects to the C# side too. Stick with IUnknown and make your typelib neat. Or, at last, define your own binary/GUID compatible versions of them from scratch.
I import two WinApi functions and use them in my class
using namespace System::Runtime::InteropServices;
[DllImport("user32",ExactSpelling = true)]
extern bool CloseWindow(int hwnd);
[DllImport("user32",ExactSpelling = true)]
extern int FindWindow(String^ classname,String^ windowname);
public ref class WinApiInvoke
{
public:
bool CloseWindowCall(String^ title)
{
int pointer = FindWindow(nullptr,title);
return CloseWindow(pointer);
}
};
Then I create object in main program and call CloseWindowCall method
Console::WriteLine("Window's title");
String ^s = Console::ReadLine();
WinApiInvoke^ obj = gcnew WinApiInvoke();
if (obj->CloseWindowCall(s))
Console::WriteLine("Window successfully closed!");
else Console::WriteLine("Some error occured!");
When I write in console for example Chess Titans to close I've got an error
Unable to find an entry point named 'FindWindow' in DLL 'user32'
What entry point?
You are using the ExactSpelling property inappropriately. There is no FindWindow function in user32.dll, just like the exception message says. There is FindWindowA and FindWindowW. The first one handles legacy 8-bit character strings, the second uses Unicode strings. Any Windows api function that accepts strings has two versions, you don't see this in C or C++ code because the UNICODE macro selects between the two.
Avoid ExactSpelling on winapi functions, the pinvoke marshaller knows how to deal with this. You have some other mistakes, the proper declaration is:
[DllImport("user32.dll", CharSet = CharSet::Auto, SetLastError = true)]
static IntPtr FindWindow(String^ classname, String^ windowname);
One method of my class need fresh copy of some array for internal stuff, so I should write something like that:
public void FrequentlyCalledMethod {
int[] a = new int[100];
....
But because method is frequently called and because content of the array doesn't make sense (it will be replaced anyway) and because array is big enough i want to optimize and write something like that:
private int[] a = new int[100];
public void FrequentlyCalledMethod {
....
Assuming that method is called 100 times per second I will save about 100 * 100 * sizeof(int) bytes of heap memory every second.
The problem is that now class declaration is "dirty". It contains in field the information that only one method needs. Having too much such fields will make class very "unreadable" as "normal" fields will be mixed with "perfomance optimizations" field.
What can I do? Or I should just choose either perfomance or readablity? Can I have both somehow?
No your class declaration is not dirty. Class declaration is dirty only when you mangle its public interface. And this is a private field. Private fields are used for this.
If you are too worried about the too many private variables then try using small classes. If a method needs 3 private variables you can create a class with those 3 variables and store the object as private filed in current class.
class A{
private int a;
private int b;
private int c;
public int get_num(){
return a+b+c;
}
}
you can use this,
class B{
private int a;
private int b;
private int c;
public int get_num(){
return a+b+c;
}
}
class A{
private B b;
public int get_num(){
return b.get_num();
}
}
If the first case, the array inside FrequentlyCalledMethod is referenced using a local variable, so it will be garbage-collected when the method ends: there's no heap over-usage in that scenario.
However, if you declare your array as a member attribute; the array instance will persist for all your parent-object life, even if the method FrequentlyCalledMethod is called or not.
In conclusion, if you wanna preserve heap-space and make your program more memory efficient go with local attributes and avoid instance variables in your particular case.
I have an ISAPI filter written for IIS6. I now need to write a wrapper for IIS7 to wrap the IIS6 filter. I plan to write HTTP module in C# and Pinvoke the unmanaged dll methods.
I need C# representation of the following code,
DWORD WINAPI HttpFilterProc(
PHTTP_FILTER_CONTEXT pfc,
DWORD notificationType,
LPVOID pvNotification
);
typedef struct _HTTP_FILTER_CONTEXT HTTP_FILTER_CONTEXT {
DWORD cbSize;
DWORD Revision;
PVOID ServerContext;
DWORD ulReserved;
BOOL fIsSecurePort;
PVOID pFilterContext;
BOOL GetServerVariable;
BOOL AddResponseHeaders;
BOOL WriteClient;
VOID * AllocMem;
BOOL ServerSupportFunction;
} HTTP_FILTER_CONTEXT, * PHTTP_FILTER_CONTEXT;
I tried using PInvoke Assistant from codeplex but i am not able to make it work.
Has anyone done anything like this before?
Can anyone provide a solution to the above?
Correction: Correct structure added
Building on the code in your answer you need to use the following:
[DllImport(#"XyzISAPI.dll")]
public static extern uint HttpFilterProc(
ref HttpFilterContext pfc,
uint notificationType,
IntPtr pvNotification
);
The native code is passed a pointer to the context struct and passing the struct by ref is the easy way to match that. The final parameter is LPVOID, which is void* and that is plain IntPtr in managed code.
As for HTTP_FILTER_ACCESS_DENIED, define it like this:
[StructLayout(LayoutKind.Sequential)]
public struct HttpFilterAccessDenied
{
IntPtr URL;
IntPtr PhysicalPath;
uint Reason;
}
You can then obtain one of those like this:
HttpFilterAccessDenied hfad = (HttpFilterAccessDenied)Marshal.PtrToStructure(
pvNotification, typeof(HttpFilterAccessDenied));
And then you can get hold of the string values from the struct with Marshal.PtrToStringUni or Marshal.PtrToStringAnsi.
I am attempting to simply add a FilterInfo class to my FilterInfo collection. I'm having a terrible time trying to understand why the following code keeps throwing the error:
System::Collections::Generic::List::Add'
: cannot convert parameter 1 from
'Ziz::FilterInfo *' to
'Ziz::FilterInfo'
I'm only learning C++/CLI, as I'm a C# developer, and I'm sure it's something simple, but I sure could use some pointers. My stripped code is as follows:
public value class FilterInfo
{
public:
char* Address;
};
public ref class Ziz
{
private:
List<FilterInfo>^ _blockList;
public:
// Constructor
Ziz(){
_blockList = gcnew List<FilterInfo>();
}
List<FilterInfo>^ GetBlockList()
{
for each(_IPFILTERINFO ip in _packetFilter->GetBlockList())
{
// _IPFILTERINFO is the native C++ struct.
FilterInfo* f = new FilterInfo();
_blockList->Add(f);
}
return _blockList;
}
You declared _blockList as
List<FilterInfo>^ _blockList;
but you are trying to add
FilterInfo* f
to it. It cannot work since one is a pointer and the other one is a reference.
I'm not sure how "value" fits in but in
public value class FilterInfo
{
public:
char* Address;
};
You are derefore declaring an unmanaged class
to make it managed, you should use
public ref class FiterInfo
This will allow you to use FilterInfo* without having to manage memory explicitely.
Finally, char* is not so great in C++/CLI, I would recommend using System::String
_blockList->Add(*f);
You have to construct your FilterInfo with gcnew as well. You can't really mix and mash these together without marshaling.
FilterInfo is not FilterInfo*. If you want a List of pointers to FilterInfo, you need to say that List<FilterInfo*>. Since FilterInfo is a value class here though you'll likely just want to skip the new.
FilterInfo fi;
_blockList->Add(fi);
public ref class A
{
};
int main(array<System::String ^> ^args)
{
Console::WriteLine(L"Hello World");
ICollection<A^>^ oCollection = gcnew List<A^>();
oCollection->Add(gcnew A());
return 0;
}