Jump to content
The simFlight Network Forums

Recommended Posts

Posted

Hello, 

my program try to used FSUIPC write data to P3D, show this Exception:

System.ArgumentOutOfRangeException: Requested range extends past the end of the array.
   at System.Runtime.InteropServices.Marshal.CopyToManaged(IntPtr source, Object destination, Int32 startIndex, Int32 length)
   at System.Runtime.InteropServices.Marshal.Copy(IntPtr source, Byte[] destination, Int32 startIndex, Int32 length)
   at FsuipcSDK.Fsuipc.FSUIPC_Process(Int32& dwResult) in D:\Sandbox\Control Loading\ControlLoadingGUI_PrimoDev\AXAviationControlLoading\AXAviationControlLoading\Simulator\FsuipcSDK.cs:line 566
   at AXAviationControlLoading.WriteDataSimulator.ReadWriteFsuipc(Int32 dwOffset, Int32 dwSize, Int32 type, Int32& dwResult) in D:\Sandbox\Control Loading\ControlLoadingGUI_PrimoDev\AXAviationControlLoading\AXAviationControlLoading\Simulator\WriteDataSimulator.cs:line 233
   at AXAviationControlLoading.WriteDataSimulator.fsuipc_write(Double[] ControlSurface) in D:\Sandbox\Control Loading\ControlLoadingGUI_PrimoDev\AXAviationControlLoading\AXAviationControlLoading\Simulator\WriteDataSimulator.cs:line 256
   at AXAviationControlLoading.WriteDataSimulator.input(Double[] ControlSurface) in D:\Sandbox\Control Loading\ControlLoadingGUI_PrimoDev\AXAviationControlLoading\AXAviationControlLoading\Simulator\WriteDataSimulator.cs:line 200
   at AXAviationControlLoading.MainProgram.input(Double[] ControlSurface) in D:\Sandbox\Control Loading\ControlLoadingGUI_PrimoDev\AXAviationControlLoading\AXAviationControlLoading\Simulator\MainProgram.cs:line 189
   at AXAviationControlLoading.MainWindow.UDPXpcValueListen() in D:\Sandbox\Control Loading\ControlLoadingGUI_PrimoDev\AXAviationControlLoading\AXAviationControlLoading\Main\MainWindow.xaml.cs:line 1108
private void UDPXpcValueListen()
        {
            string filePath = AppDomain.CurrentDomain.BaseDirectory + "/UDPXpcValue_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".txt";

            UDPXpcValueListen_Active = true;

            UDPListenXpcValueClient = new UdpClient(RemoteIpPort_XpcRV);
            ReceiveXpcValueRemoteIpAndPort = new IPEndPoint(IPAddress.Any, RemoteIpPort_XpcRV);

            try
            {
                while (true)
                {
                    UDPReceiveXpcValueBytes = Encoding.Default.GetString(UDPListenXpcValueClient.Receive(ref ReceiveXpcValueRemoteIpAndPort));

                    string[] TempArray = StringFiltering(UDPReceiveXpcValueBytes, "#").ToArray();
                    string[] Value = StringFiltering(TempArray[4], "_").ToArray();

                    double DemandColumnPosition = double.Parse(Value[0]);
                    double DemandWheelPosition = double.Parse(Value[1]);
                    double DemandRudderPosition = double.Parse(Value[2]);
                    double ActualColumnPosition = double.Parse(Value[3]);
                    double ActualWheelPosition = double.Parse(Value[4]);
                    double ActualRudderPosition = double.Parse(Value[5]);
                    double ActualColumnForce = double.Parse(Value[6]);
                    double ActualWheelForce = double.Parse(Value[7]);
                    double ActualRudderForce = double.Parse(Value[8]);
                    int WheelAlarm = int.Parse(Value[9]);
                    int ColumnAlarm = int.Parse(Value[10]);

                    XPCValueTimer.Stop();
                    XPCValueTimer.Start();

                    Console.WriteLine("{0} :{1}\t{2}", ReceiveXpcValueRemoteIpAndPort.Address.ToString(), ReceiveXpcValueRemoteIpAndPort.Port.ToString(), UDPReceiveXpcValueBytes);
                    WriteFile(UDPReceiveXpcValueBytes + DateTime.Now.ToString("\tyyyy/MM/dd HH:mm:ss.ffffff"), filePath);
                    Force[0] = ActualColumnForce.ToString();
                    Force[1] = ActualWheelForce.ToString();
                    Force[2] = ActualRudderForce.ToString();
                    double[] ControlSurface = { ActualColumnPosition, ActualWheelPosition, ActualRudderPosition };
                    if (AutopilotStatus == "1")
                    {
                        if (Math.Abs(ActualColumnForce) > 30 || Math.Abs(ActualWheelForce) > 30 || Math.Abs(ActualRudderForce) > 30)
                            mainprogram.input(0);
                    }
                    else
                    {
                        WriteFile(ControlSurface[0] + "\t" + ControlSurface[1] + "\t" + ControlSurface[2], filePath);
                        if (ControlSurface != null)
                            mainprogram.input(ControlSurface);
                            //Thread.Sleep(100);
                    }

                    UIControl receiveDatafromTarget = delegate ()
                    {
                        InfomationZone.ElevatorHardwareTextBox.Text = Convert.ToString(ActualColumnPosition) + "° / " + Convert.ToString(ActualColumnForce) + "%";
                        InfomationZone.AileronHardwareTextBox.Text = Convert.ToString(ActualWheelPosition) + "° / " + Convert.ToString(ActualWheelForce) + "%";
                        InfomationZone.RudderHardwareTextBox.Text = Convert.ToString(ActualRudderPosition) + "° / " + Convert.ToString(ActualRudderForce) + "%";
                        InfomationZone.AlarmTextBox.Text = "AL" + ColumnAlarm.ToString("X3") + "(C) / " + "AL" + WheelAlarm.ToString("X3") + "(W)";
                        //InfomationZone.ErrorCodeTextBox.Text = ErrorCode(number);

                        if (WheelAlarm != 0 || ColumnAlarm != 0)
                            SystemControl.ClearAlarmbutton.IsEnabled = true;
                        else
                            Command[3] = "0";

                        Socket.SourceIpTB_Xpc_S.Text = ReceiveXpcValueRemoteIpAndPort.Address.ToString();
                        Socket.SourcePortTB_Xpc_S_V.Text = ReceiveXpcValueRemoteIpAndPort.Port.ToString();
                    };
                    this.Dispatcher.Invoke(receiveDatafromTarget);
                };
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                WriteFile(e.ToString() + DateTime.Now.ToString("\tyyyy/MM/dd HH:mm:ss.ffffff"), filePath);
            }
            finally
            {
                UDPListenXpcValueClient.Close();
            }
        }

Anyone can help me?

Posted

Hi,

the code you show has nothing to do with FSUIPC at all. The problem is related, as it says, to the data type or structure you use for the requested information.

Btw - for using DotNET languages like C# there is the perfect Library by Paul Henty that will make you an easy life !

Thomas

 

Posted
15 hours ago, Thomas Richter said:

Hi,

the code you show has nothing to do with FSUIPC at all. The problem is related, as it says, to the data type or structure you use for the requested information.

Btw - for using DotNET languages like C# there is the perfect Library by Paul Henty that will make you an easy life !

Thomas

 

Hi, Thomas

this code try to write data to P3D.

