Click here to Skip to main content
15,867,935 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
hi all
I need help

i have a dll with this function:

int ReadRecordFor_V4XX_1(int Address,unsigned long BeginIndex,BYTE *ReadNumber,THisEvent*pHisEvents ,unsigned char *ExEvents=NULL)


and THisEvent is:

struct THisEvent
{
unsigned long RecordIndex;
BYTE pCardID[4];
Word RecordTypeID; //This value please refer to Appendix "Event table"
SYSTEMTIME RecordTime;
}
typedef struct _SYSTEMTIME
{
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME;


how can i use it on C# ?

my code doesn't work. The error messages is "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

This is my code:

C#
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 44)]
        public struct THisEvent
        {
            [FieldOffset(0)]
            public uint RecordIndex;
            [FieldOffset(4)]
            public byte[] pCardID;
            [FieldOffset(8)]
            public uint RecordTypeID;
            [FieldOffset(12)]
            public SYSTEMTIME RecordTime;
        };
        [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 32)]
        public struct SYSTEMTIME
        {
            [FieldOffset(0)]
            public uint wYear;
            [FieldOffset(4)]
            public uint wMonth;
            [FieldOffset(8)]
            public uint wDayOfWeek;
            [FieldOffset(12)]
            public uint wDay;
            [FieldOffset(16)]
            public uint wHour;
            [FieldOffset(20)]
            public uint wMinute;
            [FieldOffset(24)]
            public uint wSecond;
            [FieldOffset(28)]
            public uint wMilliseconds;
        };
.
.
.

 [DllImport("CVIOAccessAPI.dll")]
        private static extern int ReadRecordFor_V4XX_1(int Address, ulong BeginIndex, ref byte ReadNumber, ref THisEvent[] pHisEvents, ref char[] ExEvents);
.
.
.
THisEvent[] HisEvent = new THisEvent[5];
HisEvent.Initialize();
int Address = 0;
ulong RecordIndex = 0;
byte RecNumber = 5;
char[] FunKey = new char[5];
int RTN = ReadRecordFor_V4XX_1(Address, RecordIndex, ref RecNumber, ref HisEvent, ref FunKey);



Please Help me.......
====================================================================================================
now my code is like this:

