Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!swrinde!cs.utexas.edu!sun-barr!newstop!sun!imagen!imagen!glenn From: glenn@imagen.com (glenn boozer) Newsgroups: comp.windows.ms.programmer Subject: Re: Windows3/TSR interface HELP Keywords: win3 tsr interrupt selector far Message-ID: Date: 17 May 91 22:39:42 GMT References: <1991May15.133642.40@mgc.uucp> Sender: news@imagen.com Organization: imagen Lines: 298 >This is the second posting - I didn't see any replies the first time :-( > >I'm trying to write a Windows 3 application which needs to interface to a >DOS TSR which communicates via an interrupt. Everything works fine in real >mode, but I get UAEs and reboots in both standard and 386 enhanced mode. > >The code segment that's causing the trouble: > > union REGS InRegs; > union REGS OutRegs; > struct SREGS SegRegs; > HANDLE hBuffer; > LPSTR lpBuffer; > > InRegs.h.ah = 11; > InRegs.h.al = 1; > InRegs.x.dx = FP_OFF(lpBuffer); > > hBuffer = GlobalAlloc(GHND,512L); Does not work in either Protected mode > lpBuffer = GlobalLock(hBuffer); > InRegs.x.di = FP_OFF(lpBuffer); > SegRegs.es = FP_SEG(lpBuffer); > > int86x(0x7f,&InRegs,&OutRegs,&SegRegs); > >I've done a lot of RTFM-ing, but to no avail (at least, the problem isn't >solved). I didn't write the TSR, so it's difficult to get changes done >there (I don't have the source). You shouldn't need to change the TSR. > >My suspicions are that lpBuffer above is a 'selector' (whatever that is) >rather than a true, _far address, and when the TSR (assembler) uses the >ES:DI register pair, some sort of protect trap takes place. You guessed it! > >Any ideas on how to solve this? Do I need to spend $500 on the DDK and write >a special device driver? Please help - any comments would be appreciated; >if you did respond via a posting last time, please respond again. My upstream >site lost some news just about the "right" time :-(. The DDK is not needed for this. The problem is that the TSR runs in REAL mode and the windows applications running in either protected mode use selectors[LDT] and not pointers[SEG:OFF] to access buffers. What follows I hastily pieced together from code I have working. In a nutshell: To Send a buffer address to the TSR [Send it a REAL address of Segment:Offset, not a protected mode selector] 1) DosAllocate a memory buffer [This will be a buffer in the first 640K of address space. This buffer is LOCKED and will not move. [Not recomended by Microsoft] 2) Copy the data from the buffer that is in "Windows Application space" into the DOS Buffer 3) Get the Segment and Offset of the DOS buffer and pass that to the TSR. 4) Release the DOS Buffer To use the buffer address [Segment:offset] that the TSR send you: 1) Allocate a Selector [Not recomended by Microsoft] 2) Set the selector base and length with the data returned from the TSR. [Not recomended by Microsoft] 3) Use the data 4) Return the selector. [Not recomended by Microsoft] Code fragments follow. If I left anything out, give me a note. #define FarPtr far * /* Data structure for calls to the TSR */ typedef union { char FarPtr p; /* treat as pointer */ void FarPtr pv; struct /* treat as selector/offset */ { unsigned off; unsigned sel; } w; long l; /*treat as arithmetic item */ } FPTR; /* Data structure for value returned from GlobalDosAlloc*/ typedef union { struct /* treat as selector and a paragraph */ { WORD sel; WORD par; } w; DWORD d; /*treat as DWORD */ } DOSPS; /* Windows kernel calls not in WINDOWS.H */ WORD FAR PASCAL SetSelectorBase(HANDLE hSelector, DWORD dwBase); WORD FAR PASCAL SetSelectorLimit(HANDLE hSelector, DWORD dwLimit); DWORD FAR PASCAL GlobalDosAlloc(DWORD); WORD FAR PASCAL GlobalDosFree(WORD); #define WIND386ENHANCEDMODE (dwWinMemFlags & WF_ENHANCED) #define WINDPROTECTEDMODE (dwWinMemFlags & WF_PMODE) #define WINDREALMODE (!(dwWinMemFlags & WF_PMODE)) static DWORD near dwWinMemFlags; /* Window Memory configuration Flags */ static DOSPS near lpsDosParagraphSelector; static WORD near hPhysMemHandle; /* Handle to DOS memory */ static LPSTR near lpPhysPtr; /* pointer to DOS memory */ /*************************************************************************** *Name: GetWindowsMemoryConfig * * * * Get windows memory configuration word so we can execute Real Mode and * * Protected Mode specific code. * * * *Returns: Nothing * ***************************************************************************/ void GetWindowsMemoryConfig () { dwWinMemFlags = GetWinFlags(); } /*********************************************************************** Module: GetPhysicalMemoryHandle Sets up a physical memory handle which can be used to access memory in protected mode. If the selector cannot be created, the call fails and returns NULL. returns: Memory access handle. **********************************************************************/ WORD FAR PASCAL GetPhysicalMemoryHandle() { HANDLE hSel; HANDLE hSel2; /*. create a selector for use by MakePhysicalMemoryPtr() */ /* The how of this is taken from an SR response. */ if ((hSel2 = GlobalAlloc(GMEM_FIXED,(long) 64)) != NULL) { hSel = AllocSelector(hSel2); GlobalFree(hSel2); } else { return (WORD)NULL; } /* successful: return a handle */ return hSel; } /*********************************************************************** Module: MakePhysicalMemoryPtr This routine sets up a protected mode pointer to a specified physical address. This pointer is good for 4K of memory at the specified physical segment + offset address. If NULL, an error occurred. returns: Memory access handle. **********************************************************************/ LPSTR NEAR PASCAL MakePhysicalMemoryPtr( WORD wMemHandle, /* Physical memory handle created by GetPhysicalMemoryHandle(). a valid selector is passed. */ WORD wSegment, /* Segment address to be referenced. This is a real-mode paragraph number. */ WORD wOffset /* Offset from Segment address to be referenced. */ ) { /*. set selector base from wSegment parameter */ SetSelectorBase(wMemHandle, (((LONG)wSegment)<<4) + wOffset ); /*. set limit for 4K bytes accessable */ SetSelectorLimit(wMemHandle,(long) 0x0FFF); /*. make and return a long pointer using passed wMemHandle */ return (LPSTR)MAKELONG(0, wMemHandle); } /*************************************************************************** Routine: FreePhysicalMemoryPtr Deallocates the specified physical memory pointer. This call is used to free a selector in protect mode. Once this function is run on a pointer, the physical memory handle which was used to create that pointer CANNOT BE USED AGAIN. Returns: nothing ***************************************************************************/ void FAR PASCAL FreePhysicalMemoryPtr( LPSTR lpMemPtr /* Pointer used for access to physical memory. The pointer must have been constructed by MakePhysicalMemoryPtr().*/ ) { /*. free the selector */ FreeSelector(HIWORD(lpMemPtr)); } [Main code fragment] This code handles Real, Standard, and Enhanced memory models all at the same time. /* Get Memory Model [Real/Standard/Enhanced] */ GetWindowsMemoryConfig(); /* If in protected mode, assign LOW memory for use with TSR */ if (WINDPROTECTEDMODE) { /* Assign a memory handle for physical address usage with TSR */ if(!( hPhysMemHandle = GetPhysicalMemoryHandle())) { MessageBoxOKHand ((LPSTR) "Error ??: Could not get Physical Memory for TSR"); return; } } [call tsr-calling routine n times] /* if in protected mode, return the handle we allocated */ if ( WINDPROTECTEDMODE) { FreePhysicalMemoryPtr(lpPhysPtr); } return; [TSR-Calling routine] static FPTR near fp; if( WINDPROTECTEDMODE) { /* allocate DOS memory to put data into */ lpsDosParagraphSelector.d = GlobalDosAlloc((DWORD)max( APImsg.len, 4)); if(APImsg.buffer) { lmemcpy( (LPSTR)MAKELONG(0, lpsDosParagraphSelector.w.sel), APImsg.buffer, max( APImsg.len, 4)); fp.w.sel = lpsDosParagraphSelector.w.par; fp.w.off = 0; } else { /* Null Pointer */ fp.p = 0L; } } else { /* If in real mode */ fp.p = APImsg.buffer; } dx = fp.w.sel; bx = fp.w.off; /* Call the tsr */ rc = int2f(ax, cx, si, di, dx, bx, (unsigned int far *)&di, (unsigned int far *)&si, (unsigned int far *)&cx, (unsigned int far *)&dx, (unsigned int far *)&bx); if(WINDPROTECTEDMODE { (void) GlobalDosFree(lpsDosParagraphSelector.w.sel); } if(WINDREALMODE) { fp.w.sel = dx; fp.w.off = bx; } else { lpPhysPtr = MakePhysicalMemoryPtr(hPhysMemHandle, dx /* segment addr */, bx /* offset */); fp.p = lpPhysPtr; /* use pointer lpPhysPtr */ } Glenn Boozer glenn@imagen.com QMS [PostScript is what we do best]