class WriteDataSimulator
    {
        enum StatusFlag : int { Initialised, Engaged, Disengaged, Stopped };

        FsuipcSDK.Fsuipc fsuipc_Write = new FsuipcSDK.Fsuipc();   // Our main fsuipc object!
        bool result = false;                                // Return boolean for FSUIPC method calls
        int dwFSReq = 0;                                    // Any version of FS is OK
        int dwResult = -1;                                  // Variable to hold returned results
                                                            //int dwOffset = 0x02BC;			                    // 02BC = indicated airspeed
                                                            //int dwSize = 4;					                    // 4 bytes for indicated airspeed
        int token = -1;

        /* ******************************************************************************************************/
        /*                                                                                                      */
        /*                                          FSUIPC Offsets                                              */
        /*                                                                                                      */
        /*                                                                                                      */
        /********************************************************************************************************/
        // Control surface
        int ElevatorReadOffset = 0x0BB2;
        int AileronReadOffset = 0x0BB6;
        int RudderReadOffset = 0x0BBA;
        // AutoPilot Status
        int AutoPilotStatusReadOffset = 0x07BC;

        /* ******************************************************************************************************/
        /*                                                                                                      */
        /*                                          FSUIPC Values                                               */
        /*                                                                                                      */
        /*                                                                                                      */
        /********************************************************************************************************/
        // Control surface Values
        double ElevatorValue;                           //int64 (2 bytes)
        double AileronValue;                            //int64 (2 bytes)
        double RudderValue;                             //int64 (2 bytes)
        // AutoPilot Status
        int AutoPilotStatusValue;                       //int64 (4 bytes)

        // Values convert to degree
        static double ElevatorReadMax = 1180057599;               // ProSim
        static double ElevatorReadMin = -1179926526;              // ProSim
        //static double ElevatorReadMax = 1481654271;               // PMDG
        //static double ElevatorReadMin = -1481523198;              // PMDG
        static double ElevatorTrueDegreeMax = 24.3;               // +24.3(true degree)   Boeing 737-800
        static double ElevatorTrueDegreeMin = -18.1;              // -18.1(true degree)   Boeing 737-800
        double ElevatorOutputMax = ElevatorReadMax / ElevatorTrueDegreeMax;
        double ElevatorOutputMin = ElevatorReadMin / ElevatorTrueDegreeMin;
        static double AileronReadMax = 1073758207;
        static double AileronReadMin = -1073627134;
        static double AileronTrueDegreeMax = 20;                  // +20(true degree)   Boeing 737-800
        static double AileronTrueDegreeMin = -15;                 // -15(true degree)   Boeing 737-800
        double AileronOutputMax = AileronReadMax / AileronTrueDegreeMax;
        double AileronOutputMin = AileronReadMin / AileronTrueDegreeMin;
        static double RudderReadMax = 1073627135;
        static double RudderReadMin = -1073496062;
        static double RudderTrueDegreeMax = 29;                   // +29(true degree)   Boeing 737-800
        static double RudderTrueDegreeMin = -29;                  // -29(true degree)   Boeing 737-800
        double RudderOutputMax = RudderReadMax / RudderTrueDegreeMax;
        double RudderOutputMin = RudderReadMin / RudderTrueDegreeMin;

        // Show infomation
        public string InitialisingStatus;
        public string InitialisedStatus;
        public string ConnectingStatus;
        public string ConnectedStatus;
        public string DisconnectingStatus;
        public string DisconnectedStatus;
        public string StopStatus;

        /// <summary>
        /// 0 --Initialised; 1 --Engaged; 2 --Disengaged; 3 --Stopped;
        /// -1 --Failed Initialised; -2 --Failed Engaged;
        /// -3 --Failed Disengaged; -4 --Failed Stopped;
        /// </summary>
        private int[] status = new int[4] { -255, -255, -255, -255 };
        public int[] simulatorStatusOutput = new int[4] { -255, -255, -255, -255 };
        /* ******************************************************************************************************/
        /*                                                                                                      */
        /*                                          State Machine                                               */
        /*                                                                                                      */
        /*                                                                                                      */
        /********************************************************************************************************/
        public void stateMachine(int code)
        {
            switch (code)
            {
                case (int)StatusFlag.Initialised:
                    Initialise();
                    break;
                case (int)StatusFlag.Engaged:
                    Connect();
                    break;
                case (int)StatusFlag.Disengaged:
                    Disconnect();
                    break;
                case (int)StatusFlag.Stopped:
                    Stop();
                    break;
                default:
                    break;
            }
        }
        /* ******************************************************************************************************/
        /*                                                                                                      */
        /*                                     State Machine Functions                                          */
        /*                                                                                                      */
        /*                                                                                                      */
        /********************************************************************************************************/
        private void Initialise()
        {
            // only Initialization fsuipc
            fsuipc_Write.FSUIPC_Initialization();
            this.status[0] = (int)StatusFlag.Initialised;
        }

        private void Connect()
        {
            if (fsuipc_Write.FSUIPC_Open(dwFSReq, ref dwResult))
                this.status[1] = (int)StatusFlag.Engaged;
            else
                this.status[1] = -2;
        }

        private void Disconnect()
        {
            fsuipc_Write.FSUIPC_Close();
            this.status[2] = (int)StatusFlag.Disengaged;
            stateMachine((int)StatusFlag.Stopped);
        }

        private void Stop()
        {
            this.status[3] = (int)StatusFlag.Stopped;
        }
        /* ******************************************************************************************************/
        /*                                                                                                      */
        /*                                       Inputs and Outputs                                             */
        /*                                                                                                      */
        /*                                                                                                      */
        /********************************************************************************************************/
        public void output()
        {
            InitialisingStatus = "Through plug-ins FSUIPC initializing the P3D!";
            if (this.status[0] == 0)
            {
                InitialisedStatus = "Through plug-ins FSUIPC initialized the P3D!";
                this.simulatorStatusOutput[0] = this.status[0];
                ConnectingStatus = "Through plug-ins FSUIPC connecting the P3D!";
                if (this.status[1] == 1)
                {
                    ConnectedStatus = "Through plug-ins FSUIPC connected the P3D!";
                    this.simulatorStatusOutput[1] = this.status[1];

                    DisconnectingStatus = "Through plug-ins FSUIPC canceling connect the P3D!";
                    if (this.status[2] == 2)
                    {
                        DisconnectedStatus = "Through plug-ins FSUIPC canceled connect the P3D!";
                        this.simulatorStatusOutput[2] = this.status[2];

                        if (this.status[3] == 3)
                        {
                            StopStatus = "Stop using plug-in FSUIPC communicate with P3D!";
                            this.status[0] = -255;
                            this.status[1] = -255;
                            this.status[2] = -255;
                            this.status[3] = -255;
                        }
                    }
                    else
                    {
                        DisconnectedStatus = "Failed to through plug-ins FSUIPC cancel connect the P3D!";
                        this.simulatorStatusOutput[2] = -3;
                    }
                }
                else
                {
                    ConnectedStatus = "Failed to through plug-ins FSUIPC connect the P3D!";
                    this.simulatorStatusOutput[1] = this.status[1];
                }
            }
            else
            {
                InitialisedStatus = "Failed to through plug-ins FSUIPC initialized the P3D!";
                this.simulatorStatusOutput[0] = -1;
            }
        }

        public void input(double[] ControlSurface)
        {
            fsuipc_write(ControlSurface);
        }

        public void input(int AutoPilot)
        {
            fsuipc_write(AutoPilot);
        }
        /* ******************************************************************************************************/
        /*                                                                                                      */
        /*                                          Local Functions                                             */
        /*                                                                                                      */
        /*                                                                                                      */
        /********************************************************************************************************/
        /// <summary>
        /// Process read or write
        /// </summary>
        /// <param name="dwOffset">The memory offset where the referenced value is located</param>
        /// <param name="dwSize">The number of bytes comprising of the referenced value</param>
        /// <param name="type">select read or write</param>
        /// <param name="dwResult">Contains the "error-code" if method's boolean comes back false</param>
        private void ReadWriteFsuipc(int dwOffset, int dwSize, int type, ref int dwResult)
        {
            switch (type)
            {
                case 1:
                    // Read
                    result = fsuipc_Write.FSUIPC_Read(dwOffset, dwSize, ref token, ref dwResult);
                    result = fsuipc_Write.FSUIPC_Process(ref dwResult);
                    result = fsuipc_Write.FSUIPC_Get(ref token, ref dwResult);
                    break;
                case 2:
                    // write
                    result = fsuipc_Write.FSUIPC_Write(dwOffset, dwSize, ref token, ref dwResult);
                    result = fsuipc_Write.FSUIPC_Process(ref dwResult);
                    break;
                default:
                    break;
            }
            //Thread.Sleep(1);
        }

        /// <summary>
        /// To write the value of the controller into the simulator
        /// </summary>
        private void fsuipc_write(double[] ControlSurface)
        {
            //Thread.Sleep(10);
            // Elevator(Column).
            if (ControlSurface[0] >= 0)
                ReadWriteFsuipc(ElevatorReadOffset, (int)Math.Round(ControlSurface[0] * ElevatorOutputMax, 0), 2, ref dwResult);
            else
                ReadWriteFsuipc(ElevatorReadOffset, (int)Math.Round(ControlSurface[0] * ElevatorOutputMin, 0), 2, ref dwResult);

            //Thread.Sleep(10);
            // Aileron(Wheel).
            if (ControlSurface[1] >= 0)
                ReadWriteFsuipc(AileronReadOffset, (int)Math.Round(ControlSurface[1] * AileronOutputMax, 0), 2, ref dwResult);
            else
                ReadWriteFsuipc(AileronReadOffset, (int)Math.Round(ControlSurface[1] * AileronOutputMin, 0), 2, ref dwResult);

            //Thread.Sleep(10);
            // Rudder.
            if (ControlSurface[2] >= 0)
                ReadWriteFsuipc(RudderReadOffset, (int)Math.Round(ControlSurface[2] * RudderOutputMax, 0), 2, ref dwResult);
            else
                ReadWriteFsuipc(RudderReadOffset, (int)Math.Round(ControlSurface[2] * RudderOutputMin, 0), 2, ref dwResult);
        }

        private void fsuipc_write(int AutoPilot)
        {
            ReadWriteFsuipc(AutoPilotStatusReadOffset, AutoPilot, 2, ref dwResult);
        }
    }

 

