I think I'm getting closer to getting this to work. I hadn't read through the VB source enough to see that the FSUIPC_read function is indeed there so no .lib needed it seems.
It's not working yet though, but here is what I've got so far. Ofcourse, if you don't have any version of MS Flight Simulator it's harder to help, but maybe you can spot some errors.
It does compile, but doesn't quite work yet. Probably lots of noob errors
Code: Select all
Prototype.l RtlMoveMemory(destination.i, source.i, length.l)
Prototype.l RtlZeroMemory(destination.i, length.l)
Prototype.l dwMilliseconds(dwMilliseconds.l)
Prototype.l FindWindowExA(hWnd1.l, hWnd2.l, lpsz1.s, lpsz2.s)
Prototype.l RegisterWindowMessageA(lpString.s)
Prototype.l GetCurrentProcessId()
Prototype.l GlobalAddAtomA(lpString.s)
Prototype.l CreateFileMappingA(hFile.l, lpFileMappingAttributes.l, flProtect.l, dwMaximumSizeHigh.l, dwMaximumSizeLow.l, lpName.s)
Prototype.l GetLastError()
Prototype.l MapViewOfFileEx(hFileMappingObject.l, dwDesiredAccess.l, dwFileOffsetHigh.l, dwFileOffsetLow.l, dwNumberOfBytesToMap.l, lpBaseAddress.i)
Prototype.l GlobalDeleteAtom(nAtom.i)
Prototype.l UnmapViewOfFile(lpBaseAddress.l)
Prototype.l CloseHandle(hObject.l)
Prototype.l SendMessageTimeoutA(hWnd.l, Msg.l, wParam.l, lParam.l, fuFlags.l, uTimeout.l, lpdwResult.l)
If OpenLibrary(1,"user32.dll")
Global FindWindowEx.FindWindowExA=GetFunction(1,"FindWindowExA")
Global RegisterWindowMessage.RegisterWindowMessageA=GetFunction(1,"RegisterWindowMessageA")
Global SendMessageTimeout.SendMessageTimeoutA=GetFunction(1,"SendMessageTimeoutA")
EndIf
If OpenLibrary(2,"kernel32.dll")
Global CopyMem.RtlMoveMemory=GetFunction(2,"RtlMoveMemory")
Global ZeroMemory.RtlZeroMemory=GetFunction(2,"RtlZeroMemory")
Global Sleep.dwMilliseconds=GetFunction(2,"dwMilliseconds")
Global GetCurrentProcId.GetCurrentProcessId=GetFunction(2,"GetCurrentProcessId")
Global AddAtom.GlobalAddAtomA=GetFunction(2,"GlobalAddAtomA")
Global CreateFileMapping.CreateFileMappingA=GetFunction(2,"CreateFileMappingA")
Global GetLastErr.GetLastError=GetFunction(2,"GetLastError")
Global MapViewOfFile.MapViewOfFileEx=GetFunction(2,"MapViewOfFileEx")
Global DeleteAtom.GlobalDeleteAtom=GetFunction(2,"GlobalDeleteAtom")
Global UnmapVOF.UnmapViewOfFile=GetFunction(2,"UnmapViewOfFile")
Global CloseHdl.CloseHandle=GetFunction(2,"CloseHandle")
EndIf
#SMTO_BLOCK = $1
#PAGE_READWRITE = 4
#NO_ERROR = 0
#ERROR_ALREADY_EXISTS = 183
#SECTION_MAP_WRITE = $2
#FILE_MAP_WRITE = #SECTION_MAP_WRITE
; FSUIPC Specifics
;Supported sims
#SIM_ANY = 0
#SIM_FS98 = 1
#SIM_FS2K = 2
#SIM_CFS2 = 3
#SIM_CFS1 = 4
#SIM_FLY = 5
#SIM_FS2K2 = 6
#SIM_FS2K4 = 7
#SIM_FSX = 8
#SIM_ESP = 9
;Error numbers
#FSUIPC_ERR_OK = 0
#FSUIPC_ERR_OPEN = 1 ; Attempt to Open when already Open
#FSUIPC_ERR_NOFS = 2 ; Cannot link to FSUIPC or WideClient
#FSUIPC_ERR_REGMSG = 3 ; Failed to Register common message with Windows
#FSUIPC_ERR_ATOM = 4 ; Failed to create Atom for mapping filename
#FSUIPC_ERR_MAP = 5 ; Failed to create a file mapping object
#FSUIPC_ERR_VIEW = 6 ; Failed to open a view to the file map
#FSUIPC_ERR_VERSION = 7 ; Incorrect version of FSUIPC, or not FSUIPC
#FSUIPC_ERR_WRONGFS = 8 ; Sim is not version requested
#FSUIPC_ERR_NOTOPEN = 9 ; Call cannot execute, link not Open
#FSUIPC_ERR_NODATA = 10 ; Call cannot execute: no requests accumulated
#FSUIPC_ERR_TIMEOUT = 11 ; IPC timed out all retries
#FSUIPC_ERR_SENDMSG = 12 ; IPC sendmessage failed all retries
#FSUIPC_ERR_DATA = 13 ; IPC request contains bad data
#FSUIPC_ERR_RUNNING = 14 ; Maybe running on WideClient, but FS not running on Server, or wrong FSUIPC
#FSUIPC_ERR_SIZE = 15 ; Read or Write request cannot be added, memory for Process is full
; define the DWORD structure
Structure DWORD
Byt0.b
Byt1.b
Byt2.b
Byt3.b
EndStructure
; global variables for the UIPC communication
Global FSUIPC_Version.l
Global FSUIPC_FS_Version.l
Global FSUIPC_Lib_Version.l
Global m_hWnd.l
Global m_msg.l
Global m_atom.l
Global m_hMap.l
Global m_pView.l
Global m_pNext.l
#LIB_VERSION = 2004
#MAX_SIZE = $7F00
FS6IPC_MSGNAME1.s = "FSASMLIB:IPC"
FS6IPC_MSGNAME2.s = "EFISFSCOM:IPC"
#FS6IPC_MESSAGE_SUCCESS = 1
#FS6IPC_MESSAGE_FAILURE = 0
; IPC message types
#FS6IPC_READSTATEDATA_ID = 1
#FS6IPC_WRITESTATEDATA_ID = 2
#FS6IPC_SPECIALREQUEST_ID =$ABAC
; declare the record types for reading and writing comms with UIPC
Structure FS6IPC_READSTATEDATA_HDR
dwId.l
dwOffset.l
nBytes.l
pDest.l
EndStructure
Structure FS6IPC_WRITESTATEDATA_HDR
dwId.l
dwOffset.l
nBytes.l
EndStructure
;--- Read request ---
Procedure FSUIPC_READ(dwOffset.l, dwSize.l, pDest.l, dwResult.l)
pHdr.FS6IPC_READSTATEDATA_HDR
; check link is open
If m_pView=0
dwResult = #FSUIPC_ERR_NOTOPEN
FSUIPC_Read = #False
ProcedureReturn
EndIf
;Check have space for this request (including terminator)
If ((((m_pNext) - (m_pView)) + 4 + (dwSize + SizeOf(pHdr))) > #MAX_SIZE)
dwResult = #FSUIPC_ERR_SIZE
FSUIPC_Read = #False
ProcedureReturn
EndIf
; Initialise header For Read request
pHdr\dwId = #FS6IPC_READSTATEDATA_ID
pHdr\dwOffset = dwOffset
pHdr\nBytes = dwSize
pHdr\pDest = pDest
CopyMem(m_pNext, pHdr, SizeOf(pHdr))
; Move pointer past the Record
m_pNext = m_pNext + SizeOf(pHdr)
If dwSize <> 0
; Zero the reception area, so rubbish won't be returned
ZeroMemory(m_pNext, dwSize)
; Update the pointer ready For more Data
m_pNext = m_pNext + dwSize
EndIf
dwResult = #FSUIPC_ERR_OK
FSUIPC_Read = #True
EndProcedure
;--- Process read/write ---
Procedure FSUIPC_Process(dwResult.l)
dwError.l
pdw.i
pHdrR.FS6IPC_READSTATEDATA_HDR
pHdrW.FS6IPC_WRITESTATEDATA_HDR
i.i=0
If m_pView = 0
dwResult = #FSUIPC_ERR_NOTOPEN
FSUIPC_Process = #False
ProcedureReturn
EndIf
If m_pView = m_pNext
dwResult = #FSUIPC_ERR_NODATA
FSUIPC_Process = #False
ProcedureReturn
EndIf
ZeroMemory(m_pNext, 4) ; Terminator
m_pNext = m_pView
; send the request (allow up to 9 tries)
While (i < 10) And ((SendMessageTimeout(m_hWnd, m_msg, m_atom, 0, #SMTO_BLOCK, 2000, 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 = i + 1
Sleep(100) ; Allow for things to happen
Wend
If i >= 10 ; Failed all tries
If GetLastErr() = 0
dwResult = #FSUIPC_ERR_TIMEOUT
Else
dwResult = #FSUIPC_ERR_SENDMSG
FSUIPC_Process = #False
ProcedureReturn
EndIf
EndIf
; did IPC like the data request?
If dwError <> #FS6IPC_MESSAGE_SUCCESS
; no...
dwResult = #FSUIPC_ERR_DATA
FSUIPC_Process = #False
ProcedureReturn
EndIf
; Decode and store results of Read requests
m_pNext = m_pView
CopyMem(pdw, m_pNext, SizeOf(pdw))
While pdw <> 0
Select pdw
Case #FS6IPC_READSTATEDATA_ID
; copy the data we read into the user's buffer
CopyMem(pHdrR, m_pNext, SizeOf(pHdrR))
m_pNext = m_pNext + SizeOf(pHdrR)
If (pHdrR\pDest <> 0) And (pHdrR\nBytes <> 0)
CopyMem(pHdrR\pDest, m_pNext, pHdrR\nBytes)
EndIf
m_pNext = m_pNext + pHdrR\nBytes
Case #FS6IPC_WRITESTATEDATA_ID
; This is a write, so there's no returned Data To store
CopyMem(pHdrW, m_pNext, SizeOf(pHdrW))
m_pNext = m_pNext + SizeOf(pHdrW) + pHdrW\nBytes
Default
; Error! So terminate the scan
m_pNext = m_pView
Break ; !?! or end
EndSelect
CopyMem(pdw, m_pNext, SizeOf(pdw))
Wend
m_pNext = m_pView
dwResult = #FSUIPC_ERR_OK
FSUIPC_Process = #True
EndProcedure
;--- Write request ---
Procedure FSUIPC_Write(dwOffset.l, dwSize.l, pSrce.l, dwResult.l)
pHdr.FS6IPC_WRITESTATEDATA_HDR
; abort if necessary
If m_pView = 0
dwResult = #FSUIPC_ERR_NOTOPEN
FSUIPC_Write = #False
ProcedureReturn
EndIf
; Check have space for this request (including terminator)
If ((((m_pNext) - (m_pView)) + 4 + (dwSize + SizeOf(pHdr))) > #MAX_SIZE)
dwResult = #FSUIPC_ERR_SIZE
FSUIPC_Write = #False
ProcedureReturn
EndIf
; Initialise header for write request
pHdr\dwId = #FS6IPC_WRITESTATEDATA_ID
pHdr\dwOffset = dwOffset
pHdr\nBytes = dwSize
CopyMem(m_pNext, pHdr, SizeOf(pHdr))
; Move pointer past the record
m_pNext = m_pNext + SizeOf(pHdr)
If dwSize <> 0
; Copy in the data to be written
CopyMem(m_pNext, pSrce, dwSize)
; Update the pointer ready for more data
m_pNext = m_pNext + dwSize
EndIf
dwResult = #FSUIPC_ERR_OK
FSUIPC_Write = #True
EndProcedure
;--- Null Terminated String Write request ---
Procedure FSUIPC_WriteS(dwOffset.l, dwSize.l, pSrce.s, dwResult.l)
pHdr.FS6IPC_WRITESTATEDATA_HDR
; abort if necessary
If m_pView = 0
dwResult = #FSUIPC_ERR_NOTOPEN
FSUIPC_WriteS = #False
ProcedureReturn
EndIf
; Check have space for this request (including terminator)
If ((((m_pNext) - (m_pView)) + 4 + (dwSize + SizeOf(pHdr))) > #MAX_SIZE)
dwResult = #FSUIPC_ERR_SIZE
FSUIPC_WriteS = #False
ProcedureReturn
EndIf
; Initialise header for write request
pHdr\dwId = FS6IPC_WRITESTATEDATA_ID
pHdr\dwOffset = dwOffset
pHdr\nBytes = dwSize
CopyMem(m_pNext, pHdr, SizeOf(pHdr))
; Move pointer past the record
m_pNext = m_pNext + SizeOf(pHdr)
If dwSize <> 0
; Copy in the data to be written
CopyMem(m_pNext, Val(pSrce), dwSize)
; Update the pointer ready for more data
m_pNext = m_pNext + dwSize
EndIf
dwResult = #FSUIPC_ERR_OK
FSUIPC_WriteS = #True
EndProcedure
; --- Stop the Client ---
Procedure FSUIPC_Close()
m_hWnd = 0
m_msg = 0
m_pNext = 0
If (m_atom <> 0)
DeleteAtom(m_atom)
m_atom = 0
EndIf
If (m_pView <> 0)
UnmapVOF(m_pView)
m_pView = 0
EndIf
If (m_hMap <> 0)
CloseHdl(m_hMap)
m_hMap = 0
EndIf
EndProcedure
Procedure FSUIPC_Initialization()
m_hWnd = 0
m_msg = 0
m_atom = 0
m_hMap = 0
m_pView = 0
m_pNext = 0
EndProcedure
; --- Start the Client ---
; returns TRUE if successful, FALSE otherwise,
; If FALSE dwResult contains the "error-code"
Procedure FSUIPC_Open(dwFSReq.l, dwResult.l)
szName.s=Space(24)
fWideFS.i = #False
nTry.i = 0
i.i = 0
;abort if already started
If (m_pView <> 0)
dwResult = #FSUIPC_ERR_OPEN
FSUIPC_Open = #False
ProcedureReturn
EndIf
FSUIPC_Version = 0
FSUIPC_FS_Version = 0
; Connect via FSUIPC, which is known to be FSUIPC's own
; And isn't subject To user modification
m_hWnd = FindWindowEx(0, 0, "UIPCMAIN", "")
If (m_hWnd = 0)
; If there's no UIPCMAIN, we may be using WideClient
; which only simulates FS98
m_hWnd = FindWindowEx(0, 0, "FS98MAIN", "")
fWideFS = #True
If (m_hWnd = 0)
dwResult = FSUIPC_ERR_NOFS
FSUIPC_Open = #False
ProcedureReturn
EndIf
EndIf
; register the window message
m_msg = RegisterWindowMessage(FS6IPC_MSGNAME1.s)
If (m_msg = 0)
dwResult = FSUIPC_ERR_REGMSG
FSUIPC_Open = #False
ProcedureReturn
EndIf
; 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 + ":" + Hex(GetCurrentProcId) + ":" + Hex(nTry) + Chr(0)
; stuff the name into a global atom
m_atom = AddAtom(szName)
If (m_atom = 0)
dwResult = FSUIPC_ERR_ATOM
FSUIPC_Close()
FSUIPC_Open = #False
ProcedureReturn
EndIf
; create the file-mapping object
; use system paging file
m_hMap = CreateFileMapping($FFFFFFFF, 0, #PAGE_READWRITE, 0, #MAX_SIZE + 256, szName)
If (m_hMap = Null) Or (GetLastErr() = #ERROR_ALREADY_EXISTS)
dwResult = #FSUIPC_ERR_MAP
FSUIPC_Close()
FSUIPC_Open = #False
ProcedureReturn
EndIf
; get a view of the file-mapping object
m_pView = MapViewOfFile(m_hMap, #FILE_MAP_WRITE, 0, 0, 0, 0) ; ?!?
If m_pView = 0
dwResult = #FSUIPC_ERR_VIEW
FSUIPC_Close()
FSUIPC_Open = #False
ProcedureReturn
EndIf
; 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
While ((i < 5) And ((FSUIPC_Version = 0) Or (FSUIPC_FS_Version = 0)))
i = i + 1
; Read FSUIPC version
If (Not FSUIPC_Read($3304, 4, @FSUIPC_Version, dwResult)) ; !?!
FSUIPC_Close()
FSUIPC_Open = #False
ProcedureReturn
EndIf
; And FS version And validity check pattern
If (Not FSUIPC_Read($3308, 4, @FSUIPC_FS_Version, dwResult))
FSUIPC_Close()
FSUIPC_Open = #False
ProcedureReturn
EndIf
; 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
If (i < 2) And (Not FSUIPC_Write($330A, 2, @FSUIPC_Lib_Version, dwResult))
FSUIPC_Close()
FSUIPC_Open = #False
ProcedureReturn
EndIf
; Actually send the request and get the responses ("process")
If Not (FSUIPC_Process(dwResult))
FSUIPC_Close()
FSUIPC_Open = #False
ProcedureReturn
EndIf
; Maybe running on WideClient, and need another try
Sleep(100) ; Give it a chance
Wend
; Only allow running on FSUIPC 1.998e or later
; with correct check pattern &HFADE
If ((FSUIPC_Version < $19980005) Or ((FSUIPC_FS_Version & $FFFF0000) <> $FADE0000))
If fWideFS
dwResult = #FSUIPC_ERR_RUNNING
Else
dwResult = #FSUIPC_ERR_VERSION
FSUIPC_Close()
FSUIPC_Open = #False
ProcedureReturn
EndIf
EndIf
; grab the FS version number
FSUIPC_FS_Version = (FSUIPC_FS_Version & $FFFF)
; Optional version-specific request made? If so and wrong version, return error
If (dwFSReq <> 0) And (dwFSReq <> FSUIPC_FS_Version)
dwResult = #FSUIPC_ERR_WRONGFS
FSUIPC_Close()
FSUIPC_Open = #False
ProcedureReturn
EndIf
dwResult = #FSUIPC_ERR_OK
FSUIPC_Open = #True
EndProcedure
And here's a small test program that should (but doesn't) display some info when MS Flightsim (with FSUIPC) is running: