Jump to content
The simFlight Network Forums

FSUIPC, client/server interface?


Recommended Posts

But it cannot be, if the ASM code is working then the value stored must be the address of the instruction labelled "next". Can't you see what happens with single stepping?

No sorry I can't. I mean, this is not a "program" that I can follow step by step, but a dll. so that I launch it on another PC with FS and collect the values using a file.

Ouch! If I had to develop my DLLs (FSUIPC, WideServer, etc) like that I'd never finish! surely the debugger will let you attacvh to your own DLL code even in FS? With the MS debugger you simply tell it to launch FS with your DLL installed and you are in!

well the problem is that the m_pview value is modified by dwerror just after the asm code:

// send the request

__asm

{ push eax

call next

next: pop eax

mov dwError,eax

pop eax

}

*((DWORD *) m_pView) = dwError;

unless I'm wrong in understanding that, the value of dwerror is put into m_pView right? that's the reason of the changes.

But I might be wrong in understanding the instruction: *((DWORD *) m_pView) = dwError;

Yes, very wrong. "*((DWORD *) m_pView)" reads "the place whose address is given by the DWORD pointer 'm_pview'". The "*" sees to that.

If X is a pointer to a DWORD, then *X is its contents, effectively the same as X[0] .... but the latter implies an array, that's all. The compiled code is the same.

The (DWORD *) part is a "cast" and temporarily makes the m_pview value a pointer to a DWORD, instead of whatever it was before.

In other words, it is this instruction which places the (non-zero) value of dwError, computed by the ASM code, into the first DWORD addressed by m_pview!

This error explains both of your problems.

Regards,

Pete

Link to comment
Share on other sites

Hi Pete,

In these past days, and thanks to you, I have learnt lots of things.

Now everything works fine !!!

If you're interested in, I can send you my code if you want to add it to the next sdk.

But first, I've to cleand up all the debugging stuff.

Thanks a lot for your fast answers,

Regards,

Michael.

Link to comment
Share on other sites

  • 3 weeks later...

unit internal;

interface

uses messages,windows,math,sysutils;

const WM_IPCTHREADACCESS=WM_USER+130;

LIB_VERSION=1200;

MAX_SIZE=$7F00;

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_VIEW = 6; // Failed to open a view to the file map

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_DATA = 13; // IPC request contains bad data

FSUIPC_ERR_SIZE = 15; // Read or Write request cannot be added, memory for Process is full

FS6IPC_MESSAGE_SUCCESS = 1;

// IPC message types

FS6IPC_READSTATEDATA_ID = 1;

FS6IPC_WRITESTATEDATA_ID = 2;

//Misc

SIM_FS2K4 = 7;

type pword= ^word;

pbyte= ^byte;

FS6IPC_READSTATEDATA_HDR=record

dwId : dword;

dwOffset : dword;

nBytes : dword;

pDest : pointer;

end;

FS6IPC_WRITESTATEDATA_HDR=record

dwId : dword;

dwOffset : dword;

nBytes : dword;

end;

var FSUIPC_VERSION:word;

FSUIPC_FS_Version:word;

FSUIPC_Lib_Version:word;

m_hwnd:hwnd=0;

m_pview:pointer;

m_pnext:pointer;

m_ulMax:longword;

procedure FSUIPC_Close;

function FSUIPC_Open2(dwFSReq:word;var dwresult:Dword; pMem: pbyte; dwsize:word ):boolean;

function FSUIPC_Process(var dwresult:dword):boolean;

Function FSUIPC_ReadCommon(fspecial:boolean;dwOffset : DWORD; dwSize : DWORD; pDest : Pointer; var dwResult : DWORD) : Boolean;

Function FSUIPC_Read(dwOffset : DWORD; dwSize : DWORD; pDest : Pointer; var dwResult : DWORD) : Boolean;

Function FSUIPC_ReadSpecial(dwOffset : DWORD; dwSize : DWORD; pDest : Pointer; var dwResult : DWORD) : Boolean;

Function FSUIPC_Write(dwOffset : DWORD; dwSize : DWORD; pSrce : Pointer; var dwResult : DWORD) : Boolean;

implementation

procedure FSUIPC_Close;

begin

m_hWnd:=0;

m_pView:=nil;

end;

function FSUIPC_open2(dwFSReq:word;var dwresult:Dword; pMem: pbyte; dwsize:word ):boolean;

begin

// abort if already started

if m_pview<>nil then

begin

dwresult:=FSUIPC_ERR_OPEN;

FSUIPC_open2:=false;

exit;

end;

if (pMem=nil) or (dwsize<32) then

begin

dwresult:=FSUIPC_ERR_VIEW;

FSUIPC_open2:=false;

exit;

end;

// Clear version information, so know when connected

FSUIPC_FS_Version:=0;

FSUIPC_Version:=FSUIPC_FS_Version;

// Connect via FSUIPC, which is known to be FSUIPC's own

// and isn't subject to user modificiation

m_hWnd := FindWindowEx(0, 0, PChar('UIPCMAIN'), Nil);

if m_hWnd=0 then

begin

dwResult:=FSUIPC_ERR_NOFS;