Posted

Hi,

22 hours ago, Primo said:

System.ArgumentOutOfRangeException: Requested range extends past the end of the array.

I don't see anything wrong in that code snip.

Do you check on Initialize the FS version maybe and your array is too small as it needs to be increased for P3Dv4 if you work with P3Dv4?
1 = FS98
2 = FS2000
3 = CFS2
4 = CFS1
5 = reserved
6 = FS2002
7 = FS2004 “A Century of Flight”
8 = FSX
9 = ESP
10=P3D
11=(???)
12=P3Dv4

Thomas

Posted
25 minutes ago, Thomas Richter said:

Hi,

I don't see anything wrong in that code snip.

Do you check on Initialize the FS version maybe and your array is too small as it needs to be increased for P3Dv4 if you work with P3Dv4?
1 = FS98
2 = FS2000
3 = CFS2
4 = CFS1
5 = reserved
6 = FS2002
7 = FS2004 “A Century of Flight”
8 = FSX
9 = ESP
10=P3D
11=(???)
12=P3Dv4

Thomas

Thomas, Thanks for your help! 

Yes, I'm work with P3Dv4, and FSUIPC version 5.103103.

/**
*   FSUIPC Developer Kit: Library for C#.NET programmers
*   Version 1.11 (03/05/2004) by Scott McCrory <scott@mccrory.us> and Bob Scott <w6kd@yahoo.com>
*
*   Original Copyright (?) 2000 Chris Brett.  All rights reserved.
*   e-mail: chris@formulate.clara.net
*
*   Rewritten for Visual Basic .NET By Bob Scott
*   e-mail w6kd@amsat.org
*
*   Rewritten for C#.NET by Scott McCrory and revised by Bob Scott
*   e-mail scott@mccrory.us
*
*   Function library for FSUIPC based on C code supplied by Pete Dowson
*
*   BASIC USAGE GOES LIKE THIS:
*      0. Instantiate the FsuipcSdk.Fsuipc class (i.e. Fsuipc f = new Fsuipc();).
*      1. Call f.FSUIPC_Initialization() at beginning of program (optional).
*      2. Call f.FSUIPC_Open() to connect with FSUIPC if it's available.
*      3. Call f.FSUIPC_Read and/or f.FSUIPC_Write one or more times to build
*         the list of actions to be performed by the next step.
*      4. Call f.FSUIPC_Process() to actually get/set the data from/to FS.
*      5. For reads, call f.FSUIPC_Get to retrieve data read from FSUIPC.
*      6. Repeat steps 3, 4, and 5 as necessary.
*      7. At program termination, call f.FSUIPC_Close().
*
**/

using System;
using System.Runtime.InteropServices;

namespace FsuipcSDK
{
    public class Fsuipc
    {
        // Constants
        public const int SMTO_ABORTIFHUNG = 0x2;
        public const int SMTO_BLOCK = 0x1;
        public const int SMTO_NORMAL = 0x0;
        public const int PAGE_READWRITE = 0x4;
        public const int NO_ERROR = 0;
        public const int ERROR_ALREADY_EXISTS = 0x183;
        public const int SECTION_MAP_WRITE = 0x2;
        public const int FILE_MAP_WRITE = SECTION_MAP_WRITE;

        // FSUIPC SPECIFICS
        // Supported Sims
        public const int SIM_ANY = 0;
        public const int SIM_FS98 = 1;
        public const int SIM_FS2K = 2;
        public const int SIM_CFS2 = 3;
        public const int SIM_CFS1 = 4;
        public const int SIM_FLY = 5;
        public const int SIM_FS2K2 = 6;
        public const int SIM_FS2K4 = 7;
        public const int SIM_FSX = 8;
        public const int SIM_ESP = 9;

        // Error numbers
        public const int FSUIPC_ERR_OK = 0;
        public const int FSUIPC_ERR_OPEN = 1;              // Attempt to Open when already Open
        public const int FSUIPC_ERR_NOFS = 2;              // Cannot link to FSUIPC or WideClient
        public const int FSUIPC_ERR_REGMSG = 3;            // Failed to Register common message with Windows
        public const int FSUIPC_ERR_ATOM = 4;              // Failed to create Atom for mapping filename
        public const int FSUIPC_ERR_MAP = 5;               // Failed to create a file mapping object
        public const int FSUIPC_ERR_VIEW = 6;              // Failed to open a view to the file map
        public const int FSUIPC_ERR_VERSION = 7;           // Incorrect version of FSUIPC, or not FSUIPC
        public const int FSUIPC_ERR_WRONGFS = 8;           // Sim is not version requested
        public const int FSUIPC_ERR_NOTOPEN = 9;           // Call cannot execute, link not Open
        public const int FSUIPC_ERR_NODATA = 10;           // Call cannot execute: no requests accumulated
        public const int FSUIPC_ERR_TIMEOUT = 11;          // IPC timed out all retries
        public const int FSUIPC_ERR_SENDMSG = 12;          // IPC sendmessage failed all retries
        public const int FSUIPC_ERR_DATA = 13;             // IPC request contains bad data
        public const int FSUIPC_ERR_RUNNING = 14;          // Maybe running on WideClient, but FS not running on Server, or wrong FSUIPC
        public const int FSUIPC_ERR_SIZE = 15;
        public const int FSUIPC_ERR_BUFOVERFLOW = 16;

