internal API_SIGNATURE LoadJ2534Library(string FileName)
        {
            API_SIGNATURE APISignature = new API_SIGNATURE();

            pLibrary = Kernal32.LoadLibrary(FileName);

            if (pLibrary == IntPtr.Zero)
            {
                return(APISignature);
            }

            IntPtr pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruOpen");

            if (pFunction != IntPtr.Zero)
            {
                Open = Marshal.GetDelegateForFunctionPointer <PassThruOpen>(pFunction);
                APISignature.SAE_API |= SAE_API.OPEN;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruClose");
            if (pFunction != IntPtr.Zero)
            {
                Close = Marshal.GetDelegateForFunctionPointer <PassThruClose>(pFunction);
                APISignature.SAE_API |= SAE_API.CLOSE;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruConnect");
            if (pFunction != IntPtr.Zero)
            {
                //If the API is v4.04 (because it has 'PassThruOpen')
                if (APISignature.SAE_API.HasFlag(SAE_API.OPEN))
                {
                    //Make 'Connect' work directly with the library function
                    Connect = Marshal.GetDelegateForFunctionPointer <PassThruConnect>(pFunction);
                }
                else
                {
                    //Otherwise, use the v202 prototype and wrap it with the v404 call
                    Connectv202 = Marshal.GetDelegateForFunctionPointer <PassThruConnectv202>(pFunction);

                    //This wrapper delegate is not 100% air tight, but is probably good enough.
                    Connect = delegate(int DeviceID, int ProtocolID, int ConnectFlags, int Baud, IntPtr ChannelID)
                    {
                        if (DeviceID == 0)
                        {
                            return(Connectv202(ProtocolID, ConnectFlags, ChannelID));
                        }
                        else
                        {
                            return(J2534ERR.INVALID_DEVICE_ID);
                        }
                    };
                }
                APISignature.SAE_API |= SAE_API.CONNECT;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruDisconnect");
            if (pFunction != IntPtr.Zero)
            {
                Disconnect            = Marshal.GetDelegateForFunctionPointer <PassThruDisconnect>(pFunction);
                APISignature.SAE_API |= SAE_API.DISCONNECT;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruReadMsgs");
            if (pFunction != IntPtr.Zero)
            {
                ReadMsgs              = Marshal.GetDelegateForFunctionPointer <PassThruReadMsgs>(pFunction);
                APISignature.SAE_API |= SAE_API.READMSGS;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruWriteMsgs");
            if (pFunction != IntPtr.Zero)
            {
                WriteMsgs             = Marshal.GetDelegateForFunctionPointer <PassThruWriteMsgs>(pFunction);
                APISignature.SAE_API |= SAE_API.WRITEMSGS;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruStartPeriodicMsg");
            if (pFunction != IntPtr.Zero)
            {
                StartPeriodicMsg      = Marshal.GetDelegateForFunctionPointer <PassThruStartPeriodicMsg>(pFunction);
                APISignature.SAE_API |= SAE_API.STARTPERIODICMSG;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruStopPeriodicMsg");
            if (pFunction != IntPtr.Zero)
            {
                StopPeriodicMsg       = Marshal.GetDelegateForFunctionPointer <PassThruStopPeriodicMsg>(pFunction);
                APISignature.SAE_API |= SAE_API.STOPPERIODICMSG;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruStartMsgFilter");
            if (pFunction != IntPtr.Zero)
            {
                StartMsgFilter        = Marshal.GetDelegateForFunctionPointer <PassThruStartMsgFilter>(pFunction);
                APISignature.SAE_API |= SAE_API.STARTMSGFILTER;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruStopMsgFilter");
            if (pFunction != IntPtr.Zero)
            {
                StopMsgFilter         = Marshal.GetDelegateForFunctionPointer <PassThruStopMsgFilter>(pFunction);
                APISignature.SAE_API |= SAE_API.STOPMSGFILTER;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruSetProgrammingVoltage");
            if (pFunction != IntPtr.Zero)
            {
                //If the API is v4.04 (because it has 'PassThruOpen')
                if (APISignature.SAE_API.HasFlag(SAE_API.OPEN))
                {
                    //Make 'Connect' work directly with the library function
                    SetProgrammingVoltage = Marshal.GetDelegateForFunctionPointer <PassThruSetProgrammingVoltage>(pFunction);
                }
                else
                {
                    //Otherwise, use the v202 prototype and wrap it with the v404 call
                    SetProgrammingVoltagev202 = Marshal.GetDelegateForFunctionPointer <PassThruSetProgrammingVoltagev202>(pFunction);
                    SetProgrammingVoltage     = delegate(int DeviceID, int Pin, int Voltage)
                    {
                        if (DeviceID == 0)   //Is this necessary?
                        {
                            return(SetProgrammingVoltagev202(Pin, Voltage));
                        }
                        else
                        {
                            return(J2534ERR.INVALID_DEVICE_ID);
                        }
                    };
                }
                APISignature.SAE_API |= SAE_API.SETPROGRAMMINGVOLTAGE;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruReadVersion");
            if (pFunction != IntPtr.Zero)
            {
                //If the API is v4.04 (because it has 'PassThruOpen')
                if (APISignature.SAE_API.HasFlag(SAE_API.OPEN))
                {
                    //Make 'Connect' work directly with the library function
                    ReadVersion = Marshal.GetDelegateForFunctionPointer <PassThruReadVersion>(pFunction);
                }
                else
                {
                    //Otherwise, use the v202 prototype and wrap it with the v404 call
                    ReadVersionv202 = Marshal.GetDelegateForFunctionPointer <PassThruReadVersionv202>(pFunction);
                    ReadVersion     = delegate(int DeviceID, IntPtr pFirmwareVer, IntPtr pDllVer, IntPtr pAPIVer)
                    {
                        if (DeviceID == 0)
                        {
                            return(ReadVersionv202(pFirmwareVer, pDllVer, pAPIVer));
                        }
                        else
                        {
                            return(J2534ERR.INVALID_DEVICE_ID);
                        }
                    };
                }
                APISignature.SAE_API |= SAE_API.READVERSION;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruGetLastError");
            if (pFunction != IntPtr.Zero)
            {
                GetLastError          = Marshal.GetDelegateForFunctionPointer <PassThruGetLastError>(pFunction);
                APISignature.SAE_API |= SAE_API.GETLASTERROR;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruIoctl");
            if (pFunction != IntPtr.Zero)
            {
                IOCtl = Marshal.GetDelegateForFunctionPointer <PassThruIoctl>(pFunction);
                APISignature.SAE_API |= SAE_API.IOCTL;
            }

            //********************J2534v5*********************
            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruScanForDevices");
            if (pFunction != IntPtr.Zero)
            {
                ScanForDevices        = Marshal.GetDelegateForFunctionPointer <PassThruScanForDevices>(pFunction);
                APISignature.SAE_API |= SAE_API.SCANFORDEVICES;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruGetNextDevice");
            if (pFunction != IntPtr.Zero)
            {
                GetNextDevice         = Marshal.GetDelegateForFunctionPointer <PassThruGetNextDevice>(pFunction);
                APISignature.SAE_API |= SAE_API.GETNEXTDEVICE;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruLogicalConnect");
            if (pFunction != IntPtr.Zero)
            {
                LogicalConnect        = Marshal.GetDelegateForFunctionPointer <PassThruLogicalConnect>(pFunction);
                APISignature.SAE_API |= SAE_API.LOGICALCONNECT;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruLogicalDisconnect");
            if (pFunction != IntPtr.Zero)
            {
                LogicalDisconnect     = Marshal.GetDelegateForFunctionPointer <PassThruLogicalDisconnect>(pFunction);
                APISignature.SAE_API |= SAE_API.LOGICALDISCONNECT;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruSelect");
            if (pFunction != IntPtr.Zero)
            {
                Select = Marshal.GetDelegateForFunctionPointer <PassThruSelect>(pFunction);
                APISignature.SAE_API |= SAE_API.SELECT;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruQueueMsgs");
            if (pFunction != IntPtr.Zero)
            {
                QueueMsgs             = Marshal.GetDelegateForFunctionPointer <PassThruQueueMsgs>(pFunction);
                APISignature.SAE_API |= SAE_API.QUEUEMESSAGES;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruGetNextCarDAQ");
            if (pFunction != IntPtr.Zero)
            {
                GetNextCarDAQ              = Marshal.GetDelegateForFunctionPointer <PassThruGetNextCarDAQ>(pFunction);
                APISignature.DREWTECH_API |= DREWTECH_API.GETNEXTCARDAQ;
            }

            return(APISignature);
        }
        private API_Signature AssignDelegates()
        {
            if (pLibrary == IntPtr.Zero)
            {
                return(APISignature);
            }

            IntPtr pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruOpen");

            if (pFunction != IntPtr.Zero)
            {
                PTOpen = Marshal.GetDelegateForFunctionPointer <PassThruOpen>(pFunction);
                APISignature.SAE_API |= SAE_API.OPEN;
            }
            else
            {
                PTOpen = Open_shim;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruClose");
            if (pFunction != IntPtr.Zero)
            {
                PTClose = Marshal.GetDelegateForFunctionPointer <PassThruClose>(pFunction);
                APISignature.SAE_API |= SAE_API.CLOSE;
            }
            else
            {
                PTClose = Close_shim;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruConnect");
            if (pFunction != IntPtr.Zero)
            {
                //If the API is v4.04 (because it has 'PassThruOpen')
                if (APISignature.SAE_API.HasFlag(SAE_API.OPEN))
                {
                    //Make 'Connect' work directly with the library function
                    PTConnect = Marshal.GetDelegateForFunctionPointer <PassThruConnect>(pFunction);
                }
                else
                {
                    //Otherwise, use the v202 prototype and wrap it with the v404 call
                    PTConnectv202 = Marshal.GetDelegateForFunctionPointer <PassThruConnectv202>(pFunction);
                    PTConnect     = Connect_shim;
                }
                APISignature.SAE_API |= SAE_API.CONNECT;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruDisconnect");
            if (pFunction != IntPtr.Zero)
            {
                PTDisconnect          = Marshal.GetDelegateForFunctionPointer <PassThruDisconnect>(pFunction);
                APISignature.SAE_API |= SAE_API.DISCONNECT;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruReadMsgs");
            if (pFunction != IntPtr.Zero)
            {
                PTReadMsgs            = Marshal.GetDelegateForFunctionPointer <PassThruReadMsgs>(pFunction);
                APISignature.SAE_API |= SAE_API.READMSGS;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruWriteMsgs");
            if (pFunction != IntPtr.Zero)
            {
                PTWriteMsgs           = Marshal.GetDelegateForFunctionPointer <PassThruWriteMsgs>(pFunction);
                APISignature.SAE_API |= SAE_API.WRITEMSGS;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruStartPeriodicMsg");
            if (pFunction != IntPtr.Zero)
            {
                PTStartPeriodicMsg    = Marshal.GetDelegateForFunctionPointer <PassThruStartPeriodicMsg>(pFunction);
                APISignature.SAE_API |= SAE_API.STARTPERIODICMSG;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruStopPeriodicMsg");
            if (pFunction != IntPtr.Zero)
            {
                PTStopPeriodicMsg     = Marshal.GetDelegateForFunctionPointer <PassThruStopPeriodicMsg>(pFunction);
                APISignature.SAE_API |= SAE_API.STOPPERIODICMSG;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruStartMsgFilter");
            if (pFunction != IntPtr.Zero)
            {
                PTStartMsgFilter      = Marshal.GetDelegateForFunctionPointer <PassThruStartMsgFilter>(pFunction);
                APISignature.SAE_API |= SAE_API.STARTMSGFILTER;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruStopMsgFilter");
            if (pFunction != IntPtr.Zero)
            {
                PTStopMsgFilter       = Marshal.GetDelegateForFunctionPointer <PassThruStopMsgFilter>(pFunction);
                APISignature.SAE_API |= SAE_API.STOPMSGFILTER;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruSetProgrammingVoltage");
            if (pFunction != IntPtr.Zero)
            {
                //If the API is v4.04 (because it has 'PassThruOpen')
                if (APISignature.SAE_API.HasFlag(SAE_API.OPEN))
                {
                    //Make 'Connect' work directly with the library function
                    PTSetProgrammingVoltage = Marshal.GetDelegateForFunctionPointer <PassThruSetProgrammingVoltage>(pFunction);
                }
                else
                {
                    //Otherwise, use the v202 prototype and wrap it with the v404 call
                    PTSetProgrammingVoltagev202 = Marshal.GetDelegateForFunctionPointer <PassThruSetProgrammingVoltagev202>(pFunction);
                    PTSetProgrammingVoltage     = SetVoltage_shim;
                }
                APISignature.SAE_API |= SAE_API.SETPROGRAMMINGVOLTAGE;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruReadVersion");
            if (pFunction != IntPtr.Zero)
            {
                //If the API is v4.04 (because it has 'PassThruOpen')
                if (APISignature.SAE_API.HasFlag(SAE_API.OPEN))
                {
                    //Make 'Connect' work directly with the library function
                    PTReadVersion = Marshal.GetDelegateForFunctionPointer <PassThruReadVersion>(pFunction);
                }
                else
                {
                    //Otherwise, use the v202 prototype and wrap it with the v404 call
                    PTReadVersionv202 = Marshal.GetDelegateForFunctionPointer <PassThruReadVersionv202>(pFunction);
                    PTReadVersion     = ReadVersion_shim;
                }
                APISignature.SAE_API |= SAE_API.READVERSION;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruGetLastError");
            if (pFunction != IntPtr.Zero)
            {
                PTGetLastError        = Marshal.GetDelegateForFunctionPointer <PassThruGetLastError>(pFunction);
                APISignature.SAE_API |= SAE_API.GETLASTERROR;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruIoctl");
            if (pFunction != IntPtr.Zero)
            {
                PTIoctl = Marshal.GetDelegateForFunctionPointer <PassThruIoctl>(pFunction);
                APISignature.SAE_API |= SAE_API.IOCTL;
            }

            //v5.00
            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruScanForDevices");
            if (pFunction != IntPtr.Zero)
            {
                PTScanForDevices      = Marshal.GetDelegateForFunctionPointer <PassThruScanForDevices>(pFunction);
                APISignature.SAE_API |= SAE_API.SCANFORDEVICES;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruGetNextDevice");
            if (pFunction != IntPtr.Zero)
            {
                PTGetNextDevice       = Marshal.GetDelegateForFunctionPointer <PassThruGetNextDevice>(pFunction);
                APISignature.SAE_API |= SAE_API.GETNEXTDEVICE;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruLogicalConnect");
            if (pFunction != IntPtr.Zero)
            {
                PTLogicalConnect      = Marshal.GetDelegateForFunctionPointer <PassThruLogicalConnect>(pFunction);
                APISignature.SAE_API |= SAE_API.LOGICALCONNECT;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruLogicalDisconnect");
            if (pFunction != IntPtr.Zero)
            {
                PTLogicalDisconnect   = Marshal.GetDelegateForFunctionPointer <PassThruLogicalDisconnect>(pFunction);
                APISignature.SAE_API |= SAE_API.LOGICALDISCONNECT;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruSelect");
            if (pFunction != IntPtr.Zero)
            {
                PTSelect              = Marshal.GetDelegateForFunctionPointer <PassThruSelect>(pFunction);
                APISignature.SAE_API |= SAE_API.SELECT;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruQueueMsgs");
            if (pFunction != IntPtr.Zero)
            {
                PTQueueMsgs           = Marshal.GetDelegateForFunctionPointer <PassThruQueueMsgs>(pFunction);
                APISignature.SAE_API |= SAE_API.QUEUEMESSAGES;
            }

            pFunction = Kernal32.GetProcAddress(pLibrary, "PassThruGetNextCarDAQ");
            if (pFunction != IntPtr.Zero)
            {
                PTGetNextCarDAQ            = Marshal.GetDelegateForFunctionPointer <PassThruGetNextCarDAQ>(pFunction);
                APISignature.DREWTECH_API |= DrewTech_API.GETNEXTCARDAQ;
            }

            return(APISignature);
        }