FSUIPC_open2:=false;

exit;

end;

// get an area of memory

m_ulMax:=min(dwSize,MAX_SIZE);

m_pView:=pMem;

// Okay, now determine FSUIPC version AND FS type

DWORD(m_pNext):=DWORD(m_pView) + 4; // Allow space for code pointer

// Read FSUIPC version

if FSUIPC_Read($3304, 4, @FSUIPC_Version, dwResult)=false then

begin

FSUIPC_Close;

FSUIPC_open2:=false;

exit;

end;

// and FS version and validity check pattern

if FSUIPC_Read($3308, 4, @FSUIPC_FS_Version, dwResult)=false then

begin

FSUIPC_Close;

FSUIPC_open2:=false;

exit;

end;

// Write our Library version number to a special read-only offset

// This is to assist diagnosis from FSUIPC logging

if FSUIPC_Write($330a, 2, @FSUIPC_Lib_Version, dwResult)=false then

begin

FSUIPC_Close;

FSUIPC_open2:=false;

exit;

end;

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

if FSUIPC_Process(dwResult)=false then

begin

FSUIPC_Close();

FSUIPC_open2:=false;

exit;

end;

dwresult:=FSUIPC_ERR_OK;

FSUIPC_open2:=true;

end;

function fsuipc_process(var dwresult:dword):boolean;

var

dwError : DWORD;

pdw : ^DWORD; //Pointer;

pHdrR : ^FS6IPC_READSTATEDATA_HDR;

pHdrW : ^FS6IPC_WRITESTATEDATA_HDR;

pTemp:^DWORD;

begin

if (m_pView = Nil) then

begin

dwResult := FSUIPC_ERR_NOTOPEN;

Result := FALSE;

Exit;

end;

if (DWORD(m_pView)+4 >= DWORD(m_pNext)) then

begin

dwResult := FSUIPC_ERR_NODATA;

Result := FALSE;

Exit;

end;

ZeroMemory(m_pNext, 4); // Terminator

// send the request

asm

push eax

call @next

@next: pop eax

mov dwError,eax

pop eax

end;

dwError:= sendmessage(m_hwnd,WM_IPCTHREADACCESS,dword(m_pNext)-dword(m_pView)-4,dword(m_pView) );

dword(m_pnext):=dword(m_pView)+4;

if dwError<>FS6IPC_MESSAGE_SUCCESS then

begin

dwResult:=FSUIPC_ERR_DATA;

Result := FALSE;

Exit;

end;

dword(pdw):=dword(m_pview)+4;

while (pdw <> Nil) and Boolean(pdw^) do

begin

case pdw^ of

FS6IPC_READSTATEDATA_ID :

begin

pHdrR := Pointer(pdw);

DWORD(m_pNext) := DWORD(m_pNext) + sizeof(FS6IPC_READSTATEDATA_HDR);

if (pHdrR^.pDest <> Nil) and (pHdrR^.nBytes <> 0) then

begin

CopyMemory(pHdrR^.pDest, m_pNext, pHdrR^.nBytes);

end;

DWORD(m_pNext) := DWORD(m_pNext) + pHdrR^.nBytes;

end;

FS6IPC_WRITESTATEDATA_ID :

begin

// This is a write, so there's no returned data to store

pHdrW := Pointer(pdw);

DWORD(m_pNext) := DWORD(m_pNext) + sizeof(FS6IPC_WRITESTATEDATA_HDR) + pHdrW^.nBytes;

end;

else

// Error! So terminate the scan

pdw := Nil;

end;

dword(pdw):=dword(m_pNext);

end;

dword(m_pNext) := dword(m_pView)+4;

dwResult := FSUIPC_ERR_OK;

Result := TRUE;

end;

Function FSUIPC_ReadCommon(fspecial:boolean;dwOffset : DWORD; dwSize : DWORD; pDest : Pointer; var dwResult : DWORD) : Boolean;

var

pHdr : ^FS6IPC_READSTATEDATA_HDR;

begin

dword(pHdr) := dword(m_pNext);

// Check link is open

if (m_pView = Nil) then

begin

dwResult := FSUIPC_ERR_NOTOPEN;

Result := FALSE;

Exit;

end;

// Check have space for this request (including terminator)

if (((DWORD(m_pNext) - DWORD(m_pView)) + 8 + (dwSize + sizeof(FS6IPC_READSTATEDATA_HDR))) > m_ulMax) then

begin

dwResult := FSUIPC_ERR_SIZE;

Result := FALSE;

Exit;

end;

// Initialise header for read request

pHdr^.dwId := FS6IPC_READSTATEDATA_ID;

pHdr^.dwOffset := dwOffset;

pHdr^.nBytes := dwSize;

pHdr^.pDest := pDest;

//update pointer

DWORD(m_pNext) := DWORD(m_pNext) + sizeof(FS6IPC_READSTATEDATA_HDR);

// Initialise the reception area, so rubbish won't be returned

if (dwSize <> 0) then

begin

if fspecial=true

then CopyMemory(m_pNext,pdest,dwsize)

else ZeroMemory(m_pNext, dwSize);

end;

// Update the pointer ready for more data