        public const int IPC_BUFFER_SIZE = 65568;
        public const int LEN_RD_HDR = 16;                  // Length of an IPC Read Header (4x 4-byte Integers)
        public const int LEN_WR_HDR = 12;                  // Length of an IPC Write Header (3x 4-byte Integers)

        public const int LIB_VERSION = 2000;              // 2.000
        public const int MAX_SIZE = 0x7F00;               // Largest data (kept below 32k to avoid

        // any possible 16-bit sign problems
        public const int MAX_REQ_SIZE = 1024;             // Maximum single request block size

        public const string FS6IPC_MSGNAME1 = "FSASMLIB:IPC";
        public const string FS6IPC_MSGNAME2 = "EFISFSCOM:IPC";
        public const int FS6IPC_MESSAGE_SUCCESS = 1;
        public const int FS6IPC_MESSAGE_FAILURE = 0;

        // IPC message types
        public const int FS6IPC_READSTATEDATA_ID = 1;
        public const int FS6IPC_WRITESTATEDATA_ID = 2;
        public const int FS6IPC_SPECIALREQUEST_ID = 0xABAC;

        // Instance variables for the UIPC communication
        byte[] IPC = new byte[IPC_BUFFER_SIZE];     // IPC Data Buffer
        bool[] IPCdr = new bool[IPC_BUFFER_SIZE];   // Data waiting flags
        int IPCAlloc;                               // Data Buffer Allocation Index
        int FSUIPC_Version;
        int FSUIPC_FS_Version;
        int FSUIPC_Lib_Version = 0;
        int m_hWnd;       // FS window handle
        int m_msg;        // ID of registered window message
        int m_atom;       // global atom containing name of file-mapping object
        int m_hMap;       // handle of file-mapping object
        int m_pView;      // pointer to view of file-mapping object
        int m_pNext;      // pointer into FSUIPC data buffer area

        // External Win32 libraries
        public const string KER_DLL = "kernel32.dll";   // Import library for Kernel on Win32
        public const string USR_DLL = "user32.dll";     // Import library for User on Win32

        // We'll need to access some Windows API functions located in kernel32.dll
        [DllImport(KER_DLL)]
        public static extern void RtlZeroMemory(IntPtr dDestination, int length);
        [DllImport(KER_DLL)]
        public static extern void RtlMoveMemory(IntPtr pDest, IntPtr pSrc, int ByteLen);
        [DllImport(KER_DLL)]
        public static extern void Sleep(int dwMilliseconds);
        [DllImport(KER_DLL)]
        public static extern int GetCurrentProcessId();
        [DllImport(KER_DLL)]
        public static extern int GlobalAddAtomA(string lpstring);
        [DllImport(KER_DLL)]
        public static extern int CreateFileMappingA(uint hFile, int lpFileMappigAttributes, int flProtect, int dwMaximumSizeHigh, int dwMaximumSizeLow, string lpName);
        [DllImport(KER_DLL)]
        public static extern int GetLastError();
        [DllImport(KER_DLL)]
        public static extern int MapViewOfFile(int hFileMappingObject, int dwDesiredAccess, int dwFileOffsetHigh, int dwFileOffsetLow, int dwNumberOfBytesToMap);
        [DllImport(KER_DLL)]
        public static extern int MapViewOfFileEx(int hFileMappingObject, int dwDesiredAccess, int dwFileOffsetHigh, int dwFileOffsetLow, int dwNumberOfBytesToMap, IntPtr lpBaseAddress);
        [DllImport(KER_DLL)]
        public static extern int GlobalDeleteAtom(int nAtom);
        [DllImport(KER_DLL)]
        public static extern int UnmapViewOfFile(IntPtr lpBaseAddress);
        [DllImport(KER_DLL)]
        public static extern int CloseHandle(int hObject);

        // We'll also need to access some Windows API functions located in user32.dll
        [DllImport(USR_DLL)]
        public static extern int SendMessageTimeoutA(int hwnd, int msg, int wparam, int lparam, int fuFlags, int uTimeout, int lpdwResult);
        [DllImport(USR_DLL)]
        public static extern int FindWindowExA(int hWnd1, int hWnd2, string lpsz1, string lpsz2);
        [DllImport(USR_DLL)]
        public static extern int RegisterWindowMessageA(string lpstring);

        // Our main object contructor
        public Fsuipc()
        {
            FSUIPC_Close();
            FSUIPC_Initialization();
        }

        // --- Misc toggle functions ---------------------------------------------------
        ///<summary>Toggles a byte between 0 and 1</summary>
        ///<param name="arg1">The byte to toggle</param>
        ///<return>The toggled byte</return>
        public byte toggle(byte arg1)
        {
            if (arg1 == 0)
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }

        ///<summary>Toggles a short between 0 and 1</summary>
        ///<param name="arg1">The short to toggle</param>
        ///<return>The toggled short</return>
        public short toggle(short arg1)
        {
            if (arg1 == 0)
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }

        ///<summary>Toggles an int between 0 and 1</summary>
        ///<param name="arg1">The int to toggle</param>
        ///<return>The toggled int</return>
        public int toggle(int arg1)
        {
            if (arg1 == 0)
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }

        // --- Initialize the Client ---------------------------------------------------
        ///<summary>Initializes the FSUIPC Client</summary>
        public void FSUIPC_Initialization()
        {

            for (int idx = 0; idx < IPC_BUFFER_SIZE; idx++)
            {
                IPC[idx] = 0;
                IPCdr[idx] = false;
            }

            IPCAlloc = 0;
            m_hWnd = 0;
            m_msg = 0;
            m_atom = 0;
            m_hMap = 0;
            m_pView = 0;
            m_pNext = 0;
        }

