Pete Dowson Posted March 26, 2006 Report Posted March 26, 2006 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
iznogoud Posted March 26, 2006 Author Report Posted March 26, 2006 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.
Pete Dowson Posted March 26, 2006 Report Posted March 26, 2006 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. Okay. Yes, thank you -- it may well be useful to others! Regards Pete
iznogoud Posted April 12, 2006 Author Report Posted April 12, 2006 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.
Pete Dowson Posted April 12, 2006 Report Posted April 12, 2006 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
iznogoud Posted April 13, 2006 Author Report Posted April 13, 2006 Yes, it's a delphi Unit. It's the translation of your ModuleUser.c file. Simply add it to the uses declaration in a delphi program, (same as FCPuser.pas in the sdk, and that's it. I'm gonna send it to your email. Regards, Michael.
Pete Dowson Posted April 13, 2006 Report Posted April 13, 2006 Yes, it's a delphi Unit. It's the translation of your ModuleUser.c file.Simply add it to the uses declaration in a delphi program, (same as FCPuser.pas in the sdk, and that's it. I'm gonna send it to your email. Thanks! Pete
iznogoud Posted April 23, 2006 Author Report Posted April 23, 2006 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?
Pete Dowson Posted April 23, 2006 Report Posted April 23, 2006 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
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now