DWORD(m_pNext) := DWORD(m_pNext)+ dwsize;

dwResult := FSUIPC_ERR_OK;

Result := TRUE;

end;

Function FSUIPC_Read(dwOffset : DWORD; dwSize : DWORD; pDest : Pointer; var dwResult : DWORD) : Boolean;

begin

FSUIPC_ReadCommon(false,dwoffset,dwsize,pDest,dwResult);

end;

Function FSUIPC_ReadSpecial(dwOffset : DWORD; dwSize : DWORD; pDest : Pointer; var dwResult : DWORD) : Boolean;

begin

FSUIPC_ReadCommon(true,dwoffset,dwsize,pDest,dwResult);

end;

Function FSUIPC_Write(dwOffset : DWORD; dwSize : DWORD; pSrce : Pointer; var dwResult : DWORD) : Boolean;

var

pHdr : ^FS6IPC_WRITESTATEDATA_HDR;

begin

pHdr := m_pNext;

if (m_pView = Nil) then

begin

dwResult := FSUIPC_ERR_NOTOPEN;

Result := FALSE;

Exit;

end;

// Check have space for this request (including terminator)

if (((DWORD(m_pNext) - DWORD(m_pView)) + 8 +(dwSize + sizeof(FS6IPC_WRITESTATEDATA_HDR))) > m_ulMax) then

begin

dwResult := FSUIPC_ERR_SIZE;

Result := FALSE;

Exit;

end;

// Initialise header for write request

pHdr^.dwId := FS6IPC_WRITESTATEDATA_ID;

pHdr^.dwOffset := dwOffset;

pHdr^.nBytes := dwSize;

// Update the pointer ready for write

dword(m_pNext):=dword(m_pNext)+ sizeof(FS6IPC_WRITESTATEDATA_HDR);

// Copy in the data to be written

if (dwSize<>0)then CopyMemory(m_pNext, pSrce, dwSize);

// Update the pointer ready for more data

dword(m_pNext):=dword(m_pNext)+dwSize;

dwResult := FSUIPC_ERR_OK;

Result := TRUE;

end;

Initialization

//--- Initialize global variables ---

FSUIPC_Version := 0;

FSUIPC_FS_Version := 0;

FSUIPC_Lib_Version := LIB_VERSION;

//--- IPC Client Stuff ---

m_hWnd := 0; // FS6 window handle

m_pView := Nil; // pointer to view of file-mapping object

m_pNext := Nil;

finalization

//--- Automatic "close" if programmer "forgets" ---

FSUIPC_Close;

end.

Link to comment
Share on other sites

unit internal;

...

Is this the code example in Delphi? Do you think you could ZIP is and either attach it here or send it as an email attachment to petedowson@btconnect.com, please? I can copy and paste from the thread message into a text file, but I cannot easily get any correct indentation and so on, and I don't think I'd trust the result anyway.

Thanks!

Pete

Link to comment
Share on other sites

  • 2 weeks later...

Hello pete,

Following my previous work on interrogating FS " from inside " I made several tests to try to measure how often I could make such interrogations.

So I created a module that initiate a timer and try to interrogate FS. Some time measurement shows that time between 2 interrogations can't be lower than 60ms and can take as long as 130ms.

My question is regarding the way a module action takes place in the run of FS program.

-Is there a way to know when FS has a break//pause in his process to use that time in the module process? or should I continue to try to make any action when needed, not taking care of FS workload?

-Is there a way to ask FS to execute a portion of a module repetitively not using any timer to trigger it?

Link to comment
Share on other sites

So I created a module that initiate a timer and try to interrogate FS. Some time measurement shows that time between 2 interrogations can't be lower than 60ms and can take as long as 130ms.

That sounds completely wrong. What interface to FS are you using?

What timer facilities are you using? The standard timer tick is 55 mSecs, so that's the granulation you'd see, and it also applies to the Windows "SetTimer" and TIMERPROC system. For timings accurate to a millisecond you need to use the performance measurement API calls (QueryPerformanceFrequency, QueryPerformancecounter).

If you wanted to drive something more frequently than every 55 mSecs you'd need to use a separate thread sending you a message at other intervals. In the thread a Sleep(n) can be used to sleep for n milliseconds, and that time isn't abiding by the 55mSecs granularity.

My question is regarding the way a module action takes place in the run of FS program -Is there a way to know when FS has a break//pause in his process to use that time in the module process? or should I continue to try to make any action when needed, not taking care of FS workload?

It is all to do with some of the many FS chains you can hook into. There are chains related to frame rates, to gauge updates, to all sorts of events. It used to be easier to hack into -- CHAIN.DLL used to deal with it all. It's now all inside the main FS9.EXE. You might find it easier to hack into FS98 or FS2000, work things out, then track down what you found in FS2004. Or wait for FSX where it will all change again.

Is there a way to ask FS to execute a portion of a module repetitively not using any timer to trigger it?

Yes, the chain appropriate to the sort of thing you are doing.

There has been discussions here before about all this. You may find it profitable to search on the word "chain" or similar, here, or over in the program development forum in Avsim.

Regards,

Pete

Link to comment
Share on other sites

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.