        // --- Opens/Start the Client --------------------------------------------------------
        ///<summary>Opens an FSUIPC client connection</summary>
        ///<param name="dwFSReq">An int describing what FS version requested</param>
        ///<param name="dwResult">Contains the "error-code" if method's boolean comes back false</param>
        ///<return>true if successful, false otherwise.  If false, dwResult contains the "error-code"</return>
        public bool FSUIPC_Open(int dwFSReq, ref int dwResult)
        {
            string szName = "";
            //string szTemp = "";
            bool fWideFS = false;
            int nTry = -1;
            int i = -1;

            // initialize vars
            nTry = 0;
            fWideFS = false;
            i = 0;
            FSUIPC_Version = 0;
            FSUIPC_FS_Version = 0;

            // abort if already started
            if (m_pView != 0)
            {
                dwResult = FSUIPC_ERR_OPEN;
                return false;
            }

            // Connect via FSUIPC, which is known to be FSUIPC's own
            // and isn't subject to user modification

            m_hWnd = FindWindowExA(0, 0, "UIPCMAIN", null);

            if (m_hWnd == 0)
            {
                // if there's no UIPCMAIN, we may be using WideClient
                // which only simulates FS98
                m_hWnd = FindWindowExA(0, 0, "FS98MAIN", null);
                fWideFS = true;
                if (m_hWnd == 0)
                {
                    dwResult = FSUIPC_ERR_NOFS;
                    return false;
                }
            }

            // register the window message
            m_msg = RegisterWindowMessageA(FS6IPC_MSGNAME1);
            if (m_msg == 0)
            {
                dwResult = FSUIPC_ERR_REGMSG;
                return false;
            }

            // create the name of our file-mapping object
            nTry = nTry + 1; // Ensures a unique string is used in case user closes and reopens
            szName = FS6IPC_MSGNAME1 + ":" + GetCurrentProcessId().ToString("x") + ":" + nTry.ToString("x") + Convert.ToChar(0).ToString();
            if (szName.Length > 23)
            {    //24 chars max
                szName = szName.Substring(0, 23) + Convert.ToChar(0).ToString();
            }

            // stuff the name into a global atom
            m_atom = GlobalAddAtomA(szName);

            if (m_atom == 0)
            {
                dwResult = FSUIPC_ERR_ATOM;
                FSUIPC_Close();
                return false;
            }

            // create the file-mapping object
            // use system paging file
            // security attrubute (0 = can! inherit)
            // protection
            // size
            // name

            m_hMap = CreateFileMappingA(0xFFFFFFFF, 0, PAGE_READWRITE, 0, MAX_SIZE + 256, szName);

            if ((m_hMap == 0) || (GetLastError() == ERROR_ALREADY_EXISTS))
            {
                dwResult = FSUIPC_ERR_MAP;
                FSUIPC_Close();
                return false;
            }

            // spawn a view of the file-mapping object
            m_pView = MapViewOfFile(m_hMap, FILE_MAP_WRITE, 0, 0, 0);

            if (m_pView == 0)
            {
                dwResult = FSUIPC_ERR_VIEW;
                FSUIPC_Close();
                return false;
            }

            // Okay, now determine FSUIPC version AND FS type
            m_pNext = m_pView;

            // Try up to 5 times with a 100msec rest between each
            // Note that WideClient returns zeros initially, whilst waiting
            // for the Server to get the data
            do
            {
                i++;
                // Read FSUIPC version
                int t_FSUIPC_Version = 0;

                if (!FSUIPC_Read(0x3304, 4, ref t_FSUIPC_Version, ref dwResult))
                {
                    FSUIPC_Close();
                    return false;
                }

                // and FS version and validity check pattern
                int t_FSUIPC_FS_Version = 0;
                if (!FSUIPC_Read(0x3308, 4, ref t_FSUIPC_FS_Version, ref dwResult))
                {
                    FSUIPC_Close();
                    return false;
                }

                // write our Library version number to a special read-only offset
                // This is to assist diagnosis from FSUIPC logging
                // But only do this on first try
                int t_FSUIPC_Lib_Version = 0;
                if (i < 2 && FSUIPC_Write(0x330A, 2, ref t_FSUIPC_Lib_Version, ref dwResult) == false)
                {
                    FSUIPC_Close();
                    return false;
                }

                // Actually send the request and get the responses ("process")

                if (!FSUIPC_Process(ref dwResult))
                {
                    FSUIPC_Close();
                    return false;
                }

                bool VersionGet = FSUIPC_Get(ref t_FSUIPC_Version, ref FSUIPC_Version);
                VersionGet = FSUIPC_Get(ref t_FSUIPC_FS_Version, ref FSUIPC_FS_Version);
                VersionGet = FSUIPC_Get(ref t_FSUIPC_Lib_Version, ref FSUIPC_Lib_Version);

                // Maybe running on WideClient, and need another try
                Sleep(100); // Give it a chance
            }
            while ((i < 5) && ((FSUIPC_Version == 0) || (FSUIPC_FS_Version == 0)));

            // Only allow running on FSUIPC 1.998e or later
            // with correct check pattern &HFADE
            if ((FSUIPC_Version < 0x19980005) || ((FSUIPC_FS_Version & 0xFFFF0000) != 0xFADE0000))
            {
                if (fWideFS)
                {
                    dwResult = FSUIPC_ERR_RUNNING;
                }
                else
                {
                    dwResult = FSUIPC_ERR_VERSION;
                }
                FSUIPC_Close();
                return false;
            }

            // grab the FS version number
            FSUIPC_FS_Version = (FSUIPC_FS_Version & 0xFFFF);

            // Optional version-specific request made?  if so and wrong version, return error
            if (dwFSReq != 0 && dwFSReq != FSUIPC_FS_Version)
            {
                dwResult = FSUIPC_ERR_WRONGFS;
                FSUIPC_Close();
                return false;
            }

            dwResult = FSUIPC_ERR_OK;
            return true;
        }

        //--- Read request ---------------------------------------------------------------
        ///<summary>Submits a read request</summary>
        ///<param name="dwOffset">The memory offset where the requested value is located</param>
        ///<param name="dwSize">The number of bytes comprising of the requested value</param>
        ///<param name="token">Contains the unique identifier token used to Get the value</param>
        ///<param name="dwResult">Contains the "error-code" if method's boolean comes back false</param>
        ///<return>true if successful, false otherwise.  If false, dwResult contains the "error-code"</return>
        public bool FSUIPC_Read(int dwOffset, int dwSize, ref int Token, ref int dwResult)
        {
            int[] hdr = new int[4];

            if ((IPCAlloc + dwSize + 4) >= (IPC_BUFFER_SIZE - 1))
            {
                //Reset ptr to start of FifO buf
                IPCAlloc = 0;
            }
            // Assign Token as index into IPC Buffer FifO, and clear data ready flags
            Token = IPCAlloc;
            for (int i = IPCAlloc; i < (IPCAlloc + 4 + dwSize - 1); i++)
            {
                // 4=size of integer datablock size hdr
                IPC[i] = 0;
                IPCdr[i] = false;
            }
            IPCAlloc = IPCAlloc + 4 + dwSize;    //first four bytes data block size (Int) plus data

            if (Token >= IPC_BUFFER_SIZE)
            {
                Token = -1;
                dwResult = FSUIPC_ERR_BUFOVERFLOW;
                return false;
            }

            // Check link is open
            if (m_pView == 0)
            {
                dwResult = FSUIPC_ERR_NOTOPEN;
                return false;
            }

            // Check have space for ( this request (including terminator)
            if ((m_pNext - m_pView + 4 + dwSize + LEN_RD_HDR) > MAX_SIZE)
            {
                dwResult = FSUIPC_ERR_SIZE;
                return false;
            }

            hdr[0] = FS6IPC_READSTATEDATA_ID;     //Read request ID
            hdr[1] = dwOffset;                    //FSUIPC offset
            hdr[2] = dwSize;                      //data element size
            hdr[3] = Token;                       //index into managed data buffer IPC

            IntPtr _pNext = new IntPtr(m_pNext);
            Marshal.Copy(hdr, 0, _pNext, 4);    //Header to FSUIPC data buffer 

            // Move pointer past the Record
            m_pNext = m_pNext + LEN_RD_HDR;
            if (dwSize != 0)
            {
                // Zero the data reception area, so rubbish won//t be returned
                _pNext = new IntPtr(m_pNext);
                RtlZeroMemory(_pNext, dwSize);
                // Update the pointer ready for ( more data
                m_pNext = m_pNext + dwSize;
            }

            dwResult = FSUIPC_ERR_OK;
            return true;
        }