C#
<pre lang="midl">[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 2)]
        public struct SYSTEMTIME
        {
            [MarshalAs(UnmanagedType.I2)]
            public short wYear;
            [MarshalAs(UnmanagedType.I2)]
            public short wMonth;
            [MarshalAs(UnmanagedType.I2)]
            public short wDayOfWeek;
            [MarshalAs(UnmanagedType.I2)]
            public short wDay;
            [MarshalAs(UnmanagedType.I2)]
            public short wHour;
            [MarshalAs(UnmanagedType.I2)]
            public short wMinute;
            [MarshalAs(UnmanagedType.I2)]
            public short wSecond;
            [MarshalAs(UnmanagedType.I2)]
            public short wMilliseconds;
        };

       [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 2)]
       struct THisEvent
       {
           [MarshalAs(UnmanagedType.U4)]
           public uint RecordIndex;
           [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
           public byte[] pCardID;
           [MarshalAs(UnmanagedType.U2)]
           public ushort RecordTypeID;
           [MarshalAs(UnmanagedType.Struct)]
           public SYSTEMTIME RecordTime;
       };

.
.
.
.
.
C#
[DllImport("CVIOAccessAPI.dll")]
        private static extern int ReadRecordFor_V4XX_1(int Address, uint BeginIndex, out byte ReadNumber, IntPtr pHisEvents, out byte ExEvents);

.
.
.
.
C#
int Address = 0;
            uint BeginIndex = 1;
            byte ReadNumber = 1;
            THisEvent temp = new THisEvent();
            IntPtr pHisEvents = Marshal.AllocHGlobal(4);
            byte ExEvents = 0;
            int RTN = ReadRecordFor_V4XX_1(Address, BeginIndex, out ReadNumber, pHisEvents, out ExEvents);
            if (RTN == 0)
            {
                temp = (THisEvent)Marshal.PtrToStructure(pHisEvents, typeof(THisEvent));
            }
            Marshal.FreeHGlobal(pHisEvents);




it is work, but actually "pHisEvents" is an array of "THisEvent" struct, I do not know how to retrieve the value of the array.

Does anyone can help?
Posted
Updated 27-Jul-11 22:17pm
v3

Be careful, in c# long is 64 bits, in C/C++ it is 32 bits. And a WORD is 16 bits, not 32 bits.

Declare the structs like this:
C#
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct SYSTEMTIME
{
    public short wYear;
    public short wMonth;
    public short wDayOfWeek;
    public short wDay;
    public short wHour;
    public short wMinute;
    public short wSecond;
    public short wMilliseconds;
}

[StructLayout(LayoutKind.Explicit, Pack = 1]
struct THisEvent
{
    uint RecordIndex;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    byte[] pCardID;
    ushort RecordTypeID;
    SYSTEMTIME RecordTime;
}


Try to declare the function like this:
C#
[DllImport("CVIOAccessAPI.dll")]
private static extern int ReadRecordFor_V4XX_1(int Address, uint BeginIndex,
    out byte ReadNumber, THisEvent[] pHisEvents, IntPtr ExEvents);

Declaring the function like that is OK to send the array pHisEvents in readonly. If your C code modifies its content, then you should do something a little bit more complicated (I will explain if necessary).

I am not sure about the last parameter ExEvents: what do you want to do with this one?

Additionnaly, to help you with marshaling WIN32 functions and types, you may have a look to this usefull site: http://www.pinvoke.net[^]

--------------------------------------------------

Sending pHisEvents in read/write mode requires a little bit more work:

First, you must change the imported function prototype (use IntPtr instead of THisEvent[]):
C#
[DllImport("CVIOAccessAPI.dll")]
private static extern int ReadRecordFor_V4XX_1(int Address, uint BeginIndex,
    out byte ReadNumber, IntPtr pHisEvents, IntPtr ExEvents);


Then, you must marshal your array manually:
C#
//we will send this array in read/write mode
THisEvent[] pHisEvents = ...;

//get the size of one struct
int sizeOfStruct = Marshal.SizeOf(typeof(THisEvent));
//1. allocate unmanaged memory
IntPtr ptr = Marshal.AllocHGlobal(pHisEvents.Length * sizeOfStruct);
//2. fill the unmanaged memory
for (int i = 0; i < pHisEvents.Length; i++)
{
    //points to the i-th element 
    IntPtr ptri = (IntPtr)((int)ptr + i * sizeOfStruct);
    //copy the managed structure into the unmanaged memory
    Marshal.StructureToPtr(pHisEvents[i], ptri, false);
}
//3. call the DLL funtion with the unmanaged memory
ReadRecordFor_V4XX_1(..., ptr, ...);
//4. marshal the unmanaged memory back to the managed array
for (int i = 0; i < pHisEvents.Length; i++)
{
    //points to the i-th element 
    IntPtr ptri = (IntPtr)((int)ptr + i * sizeOfStruct);
    //creates a managed structure from the unmanaged memory
    pHisEvents[i] = (THisEvent)Marshal.PtrToStructure(ptri, typeof(THisEvent));
}
//5. free the unmanaged memory
Marshal.FreeHGlobal(ptr);


I hope this will work.
 
Share this answer
 
v4
Comments
DaveyM69 27-Jul-11 13:12pm    
Good answer - 5ed
Olivier Levrey 28-Jul-11 3:26am    
Thank you DaveyM69
kurniawan Indra 27-Jul-11 21:56pm    
thanks Olivier Levrey, pHisEvents and ExEvents are output of this DLL. Can u explain to me how to do that?
Olivier Levrey 28-Jul-11 3:45am    
I updated my answer for the array. But you still didn't explain about the last parameter: is it just a value, or a string? how is it filled? As you can see, marshaling technique changes depending on what you want.
kurniawan Indra 28-Jul-11 4:32am    
thanks Olivier Levrey. From the manual of this DLL, the last parameter is a 8 bit value.
"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

My advise is to use mashaling. Your dll is obviously working in an unmanaged environment. Thus you need to store HisEvent in an unmanaged memory.

Something like:
C#
// Allocate memory
IntPtr pointer = Marshal.AllocHGlobal(44);
// Do your stuff...
// Free unmanaged memory, else you get a memory leak
Marshal.FreeHGlobal(pointer);


Found an article: Handling Unmanaged Memory Pointers in Managed Memory
 
Share this answer
 
Comments
kurniawan Indra 27-Jul-11 22:41pm    
Thanks for your help Amund Gjersøe
Olivier Levrey 28-Jul-11 3:48am    
Your advice is a good point and this article is a good start, but when dealing with arrays in read/write mode everything becomes more complicated...
I voted 4.
Amund Gjersøe 28-Jul-11 5:17am    
Your solution is now great, voted 5.
Olivier Levrey 28-Jul-11 5:18am    
Thank you very much Amund.
RaviRanjanKr 28-Jul-11 7:21am    
Good, My 5+

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900