        //--- Process read/write ------------------------------------------------------
        ///<summary>Processes read or write request</summary>
        ///<param name="dwResult">Contains the "error-code" if method's boolean comes back false</param>
        ///<return>true if successful, false otherwise.  If false, dwResult contains the "error-code"</return>
        public bool FSUIPC_Process(ref int dwResult)
        {
            int dwError = 0;
            int[] hdr = new int[4];
            int i = 0;
            if (m_pView == 0)
            {
                dwResult = FSUIPC_ERR_NOTOPEN;
                return false;
            }

            if (m_pView == m_pNext)
            {
                dwResult = FSUIPC_ERR_NODATA;
                return false;
            }

            // Write FSUIPC Data Area Terminator
            IntPtr _pNext = new IntPtr(m_pNext);
            RtlZeroMemory(_pNext, 4);

            m_pNext = m_pView;

            // send the request (allow up to 10 tries)
            i = 0;
            while (i < 10 && SendMessageTimeoutA(m_hWnd, m_msg, m_atom, 0, SMTO_BLOCK, 5000, dwError) == 0)
            //                         m_hWnd,              // FS6 window handle
            //                         m_msg,               // our registered message id
            //                         m_atom,              // wparam: name of file-mapping object
            //                         0,                   // lparam: offset of request into file-mapping obj
            //                         SMTO_BLOCK,          // halt this thread until we get a response
            //                         2000,                // time out interval
            //                         dwError)) = 0) do begin  // return value
            {
                i++;
                Sleep(100);  // Allow for things to happen
            }

            if (i >= 10)
            {
                // Failed all tries
                if (GetLastError() == 0)
                {
                    dwResult = FSUIPC_ERR_TIMEOUT;
                }
                else
                {
                    dwResult = FSUIPC_ERR_SENDMSG;
                }

                return false;
            }

            // did IPC like the data request?
            //if (dwError != FS6IPC_MESSAGE_SUCCESS) {
            //	// no...
            //	dwResult = FSUIPC_ERR_DATA;
            //	return false;
            //}

            // Decode and store results of Read requests
            m_pNext = m_pView;
            _pNext = new IntPtr(m_pNext);

            Marshal.Copy(_pNext, hdr, 0, 1);
            m_pNext = m_pNext + 4;              //Advance ptr 4 bytes for Header pre-read

            // hdr[0) Operation ID (1=Read, 2=Write)
            // hdr[1) FSUIPC Offset value
            // hdr[2) Size of bata block to pass (bytes)
            // hdr[3) Token (offset into IPC FifO buffer)

            while (hdr[0] != 0)
            {
                switch (hdr[0])
                {
                    case FS6IPC_READSTATEDATA_ID:

                        // copy the data FSUIPC read into the local FifO buffer
                        _pNext = new IntPtr(m_pNext);
                        Marshal.Copy(_pNext, hdr, 1, 3);
                        m_pNext = m_pNext + LEN_RD_HDR - 4;

                        if (hdr[2] != 0)
                        {
                            _pNext = new IntPtr(m_pNext);
                            IntPtr _nBytes = Marshal.AllocHGlobal(4);    //Ptr to # of bytes in record
                            Marshal.WriteInt32(_nBytes, hdr[2]);                //Write datablock size as block header
                            Marshal.Copy(_nBytes, IPC, hdr[3], 4);              //Write data into FifO buffer
                            Marshal.FreeHGlobal(_nBytes);
                            Marshal.Copy(_pNext, IPC, hdr[3] + 4, hdr[2]);      //Copy data to IPC(Token)
                            IPCdr[hdr[3]] = true;                               //Flag - data available for retrieval
                        }

                        m_pNext = m_pNext + hdr[2];  //Increment read buffer ptr by size of data element passed
                        break;

                    case FS6IPC_WRITESTATEDATA_ID:

                        // Write transaction, no return data...pull header from datastream and waste
                        _pNext = new IntPtr(m_pNext);
                        Marshal.Copy(_pNext, hdr, 1, 2);
                        m_pNext = m_pNext + LEN_WR_HDR - 4 + hdr[2];
                        break;

                    default:
                        // Invalid Operation ID...abort
                        m_pNext = m_pView;
                        return false;
                }

                _pNext = new IntPtr(m_pNext);
                Marshal.Copy(_pNext, hdr, 0, 1);
                m_pNext = m_pNext + 4;
            }

            m_pNext = m_pView;    
            dwResult = FSUIPC_ERR_OK;
            return true;
        }

        //--- Internal Write request ------------------------------------------------------
        ///<summary>Submits an "internal" write request, used by FSUIPC_Write</summary>
        ///<param name="dwOffset">The memory offset where the referenced value is located</param>
        ///<param name="dwSize">The number of bytes comprising of the referenced value</param>
        ///<param name="token">Contains the unique identifier token used to Get the value</param>
        ///<param name="dwResult">Contains the "error-code" if method's boolean comes back false</param>
        ///<return>true if successful, false otherwise.  If false, dwResult contains the "error-code"</return>
        private bool FSUIPC_Write_Req(int dwOffset, int dwSize, int Token, ref int dwResult)
        {
            int[] hdr = new int[4];

            if (Token >= IPC_BUFFER_SIZE)
            {
                Token = -1;
                dwResult = FSUIPC_ERR_BUFOVERFLOW;
                return false;
            }

            // abort if necessary
            if (m_pView == 0)
            {
                dwResult = FSUIPC_ERR_NOTOPEN;
                return false;
            }

            // Check have FSUIPC buffer space for this request (including terminator)
            if ((((m_pNext) - (m_pView)) + 4 + (dwSize + LEN_WR_HDR)) > MAX_SIZE)
            {
                dwResult = FSUIPC_ERR_SIZE;
                return false;
            }

            // Initialise header for write request

            hdr[0] = FS6IPC_WRITESTATEDATA_ID;
            hdr[1] = dwOffset;
            hdr[2] = dwSize;

            IntPtr _pNext = new IntPtr(m_pNext);
            Marshal.Copy(hdr, 0, _pNext, 3);    //Write header to FSUIPC data buffer
                                                // Move pointer past the record
            m_pNext = m_pNext + LEN_WR_HDR;
            if (dwSize != 0)
            {
                _pNext = new IntPtr(m_pNext);    //convert int index to ptr into FSUIPC buffer
                Marshal.Copy(IPC, Token + 4, _pNext, dwSize);
                // Update the pointer ready for more data
                m_pNext = m_pNext + dwSize;
            }

            dwResult = FSUIPC_ERR_OK;
            return true;
        }

        //--- Write requests --------------------------------------------------------------
        ///<summary>Submits a write request</summary>
        ///<param name="dwOffset">The memory offset where the referenced value is located</param>
        ///<param name="param">The value to be written</param>
        ///<param name="token">Contains the unique identifier token used to Get the value</param>
        ///<param name="dwResult">Contains the "error-code" if method's boolean comes back false</param>
        ///<return>true if successful, false otherwise.  If false, dwResult contains the "error-code"</return>
        public bool FSUIPC_Write(int dwOffset, byte param, ref int Token, ref int dwResult)
        {
            int DataElementSize = 1;

            if ((IPCAlloc + DataElementSize + 4) >= (IPC_BUFFER_SIZE - 1))
            {  //Reset ptr to startbuf
                IPCAlloc = 0;
            }
            // Assign Token as index into IPC Buffer FifO, and clear data ready flags
            Token = IPCAlloc;
            int i;
            for (i = IPCAlloc; i < (IPCAlloc + 4 + DataElementSize - 1); i++)
            { // 4=size of int datablock size hdr
                IPC[i] = 0;
                IPCdr[i] = false;
            }
            IPCAlloc = IPCAlloc + 4 + DataElementSize;    //first four bytes data block size (Int) plus data
            IntPtr heapbuf = Marshal.AllocHGlobal(4 + DataElementSize);
            Marshal.WriteInt32(heapbuf, DataElementSize);      // Translate token to unmanaged byte stream
            Marshal.Copy(heapbuf, IPC, Token, 4);
            Marshal.WriteByte(heapbuf, param);                 // Transloate data and put in IPC array
            Marshal.Copy(heapbuf, IPC, Token + 4, DataElementSize);
            Marshal.FreeHGlobal(heapbuf);

            return FSUIPC_Write_Req(dwOffset, DataElementSize, Token, ref dwResult);
        }

        ///<summary>Submits a write request</summary>
        ///<param name="dwOffset">The memory offset where the referenced value is located</param>
        ///<param name="param">The value to be written</param>
        ///<param name="token">Contains the unique identifier token used to Get the value</param>
        ///<param name="dwResult">Contains the "error-code" if method's boolean comes back false</param>
        ///<return>true if successful, false otherwise.  If false, dwResult contains the "error-code"</return>
        public bool FSUIPC_Write(int dwOffset, short param, ref int Token, ref int dwResult)
        {
            int DataElementSize = 2;

            if ((IPCAlloc + DataElementSize + 4) >= (IPC_BUFFER_SIZE - 1))
            {  //Reset ptr to startbuf
                IPCAlloc = 0;
            }
            // Assign Token as index into IPC Buffer FifO, and clear data ready flags
            Token = IPCAlloc;
            int i;
            for (i = IPCAlloc; i < (IPCAlloc + 4 + DataElementSize - 1); i++)
            { // 4=size of int datablock size hdr
                IPC[i] = 0;
                IPCdr[i] = false;
            }
            IPCAlloc = IPCAlloc + 4 + DataElementSize;    //first four bytes data block size (Int) plus data

            IntPtr heapbuf = Marshal.AllocHGlobal(4 + DataElementSize);
            Marshal.WriteInt32(heapbuf, DataElementSize);      // Translate token to unmanaged byte stream
            Marshal.Copy(heapbuf, IPC, Token, 4);
            Marshal.WriteInt16(heapbuf, param);                 // Transloate data and put in IPC array
            Marshal.Copy(heapbuf, IPC, Token + 4, DataElementSize);
            Marshal.FreeHGlobal(heapbuf);

            return FSUIPC_Write_Req(dwOffset, DataElementSize, Token, ref dwResult);
        }

        ///<summary>Submits a write request</summary>
        ///<param name="dwOffset">The memory offset where the referenced value is located</param>
        ///<param name="param">The value to be written</param>
        ///<param name="token">Contains the unique identifier token used to Get the value</param>
        ///<param name="dwResult">Contains the "error-code" if method's boolean comes back false</param>
        ///<return>true if successful, false otherwise.  If false, dwResult contains the "error-code"</return>
        public bool FSUIPC_Write(int dwOffset, int param, ref int Token, ref int dwResult)
        {
            int DataElementSize = 4;

            if ((IPCAlloc + DataElementSize + 4) >= (IPC_BUFFER_SIZE - 1))
            {  //Reset ptr to startbuf
                IPCAlloc = 0;
            }
            // Assign Token as index into IPC Buffer FifO, and clear data + ready flags
            Token = IPCAlloc;
            int i;
            for (i = IPCAlloc; i < (IPCAlloc + 4 + DataElementSize - 1); i++)
            { // 4=size of int datablock size hdr
                IPC[i] = 0;
                IPCdr[i] = false;
            }
            IPCAlloc = IPCAlloc + 4 + DataElementSize;    //first four bytes data block size (Int) plus data
            IntPtr heapbuf = Marshal.AllocHGlobal(4 + DataElementSize);
            Marshal.WriteInt32(heapbuf, DataElementSize);      // Translate token to unmanaged byte stream
            Marshal.Copy(heapbuf, IPC, Token, 4);
            Marshal.WriteInt32(heapbuf, param);                 // Transloate data and put in IPC array
            Marshal.Copy(heapbuf, IPC, Token + 4, DataElementSize);
            Marshal.FreeHGlobal(heapbuf);

            return FSUIPC_Write_Req(dwOffset, DataElementSize, Token, ref dwResult);
        }

        ///<summary>Submits a write request</summary>
        ///<param name="dwOffset">The memory offset where the referenced value is located</param>
        ///<param name="param">The value to be written</param>
        ///<param name="token">Contains the unique identifier token used to Get the value</param>
        ///<param name="dwResult">Contains the "error-code" if method's boolean comes back false</param>
        ///<return>true if successful, false otherwise.  If false, dwResult contains the "error-code"</return>
        public bool FSUIPC_Write(int dwOffset, long param, ref int Token, ref int dwResult)
        {
            int DataElementSize = 8;

            if ((IPCAlloc + DataElementSize + 4) >= (IPC_BUFFER_SIZE - 1))
            {  //Reset ptr to startbuf
                IPCAlloc = 0;
            }
            // Assign Token as index into IPC Buffer FifO, and clear data ready flags
            Token = IPCAlloc;
            int i;
            for (i = IPCAlloc; i < (IPCAlloc + 4 + DataElementSize - 1); i++)
            { // 4=size of int datablock size hdr
                IPC[i] = 0;
                IPCdr[i] = false;
            }
            IPCAlloc = IPCAlloc + 4 + DataElementSize;    //first four bytes data block size (Int) plus data
            IntPtr heapbuf = Marshal.AllocHGlobal(4 + DataElementSize);
            Marshal.WriteInt32(heapbuf, DataElementSize);      // Translate token to unmanaged byte stream
            Marshal.Copy(heapbuf, IPC, Token, 4);
            Marshal.WriteInt64(heapbuf, param);                 // Transloate data and put in IPC array
            Marshal.Copy(heapbuf, IPC, Token + 4, DataElementSize);
            Marshal.FreeHGlobal(heapbuf);

            return FSUIPC_Write_Req(dwOffset, DataElementSize, Token, ref dwResult);
        }

        ///<summary>Submits a write request</summary>
        ///<param name="dwOffset">The memory offset where the referenced value is located</param>
        ///<param name="param">The value to be written</param>
        ///<param name="token">Contains the unique identifier token used to Get the value</param>
        ///<param name="dwResult">Contains the "error-code" if method's boolean comes back false</param>
        ///<return>true if successful, false otherwise.  If false, dwResult contains the "error-code"</return>
        public bool FSUIPC_Write(int dwOffset, int dwSize, ref byte[] param, ref int Token, ref int dwResult)
        {
            if ((IPCAlloc + dwSize + 4) >= (IPC_BUFFER_SIZE - 1))
            {
                //Reset ptr to startbuf
                IPCAlloc = 0;
            }
            // Assign Token as index into IPC Buffer FifO, and clear data ready flags
            Token = IPCAlloc;
            int i;
            for (i = IPCAlloc; i < (IPCAlloc + 4 + dwSize - 1); i++)
            {
                // 4=size of int datablock size hdr
                IPC[i] = 0;
                IPCdr[i] = false;
            }
            IPCAlloc = IPCAlloc + 4 + dwSize;    //first four bytes data block size (Int) plus data
            IntPtr heapbuf = Marshal.AllocHGlobal(4);
            Marshal.WriteInt32(heapbuf, dwSize);      // Translate size Int32 to unmanaged byte stream
            Marshal.Copy(heapbuf, IPC, Token, 4);     // Write size header to IPC array
            Marshal.FreeHGlobal(heapbuf);
            for (i = 0; i < dwSize; i++)
            {
                IPC[Token + 4 + i] = param[i];       //xfer byte array to IPC managed FifO buffer
            }

            return FSUIPC_Write_Req(dwOffset, dwSize, Token, ref dwResult);
        }

        //--- Read requests ----------------------------------------------------------------
        ///<summary>Retrieve data read from FSUIPC using token passed during read request</summary>
        ///<param name="token">The unique identifier token returned from the Read call</param>
        ///<param name="result">Contains the "error-code" if method's boolean comes back false</param>
        ///<return>true if successful, false otherwise.  If false, dwResult contains the "error-code"</return>
        public bool FSUIPC_Get(ref int Token, ref byte Result)
        {
            int Size = 1;    // 1 byte
            if ((Token < 0) || (Token > IPC_BUFFER_SIZE - (4 + Size)))
            {
                //Token out of range
                Result = 0;
                return false;
            }
            IntPtr heapbuf = Marshal.AllocHGlobal(Size);
            Marshal.Copy(IPC, Token + 4, heapbuf, 1);
            Result = Marshal.ReadByte(heapbuf);
            Marshal.FreeHGlobal(heapbuf);
            if (IPCdr[Token])
            {
                IPCdr[Token] = false;    // reset data ready flag
                return true;
            }
            else
            {  // if (data ready flag not set, function returns false and old buffer value
                return false;
            }
        }

        ///<summary>Retrieve data read from FSUIPC using token passed during read request</summary>
        ///<param name="token">The unique identifier token returned from the Read call</param>
        ///<param name="result">Contains the "error-code" if method's boolean comes back false</param>
        ///<return>true if successful, false otherwise.  If false, dwResult contains the "error-code"</return>
        public bool FSUIPC_Get(ref int Token, ref short Result)
        {
            int Size = 2;    // 2 bytes in a short
            if ((Token < 0) || (Token > IPC_BUFFER_SIZE - (4 + Size)))
            {
                //Token out of range
                Result = 0;
                return false;
            }
            IntPtr heapbuf = Marshal.AllocHGlobal(Size);
            Marshal.Copy(IPC, Token + 4, heapbuf, 2);
            Result = Marshal.ReadInt16(heapbuf);
            Marshal.FreeHGlobal(heapbuf);
            if (IPCdr[Token])
            {
                IPCdr[Token] = false;    // reset data ready flag
                return true;
            }
            else
            {
                // if (data ready flag not set, function returns false and old buffer value
                return false;
            }
        }

        ///<summary>Retrieve data read from FSUIPC using token passed during read request</summary>
        ///<param name="token">The unique identifier token returned from the Read call</param>
        ///<param name="result">Contains the "error-code" if method's boolean comes back false</param>
        ///<return>true if successful, false otherwise.  If false, dwResult contains the "error-code"</return>
        public bool FSUIPC_Get(ref int Token, ref int Result)
        {
            int Size = 4;    // 2 bytes in an int
            if ((Token < 0) || (Token > IPC_BUFFER_SIZE - (4 + Size)))
            {
                //Token out of range
                Result = 0;
                return false;
            }
            IntPtr heapbuf = Marshal.AllocHGlobal(Size);
            Marshal.Copy(IPC, Token + 4, heapbuf, 4);
            Result = Marshal.ReadInt32(heapbuf);
            Marshal.FreeHGlobal(heapbuf);
            if (IPCdr[Token])
            {
                IPCdr[Token] = false;
                return true;
            }
            else
            {
                // if (data ready flag not set, function returns false and value found
                return false;
            }
        }

        ///<summary>Retrieve data read from FSUIPC using token passed during read request</summary>
        ///<param name="token">The unique identifier token returned from the Read call</param>
        ///<param name="result">Contains the "error-code" if method's boolean comes back false</param>
        ///<return>true if successful, false otherwise.  If false, dwResult contains the "error-code"</return>
        public bool FSUIPC_Get(ref int Token, ref long Result)
        {
            int Size = 8;    // 8 bytes in a Long Int
            IntPtr heapbuf = Marshal.AllocHGlobal(Size);
            if ((Token < 0) || (Token > IPC_BUFFER_SIZE - (4 + Size)))
            {
                //Token out of range
                Result = 0;
                return false;
            }
            Marshal.Copy(IPC, Token + 4, heapbuf, 8);
            Result = Marshal.ReadInt64(heapbuf);
            Marshal.FreeHGlobal(heapbuf);
            if (IPCdr[Token])
            {
                IPCdr[Token] = false;
                return true;
            }
            else
            {
                // if (data ready flag not set, function returns false and value found
                return false;
            }
        }

        ///<summary>Retrieve data read from FSUIPC using token passed during read request</summary>
        ///<param name="token">The unique identifier token returned from the Read call</param>
        ///<param name="dwSize">The size of memory locations in bytes</param>
        ///<param name="result">Contains the "error-code" if method's boolean comes back false</param>
        ///<return>true if successful, false otherwise.  If false, dwResult contains the "error-code"</return>
        public bool FSUIPC_Get(ref int Token, int dwSize, ref byte[] Result)
        {

            if ((Token < 0) || (Token > IPC_BUFFER_SIZE - (4 + dwSize)))
            {
                //Token out of range
                return false;
            }
            IntPtr heapbuf = Marshal.AllocHGlobal(4);
            Marshal.Copy(IPC, Token, heapbuf, 4);
            int Size = Marshal.ReadInt32(heapbuf);
            Marshal.FreeHGlobal(heapbuf);
            if (dwSize > Size)
            {
                dwSize = Size;    //Max size of return block is size of block written
            }
            int idx = Token + 4;    //go past size block
            while (idx < Token + 4 + dwSize)
            {
                Result[idx - Token - 4] = IPC[idx];
                idx = idx + 1;
            }

            if (IPCdr[Token])
            {
                IPCdr[Token] = false;
                return true;
            }
            else
            {
                // if (data ready flag not set, function returns false and value found
                return false;
            }
        }

        // --- Stop the Client ---------------------------------------------------------
        ///<summary>Closes the FSUIPC client connection</summary>
        public void FSUIPC_Close()
        {

            m_hWnd = 0;
            m_msg = 0;
            m_pNext = 0;

            if (m_atom != 0)
            {
                GlobalDeleteAtom(m_atom);
                m_atom = 0;
            }

            if (m_pView != 0)
            {
                IntPtr _pView = new IntPtr(m_pView);
                UnmapViewOfFile(_pView);
                m_pView = 0;
            }

            if (m_hMap != 0)
            {
                CloseHandle(m_hMap);
                m_hMap = 0;
            }
        }
    }
}

 

Posted

Hi,

just increase your FS versions check up to value 12 as P3Dv4 returns for Offset 0x3308 value 12.

But also see below

40 minutes ago, Primo said:

if (!FSUIPC_Read(0x3308, 4, ref t_FSUIPC_FS_Version, ref dwResult))

Offset 0x3308 is not 4 byte (int32) but it is 2 byte (int16, short), so you read for FS_Version Offset 0x3308 & 0x330A.

Thomas

Posted
15 minutes ago, Thomas Richter said:

Hi,

just increase your FS versions check up to value 12 as P3Dv4 returns for Offset 0x3308 value 12.

But also see below

Offset 0x3308 is not 4 byte (int32) but it is 2 byte (int16, short), so you read for FS_Version Offset 0x3308 & 0x330A.

Thomas

OK, Thanks for your help! 

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use. Guidelines Privacy Policy We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.