/*++ Copyright (c) 1992 Microsoft Corporation Module Name: wcomdlg.c Abstract: 32-bit support for thunking COMMDLG in WOW Author: John Vert (jvert) 31-Dec-1992 Revision History: John Vert (jvert) 31-Dec-1992 created --*/ #include "precomp.h" #pragma hdrstop #include #include #include MODNAME(wcommdlg.c); // // Debugging stuff... // #if DEBUG void WCDDumpCHOOSECOLORData16(PCHOOSECOLORDATA16 p16); void WCDDumpCHOOSECOLORData32(CHOOSECOLOR *p32); void WCDDumpCHOOSEFONTData16(PCHOOSEFONTDATA16 p16); void WCDDumpCHOOSEFONTData32(CHOOSEFONT *p32); void WCDDumpFINDREPLACE16(PFINDREPLACE16 p16); void WCDDumpFINDREPLACE32(FINDREPLACE *p32); void WCDDumpOPENFILENAME16(POPENFILENAME16 p16); void WCDDumpOPENFILENAME32(OPENFILENAME *p32); void WCDDumpPRINTDLGData16(PPRINTDLGDATA16 p16); void WCDDumpPRINTDLGData32(PRINTDLG *p32); // macros to dump the 16 & 32 bit structs #define WCDDUMPCHOOSECOLORDATA16(p16) WCDDumpCHOOSECOLORData16(p16) #define WCDDUMPCHOOSECOLORDATA32(p32) WCDDumpCHOOSECOLORData32(p32) #define WCDDUMPCHOOSEFONTDATA16(p16) WCDDumpCHOOSEFONTData16(p16) #define WCDDUMPCHOOSEFONTDATA32(p32) WCDDumpCHOOSEFONTData32(p32) #define WCDDUMPFINDREPLACE16(p16) WCDDumpFINDREPLACE16(p16) #define WCDDUMPFINDREPLACE32(p32) WCDDumpFINDREPLACE32(p32) #define WCDDUMPOPENFILENAME16(p16) WCDDumpOPENFILENAME16(p16) #define WCDDUMPOPENFILENAME32(p32) WCDDumpOPENFILENAME32(p32) #define WCDDUMPPRINTDLGDATA16(p16) WCDDumpPRINTDLGData16(p16) #define WCDDUMPPRINTDLGDATA32(p32) WCDDumpPRINTDLGData32(p32) #else // !DEBUG #define WCDDUMPCHOOSECOLORDATA16(p16) #define WCDDUMPCHOOSECOLORDATA32(p32) #define WCDDUMPCHOOSEFONTDATA16(p16) #define WCDDUMPCHOOSEFONTDATA32(p32) #define WCDDUMPOPENFILENAME16(p16) #define WCDDUMPOPENFILENAME32(p32) #define WCDDUMPPRINTDLGDATA16(p16) #define WCDDUMPPRINTDLGDATA32(p32) #define WCDDUMPFINDREPLACE16(p16) #define WCDDUMPFINDREPLACE32(p32) #endif // !DEBUG // global data WORD msgCOLOROK = 0; WORD msgFILEOK = 0; WORD msgWOWLFCHANGE = 0; WORD msgWOWDIRCHANGE = 0; WORD msgWOWCHOOSEFONT = 0; WORD msgSHAREVIOLATION = 0; WORD msgFINDREPLACE = 0; /* external global stuff */ extern WORD gwKrnl386CodeSeg1; extern WORD gwKrnl386CodeSeg2; extern WORD gwKrnl386CodeSeg3; extern WORD gwKrnl386DataSeg1; ULONG dwExtError = 0; #define SETEXTENDEDERROR(Code) (dwExtError=Code) /*+++ For reference only -- which flags are set on output #define FR_OUTPUTFLAGS (FR_DOWN | FR_WHOLEWORD | FR_MATCHCASE | \ FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL | \ FR_DIALOGTERM | FR_SHOWHELP | FR_NOUPDOWN | \ FR_NOMATCHCASE | FR_NOWHOLEWORD | FR_HIDEUPDOWN | \ FR_HIDEMATCHCASE | FR_HIDEWHOLEWORD) #define PD_OUTPUTFLAGS (PD_ALLPAGES | PD_COLLATE | PD_PAGENUMS | \ PD_PRINTTOFILE | PD_SELECTION) #define FO_OUTPUTFLAGS (OFN_READONLY | OFN_EXTENSIONDIFFERENT) #define CF_OUTPUTFLAGS (CF_NOFACESEL | CF_NOSIZESEL | CF_NOSTYLESEL) ---*/ // private typedefs and structs typedef BOOL (APIENTRY* FILENAMEPROC)(LPOPENFILENAME); typedef HWND (APIENTRY* FINDREPLACEPROC)(LPFINDREPLACE); // exported by comdlg32.dll to allow us to ultimately keep 16-bit common dialog // structs in sync with the UNICODE version maintained by comdlg32. extern VOID Ssync_ANSI_UNICODE_Struct_For_WOW(HWND hDlg, BOOL fANSI_To_UNICODE, DWORD dwID); // private function prototypes VOID Thunk_OFNstrs16to32(IN OPENFILENAME *pOFN32, IN POPENFILENAME16 pOFN16); BOOL Alloc_OFN32_strs(IN OPENFILENAME *pOFN32, IN POPENFILENAME16 pOFN16); VOID Free_OFN32_strs(IN OPENFILENAME *pOFN32); PCOMMDLGTD GetCommdlgTd(IN HWND Hwnd32); HINSTANCE ThunkCDTemplate16to32(IN HAND16 hInst16, IN DWORD hPrintTemp16, IN VPVOID vpTemplateName, IN DWORD dwFlags16, IN OUT DWORD *pFlags, IN DWORD ETFlag, IN DWORD ETHFlag, OUT PPRES pRes, OUT PBOOL fError); VOID FreeCDTemplate32(IN PRES pRes, IN HINSTANCE hInst, IN BOOL bETFlag, IN BOOL bETHFlag); PRES GetTemplate16(IN HAND16 hInstance, IN VPCSTR TemplateName, IN BOOLEAN UseHandle); HGLOBAL ThunkhDevMode16to32(IN HAND16 hDevMode16); VOID ThunkhDevMode32to16(IN OUT HAND16 *phDevMode16, IN HANDLE hDevMode32); HANDLE ThunkhDevNames16to32(IN HAND16 hDevNames16); VOID ThunkhDevNames32to16(IN OUT HAND16 *phDevNames16, IN HANDLE hDevNames); VOID ThunkCHOOSECOLOR16to32(OUT CHOOSECOLOR *pCC32, IN PCHOOSECOLORDATA16 pCC16); VOID ThunkCHOOSECOLOR32to16(OUT PCHOOSECOLORDATA16 pCC16, IN CHOOSECOLOR *pCC32); VOID ThunkCHOOSEFONT16to32(OUT CHOOSEFONT *pCF32, IN PCHOOSEFONTDATA16 pCF16); VOID ThunkCHOOSEFONT32to16(OUT PCHOOSEFONTDATA16 pCF16, IN CHOOSEFONT *pCF32); VOID ThunkFINDREPLACE16to32(OUT FINDREPLACE *pFR32, IN PFINDREPLACE16 pFR16); VOID ThunkFINDREPLACE32to16(OUT PFINDREPLACE16 pFR16, IN FINDREPLACE *pFR32); BOOL ThunkOPENFILENAME16to32(OUT OPENFILENAME *pOFN32, IN POPENFILENAME16 pOFN16); VOID ThunkOPENFILENAME32to16(OUT POPENFILENAME16 pOFN16, IN OPENFILENAME *pOFN32, IN BOOLEAN bUpperStrings); VOID ThunkPRINTDLG16to32(OUT PRINTDLG *pPD32, IN PPRINTDLGDATA16 pPD16); VOID ThunkPRINTDLG32to16(IN VPVOID vppd, OUT PRINTDLG *pPD32); VOID ThunkCDStruct16to32(IN HWND hDlg, IN CHOOSECOLOR *pCC, IN VPVOID vp); VOID ThunkCDStruct32to16(IN HWND hDlg, IN VPVOID vp, IN CHOOSECOLOR *pCC); UINT APIENTRY WCD32CommonDialogProc(HWND hdlg, UINT uMsg, WPARAM uParam, LPARAM lParam, PCOMMDLGTD pCTD, VPVOID vpfnHook); UINT APIENTRY WCD32PrintSetupDialogProc(HWND hdlg, UINT uMsg, WPARAM uParam, LPARAM lParam); UINT APIENTRY WCD32DialogProc(HWND hdlg, UINT uMsg, WPARAM uParam, LPARAM lParam); ULONG WCD32GetFileName(IN PVDMFRAME pFrame, IN FILENAMEPROC Function); ULONG WCD32FindReplaceText(IN PVDMFRAME pFrame, IN FINDREPLACEPROC Function); UINT APIENTRY WCD32FindReplaceDialogProc(HWND hdlg, UINT uMsg, WPARAM uParam, LPARAM lParam); #define VALID_OFN16_FLAGS (OFN_READONLY | \ OFN_OVERWRITEPROMPT | \ OFN_HIDEREADONLY | \ OFN_NOCHANGEDIR | \ OFN_SHOWHELP | \ OFN_ENABLEHOOK | \ OFN_ENABLETEMPLATE | \ OFN_ENABLETEMPLATEHANDLE | \ OFN_NOVALIDATE | \ OFN_ALLOWMULTISELECT | \ OFN_EXTENSIONDIFFERENT | \ OFN_PATHMUSTEXIST | \ OFN_FILEMUSTEXIST | \ OFN_CREATEPROMPT | \ OFN_SHAREAWARE | \ OFN_NOREADONLYRETURN | \ OFN_NOTESTFILECREATE) // // unique message thunks // // This function thunks the private messages // msgCOLOROK BOOL FASTCALL WM32msgCOLOROK(LPWM32MSGPARAMEX lpwm32mpex) { LPCHOOSECOLOR pCC32; PCHOOSECOLORDATA16 pCC16; GETVDMPTR((VPVOID)lpwm32mpex->Parm16.WndProc.lParam, sizeof(CHOOSECOLORDATA16), pCC16); pCC32 = (LPCHOOSECOLOR)lpwm32mpex->lParam; if(pCC16 && pCC32) { if(lpwm32mpex->fThunk) { ThunkCHOOSECOLOR32to16(pCC16, pCC32); } else { ThunkCHOOSECOLOR16to32(pCC32, pCC16); } } else { return(FALSE); } FREEVDMPTR(pCC16); return (TRUE); } // This function thunks the private messages // msgFILEOK BOOL FASTCALL WM32msgFILEOK(LPWM32MSGPARAMEX lpwm32mpex) { VPOPENFILENAME vpof; POPENFILENAME16 pOFN16; OPENFILENAME *pOFN32; vpof = (VPOPENFILENAME)(GetCommdlgTd(lpwm32mpex->hwnd)->vpData); pOFN32 = (OPENFILENAME *)lpwm32mpex->lParam; // // Approach sends its own fileok message when you click on its // secret listbox that it displays over lst1 sometimes. It // sends NULL for the LPARAM instead of the address of the // openfilename structure. if(pOFN32 == NULL) { lpwm32mpex->Parm16.WndProc.lParam = (LPARAM)NULL; return(TRUE); } GETVDMPTR(vpof, sizeof(OPENFILENAME16), pOFN16); if (lpwm32mpex->fThunk) { UpdateDosCurrentDirectory(DIR_NT_TO_DOS); lpwm32mpex->Parm16.WndProc.lParam = (LPARAM)vpof; // sudeepb 12-Mar-1996 // // The selected file name needs to be uppercased for // apps like symanatec QA 4.0. So changed the following parameter // in ThunkOpenFileName from FALSE to TRUE. ThunkOPENFILENAME32to16(pOFN16, pOFN32, TRUE); } else { ThunkOPENFILENAME16to32(pOFN32, pOFN16); } FREEVDMPTR(pOFN16); return (TRUE); } // This function thunks the private messages // msgWOWDIRCHANGE BOOL FASTCALL WM32msgWOWDIRCHANGE(LPWM32MSGPARAMEX lpwm32mpex) { if (lpwm32mpex->fThunk) { UpdateDosCurrentDirectory(DIR_NT_TO_DOS); } return (TRUE); } // This function thunks the private message // msgWOWLFCHANGE BOOL FASTCALL WM32msgWOWLFCHANGE(LPWM32MSGPARAMEX lpwm32mpex) { VPCHOOSEFONTDATA vpcf; PCHOOSEFONTDATA16 pCF16; vpcf = (VPCHOOSEFONTDATA)(GetCommdlgTd(lpwm32mpex->hwnd)->vpData); GETVDMPTR(vpcf, sizeof(CHOOSEFONTDATA16), pCF16); WOW32ASSERT(pCF16); if (lpwm32mpex->fThunk) { PUTLOGFONT16(DWORD32(pCF16->lpLogFont), sizeof(LOGFONT), (LPLOGFONT)lpwm32mpex->lParam); } FREEVDMPTR(pCF16); return(TRUE); } // This function thunks the private message // msgSHAREVIOLATION BOOL FASTCALL WM32msgSHAREVIOLATION(LPWM32MSGPARAMEX lpwm32mpex) { INT cb; PLONG plParamNew = &lpwm32mpex->Parm16.WndProc.lParam; if (lpwm32mpex->fThunk) { if (lpwm32mpex->lParam) { cb = strlen((LPSZ)lpwm32mpex->lParam)+1; if (!(*plParamNew = malloc16(cb))) { return(FALSE); } putstr16((VPSZ)*plParamNew, (LPSZ)lpwm32mpex->lParam, cb); } } else { if (*plParamNew) { free16((VPVOID) *plParamNew); } } return (TRUE); } // This function thunks the private messages // WM_CHOOSEFONT_GETLOGFONT BOOL FASTCALL WM32msgCHOOSEFONTGETLOGFONT(LPWM32MSGPARAMEX lpwm32mpex) { LOGFONT LogFont32; // The mere fact that we access the buffer after allowing the 16-bit // hook proc to step in breaks Serif PagePlus app which wants it's // hook proc to always have a shot and commdlg to check the return value. // If hook proc returns TRUE, no further action is taken // // This is the message an app sends the dialog if it wants to find // out what font is currently selected. // // We thunk this by sending yet another hackorama message to comdlg32, // who will then fill in the 32-bit structure we pass in so we can // thunk it back to the 16-bit structure. Then we return TRUE so // comdlg32 doesn't reference the 16-bit logfont. // if (!lpwm32mpex->fThunk && !lpwm32mpex->lReturn) { SendMessage(lpwm32mpex->hwnd, msgWOWCHOOSEFONT, 0, (LPARAM)&LogFont32); PUTLOGFONT16(lpwm32mpex->lParam, sizeof(LOGFONT), &LogFont32); lpwm32mpex->lReturn = TRUE; } return (TRUE); } // // Dialog callback hook thunks // UINT APIENTRY WCD32DialogProc(HWND hdlg, UINT uMsg, WPARAM uParam, LPARAM lParam) /*++ Routine Description: This is the hook proc used by ChooseColor, ChooseFont, GetOpenFileName, GetSaveFileName, and PrintDlg. It pulls the 16-bit callback out of the thread data and calls the common dialog proc to do the rest of the work. --*/ { PCOMMDLGTD Td; Td = GetCommdlgTd(hdlg); if(Td) { return(WCD32CommonDialogProc(hdlg, uMsg, uParam, lParam, Td, Td->vpfnHook)); } else { return(0); } } UINT APIENTRY WCD32PrintSetupDialogProc(HWND hdlg, UINT uMsg, WPARAM uParam, LPARAM lParam) /*++ Routine Description: This is the hook proc used by PrintSetup. It is only used when the Setup button on the Print dialog directly creates the PrintSetup dialog. We find the correct TD by looking for the TD of our owner window (which is the print dialog) It calls the common dialog proc to do the rest of the work. --*/ { PCOMMDLGTD pTD; pTD = CURRENTPTD()->CommDlgTd; if(pTD) { while (pTD->SetupHwnd != GETHWND16(hdlg)) { pTD = pTD->Previous; if(!pTD) { WOW32ASSERT(FALSE); return(0); } } return(WCD32CommonDialogProc(hdlg, uMsg, uParam, lParam, pTD, pTD->vpfnSetupHook)); } else { return(0); } } UINT APIENTRY WCD32FindReplaceDialogProc(HWND hdlg, UINT uMsg, WPARAM uParam, LPARAM lParam) /*++ Routine Description: This is the hook proc used by FindText and ReplaceText. It does cleanup on WM_DESTROY and calls WCD32CommonDialogProc to handle the 16-bit dialog hook callback on all messages, if needed. --*/ { PFINDREPLACE16 pFR16; VPFINDREPLACE vpfr; LPFINDREPLACE pFR32; PCOMMDLGTD ptdDlg; PCOMMDLGTD ptdOwner; UINT uRet = FALSE; // If the ptdDlg is invalid, do nothing. ptdDlg = GetCommdlgTd(hdlg); if (ptdDlg == NULL) { return(uRet); } if (uMsg != WM_DESTROY) { // this will be FALSE if the app didn't specify a 16-bit hookproc // we always set the 32-bit hookproc in ThunkFINDREPLACE16to32() if (ptdDlg->vpfnHook) { uRet = WCD32CommonDialogProc(hdlg, uMsg, uParam, lParam, ptdDlg, ptdDlg->vpfnHook); } } else { pFR32 = (LPFINDREPLACE)ptdDlg->pData32; // UnLink both per thread data structs from the list. ptdOwner = GetCommdlgTd(pFR32->hwndOwner); CURRENTPTD()->CommDlgTd = ptdDlg->Previous; WOW32ASSERT(ptdOwner->Previous == ptdDlg); vpfr = ptdDlg->vpData; GETVDMPTR(vpfr, sizeof(FINDREPLACE16), pFR16); // CleanUp template if used. FreeCDTemplate32((PRES)ptdDlg->pRes, pFR32->hInstance, DWORD32(pFR16->Flags) & FR_ENABLETEMPLATE, DWORD32(pFR16->Flags) & FR_ENABLETEMPLATEHANDLE); FREEVDMPTR(pFR16); // Free the per thread data structs. free_w(ptdDlg); free_w(ptdOwner); // Free the 32-bit FINDREPLACE structure. free_w(pFR32->lpstrFindWhat); free_w(pFR32->lpstrReplaceWith); free_w(pFR32); } if (uMsg == WM_INITDIALOG) { // Force COMDLG32!FindReplaceDialogProc to handle WM_INITDIALOG. uRet = TRUE; } return(uRet); } UINT APIENTRY WCD32CommonDialogProc(HWND hdlg, UINT uMsg, WPARAM uParam, LPARAM lParam, PCOMMDLGTD pCTD, VPVOID vpfnHook) /*++ Routine Description: This thunks the 32-bit dialog callback into a 16-bit callback This is the common code used by all the dialog callback thunks that actually calls the 16-bit callback. --*/ { BOOL fSuccess; LPFNM32 pfnThunkMsg; WM32MSGPARAMEX wm32mpex; BOOL fMessageNeedsThunking; // If the app has GP Faulted we don't want to pass it any more input // This should be removed when USER32 does clean up on task death so // it doesn't call us - mattfe june 24 92 // LOGDEBUG(10, ("CommonDialogProc In: %lX %X %X %lX\n", // (DWORD)hdlg, // uMsg, // uParam, // lParam)); if(CURRENTPTD()->dwFlags & TDF_IGNOREINPUT) { LOGDEBUG(6, (" WCD32OpenFileDialog Ignoring Input Messsage %04X\n", uMsg)); WOW32ASSERTMSG(gfIgnoreInputAssertGiven, "WCD32CommonDialogProc: TDF_IGNOREINPUT hack was used, shouldn't be, " "please email DaveHart with repro instructions. Hit 'g' to ignore " "this and suppress this assertion from now on.\n"); gfIgnoreInputAssertGiven = TRUE; goto SilentError; } #if DBG if(pCTD==NULL) { LOGDEBUG(0,(" WCD32OpenFileDialog ERROR: pCTD==NULL\n")); goto Error; } // If pCTD->vpfnHook is NULL, then something is broken; we // certainly can't continue because we don't know what 16-bit func to call if(!vpfnHook) { LOGDEBUG(0,(" WCD32OpenFileDialog ERROR: no hook proc for message %04x Dlg = %08lx\n", uMsg, hdlg )); goto Error; } #endif wm32mpex.Parm16.WndProc.hwnd = GETHWND16(hdlg); wm32mpex.Parm16.WndProc.wMsg = (WORD)uMsg; wm32mpex.Parm16.WndProc.wParam = (WORD)uParam; wm32mpex.Parm16.WndProc.lParam = (LONG)lParam; wm32mpex.Parm16.WndProc.hInst = (WORD)GetWindowLong(hdlg, GWL_HINSTANCE); // On Win3.1, the app & the system share the ptr to the same structure that // the app passed to the common dialog API. Therefore, when one side makes // a change to the struct, the other is aware of the change. This is not // the case on NT since we thunk the struct into a 32-bit ANSI struct which // is then thunked into a 32-bit UNICODE struct in the comdlg32 code. We // attempt to synchronize all these structs by rethunking them for every // message sent to the 16-bit side & for every API call the app makes. // See sync code in callback16(), fastwow bopping code, and w32Dispatch(). // ComDlg32 thunks UNICODEtoANSI before calling us & ASNItoUNICODE when we // return. Ug!!! Apparently a fair number of apps depend on this // behavior since we've debugged this problem about 6 times to date and // each time we have put in special hacks for each case. With any luck // this should be a general fix. 08/97 CMJones if(uMsg < 0x400) { LOGDEBUG(3, ("%04X (%s)\n", CURRENTPTD()->htask16, (aw32Msg[uMsg].lpszW32))); pfnThunkMsg = aw32Msg[uMsg].lpfnM32; if(uMsg == WM_INITDIALOG) { // The address of the 16-bit structure that the app passed to the // original common dialog API is passed in lParam in WM_INITDIALOG // messages in Win 3.1 wm32mpex.Parm16.WndProc.lParam = lParam = (LPARAM)pCTD->vpData; } // Check for unique messages } else if(uMsg >= 0x400) { if (uMsg == msgFILEOK) { pfnThunkMsg = WM32msgFILEOK; } else if(uMsg == msgCOLOROK) { wm32mpex.Parm16.WndProc.lParam = (LPARAM)pCTD->vpData; pfnThunkMsg = WM32msgCOLOROK; } else if(uMsg == msgSHAREVIOLATION) { pfnThunkMsg = WM32msgSHAREVIOLATION; } else if(uMsg == msgWOWDIRCHANGE) { pfnThunkMsg = WM32msgWOWDIRCHANGE; } else if(uMsg == msgWOWLFCHANGE) { pfnThunkMsg = WM32msgWOWLFCHANGE; } else if(pCTD->Flags & WOWCD_ISCHOOSEFONT) { // special ChooseFont thunks to handle goofy GETLOGFONT message if(uMsg == WM_CHOOSEFONT_GETLOGFONT) { pfnThunkMsg = WM32msgCHOOSEFONTGETLOGFONT; } else if(uMsg == msgWOWCHOOSEFONT) { // // no wow app will expect this, so don't send it. // return(FALSE); } else { pfnThunkMsg = WM32NoThunking; } } else { pfnThunkMsg = WM32NoThunking; } } fMessageNeedsThunking = (pfnThunkMsg != WM32NoThunking); if(fMessageNeedsThunking) { wm32mpex.fThunk = THUNKMSG; wm32mpex.hwnd = hdlg; wm32mpex.uMsg = uMsg; wm32mpex.uParam = uParam; wm32mpex.lParam = lParam; wm32mpex.pww = NULL; wm32mpex.lpfnM32 = pfnThunkMsg; if(!(pfnThunkMsg)(&wm32mpex)) { LOGDEBUG(LOG_ERROR,(" WCD32OpenFileDialog ERROR: cannot thunk 32-bit message %04x\n", uMsg)); goto Error; } } else { LOGDEBUG(6,("WCD32CommonDialogProc, No Thunking was required for the 32-bit message %s(%04x)\n", (LPSZ)GetWMMsgName(uMsg), uMsg)); } // this call may cause 16-bit memory to move // this call will call 32->16 sync code before the callback & the 16->32 // sync upon return from the callback fSuccess = CallBack16(RET_WNDPROC, &wm32mpex.Parm16, vpfnHook, (PVPVOID)&wm32mpex.lReturn); // flat ptrs to 16-bit mem are now invalid due to possible memory movement // the callback function of a dialog is of type FARPROC whose return value // is of type 'int'. Since dx:ax is copied into lReturn in the above // CallBack16 call, we need to zero out the hiword, otherwise we will be // returning an erroneous value. wm32mpex.lReturn = (LONG)LOWORD(wm32mpex.lReturn); if(fMessageNeedsThunking) { wm32mpex.fThunk = UNTHUNKMSG; (pfnThunkMsg)(&wm32mpex); } if(!fSuccess) goto Error; Done: // Uncomment this to receive message on exit // LOGDEBUG(10, ("CommonDialogProc Out: Return %lX\n", wm32mpex.lReturn)); return wm32mpex.lReturn; Error: LOGDEBUG(5,(" WCD32OpenFileDialog WARNING: cannot call back, using default message handling\n")); SilentError: wm32mpex.lReturn = 0; goto Done; } ULONG FASTCALL WCD32ExtendedError( IN PVDMFRAME pFrame ) /*++ Routine Description: 32-bit thunk for CommDlgExtendedError() Arguments: pFrame - Supplies 16-bit argument frame Return Value: error code to be returned --*/ { if (dwExtError != 0) { return(dwExtError); } return(CommDlgExtendedError()); } ULONG FASTCALL WCD32ChooseColor(PVDMFRAME pFrame) /*++ Routine Description: This routine thunks the 16-bit ChooseColor common dialog to the 32-bit side. Arguments: pFrame - Supplies 16-bit argument frame Return Value: 16-bit BOOLEAN to be returned. --*/ { ULONG ul = GETBOOL16(FALSE); register PCHOOSECOLOR16 parg16; VPCHOOSECOLORDATA vpcc; CHOOSECOLOR CC32; PCHOOSECOLORDATA16 pCC16; PRES pRes = NULL; COMMDLGTD ThreadData; COLORREF CustColors32[16]; // on stack for DWORD alignment DWORD dwFlags16; BOOL fError = FALSE; GETARGPTR(pFrame, sizeof(CHOOSECOLOR16), parg16); vpcc = parg16->lpcc; SETEXTENDEDERROR( 0 ); // invalidate this now FREEVDMPTR( parg16 ); // initialize unique window message if (msgCOLOROK == 0) { if(!(msgCOLOROK = (WORD)RegisterWindowMessage(COLOROKSTRING))) { SETEXTENDEDERROR( CDERR_REGISTERMSGFAIL ); LOGDEBUG(2,("WCD32ChooseColor:RegisterWindowMessage failed\n")); return(0); } } GETVDMPTR(vpcc, sizeof(CHOOSECOLORDATA16), pCC16); WCDDUMPCHOOSECOLORDATA16(pCC16); if(DWORD32(pCC16->lStructSize) != sizeof(CHOOSECOLORDATA16)) { SETEXTENDEDERROR( CDERR_STRUCTSIZE ); FREEVDMPTR(pCC16); return(0); } RtlZeroMemory(&ThreadData, sizeof(COMMDLGTD)); ThreadData.Previous = CURRENTPTD()->CommDlgTd; ThreadData.hdlg = (HWND16)-1; ThreadData.pData32 = &CC32; ThreadData.Flags = 0; if(DWORD32(pCC16->Flags) & CC_ENABLEHOOK) { ThreadData.vpfnHook = DWORD32(pCC16->lpfnHook); if(!ThreadData.vpfnHook) { SETEXTENDEDERROR(CDERR_NOHOOK); FREEVDMPTR(pCC16); return(0); } ThreadData.vpData = vpcc; } else { STOREDWORD(pCC16->lpfnHook, 0); } RtlZeroMemory(&CC32, sizeof(CHOOSECOLOR)); CC32.lpCustColors = CustColors32; ThunkCHOOSECOLOR16to32(&CC32, pCC16); dwFlags16 = DWORD32(pCC16->Flags); // this call invalidates flat ptrs to 16-bit memory CC32.hInstance = (HWND)ThunkCDTemplate16to32(WORD32(pCC16->hInstance), 0, DWORD32(pCC16->lpTemplateName), dwFlags16, &(CC32.Flags), CC_ENABLETEMPLATE, CC_ENABLETEMPLATEHANDLE, &pRes, &fError); if(fError) { goto ChooseColorExit; } // invalidate flat ptrs to 16-bit memory FREEVDMPTR(pCC16); WCDDUMPCHOOSECOLORDATA32(&CC32); // Set this just before the calling into comdlg32. This prevents the // synchronization stuff from firing until we actually need it. CURRENTPTD()->CommDlgTd = &ThreadData; // this call invalidates flat ptrs to 16-bit memory ul = GETBOOL16(ChooseColor(&CC32)); CURRENTPTD()->CommDlgTd = ThreadData.Previous; if (ul) { WCDDUMPCHOOSECOLORDATA32(&CC32); GETVDMPTR(vpcc, sizeof(CHOOSECOLOR16), pCC16); ThunkCHOOSECOLOR32to16(pCC16, &CC32); WCDDUMPCHOOSECOLORDATA16(pCC16); FREEVDMPTR(pCC16); } ChooseColorExit: FreeCDTemplate32(pRes, (HINSTANCE)CC32.hInstance, dwFlags16 & CC_ENABLETEMPLATE, dwFlags16 & CC_ENABLETEMPLATEHANDLE); FREEVDMPTR(pCC16); return(ul); } VOID ThunkCHOOSECOLOR16to32(OUT CHOOSECOLOR *pCC32, IN PCHOOSECOLORDATA16 pCC16) { COLORREF *pCustColors16; DWORD Flags; if(pCC16 && pCC32) { pCC32->lStructSize = sizeof(CHOOSECOLOR); pCC32->hwndOwner = HWND32(pCC16->hwndOwner); // hInstance thunked separately pCC32->rgbResult = DWORD32(pCC16->rgbResult); if(pCC32->lpCustColors) { GETVDMPTR(pCC16->lpCustColors, 16*sizeof(COLORREF), pCustColors16); if(pCustColors16) { RtlCopyMemory(pCC32->lpCustColors, pCustColors16, 16*sizeof(COLORREF)); } FREEVDMPTR(pCustColors16); } // preserve the template flag state while copying flags // 1. save template flag state // note: we never will have a 32-bit CC_ENABLETEMPLATE flag // 2. copy flags from 16-bit struct (add the WOWAPP flag) // 3. turn off all template flags // 4. restore original template flag state Flags = pCC32->Flags & CC_ENABLETEMPLATEHANDLE; pCC32->Flags = DWORD32(pCC16->Flags) | CD_WOWAPP; pCC32->Flags &= ~(CC_ENABLETEMPLATE | CC_ENABLETEMPLATEHANDLE); pCC32->Flags |= Flags; pCC32->lCustData = DWORD32(pCC16->lCustData); if((DWORD32(pCC16->Flags) & CC_ENABLEHOOK) && DWORD32(pCC16->lpfnHook)){ pCC32->lpfnHook = WCD32DialogProc; } // lpTemplateName32 is thunked separately } } VOID ThunkCHOOSECOLOR32to16(OUT PCHOOSECOLORDATA16 pCC16, IN CHOOSECOLOR *pCC32) { COLORREF *pCustColors16; DWORD Flags, Flags32; if(pCC16 && pCC32) { STOREDWORD(pCC16->rgbResult, pCC32->rgbResult); // preserve the template flag state while copying flags // 1. save template flag state // 2. copy flags from 32-bit struct // 3. turn off all template flags and the WOWAPP flag // 4. restore original template flag state Flags = DWORD32(pCC16->Flags) & (CC_ENABLETEMPLATE | CC_ENABLETEMPLATEHANDLE); Flags32 = pCC32->Flags; Flags32 &= ~(CC_ENABLETEMPLATE | CC_ENABLETEMPLATEHANDLE | CD_WOWAPP); Flags32 |= Flags; STOREDWORD(pCC16->Flags, Flags32); GETVDMPTR(pCC16->lpCustColors, 16*sizeof(COLORREF), pCustColors16); if(pCustColors16) { RtlCopyMemory(pCustColors16, pCC32->lpCustColors, 16*sizeof(COLORREF)); FREEVDMPTR(pCustColors16); } } } ULONG FASTCALL WCD32ChooseFont( PVDMFRAME pFrame ) /*++ Routine Description: This routine thunks the 16-bit ChooseFont common dialog to the 32-bit side. Arguments: pFrame - Supplies 16-bit argument frame Return Value: 16-bit BOOLEAN to be returned. --*/ { ULONG ul = GETBOOL16(FALSE); register PCHOOSEFONT16 parg16; VPCHOOSEFONTDATA vpcf; CHOOSEFONT CF32; LOGFONT LogFont32; PCHOOSEFONTDATA16 pCF16; PRES pRes = NULL; COMMDLGTD ThreadData; DWORD dwFlags16; CHAR sStyle[2 * LF_FACESIZE]; BOOL fError = FALSE; GETARGPTR(pFrame, sizeof(CHOOSEFONT16), parg16); vpcf = parg16->lpcf; SETEXTENDEDERROR( 0 ); // invalidate this now FREEVDMPTR( parg16 ); // initialize unique window messages if (msgWOWCHOOSEFONT == 0) { // private WOW<->comdlg32 message for handling WM_CHOOSEFONT_GETLOGFONT if(!(msgWOWCHOOSEFONT = (WORD)RegisterWindowMessage("WOWCHOOSEFONT_GETLOGFONT"))) { SETEXTENDEDERROR( CDERR_REGISTERMSGFAIL ); LOGDEBUG(2,("WCD32ChooseFont:RegisterWindowMessage failed\n")); return(0); } } if (msgWOWLFCHANGE == 0) { // private message for thunking logfont changes if(!(msgWOWLFCHANGE = (WORD)RegisterWindowMessage("WOWLFChange"))) { SETEXTENDEDERROR( CDERR_REGISTERMSGFAIL ); LOGDEBUG(2,("WCD32ChooseFont:RegisterWindowMessage 2 failed\n")); return(0); } } GETVDMPTR(vpcf, sizeof(CHOOSEFONTDATA16), pCF16); WCDDUMPCHOOSEFONTDATA16(pCF16); if(DWORD32(pCF16->lStructSize) != sizeof(CHOOSEFONTDATA16)) { SETEXTENDEDERROR( CDERR_STRUCTSIZE ); FREEVDMPTR(pCF16); return(0); } RtlZeroMemory(&ThreadData, sizeof(COMMDLGTD)); ThreadData.Previous = CURRENTPTD()->CommDlgTd; ThreadData.hdlg = (HWND16)-1; ThreadData.pData32 = &CF32; ThreadData.Flags = WOWCD_ISCHOOSEFONT; if(DWORD32(pCF16->Flags) & CF_ENABLEHOOK) { ThreadData.vpfnHook = DWORD32(pCF16->lpfnHook); if(!ThreadData.vpfnHook) { SETEXTENDEDERROR(CDERR_NOHOOK); FREEVDMPTR(pCF16); return(0); } ThreadData.vpData = vpcf; } else { STOREDWORD(pCF16->lpfnHook, 0); } RtlZeroMemory(&CF32, sizeof(CHOOSEFONT)); CF32.lpLogFont = &LogFont32; CF32.lpszStyle = sStyle; sStyle[0] = '\0'; ThunkCHOOSEFONT16to32(&CF32, pCF16); dwFlags16 = DWORD32(pCF16->Flags); // this call invalidates flat ptrs to 16-bit memory CF32.hInstance = ThunkCDTemplate16to32(WORD32(pCF16->hInstance), 0, DWORD32(pCF16->lpTemplateName), dwFlags16, &(CF32.Flags), CF_ENABLETEMPLATE, CF_ENABLETEMPLATEHANDLE, &pRes, &fError); if(fError) { goto ChooseFontExit; } // invalidate flat ptrs to 16-bit memory FREEVDMPTR(pCF16); WCDDUMPCHOOSEFONTDATA32(&CF32); // Set this just before the calling into comdlg32. This prevents the // synchronization stuff from firing until we actually need it. CURRENTPTD()->CommDlgTd = &ThreadData; // this call invalidates flat ptrs to 16-bit memory ul = GETBOOL16(ChooseFont(&CF32)); CURRENTPTD()->CommDlgTd = ThreadData.Previous; if (ul) { WCDDUMPCHOOSEFONTDATA32(&CF32); GETVDMPTR(vpcf, sizeof(CHOOSEFONT16), pCF16); ThunkCHOOSEFONT32to16(pCF16, &CF32); WCDDUMPCHOOSEFONTDATA16(pCF16); } ChooseFontExit: FreeCDTemplate32(pRes, CF32.hInstance, dwFlags16 & CF_ENABLETEMPLATE, dwFlags16 & CF_ENABLETEMPLATEHANDLE); FREEVDMPTR(pCF16); return(ul); } VOID ThunkCHOOSEFONT16to32(OUT CHOOSEFONT *pCF32, IN PCHOOSEFONTDATA16 pCF16) { LPSTR lpstr; DWORD Flags; if(pCF16 && pCF32) { pCF32->lStructSize = sizeof(CHOOSEFONT); pCF32->hwndOwner = HWND32(pCF16->hwndOwner); if(DWORD32(pCF16->Flags) & CF_PRINTERFONTS) { pCF32->hDC = HDC32(pCF16->hDC); } if(DWORD32(pCF16->lpLogFont) && pCF32->lpLogFont) { GETLOGFONT16(DWORD32(pCF16->lpLogFont), pCF32->lpLogFont); } pCF32->iPointSize = INT32(pCF16->iPointSize); // preserve the template flag state while copying flags // 1. save template flag state // note: we never will have a 32-bit CF_ENABLETEMPLATE flag // 2. copy flags from 16-bit struct (add the WOWAPP flag) // 3. turn off all template flags // 4. restore original template flag state Flags = pCF32->Flags & CF_ENABLETEMPLATEHANDLE; pCF32->Flags = DWORD32(pCF16->Flags) | CD_WOWAPP; pCF32->Flags &= ~(CF_ENABLETEMPLATE | CF_ENABLETEMPLATEHANDLE); pCF32->Flags |= Flags; pCF32->rgbColors = DWORD32(pCF16->rgbColors); pCF32->lCustData = DWORD32(pCF16->lCustData); if((DWORD32(pCF16->Flags) & CF_ENABLEHOOK) && pCF16->lpfnHook) { pCF32->lpfnHook = WCD32DialogProc; } // lpTemplateName32 is thunked separately // hInstance thunked separately // Note: we shouldn't have to free or re-alloc this since they // will only need LF_FACESIZE bytes to handle the string GETPSZPTR(pCF16->lpszStyle, lpstr); if(lpstr && pCF32->lpszStyle) { if(DWORD32(pCF16->Flags) & CF_USESTYLE) { strcpy(pCF32->lpszStyle, lpstr); } FREEPSZPTR(lpstr); } pCF32->nFontType = WORD32(pCF16->nFontType); pCF32->nSizeMin = INT32(pCF16->nSizeMin); pCF32->nSizeMax = INT32(pCF16->nSizeMax); } } VOID ThunkCHOOSEFONT32to16(OUT PCHOOSEFONTDATA16 pCF16, IN CHOOSEFONT *pCF32) { LPSTR lpstr; DWORD Flags, Flags32; if(pCF16 && pCF32) { STOREWORD(pCF16->iPointSize, pCF32->iPointSize); STOREDWORD(pCF16->rgbColors, pCF32->rgbColors); STOREWORD(pCF16->nFontType, pCF32->nFontType); // preserve the template flag state while copying flags // 1. save template flag state // 2. copy flags from 32-bit struct // 3. turn off all template flags and the WOWAPP flag // 4. restore original template flag state Flags = DWORD32(pCF16->Flags) & (CF_ENABLETEMPLATE | CF_ENABLETEMPLATEHANDLE); Flags32 = pCF32->Flags; Flags32 &= ~(CF_ENABLETEMPLATE | CF_ENABLETEMPLATEHANDLE | CD_WOWAPP); Flags32 |= Flags; STOREDWORD(pCF16->Flags, Flags32); if(DWORD32(pCF16->lpLogFont) && pCF32->lpLogFont) { PUTLOGFONT16(DWORD32(pCF16->lpLogFont), sizeof(LOGFONT), pCF32->lpLogFont); } GETPSZPTR(pCF16->lpszStyle, lpstr); if(lpstr && pCF32->lpszStyle) { if(DWORD32(pCF16->Flags) & CF_USESTYLE) { strcpy(lpstr, pCF32->lpszStyle); } FREEPSZPTR(lpstr); } } } ULONG FASTCALL WCD32PrintDlg(IN PVDMFRAME pFrame) /*++ Routine Description: This routine thunks the 16-bit PrintDlg common dialog to the 32-bit side. Arguments: pFrame - Supplies 16-bit argument frame Return Value: 16-bit BOOLEAN to be returned --*/ { ULONG ul = GETBOOL16(FALSE); register PPRINTDLG16 parg16; VPPRINTDLGDATA vppd; PRINTDLG PD32; PPRINTDLGDATA16 pPD16; PRES hSetupRes = NULL; PRES hPrintRes = NULL; COMMDLGTD ThreadData; DWORD dwFlags16; HMEM16 hDM16; HMEM16 hDN16; BOOL fError = FALSE; GETARGPTR(pFrame, sizeof(PRINTDLG16), parg16); vppd = parg16->lppd; // invalidate this now FREEARGPTR(parg16); SETEXTENDEDERROR(0); GETVDMPTR(vppd, sizeof(PRINTDLGDATA16), pPD16); WCDDUMPPRINTDLGDATA16(pPD16); if(DWORD32(pPD16->lStructSize) != sizeof(PRINTDLGDATA16)) { SETEXTENDEDERROR( CDERR_STRUCTSIZE ); FREEVDMPTR(pPD16); return(0); } if(DWORD32(pPD16->Flags) & PD_RETURNDEFAULT) { // spec says these must be NULL if(WORD32(pPD16->hDevMode) || WORD32(pPD16->hDevNames)) { SETEXTENDEDERROR(PDERR_RETDEFFAILURE); FREEVDMPTR(pPD16); return(0); } } RtlZeroMemory((PVOID)&PD32, sizeof(PRINTDLG)); RtlZeroMemory((PVOID)&ThreadData, sizeof(COMMDLGTD)); ThreadData.Previous = CURRENTPTD()->CommDlgTd; ThreadData.hdlg = (HWND16)-1; ThreadData.pData32 = (PVOID)&PD32; ThreadData.Flags = 0; // this flag causes the system to put up the setup dialog rather // than the print dialog if(DWORD32(pPD16->Flags) & PD_PRINTSETUP) { if(DWORD32(pPD16->Flags) & PD_ENABLESETUPHOOK) { ThreadData.vpfnHook = DWORD32(pPD16->lpfnSetupHook); if(!ThreadData.vpfnHook) { SETEXTENDEDERROR(CDERR_NOHOOK); FREEVDMPTR(pPD16); return(0); } ThreadData.vpData = vppd; PD32.lpfnSetupHook = WCD32DialogProc; } } else { if (DWORD32(pPD16->Flags) & PD_ENABLEPRINTHOOK) { ThreadData.vpfnHook = DWORD32(pPD16->lpfnPrintHook); if(!ThreadData.vpfnHook) { SETEXTENDEDERROR(CDERR_NOHOOK); FREEVDMPTR(pPD16); return(0); } ThreadData.vpData = vppd; PD32.lpfnPrintHook = WCD32DialogProc; } if (DWORD32(pPD16->Flags) & PD_ENABLESETUPHOOK) { ThreadData.vpfnSetupHook = DWORD32(pPD16->lpfnSetupHook); if(!ThreadData.vpfnSetupHook) { SETEXTENDEDERROR(CDERR_NOHOOK); FREEVDMPTR(pPD16); return(0); } ThreadData.vpData = vppd; ThreadData.SetupHwnd = (HWND16)1; PD32.lpfnSetupHook = WCD32PrintSetupDialogProc; } } // lock the original 16-bit hDevMode & hDevNames so they won't get thrown // out by our thunking. (we need to restore them to the original handles // if there is an error in PrintDlg() ). hDM16 = WORD32(pPD16->hDevMode); hDN16 = WORD32(pPD16->hDevNames); WOWGlobalLock16(hDM16); WOWGlobalLock16(hDN16); dwFlags16 = DWORD32(pPD16->Flags); // get a new 32-bit devmode struct PD32.hDevMode = ThunkhDevMode16to32(WORD32(pPD16->hDevMode)); // get a new 32-bit devnames struct PD32.hDevNames = ThunkhDevNames16to32(WORD32(pPD16->hDevNames)); ThunkPRINTDLG16to32(&PD32, pPD16); GETVDMPTR(vppd, sizeof(PRINTDLGDATA16), pPD16); // this call invalidates flat ptrs to 16-bit memory PD32.hPrintTemplate = ThunkCDTemplate16to32(WORD32(pPD16->hInstance), MAKELONG(WORD32(pPD16->hPrintTemplate),1), DWORD32(pPD16->lpPrintTemplateName), dwFlags16, &(PD32.Flags), PD_ENABLEPRINTTEMPLATE, PD_ENABLEPRINTTEMPLATEHANDLE, &hPrintRes, &fError); if(fError) { goto PrintDlgError; } // memory may have moved - invalidate flat pointers now FREEVDMPTR(pPD16); GETVDMPTR(vppd, sizeof(PRINTDLGDATA16), pPD16); // this call invalidates flat ptrs to 16-bit memory PD32.hSetupTemplate = ThunkCDTemplate16to32(WORD32(pPD16->hInstance), MAKELONG(WORD32(pPD16->hSetupTemplate),1), DWORD32(pPD16->lpSetupTemplateName), dwFlags16, &(PD32.Flags), PD_ENABLESETUPTEMPLATE, PD_ENABLESETUPTEMPLATEHANDLE, &hSetupRes, &fError); PrintDlgError: if(fError) { WOWGlobalUnlock16(hDM16); WOWGlobalUnlock16(hDN16); goto PrintDlgExit; } // memory may have moved - invalidate flat pointers now FREEVDMPTR(pPD16); WCDDUMPPRINTDLGDATA32(&PD32); // Set this just before the calling into comdlg32. This prevents the // synchronization stuff from firing until we actually need it. CURRENTPTD()->CommDlgTd = &ThreadData; ul = GETBOOL16(PrintDlg(&PD32)); CURRENTPTD()->CommDlgTd = ThreadData.Previous; // blow away our locks so these really can be free'd if needed WOWGlobalUnlock16(hDM16); WOWGlobalUnlock16(hDN16); if(ul) { WCDDUMPPRINTDLGDATA32(&PD32); // this call invalidates flat ptrs to 16-bit mem ThunkPRINTDLG32to16(vppd, &PD32); GETVDMPTR(vppd, sizeof(PRINTDLGDATA16), pPD16); WCDDUMPPRINTDLGDATA16(pPD16); // throw out the old ones if the structs were updated if(WORD32(pPD16->hDevMode) != hDM16) { WOWGlobalFree16(hDM16); } if(WORD32(pPD16->hDevNames) != hDN16) { WOWGlobalFree16(hDN16); } } else { // throw away any new hDevMode's & hDevNames that we might have created // as a result of our thunking & restore the originals GETVDMPTR(vppd, sizeof(PRINTDLGDATA16), pPD16); if(WORD32(pPD16->hDevMode) != hDM16) { WOWGlobalFree16(WORD32(pPD16->hDevMode)); STOREWORD(pPD16->hDevMode, hDM16); } if(WORD32(pPD16->hDevNames) != hDN16) { WOWGlobalFree16(WORD32(pPD16->hDevNames)); STOREWORD(pPD16->hDevNames, hDN16); } } PrintDlgExit: WOWGLOBALFREE(PD32.hDevMode); WOWGLOBALFREE(PD32.hDevNames); if(PD32.hPrintTemplate) { FreeCDTemplate32(hPrintRes, PD32.hPrintTemplate, dwFlags16 & PD_ENABLEPRINTTEMPLATE, dwFlags16 & PD_ENABLEPRINTTEMPLATEHANDLE); } if(PD32.hSetupTemplate) { FreeCDTemplate32(hSetupRes, PD32.hSetupTemplate, dwFlags16 & PD_ENABLESETUPTEMPLATE, dwFlags16 & PD_ENABLESETUPTEMPLATEHANDLE); } FREEVDMPTR(pPD16); return(ul); } #define PD_TEMPLATEMASK32 (PD_ENABLEPRINTTEMPLATE | \ PD_ENABLESETUPTEMPLATE) #define PD_TEMPLATEHANDLEMASK32 (PD_ENABLEPRINTTEMPLATEHANDLE | \ PD_ENABLESETUPTEMPLATEHANDLE) VOID ThunkPRINTDLG16to32(OUT PRINTDLG *pPD32, IN PPRINTDLGDATA16 pPD16) { DWORD Flags; HANDLE h32New; LPVOID lp32New; LPVOID lp32Cur; if(pPD16 && pPD32) { pPD32->lStructSize = sizeof(PRINTDLG); pPD32->hwndOwner = HWND32(pPD16->hwndOwner); // get a new 32-bit devmode thunked from the 16-bit one... if(h32New = ThunkhDevMode16to32(WORD32(pPD16->hDevMode))) { lp32New = GlobalLock(h32New); lp32Cur = GlobalLock(pPD32->hDevMode); // ...and copy it over the current 32-bit devmode struct if(lp32New && lp32Cur) { RtlCopyMemory(lp32Cur, lp32New, ((LPDEVMODE)lp32New)->dmSize); GlobalUnlock(pPD32->hDevMode); GlobalUnlock(h32New); } WOWGLOBALFREE(h32New); } // we assume that the DEVNAMES struct will never change // hDC filled on output only // preserve the template flag state while copying flags // 1. save original template flags // note: we never set the 32-bit PD_ENABLExxxxTEMPLATE flags // 2. copy flags from 16-bit struct (and add WOWAPP flag) // 3. turn off all template flags // 4. restore original template flag state Flags = pPD32->Flags & PD_TEMPLATEHANDLEMASK32; pPD32->Flags = DWORD32(pPD16->Flags) | CD_WOWAPP; pPD32->Flags &= ~(PD_TEMPLATEMASK32 | PD_TEMPLATEHANDLEMASK32); pPD32->Flags |= Flags; pPD32->nFromPage = WORD32(pPD16->nFromPage); pPD32->nToPage = WORD32(pPD16->nToPage); pPD32->nMinPage = WORD32(pPD16->nMinPage); pPD32->nMaxPage = WORD32(pPD16->nMaxPage); pPD32->nCopies = WORD32(pPD16->nCopies); pPD32->lCustData = DWORD32(pPD16->lCustData); // hInstance thunked separately // hPrintTemplate & hSetupTemplate thunked separately } } #define PD_TEMPLATEMASK16 (PD_ENABLEPRINTTEMPLATE | \ PD_ENABLESETUPTEMPLATE | \ PD_ENABLEPRINTTEMPLATEHANDLE | \ PD_ENABLESETUPTEMPLATEHANDLE) VOID ThunkPRINTDLG32to16(IN VPVOID vppd, OUT PRINTDLG *pPD32) { HAND16 hDevMode16; HAND16 hDevNames16; PPRINTDLGDATA16 pPD16; DWORD Flags, Flags16; GETVDMPTR(vppd, sizeof(PRINTDLGDATA16), pPD16); if(pPD16 && pPD32) { if(pPD32->Flags & (PD_RETURNIC | PD_RETURNDC)) { STOREWORD(pPD16->hDC, GETHDC16(pPD32->hDC)); } // thunk 32-bit DEVMODE structure back to 16-bit // hDevXXXX16 take care of RISC alignment problems hDevMode16 = WORD32(pPD16->hDevMode); hDevNames16 = WORD32(pPD16->hDevNames); // this call invalidates flat ptrs to 16-bit mem ThunkhDevMode32to16(&hDevMode16, pPD32->hDevMode); FREEVDMPTR(pPD16); GETVDMPTR(vppd, sizeof(PRINTDLGDATA16), pPD16); // this call invalidates flat ptrs to 16-bit mem ThunkhDevNames32to16(&hDevNames16, pPD32->hDevNames); FREEVDMPTR(pPD16); GETVDMPTR(vppd, sizeof(PRINTDLGDATA16), pPD16); STOREWORD(pPD16->hDevMode, hDevMode16); STOREWORD(pPD16->hDevNames, hDevNames16); // preserve the template flag state while copying flags // 1. save original template flags // 2. copy flags from 32-bit struct // 3. turn off all template flags and WOWAPP flag // 4. restore original template flag state Flags = DWORD32(pPD16->Flags) & PD_TEMPLATEMASK16; Flags16 = pPD32->Flags; Flags16 &= ~(PD_TEMPLATEMASK16 | CD_WOWAPP); Flags16 |= Flags; STOREDWORD(pPD16->Flags, Flags16); STOREWORD(pPD16->nFromPage, GETUINT16(pPD32->nFromPage)); STOREWORD(pPD16->nToPage, GETUINT16(pPD32->nToPage)); STOREWORD(pPD16->nMinPage, GETUINT16(pPD32->nMinPage)); STOREWORD(pPD16->nMaxPage, GETUINT16(pPD32->nMaxPage)); STOREWORD(pPD16->nCopies, GETUINT16(pPD32->nCopies)); FREEVDMPTR(pPD16); } } HGLOBAL ThunkhDevMode16to32(IN HAND16 hDevMode16) { INT nSize; LPDEVMODE lpdm32, pdm32; HGLOBAL hDevMode32 = NULL; VPDEVMODE31 vpDevMode16; if (hDevMode16) { vpDevMode16 = GlobalLock16(hDevMode16, NULL); if(FETCHDWORD(vpDevMode16)) { if(pdm32 = ThunkDevMode16to32(vpDevMode16)) { nSize = FETCHWORD(pdm32->dmSize) + FETCHWORD(pdm32->dmDriverExtra); hDevMode32 = WOWGLOBALALLOC(GMEM_MOVEABLE, nSize); if(lpdm32 = GlobalLock(hDevMode32)) { RtlCopyMemory((PVOID)lpdm32, (PVOID)pdm32, nSize); GlobalUnlock(hDevMode32); } free_w(pdm32); } GlobalUnlock16(hDevMode16); } } return(hDevMode32); } VOID ThunkhDevMode32to16(IN OUT HAND16 *phDevMode16, IN HANDLE hDevMode32) /*++ Routine Description: This routine thunks a 32-bit DevMode structure back into the 16-bit one. It will reallocate the 16-bit global memory block as necessary. WARNING: This may cause 16-bit memory to move, invalidating flat pointers. Arguments: hDevMode - Supplies a handle to a movable global memory object that contains a 32-bit DEVMODE structure phDevMode16 - Supplies a pointer to a 16-bit handle to a movable global memory object that will return the 16-bit DEVMODE structure. If the handle is NULL, the object will be allocated. It may also be reallocated if its current size is not enough. Return Value: None --*/ { UINT CurrentSize; UINT RequiredSize; VPDEVMODE31 vpDevMode16; LPDEVMODE lpDevMode32; if (hDevMode32 == NULL) { *phDevMode16 = (HAND16)NULL; return; } lpDevMode32 = GlobalLock(hDevMode32); if (lpDevMode32==NULL) { *phDevMode16 = (HAND16)NULL; return; } RequiredSize = lpDevMode32->dmSize + lpDevMode32->dmDriverExtra + sizeof(WOWDM31); // see notes in wstruc.c if (*phDevMode16 == (HAND16)NULL) { vpDevMode16 = GlobalAllocLock16(GMEM_MOVEABLE, RequiredSize, phDevMode16); } else { vpDevMode16 = GlobalLock16(*phDevMode16, &CurrentSize); if (CurrentSize < RequiredSize) { GlobalUnlockFree16(vpDevMode16); vpDevMode16 = GlobalAllocLock16(GMEM_MOVEABLE, RequiredSize, phDevMode16); } } if(ThunkDevMode32to16(vpDevMode16, lpDevMode32, RequiredSize)) { GlobalUnlock16(*phDevMode16); } else { *phDevMode16 = (HAND16)NULL; } GlobalUnlock(hDevMode32); } HANDLE ThunkhDevNames16to32(IN HAND16 hDevNames16) { INT nSize; HANDLE hDN32 = NULL; LPDEVNAMES pdn32; PDEVNAMES16 pdn16; if(FETCHDWORD(hDevNames16)) { VPDEVNAMES vpDevNames; vpDevNames = GlobalLock16(hDevNames16, &nSize); if(nSize) { GETVDMPTR(vpDevNames, sizeof(DEVNAMES16), pdn16); if(pdn16) { hDN32 = WOWGLOBALALLOC(GMEM_MOVEABLE, nSize); if(pdn32 = GlobalLock(hDN32)) { RtlCopyMemory((PVOID)pdn32, (PVOID)pdn16, nSize); GlobalUnlock(hDN32); } else { LOGDEBUG(0, ("ThunkhDEVNAMES16to32, 32-bit allocation(s) failed!\n")); } FREEVDMPTR(pdn16); } GlobalUnlock16(hDevNames16); } } return(hDN32); } VOID ThunkhDevNames32to16(IN OUT HAND16 *phDevNames16, IN HANDLE hDevNames) /*++ Routine Description: This routine thunks a 32-bit DevNames structure back into the 16-bit one. It will reallocate the 16-bit global memory block as necessary. WARNING: This may cause 16-bit memory to move, invalidating flat pointers. Arguments: hDevNames - Supplies a handle to a movable global memory object that contains a 32-bit DEVNAMES structure phDevNames16 - Supplies a pointer to a 16-bit handle to a movable global memory object that will return the 16-bit DEVNAMES structure. If the handle is NULL, the object will be allocated. It may also be reallocated if its current size is not enough. Return Value: None --*/ { UINT CurrentSize; UINT RequiredSize; UINT CopySize; UINT MaxOffset; PDEVNAMES16 pdn16; VPDEVNAMES DevNames16; LPDEVNAMES DevNames32; if (hDevNames==NULL) { *phDevNames16=(HAND16)NULL; return; } DevNames32 = GlobalLock(hDevNames); if (DevNames32==NULL) { *phDevNames16=(HAND16)NULL; } MaxOffset = max(max(DevNames32->wDriverOffset,DevNames32->wDeviceOffset), DevNames32->wOutputOffset); // ProComm Plus copies 0x48 constant bytes after Print Setup. CopySize = MaxOffset + strlen((PCHAR)DevNames32+MaxOffset) + 1; RequiredSize = max(CopySize, 0x48); if (*phDevNames16==(HAND16)NULL) { DevNames16 = GlobalAllocLock16(GMEM_MOVEABLE, RequiredSize, phDevNames16); } else { DevNames16 = GlobalLock16(*phDevNames16, &CurrentSize); if (CurrentSize < RequiredSize) { GlobalUnlockFree16(DevNames16); DevNames16 = GlobalAllocLock16(GMEM_MOVEABLE, RequiredSize, phDevNames16); } } GETVDMPTR(DevNames16, RequiredSize, pdn16); if (pdn16==NULL) { *phDevNames16=(HAND16)NULL; GlobalUnlock(hDevNames); return; } RtlCopyMemory(pdn16,DevNames32,CopySize); FREEVDMPTR(pdn16); GlobalUnlock16(*phDevNames16); GlobalUnlock(hDevNames); } ULONG FASTCALL WCD32GetOpenFileName( PVDMFRAME pFrame ) /*++ Routine Description: This routine thunks the 16-bit GetOpenFileName common dialog to the 32-bit side. Arguments: pFrame - Supplies 16-bit argument frame Return Value: 16-bit BOOLEAN to be returned. --*/ { return(WCD32GetFileName(pFrame,GetOpenFileName)); } ULONG FASTCALL WCD32GetSaveFileName( PVDMFRAME pFrame ) /*++ Routine Description: This routine thunks the 16-bit GetOpenFileName common dialog to the 32-bit side. Arguments: pFrame - Supplies 16-bit argument frame Return Value: 16-bit BOOLEAN to be returned. --*/ { return(WCD32GetFileName(pFrame,GetSaveFileName)); } ULONG WCD32GetFileName(IN PVDMFRAME pFrame, IN FILENAMEPROC Function) /*++ Routine Description: This routine is called by WCD32GetOpenFileName and WCD32GetSaveFileName. It does all the real thunking work. Arguments: pFrame - Supplies 16-bit argument frame Function - supplies a pointer to the 32-bit function to call (either GetOpenFileName or GetSaveFileName) Return Value: 16-bit BOOLEAN to be returned. --*/ { ULONG ul = 0; register PGETOPENFILENAME16 parg16; VPOPENFILENAME vpof; OPENFILENAME OFN32; POPENFILENAME16 pOFN16; COMMDLGTD ThreadData; PRES pRes = NULL; DWORD dwFlags16 = 0; USHORT cb; PBYTE lpcb; BOOL fError = FALSE; GETARGPTR(pFrame, sizeof(GETOPENFILENAME16), parg16); vpof = parg16->lpof; SETEXTENDEDERROR(0); // invalidate this now FREEARGPTR(parg16); // initialize unique window messages if (msgFILEOK == 0) { if(!(msgSHAREVIOLATION = (WORD)RegisterWindowMessage(SHAREVISTRING))) { SETEXTENDEDERROR( CDERR_REGISTERMSGFAIL ); LOGDEBUG(2,("WCD32GetFileName:RegisterWindowMessage failed\n")); return(0); } if(!(msgFILEOK = (WORD)RegisterWindowMessage(FILEOKSTRING))) { SETEXTENDEDERROR( CDERR_REGISTERMSGFAIL ); LOGDEBUG(2,("WCD32GetFileName:RegisterWindowMessage 2 failed\n")); return(0); } // initialize private WOW-comdlg32 message msgWOWDIRCHANGE = (WORD)RegisterWindowMessage("WOWDirChange"); } GETVDMPTR(vpof, sizeof(OPENFILENAME16), pOFN16); WCDDUMPOPENFILENAME16(pOFN16); if(DWORD32(pOFN16->lStructSize) != sizeof(OPENFILENAME16)) { SETEXTENDEDERROR( CDERR_STRUCTSIZE ); FREEVDMPTR(pOFN16); return(0); } RtlZeroMemory(&ThreadData, sizeof(COMMDLGTD)); ThreadData.Previous = CURRENTPTD()->CommDlgTd; ThreadData.hdlg = (HWND16)-1; ThreadData.pData32 = (PVOID)&OFN32; ThreadData.Flags = WOWCD_ISOPENFILE; if(DWORD32(pOFN16->Flags) & OFN_ENABLEHOOK) { ThreadData.vpfnHook = DWORD32(pOFN16->lpfnHook); if(!ThreadData.vpfnHook) { SETEXTENDEDERROR(CDERR_NOHOOK); FREEVDMPTR(pOFN16); return(0); } ThreadData.vpData = vpof; } RtlZeroMemory(&OFN32, sizeof(OPENFILENAME)); if(!Alloc_OFN32_strs(&OFN32, pOFN16)) { SETEXTENDEDERROR(CDERR_MEMALLOCFAILURE); goto GetFileNameExit; } // On Win3.1, the system sets these flags in the app's struct under the // shown conditions so we need to update the 16-bit struct too. dwFlags16 = DWORD32(pOFN16->Flags); if(dwFlags16 & OFN_CREATEPROMPT) { dwFlags16 |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST; } else if(dwFlags16 & OFN_FILEMUSTEXIST) { dwFlags16 |= OFN_PATHMUSTEXIST; } // A bug in Serif PagePlus 3.0 sets the high word to 0xFFFF which causes // the new moniker stuff in comdlg32 to break. #148137 - cmjones // VadimB: the mask below causes apps that do want lfn to break, so check // for those apps via the compat flag and let them go unpunished if ((dwFlags16 & OFN_LONGNAMES) && (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_ALLOWLFNDIALOGS)) { dwFlags16 = (dwFlags16 & VALID_OFN16_FLAGS) | OFN_LONGNAMES; } else { dwFlags16 &= VALID_OFN16_FLAGS; } STOREDWORD(pOFN16->Flags, dwFlags16); if(!ThunkOPENFILENAME16to32(&OFN32, pOFN16)) { SETEXTENDEDERROR(CDERR_MEMALLOCFAILURE); goto GetFileNameExit; } dwFlags16 = DWORD32(pOFN16->Flags); // get updated flags // make sure the current directory is up to date UpdateDosCurrentDirectory(DIR_DOS_TO_NT); // this call invalidates flat ptrs to 16-bit memory OFN32.hInstance = ThunkCDTemplate16to32(WORD32(pOFN16->hInstance), 0, DWORD32(pOFN16->lpTemplateName), dwFlags16, &(OFN32.Flags), OFN_ENABLETEMPLATE, OFN_ENABLETEMPLATEHANDLE, &pRes, &fError); if(fError) { goto GetFileNameExit; } // memory may move - free flat pointers now FREEVDMPTR(pOFN16); WCDDUMPOPENFILENAME32(&OFN32); // Set this just before the calling into comdlg32. This prevents the // synchronization stuff from firing until we actually need it. CURRENTPTD()->CommDlgTd = &ThreadData; // this call invalidates flat ptrs to 16-bit memory ul = GETBOOL16((*Function)(&OFN32)); CURRENTPTD()->CommDlgTd = ThreadData.Previous; WCDDUMPOPENFILENAME32(&OFN32); UpdateDosCurrentDirectory(DIR_NT_TO_DOS); GETVDMPTR(vpof, sizeof(OPENFILENAME16), pOFN16); if (ul) { ThunkOPENFILENAME32to16(pOFN16, &OFN32, TRUE); } // else if the buffer is too small, lpstrFile contains the required buffer // size for the specified file else if (CommDlgExtendedError() == FNERR_BUFFERTOOSMALL) { SETEXTENDEDERROR(FNERR_BUFFERTOOSMALL); if(OFN32.lpstrFile && pOFN16->lpstrFile) { cb = *((PUSHORT)(OFN32.lpstrFile)); // is a WORD for comdlg32 too // 3 is the documented minimum size of the lpstrFile buffer GETVDMPTR(pOFN16->lpstrFile, 3, lpcb); // Win3.1 assumes that lpstrFile buffer is at least 3 bytes long // we'll try to be a little smarter than that... if(lpcb && (cb > pOFN16->nMaxFile)) { if(pOFN16->nMaxFile) lpcb[0] = LOBYTE(cb); if(pOFN16->nMaxFile > 1) lpcb[1] = HIBYTE(cb); if(pOFN16->nMaxFile > 2) lpcb[2] = 0; // Win3.1 appends a NULL FREEVDMPTR(lpcb); } } } WCDDUMPOPENFILENAME16(pOFN16); GetFileNameExit: FreeCDTemplate32(pRes, OFN32.hInstance, dwFlags16 & OFN_ENABLETEMPLATE, dwFlags16 & OFN_ENABLETEMPLATEHANDLE); Free_OFN32_strs(&OFN32); FREEVDMPTR(pOFN16); return(ul); } BOOL ThunkOPENFILENAME16to32(OUT OPENFILENAME *pOFN32, IN POPENFILENAME16 pOFN16) /*++ Routine Description: This routine thunks a 16-bit OPENFILENAME structure to the 32-bit OPENFILENAME structure Arguments: pOFN16 - Supplies a flat pointer to the 16-bit OPENFILENAME structure. pOFN32 - Supplies a pointer to the 32-bit OPENFILENAME structure. Return Value: None. --*/ { DWORD Flags; if(pOFN16 && pOFN32) { // Re-thunk all of the strings!!! // Persuasion 3.0 changes the various ptrs to strings depending on which // dialog buttons are pushed so we might have to dynamically re-alloc // some of the 32-bit string buffers. Thunk_OFNstrs16to32(pOFN32, pOFN16); pOFN32->lStructSize = sizeof(OPENFILENAME); pOFN32->hwndOwner = HWND32(pOFN16->hwndOwner); // hInstance thunked separately pOFN32->nMaxCustFilter = DWORD32(pOFN16->nMaxCustFilter); pOFN32->nFilterIndex = DWORD32(pOFN16->nFilterIndex); pOFN32->nMaxFile = DWORD32(pOFN16->nMaxFile); pOFN32->nMaxFileTitle = DWORD32(pOFN16->nMaxFileTitle); // preserve the template flag state while copying flags // 1. save template flag state // note: we never will have a 32-bit OFN_ENABLETEMPLATE flag // we may or may not have a OFN_ENABLETEMPLATEHANDLE flag // 2. copy flags from 16-bit struct // 3. turn off all template flags // 4. restore original template flag state // 5. add the WOWAPP and no-long-names flags Flags = pOFN32->Flags & OFN_ENABLETEMPLATEHANDLE; pOFN32->Flags = DWORD32(pOFN16->Flags); pOFN32->Flags &= ~(OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE); pOFN32->Flags |= Flags; if ((pOFN32->Flags & OFN_LONGNAMES) && (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_ALLOWLFNDIALOGS)) { pOFN32->Flags |= CD_WOWAPP; } else { pOFN32->Flags |= (OFN_NOLONGNAMES | CD_WOWAPP); } pOFN32->nFileOffset = WORD32(pOFN16->nFileOffset); pOFN32->nFileExtension = WORD32(pOFN16->nFileExtension); pOFN32->lCustData = DWORD32(pOFN16->lCustData); if(DWORD32(pOFN16->Flags) & OFN_ENABLEHOOK) { pOFN32->lpfnHook = WCD32DialogProc; } // lpTemplateName32 is thunked separately // This is a hack to fix a bug in Win3.1 commdlg.dll. // Win3.1 doesn't check nMaxFileTitle before copying the FileTitle str. // (see Win3.1 src's \\pucus\win31aro\src\sdk\commdlg\fileopen.c) // TaxCut'95 depends on the title string being returned. if(pOFN32->lpstrFileTitle) { // if nMaxFileTitle > 0, NT will copy lpstrFileTitle if(pOFN32->nMaxFileTitle == 0) { pOFN32->nMaxFileTitle = 13; // 8.3 filename + NULL } } return(TRUE); } return(FALSE); } VOID ThunkOPENFILENAME32to16(OUT POPENFILENAME16 pOFN16, IN OPENFILENAME *pOFN32, IN BOOLEAN bUpperStrings) /*++ Routine Description: This routine thunks a 32-bit OPENFILENAME structure back to a 16-bit OPENFILENAME structure. Arguments: pOFN32 - Supplies a pointer to the 32-bit OPENFILENAME struct. pOFN16 - Supplies a flat pointer to the 16-bit OPENFILENAME struct Return Value: None. --*/ { LPSTR lpstr; DWORD Flags, Flags32; if(pOFN16 && pOFN32) { STOREWORD(pOFN16->nFileOffset, pOFN32->nFileOffset); STOREWORD(pOFN16->nFileExtension, pOFN32->nFileExtension); STOREDWORD(pOFN16->nFilterIndex, pOFN32->nFilterIndex); // preserve the template flag state while copying flags // 1. save template flag state // 2. copy flags from 32-bit struct // 3. turn off all template flags and the WOWAPP flag // 4. restore original template flag state Flags = DWORD32(pOFN16->Flags) & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE); Flags32 = pOFN32->Flags; Flags32 &= ~(OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE | CD_WOWAPP); Flags32 |= Flags; STOREDWORD(pOFN16->Flags, Flags32); if(bUpperStrings && pOFN32->lpstrFile) { // Note we have to upcase the pOFN32 here because some apps // (notably QC/Win) do case-sensitive compares on the extension. // In Win3.1, the upcasing happens as a side-effect of the // OpenFile call. Here we do it explicitly. CharUpperBuff(pOFN32->lpstrFile, strlen(pOFN32->lpstrFile)); } GETPSZPTR(pOFN16->lpstrFile, lpstr); if(lpstr && pOFN32->lpstrFile) { strcpy(lpstr, pOFN32->lpstrFile); FREEPSZPTR(lpstr); } GETPSZPTR(pOFN16->lpstrFilter, lpstr); if(lpstr && pOFN32->lpstrFilter) { Multi_strcpy(lpstr, pOFN32->lpstrFilter); FREEPSZPTR(lpstr); } GETPSZPTR(pOFN16->lpstrCustomFilter, lpstr); if(lpstr && pOFN32->lpstrCustomFilter) { Multi_strcpy(lpstr, pOFN32->lpstrCustomFilter); FREEPSZPTR(lpstr); } if(bUpperStrings && (pOFN32->lpstrFileTitle)) { // Not sure if we really need to upcase this or not, but I figure // somewhere there is an app that depends on this being uppercased // like Win3.1 CharUpperBuff(pOFN32->lpstrFileTitle, strlen(pOFN32->lpstrFileTitle)); } GETPSZPTR(pOFN16->lpstrFileTitle , lpstr); if(lpstr && pOFN32->lpstrFileTitle) { strcpy(lpstr, pOFN32->lpstrFileTitle); FREEPSZPTR(lpstr); } // even though this is doc'd as being filled by the app only, Adobe // distiller depends on it being copied back to the app GETPSZPTR(pOFN16->lpstrInitialDir , lpstr); if(lpstr && pOFN32->lpstrInitialDir) { strcpy(lpstr, pOFN32->lpstrInitialDir); FREEPSZPTR(lpstr); } // who knows who depends on this GETPSZPTR(pOFN16->lpstrTitle, lpstr); if(lpstr && pOFN32->lpstrTitle) { strcpy(lpstr, pOFN32->lpstrTitle); FREEPSZPTR(lpstr); } } } BOOL Alloc_OFN32_strs(IN OPENFILENAME *pOFN32, IN POPENFILENAME16 pOFN16) { if(DWORD32(pOFN16->lpstrFilter)) { if(!(pOFN32->lpstrFilter = malloc_w_strcpy_vp16to32(DWORD32(pOFN16->lpstrFilter), TRUE, 0))) { goto ErrorExit; } } if(DWORD32(pOFN16->lpstrCustomFilter)) { if(!(pOFN32->lpstrCustomFilter = malloc_w_strcpy_vp16to32(DWORD32(pOFN16->lpstrCustomFilter), TRUE, DWORD32(pOFN16->nMaxCustFilter) ))) { goto ErrorExit; } } if(DWORD32(pOFN16->lpstrFile)) { if(!(pOFN32->lpstrFile = malloc_w_strcpy_vp16to32(DWORD32(pOFN16->lpstrFile), FALSE, DWORD32(pOFN16->nMaxFile) ))) { goto ErrorExit; } } if(DWORD32(pOFN16->lpstrFileTitle)) { if(!(pOFN32->lpstrFileTitle = malloc_w_strcpy_vp16to32(DWORD32(pOFN16->lpstrFileTitle), FALSE, DWORD32(pOFN16->nMaxFileTitle) ))) { goto ErrorExit; } } if(DWORD32(pOFN16->lpstrInitialDir)) { if(!(pOFN32->lpstrInitialDir = malloc_w_strcpy_vp16to32(DWORD32(pOFN16->lpstrInitialDir), FALSE, 0))) { goto ErrorExit; } } if(DWORD32(pOFN16->lpstrTitle)) { if(!(pOFN32->lpstrTitle = malloc_w_strcpy_vp16to32(DWORD32(pOFN16->lpstrTitle), FALSE, 0))) { goto ErrorExit; } } if(DWORD32(pOFN16->lpstrDefExt)) { if(!(pOFN32->lpstrDefExt = malloc_w_strcpy_vp16to32(DWORD32(pOFN16->lpstrDefExt), FALSE, 0))) { goto ErrorExit; } } return(TRUE); ErrorExit: LOGDEBUG(0, ("Alloc_OFN32_strs, 32-bit allocation(s) failed!\n")); Free_OFN32_strs(pOFN32); return(FALSE); } VOID Free_OFN32_strs(IN OPENFILENAME *pOFN32) { if(pOFN32->lpstrFilter) { free_w((PVOID)pOFN32->lpstrFilter); pOFN32->lpstrFilter = NULL; } if(pOFN32->lpstrCustomFilter) { free_w((PVOID)pOFN32->lpstrCustomFilter); pOFN32->lpstrCustomFilter = NULL; } if(pOFN32->lpstrFile) { free_w((PVOID)pOFN32->lpstrFile); pOFN32->lpstrFile = NULL; } if(pOFN32->lpstrFileTitle) { free_w((PVOID)pOFN32->lpstrFileTitle); pOFN32->lpstrFileTitle = NULL; } if(pOFN32->lpstrInitialDir) { free_w((PVOID)pOFN32->lpstrInitialDir); pOFN32->lpstrInitialDir = NULL; } if(pOFN32->lpstrTitle) { free_w((PVOID)pOFN32->lpstrTitle); pOFN32->lpstrTitle = NULL; } if(pOFN32->lpstrDefExt) { free_w((PVOID)pOFN32->lpstrDefExt); pOFN32->lpstrDefExt = NULL; } } VOID Thunk_OFNstrs16to32(IN OPENFILENAME *pOFN32, IN POPENFILENAME16 pOFN16) { pOFN32->lpstrFilter = ThunkStr16toStr32((LPSTR)pOFN32->lpstrFilter, DWORD32(pOFN16->lpstrFilter), MAX_PATH, TRUE); pOFN32->lpstrCustomFilter = ThunkStr16toStr32(pOFN32->lpstrCustomFilter, DWORD32(pOFN16->lpstrCustomFilter), DWORD32(pOFN16->nMaxCustFilter), TRUE); pOFN32->lpstrFile = ThunkStr16toStr32(pOFN32->lpstrFile, DWORD32(pOFN16->lpstrFile), DWORD32(pOFN16->nMaxFile), FALSE); pOFN32->lpstrFileTitle = ThunkStr16toStr32(pOFN32->lpstrFileTitle, DWORD32(pOFN16->lpstrFileTitle), DWORD32(pOFN16->nMaxFileTitle), FALSE); pOFN32->lpstrInitialDir = ThunkStr16toStr32((LPSTR)pOFN32->lpstrInitialDir, DWORD32(pOFN16->lpstrInitialDir), MAX_PATH, FALSE); pOFN32->lpstrTitle = ThunkStr16toStr32((LPSTR)pOFN32->lpstrTitle, DWORD32(pOFN16->lpstrTitle), MAX_PATH, FALSE); pOFN32->lpstrDefExt = ThunkStr16toStr32((LPSTR)pOFN32->lpstrDefExt, DWORD32(pOFN16->lpstrDefExt), 10, FALSE); } ULONG FASTCALL WCD32FindText(PVDMFRAME pFrame) /*++ Routine Description: This routine thunks the 16-bit FindText common dialog to the 32-bit side. Arguments: pFrame - Supplies 16-bit argument frame Return Value: 16-bit BOOLEAN to be returned. --*/ { return(WCD32FindReplaceText(pFrame, FindText)); } ULONG FASTCALL WCD32ReplaceText(PVDMFRAME pFrame) /*++ Routine Description: This routine thunks the 16-bit ReplaceText common dialog to the 32-bit side. Arguments: pFrame - Supplies 16-bit argument frame Return Value: 16-bit BOOLEAN to be returned. --*/ { return(WCD32FindReplaceText(pFrame, ReplaceText)); } ULONG WCD32FindReplaceText(IN PVDMFRAME pFrame, IN FINDREPLACEPROC Function) /*++ Routine Description: This routine is called by WCD32FindText and WCD32RepalceText. It copies a 16-bit FINDREPLACE structure to a 32-bit structure. Two per thread data entries are maintained. One is indexed by the owner hwnd, the other is indexed by the dialog hwnd. The dialog is always hooked by WCD32FindReplaceDialogProc, which dispatches to the 16-bit hookproc, and takes care of clean-up on WM_DESTROY, with dialog per thread data providing context. WCD32UpdateFindReplaceTextAndFlags updates the 16-bit FINDREPLACE structure when called by the WOW message dispatching logic upon reciept of a WM_NOTIFYWOW message from COMDLG32. The owner per thread data provides context for this operation. Arguments: pFrame - Supplies 16-bit argument frame Function - supplies a pointer to the 32-bit function to call (either FindText or RepalceText) Return Value: 16-bit BOOLEAN to be returned. --*/ { register PFINDTEXT16 parg16; VPFINDREPLACE vpfr; FINDREPLACE *pFR32; PFINDREPLACE16 pFR16; PCOMMDLGTD pTDDlg; PCOMMDLGTD pTDOwner; HWND hwndDlg = NULL; DWORD dwFlags16 = 0; BOOL fError = FALSE; GETARGPTR(pFrame, sizeof(FINDREPLACE16), parg16); vpfr = parg16->lpfr; SETEXTENDEDERROR(0); // invalidate this now FREEVDMPTR( parg16 ); GETVDMPTR(vpfr, sizeof(FINDREPLACE16), pFR16); WCDDUMPFINDREPLACE16(pFR16); if(DWORD32(pFR16->lStructSize) != sizeof(FINDREPLACE16)) { SETEXTENDEDERROR( CDERR_STRUCTSIZE ); FREEVDMPTR(pFR16); return(0); } if(!DWORD32(pFR16->lpstrFindWhat) || !WORD32(pFR16->wFindWhatLen) || !IsWindow(HWND32(pFR16->hwndOwner))) { SETEXTENDEDERROR(FRERR_BUFFERLENGTHZERO); FREEVDMPTR(pFR16); return(0); } // check the hook proc if(DWORD32(pFR16->Flags) & FR_ENABLEHOOK) { if(!DWORD32(pFR16->lpfnHook)) { SETEXTENDEDERROR(CDERR_NOHOOK); FREEVDMPTR(pFR16); return(0); } } else { STOREDWORD(pFR16->lpfnHook, 0); } // WCD32UpdateFindReplaceTextAndFlags will update the 16-bit FINDREPLACE // struct and help thunk the WM_NOTIFYWOW message to the // "commdlg_FindReplace" registered message. if (msgFINDREPLACE == 0) { if(!(msgFINDREPLACE = (WORD)RegisterWindowMessage(FINDMSGSTRING))) { LOGDEBUG(2,("WCD32FindReplaceText:RegisterWindowMessage failed\n")); SETEXTENDEDERROR( CDERR_REGISTERMSGFAIL ); FREEVDMPTR(pFR16); return(0); } } // Allocate the required memory // Note: these can't be alloc'd off our stack since FindText & ReplaceText // eventually call CreateDialogIndirectParam which returns immediately // after displaying the dialog box. pFR32 = (FINDREPLACE *)malloc_w_zero(sizeof(FINDREPLACE)); if(pFR32) { pFR32->lpstrFindWhat = (LPTSTR)malloc_w(WORD32(pFR16->wFindWhatLen)); pFR32->lpstrReplaceWith = (LPTSTR)malloc_w(WORD32(pFR16->wReplaceWithLen)); pTDDlg = malloc_w_zero(sizeof(COMMDLGTD)); pTDOwner = malloc_w_zero(sizeof(COMMDLGTD)); } if( (pFR32 && pFR32->lpstrFindWhat && pFR32->lpstrReplaceWith && pTDDlg && pTDOwner) == FALSE) { LOGDEBUG(0, ("WCD32FindReplaceText, 32-bit allocation(s) failed!\n")); SETEXTENDEDERROR(CDERR_MEMALLOCFAILURE); goto FindReplaceError; } pTDDlg->pData32 = pTDOwner->pData32 = (PVOID)pFR32; pTDDlg->vpData = pTDOwner->vpData = vpfr; // Set the per thread data indicies pTDDlg->hdlg = (HWND16)-1; pTDOwner->hdlg = GETHWND16(pFR16->hwndOwner); // save the hook proc if any if(DWORD32(pFR16->Flags) & FR_ENABLEHOOK) { pTDDlg->vpfnHook = pTDOwner->vpfnHook = DWORD32(pFR16->lpfnHook); } ThunkFINDREPLACE16to32(pFR32, pFR16); dwFlags16 = DWORD32(pFR16->Flags); // this call invalidates flat ptrs to 16-bit memory pFR32->hInstance = ThunkCDTemplate16to32(WORD32(pFR16->hInstance), 0, DWORD32(pFR16->lpTemplateName), dwFlags16, &(pFR32->Flags), FR_ENABLETEMPLATE, FR_ENABLETEMPLATEHANDLE, &(PRES)(pTDDlg->pRes), &fError); if(fError) { goto FindReplaceError; } // invalidate flat ptrs to 16-bit memory FREEVDMPTR(pFR16); WCDDUMPFINDREPLACE32(pFR32); // Link both per thread data structs into the list // do this just before calling into comdlg32 pTDDlg->Previous = CURRENTPTD()->CommDlgTd; pTDOwner->Previous = pTDDlg; CURRENTPTD()->CommDlgTd = pTDOwner; // this call invalidates flat ptrs to 16-bit memory hwndDlg = (*Function)(pFR32); if (hwndDlg) { pTDDlg->hdlg = (HWND16)hwndDlg; } else { FindReplaceError: LOGDEBUG(0, ("WCD32FindReplaceText, Failed!\n")); if(pTDDlg) { CURRENTPTD()->CommDlgTd = pTDDlg->Previous; FreeCDTemplate32(pTDDlg->pRes, pFR32->hInstance, dwFlags16 & FR_ENABLETEMPLATE, dwFlags16 & FR_ENABLETEMPLATEHANDLE); free_w(pTDDlg); } if(pFR32) { if(pFR32->lpstrFindWhat) free_w(pFR32->lpstrFindWhat); if(pFR32->lpstrReplaceWith) free_w(pFR32->lpstrReplaceWith); free_w(pFR32); } if(pTDOwner) free_w(pTDOwner); } return(GETHWND16(hwndDlg)); } VOID ThunkFINDREPLACE16to32(OUT FINDREPLACE *pFR32, IN PFINDREPLACE16 pFR16) /*++ Routine Description: This routine thunks a 16-bit FINDREPLACE structure to the 32-bit structure Arguments: pFR32 - Supplies a pointer to the 32-bit FINDREPLACE structure. pFR16 - Supplies a pointer to the 16-bit FINDREPLACE structure. Return Value: None. --*/ { LPSTR lpstr; DWORD Flags; if(pFR16 && pFR32) { pFR32->lStructSize = sizeof(FINDREPLACE); pFR32->hwndOwner = HWND32(pFR16->hwndOwner); // hInstance is thunked separately // preserve the template flag state while copying flags // 1. save template flag state // note: we never will have a 32-bit FR_ENABLETEMPLATE flag // 2. copy flags from 16-bit struct (add the WOWAPP flag) // 3. turn off all template flags // 4. restore original template flag state Flags = pFR32->Flags & FR_ENABLETEMPLATEHANDLE; pFR32->Flags = DWORD32(pFR16->Flags) | CD_WOWAPP; pFR32->Flags &= ~(FR_ENABLETEMPLATE | FR_ENABLETEMPLATEHANDLE); pFR32->Flags |= Flags; GETPSZPTR(pFR16->lpstrFindWhat, lpstr); if(lpstr && pFR32->lpstrFindWhat) { WOW32_strncpy(pFR32->lpstrFindWhat, lpstr, WORD32(pFR16->wFindWhatLen)); FREEPSZPTR(lpstr); } GETPSZPTR(pFR16->lpstrReplaceWith, lpstr); if(lpstr && pFR32->lpstrReplaceWith) { WOW32_strncpy(pFR32->lpstrReplaceWith, lpstr, WORD32(pFR16->wReplaceWithLen)); FREEPSZPTR(lpstr); } pFR32->wFindWhatLen = WORD32(pFR16->wFindWhatLen); pFR32->wReplaceWithLen = WORD32(pFR16->wReplaceWithLen); pFR32->lCustData = DWORD32(pFR16->lCustData); // we always put this WOW hook in so we can destroy the modeless dialog. // WCD32FindReplaceDialogPRoc will determine whether to really dispatch // to a 16-bit hookproc or not. pFR16->lpfnHook will be NULL if there // isn't a 16-bit hook proc pFR32->lpfnHook = WCD32FindReplaceDialogProc; pFR32->Flags |= FR_ENABLEHOOK; // lpTemplateName32 is thunked separately } } VOID ThunkFINDREPLACE32to16(OUT PFINDREPLACE16 pFR16, IN FINDREPLACE *pFR32) { LPSTR lpstr; DWORD Flags, Flags32; if(pFR16 && pFR32) { // Update the 16-bit structure. // preserve the template flag state while copying flags // 1. save template flag state // 2. copy flags from 32-bit struct // 3. turn off all template flags and the WOWAPP flag // 4. restore original template flag state Flags = DWORD32(pFR16->Flags) & (FR_ENABLETEMPLATE | FR_ENABLETEMPLATEHANDLE); Flags32 = pFR32->Flags; Flags32 &= ~(FR_ENABLETEMPLATE | FR_ENABLETEMPLATEHANDLE | CD_WOWAPP); Flags32 |= Flags; // we may have to turn off the hookproc flag if we added it in // ThunkFINDREPLACE16to32(). if(!DWORD32(pFR16->lpfnHook)) { Flags32 &= ~FR_ENABLEHOOK; } STOREDWORD(pFR16->Flags, Flags32); GETPSZPTR(pFR16->lpstrFindWhat, lpstr); if(lpstr && pFR32->lpstrFindWhat) { WOW32_strncpy(lpstr, pFR32->lpstrFindWhat, WORD32(pFR16->wFindWhatLen)); FREEPSZPTR(lpstr); } GETPSZPTR(pFR16->lpstrReplaceWith, lpstr); if(lpstr && pFR32->lpstrReplaceWith) { WOW32_strncpy(lpstr, pFR32->lpstrReplaceWith, WORD32(pFR16->wReplaceWithLen)); FREEPSZPTR(lpstr); } } } LONG APIENTRY WCD32UpdateFindReplaceTextAndFlags(HWND hwndOwner, LPARAM lParam) { PCOMMDLGTD ptdOwner; PFINDREPLACE16 pFR16; VPFINDREPLACE vpfr; LPFINDREPLACE pFR32 = (LPFINDREPLACE) lParam; LONG lRet = 0; ptdOwner = GetCommdlgTd(hwndOwner); WOW32ASSERT(ptdOwner); vpfr = ptdOwner->vpData; GETVDMPTR(vpfr, sizeof(FINDREPLACE16), pFR16); ThunkFINDREPLACE32to16(pFR16, pFR32); WCDDUMPFINDREPLACE16(pFR16); FREEVDMPTR(pFR16); return(vpfr); } PCOMMDLGTD GetCommdlgTd(IN HWND Hwnd32) /*++ Routine Description: Searches the thread's chain of commdlg data for the given 32-bit window. If the window is not already in the chain, it is added. Arguments: Hwnd32 - Supplies the 32-bit hwnd that the dialog procedure was called with. Return Value: Pointer to commdlg data. --*/ { PCOMMDLGTD pTD; if ((pTD = CURRENTPTD()->CommDlgTd) == NULL) { return(NULL); } // look for the CommDlgTD struct for this dialog -- usually will be first // unless there are nested dialogs while (pTD->hdlg != GETHWND16(Hwnd32)) { pTD = pTD->Previous; // If Hwnd32 isn't in the list, we're probably getting called back // from user32 via WOWTellWOWThehDlg(). This means that the dialog // window was just created in user32. Note that this can be either a // new dialog or a PrintSetup dialog. if (pTD==NULL) { pTD = CURRENTPTD()->CommDlgTd; while (pTD->hdlg != (HWND16)-1) { // Check to see if this is the first call for a PrintSetupHook. // It will share the same CommDlgTD as the PrintDlgHook. // Note: SetupHwnd will be 1 if this is the 1st time the user // clicks the Setup button in the PrintDlg. Otherwise // it will be the old Hwnd32 from the previous time he // clicked the Setup button from within the same instance // of the PrintDlg. Either way it is non-zero. if(pTD->SetupHwnd) { // if the current CommDlgTD->hdlg is the owner of Hwnd32, // we found the CommDlgTD for the PrintSetup dialog. if(pTD->hdlg == GETHWND16(GetWindow(Hwnd32, GW_OWNER))) { pTD->SetupHwnd = GETHWND16(Hwnd32); return(pTD); } } pTD = pTD->Previous; if(pTD == NULL) { WOW32ASSERT(FALSE); return(NULL); } } // set the hdlg for this CommDlgTD pTD->hdlg = GETHWND16(Hwnd32); return(pTD); } } return(pTD); } // Thunks 16-bit Common dialog templates to 32-bit // Note: this calls back to 16-bit code causing possible 16-bit memory movement // Note: GetTemplate16 call SETEXTENDEDERROR for *most* failures HINSTANCE ThunkCDTemplate16to32(IN HAND16 hInst16, IN DWORD hPT16, // for PrintDlg only IN VPVOID vpTemplateName, IN DWORD dwFlags16, IN OUT DWORD *pFlags, IN DWORD ETFlag, // XX_ENABLETEMPLATE flag IN DWORD ETHFlag, // XX_ENABLETEMPLATEHANDLE flag OUT PPRES pRes, OUT PBOOL fError) { // Note: struct->hInstance == NULL if neither xx_ENABLExxx flag is set HINSTANCE hInst32 = NULL; HAND16 hPrintTemp16 = (HAND16)NULL; SETEXTENDEDERROR( CDERR_NOTEMPLATE ); // most common error ret if(hPT16) { hPrintTemp16 = (HAND16)LOWORD(hPT16); } *pRes = NULL; if(dwFlags16 & ETFlag) { if(!vpTemplateName) { *fError = TRUE; return(NULL); } if(!hInst16) { SETEXTENDEDERROR( CDERR_NOHINSTANCE ); *fError = TRUE; return(NULL); } // Note: calls to GetTemplate16 may cause 16-bit memory to move *pRes = GetTemplate16(hInst16, vpTemplateName, FALSE); if(*pRes == NULL) { *fError = TRUE; return(NULL); } hInst32 = (HINSTANCE)LockResource16(*pRes); if(!hInst32) { *fError = TRUE; SETEXTENDEDERROR( CDERR_LOCKRESFAILURE ); return(NULL); } *pFlags &= ~ETFlag; *pFlags |= ETHFlag; } else if(dwFlags16 & ETHFlag) { // Win'95 does the following if !hInst && ETHFlag. // Note: the return val == FALSE in all cases except the last PD case // CC (0x00040) -> CDERR_NOTEMPLATE // CF (0x00020) -> No error (comdlg32 err = CDERR_LOCKRESFAILURE) // FR (0x02000) -> CDERR_LOCKRESFAILURE // OFN (0x00080) -> CDERR_LOCKRESFAILURE // PD (0x10000) -> CDERR_LOCKRESFAILURE (hInstance) // PD (0x20040) -> CDERR_LOCKRESFAILURE (with PD_PRINTSETUP) // PD (0x20000) -> CDERR_LOCKRESFAILURE // // I think the error value is probably irrelavant since most of these // are pathological cases that only developers would see while building // and debugging their app. In the cases where the Win'95 error code is // CDERR_LOCKRESFAILURE, comdlg32 sets it to CDERR_NOTEMPLATE (as we // now return for WOW) for 32-bit apps // one of the hTemplate's should always be set with the // ENABLETEMPLATEHANDLE flag // if it's a printdlg... if(hPT16) { // ...the hTemplate should be in either hPrintTemplate or // hPrintSetupTemplate if(!hPrintTemp16) { *fError = TRUE; } } // else for non-printdlg's, the hTemplate should be in hInstance else { if(!hInst16) { *fError = TRUE; } } if(*fError) { return(NULL); } // Note: calls to GetTemplate16 may cause 16-bit memory to move if(hPT16) { hInst32 = (HINSTANCE) GetTemplate16(hPrintTemp16,(VPCSTR)NULL,TRUE); } else { hInst32 = (HINSTANCE) GetTemplate16(hInst16, (VPCSTR)NULL, TRUE); } if(!hInst32) { *fError = TRUE; return(NULL); } *pFlags |= ETHFlag; } SETEXTENDEDERROR( 0 ); // reset to no error return(hInst32); } VOID FreeCDTemplate32(IN PRES pRes, IN HINSTANCE hInst, IN BOOL bETFlag, IN BOOL bETHFlag) { if(pRes && bETFlag) { UnlockResource16(pRes); FreeResource16(pRes); } else if(hInst && bETHFlag) { free_w((PVOID)hInst); } } PRES GetTemplate16(IN HAND16 hInstance, IN VPCSTR lpTemplateName, IN BOOLEAN UseHandle) /*++ Routine Description: Finds and loads the specified 16-bit dialog template. WARNING: This may cause memory movement, invalidating flat pointers Arguments: hInstance - Supplies the data block containing the dialog box template TemplateName - Supplies the name of the resource file for the dialog box template. This may be either a null-terminated string or a numbered resource created with the MAKEINTRESOURCE macro. UseHandle - Indicates that hInstance identifies a pre-loaded dialog box template. If this is TRUE, Templatename is ignored. Return Value: success - A pointer to the loaded resource failure - NULL, dwLastError will be set. --*/ { LPSZ TemplateName=NULL; PRES pRes; PBYTE pDlg = NULL; INT cb; INT cb16; if (!UseHandle) { GETPSZIDPTR(lpTemplateName, TemplateName); // Both custom instance handle and the dialog template name are // specified. Locate the 16-bit dialog resource in the specified // instance block and load it. pRes = FindResource16(hInstance, TemplateName, (LPSZ)RT_DIALOG); if (HIWORD(lpTemplateName) != 0) { FREEVDMPTR(TemplateName); } if (!pRes) { SETEXTENDEDERROR( CDERR_FINDRESFAILURE ); return(NULL); } if (!(pRes = LoadResource16(hInstance,pRes))) { SETEXTENDEDERROR( CDERR_LOADRESFAILURE ); return(NULL); } return(pRes); } else { VPVOID pDlg16; if (pDlg16 = RealLockResource16(hInstance, &cb16)) { cb = ConvertDialog16(NULL, pDlg16, 0, cb16); if (cb != 0) { if (pDlg = malloc_w(cb)) { ConvertDialog16(pDlg, pDlg16, cb, cb16); } } GlobalUnlock16(hInstance); } else { SETEXTENDEDERROR( CDERR_LOCKRESFAILURE ); } return((PRES)pDlg); } } // When an app calls a ComDlg API it passes a ptr to the appropriate structure. // On Win3.1 the app & the system share a ptr to the same structure, so when // either updates the struct, the other is aware of the change. On NT we thunk // the 16-bit struct to a 32-bit ANSI struct which is then thunked to a 32-bit // UNICODE struct by the ComDlg32 code. We need a mechanism to put all three // structs in sync. We attempt to do this by calling ThunkCDStruct32to16() // from the WCD32xxxxDialogProc()'s (xxxx = Common OR FindReplace) for // WM_INITDIALOG and WM_COMMAND messages before we callback the 16-bit hook // proc. We call ThunkCDStruct16to32() when we return from the 16-bit hook. VOID ThunkCDStruct16to32(IN HWND hDlg, IN CHOOSECOLOR *p32, IN VPVOID vp) { PCHOOSECOLORDATA16 p16; GETVDMPTR(vp, sizeof(CHOOSECOLORDATA16), p16); if(p16) { switch(p16->lStructSize) { case sizeof(CHOOSECOLORDATA16): ThunkCHOOSECOLOR16to32(p32, p16); Ssync_ANSI_UNICODE_Struct_For_WOW(hDlg, TRUE, WOW_CHOOSECOLOR); break; case sizeof(CHOOSEFONTDATA16): ThunkCHOOSEFONT16to32((CHOOSEFONT *) p32, (PCHOOSEFONTDATA16) p16); Ssync_ANSI_UNICODE_Struct_For_WOW(hDlg, TRUE, WOW_CHOOSEFONT); break; case sizeof(FINDREPLACE16): ThunkFINDREPLACE16to32((FINDREPLACE *) p32, (PFINDREPLACE16) p16); // Find/Replace ANSI-UNICODE sync's are handled by // WCD32UpdateFindReplaceTextAndFlags() mechanism break; case sizeof(OPENFILENAME16): ThunkOPENFILENAME16to32((OPENFILENAME *) p32, (POPENFILENAME16) p16); Ssync_ANSI_UNICODE_Struct_For_WOW(hDlg, TRUE, WOW_OPENFILENAME); break; case sizeof(PRINTDLGDATA16): ThunkPRINTDLG16to32((PRINTDLG *) p32, (PPRINTDLGDATA16) p16); Ssync_ANSI_UNICODE_Struct_For_WOW(hDlg, TRUE, WOW_PRINTDLG); break; } FREEVDMPTR(p16); } } VOID ThunkCDStruct32to16(IN HWND hDlg, IN VPVOID vp, IN CHOOSECOLOR *p32) { PCHOOSECOLORDATA16 p16; GETVDMPTR(vp, sizeof(CHOOSECOLORDATA16), p16); if(p16) { switch(p16->lStructSize) { case sizeof(CHOOSECOLORDATA16): Ssync_ANSI_UNICODE_Struct_For_WOW(hDlg, FALSE, WOW_CHOOSECOLOR); ThunkCHOOSECOLOR32to16(p16, p32); break; case sizeof(CHOOSEFONTDATA16): Ssync_ANSI_UNICODE_Struct_For_WOW(hDlg, FALSE, WOW_CHOOSEFONT); ThunkCHOOSEFONT32to16((PCHOOSEFONTDATA16) p16, (CHOOSEFONT *) p32); break; case sizeof(FINDREPLACE16): // Find/Replace ANSI-UNICODE sync's are handled by // WCD32UpdateFindReplaceTextAndFlags() mechanism ThunkFINDREPLACE32to16((PFINDREPLACE16) p16, (FINDREPLACE *) p32); break; case sizeof(OPENFILENAME16): Ssync_ANSI_UNICODE_Struct_For_WOW(hDlg, FALSE, WOW_OPENFILENAME); ThunkOPENFILENAME32to16((POPENFILENAME16) p16, (OPENFILENAME *) p32, TRUE); break; case sizeof(PRINTDLGDATA16): Ssync_ANSI_UNICODE_Struct_For_WOW(hDlg, FALSE, WOW_PRINTDLG); ThunkPRINTDLG32to16(vp, (PRINTDLG *) p32); break; } FREEVDMPTR(p16); } } VOID Multi_strcpy(LPSTR dst, LPCSTR src) /*++ strcpy for string lists that have several strings that are separated by a null char and is terminated by two NULL chars. --*/ { if(src && dst) { while(*src) { while(*dst++ = *src++) ; } *dst = '\0'; } } INT Multi_strlen(LPCSTR str) /*++ strlen for string lists that have several strings that are separated by a null char and is terminated by two NULL chars. Returns len of str including all NULL *separators* but not the 2nd NULL terminator. ie. cat0dog00 would return len = 8; --*/ { INT i = 0; if(str) { while(*str) { while(*str++) i++; i++; // count the NULL separator } } return(i); } VOID Ssync_WOW_CommDlg_Structs(PCOMMDLGTD pTDIn, BOOL f16to32, DWORD dwThunkCSIP) { HWND hDlg; WORD wCS16; PCOMMDLGTD pTDPrev; PCOMMDLGTD pTD = pTDIn; // we shouldn't sync for calls from krnl386 into wow32 (we found out) // eg. when kernel is handling segment not present faults etc. if(dwThunkCSIP) { wCS16 = HIWORD(dwThunkCSIP); if((wCS16 == gwKrnl386CodeSeg1) || (wCS16 == gwKrnl386CodeSeg2) || (wCS16 == gwKrnl386CodeSeg3)) { return; } } // since we don't have an hwnd to compare with we really don't know which // PCOMMDLGTD is the one we want -- so we have to sync them all. // This is only a problem for nested dialogs which is fairly rare. while(pTD) { // if this hasn't been initialized yet there is nothing to do if(pTD->hdlg == (HWND16)-1) { break; } hDlg = HWND32(pTD->hdlg); WOW32ASSERTMSG(hDlg, ("WOW:Ssync_WOW_CommDlg_Structs: hDlg not found!\n")); //BlockWOWIdle(TRUE); if(f16to32) { ThunkCDStruct16to32(hDlg, (CHOOSECOLOR *)pTD->pData32, pTD->vpData); } else { ThunkCDStruct32to16(hDlg, pTD->vpData, (CHOOSECOLOR *)pTD->pData32); } //BlockWOWIdle(FALSE); pTDPrev = pTD->Previous; // multiple PCOMMDLGTD's in the list means 1 of 2 things: // 1. This is a find/replace text dialog // 2. This is a screwy nested dialog situation if(pTDPrev) { // 1. check for find/replace (it uses two PCOMMDLGTD structs and // shares the same pData32 pointer with both) if(pTDPrev->pData32 == pTD->pData32) { // nothing to do -- they share the same data which was thunked // above so we'll go on to the next PCOMMDLGTD in the list pTD = pTDPrev->Previous; } // 2. there are nested dialogs lurking about & we need to sync // each one! else { pTD = pTDPrev; } } else { break; } } } // There is a special case issue (we found) where certain dialog box // API calls can pass a pszptr that is in a common dialog struct ie: // GetDlgItemText(hDlg, id, OFN16->lpstrFile, size). Our synchronization // mechanism actually trashes OFN16->lpstrFile when we sync 32->16 upon // returning from the API call. To avoid this we will sync 16->32 upon // returning from the API call (if needed as per the conditions below) // before we sync 32->16 thus preserving the string returned in the 16-bit // buffer. The special case API's identified so far are: // GetDlgItemText, GetWindowText(), DlgDirSelectxxxx, and SendDlgItemMessage. VOID Check_ComDlg_pszptr(PCOMMDLGTD ptd, VPVOID vp) { VPVOID vpData; POPENFILENAME16 p16; if(ptd) { vpData = ptd->vpData; if(vpData) { GETVDMPTR(vpData, sizeof(CHOOSECOLORDATA16), p16); if(p16) { switch(p16->lStructSize) { // Only these 2 ComDlg structures have OUTPUT buffers. case sizeof(CHOOSEFONTDATA16): if((VPVOID)((PCHOOSEFONTDATA16)p16)->lpszStyle == vp) { Ssync_WOW_CommDlg_Structs(ptd, w16to32, 0); } break; case sizeof(OPENFILENAME16): if(((VPVOID)p16->lpstrFilter == vp) || ((VPVOID)p16->lpstrCustomFilter == vp) || ((VPVOID)p16->lpstrFile == vp) || ((VPVOID)p16->lpstrFileTitle == vp) || ((VPVOID)p16->lpstrInitialDir == vp) || ((VPVOID)p16->lpstrTitle == vp) || ((VPVOID)p16->lpstrDefExt == vp)) { Ssync_WOW_CommDlg_Structs(ptd, w16to32, 0); } break; } // end switch } } } } VOID FASTCALL WOWTellWOWThehDlg(HWND hDlg) { if(CURRENTPTD()->CommDlgTd) { if(GetCommdlgTd(hDlg) == NULL) { WOW32WARNMSGF(FALSE, ("WOW::WOWTellWOWThehDlg: No unassigned hDlgs\n")); } } } #ifdef DEBUG void WCDDumpCHOOSECOLORData16(PCHOOSECOLORDATA16 p16) { if (fLogFilter & FILTER_COMMDLG) { LOGDEBUG(10, ("CHOOSECOLORDATA16:\n")); LOGDEBUG(10, ("\tlStructSize = %x\n",(p16)->lStructSize)); LOGDEBUG(10, ("\thwndOwner = %lx\n",(p16)->hwndOwner)); LOGDEBUG(10, ("\thInstance = %lx\n",(p16)->hInstance)); LOGDEBUG(10, ("\trgbResult = %lx\n",(p16)->rgbResult)); LOGDEBUG(10, ("\tlpCustColors = %lx\n",(p16)->lpCustColors)); LOGDEBUG(10, ("\tFlags = %lx\n",(p16)->Flags)); LOGDEBUG(10, ("\tlCustData = %lx\n",(p16)->lCustData)); LOGDEBUG(10, ("\tlpfnHook = %lx\n",(p16)->lpfnHook)); LOGDEBUG(10, ("\tlpTemplateName = %lx\n",(p16)->lpTemplateName)); } } void WCDDumpCHOOSECOLORData32(CHOOSECOLOR *p32) { if (fLogFilter & FILTER_COMMDLG) { LOGDEBUG(10, ("CHOOSECOLORDATA32:\n")); LOGDEBUG(10, ("\tlStructSize = %x\n",(p32)->lStructSize)); LOGDEBUG(10, ("\thwndOwner = %lx\n",(p32)->hwndOwner)); LOGDEBUG(10, ("\thInstance = %lx\n",(p32)->hInstance)); LOGDEBUG(10, ("\trgbResult = %lx\n",(p32)->rgbResult)); LOGDEBUG(10, ("\tlpCustColors = %lx\n",(p32)->lpCustColors)); LOGDEBUG(10, ("\tFlags = %lx\n",(p32)->Flags)); LOGDEBUG(10, ("\tlCustData = %lx\n",(p32)->lCustData)); LOGDEBUG(10, ("\tlpfnHook = %lx\n",(p32)->lpfnHook)); LOGDEBUG(10, ("\tlpTemplateName = %lx\n",(p32)->lpTemplateName)); } } void WCDDumpCHOOSEFONTData16(PCHOOSEFONTDATA16 p16) { if (fLogFilter & FILTER_COMMDLG) { LOGDEBUG(10, ("CHOOSEFONT16:\n")); LOGDEBUG(10, ("\tlStructSize = %lx\n",(p16)->lStructSize)); LOGDEBUG(10, ("\thwndOwner = %lx\n",(p16)->hwndOwner)); LOGDEBUG(10, ("\thDC = %lx\n",(p16)->hDC)); LOGDEBUG(10, ("\tlpLogFont = %lx\n",(p16)->lpLogFont)); LOGDEBUG(10, ("\tiPointSize = %x\n",(p16)->iPointSize)); LOGDEBUG(10, ("\tiFlags = %lx\n",(p16)->Flags)); LOGDEBUG(10, ("\trbgColors = %lx\n",(p16)->rgbColors)); LOGDEBUG(10, ("\tlCustData = %lx\n",(p16)->lCustData)); LOGDEBUG(10, ("\tlpfnHook = %lx\n",(p16)->lpfnHook)); LOGDEBUG(10, ("\tlpTemplateName= %lx\n",(p16)->lpTemplateName)); LOGDEBUG(10, ("\thInstance = %lx\n",(p16)->hInstance)); LOGDEBUG(10, ("\tlpszStyle = %lx\n",(p16)->lpszStyle)); LOGDEBUG(10, ("\tnFontType = %x\n",(p16)->nFontType)); LOGDEBUG(10, ("\tnSizeMin = %x\n",(p16)->nSizeMin)); LOGDEBUG(10, ("\tnSizeMax = %x\n",(p16)->nSizeMax)); } } void WCDDumpCHOOSEFONTData32(CHOOSEFONT *p32) { if (fLogFilter & FILTER_COMMDLG) { LOGDEBUG(10, ("CHOOSEFONT32:\n")); LOGDEBUG(10, ("\tlStructSize = %lx\n",(p32)->lStructSize)); LOGDEBUG(10, ("\thwndOwner = %lx\n",(p32)->hwndOwner)); LOGDEBUG(10, ("\thDC = %lx\n",(p32)->hDC)); LOGDEBUG(10, ("\tlpLogFont = %lx\n",(p32)->lpLogFont)); LOGDEBUG(10, ("\tiPointSize = %lx\n",(p32)->iPointSize)); LOGDEBUG(10, ("\tiFlags = %lx\n",(p32)->Flags)); LOGDEBUG(10, ("\trbgColors = %lx\n",(p32)->rgbColors)); LOGDEBUG(10, ("\tlCustData = %lx\n",(p32)->lCustData)); LOGDEBUG(10, ("\tlpfnHook = %lx\n",(p32)->lpfnHook)); LOGDEBUG(10, ("\tlpTemplateName= %lx\n",(p32)->lpTemplateName)); LOGDEBUG(10, ("\thInstance = %lx\n",(p32)->hInstance)); LOGDEBUG(10, ("\tlpszStyle = %lx\n",(p32)->lpszStyle)); LOGDEBUG(10, ("\tnFontType = %x\n",(p32)->nFontType)); LOGDEBUG(10, ("\tnSizeMin = %lx\n",(p32)->nSizeMin)); LOGDEBUG(10, ("\tnSizeMax = %lx\n",(p32)->nSizeMax)); } } void WCDDumpFINDREPLACE16(PFINDREPLACE16 p16) { if (fLogFilter & FILTER_COMMDLG) { LOGDEBUG(10, ("FINDREPLACE16:\n")); LOGDEBUG(10, ("\tlStructSize = %lx\n",(p16)->lStructSize)); LOGDEBUG(10, ("\thwndOwner = %x\n",(p16)->hwndOwner)); LOGDEBUG(10, ("\thInstance = %x\n",(p16)->hInstance)); LOGDEBUG(10, ("\tFlags = %x\n",(p16)->Flags)); LOGDEBUG(10, ("\tlpstrFindWhat = %lx\n",(p16)->lpstrFindWhat)); LOGDEBUG(10, ("\tlpstrReplaceWith = %lx\n",(p16)->lpstrReplaceWith)); LOGDEBUG(10, ("\twFindWhatLen = %x\n",(p16)->wFindWhatLen)); LOGDEBUG(10, ("\twReplaceWithLen = %x\n",(p16)->wReplaceWithLen)); LOGDEBUG(10, ("\tlCustData = %lx\n",(p16)->lCustData)); LOGDEBUG(10, ("\tlpfnHook = %lx\n",(p16)->lpfnHook)); LOGDEBUG(10, ("\tlpTemplateName= %lx\n",(p16)->lpTemplateName)); } } void WCDDumpFINDREPLACE32(FINDREPLACE *p32) { if (fLogFilter & FILTER_COMMDLG) { LOGDEBUG(10, ("FINDREPLACE32:\n")); LOGDEBUG(10, ("\tlStructSize = %lx\n",(p32)->lStructSize)); LOGDEBUG(10, ("\thwndOwner = %x\n",(p32)->hwndOwner)); LOGDEBUG(10, ("\thInstance = %x\n",(p32)->hInstance)); LOGDEBUG(10, ("\tFlags = %x\n",(p32)->Flags)); LOGDEBUG(10, ("\tlpstrFindWhat = %s\n",(p32)->lpstrFindWhat)); LOGDEBUG(10, ("\tlpstrReplaceWith = %s\n",(p32)->lpstrReplaceWith)); LOGDEBUG(10, ("\twFindWhatLen = %x\n",(p32)->wFindWhatLen)); LOGDEBUG(10, ("\twReplaceWithLen = %x\n",(p32)->wReplaceWithLen)); LOGDEBUG(10, ("\tlCustData = %lx\n",(p32)->lCustData)); LOGDEBUG(10, ("\tlpfnHook = %lx\n",(p32)->lpfnHook)); LOGDEBUG(10, ("\tlpTemplateName= %lx\n",(p32)->lpTemplateName)); } } void WCDDumpOPENFILENAME16(POPENFILENAME16 p16) { if (fLogFilter & FILTER_COMMDLG) { LOGDEBUG(10, ("OPENFILENAME16:\n")); LOGDEBUG(10, ("\tlStructSize = %x\n",(p16)->lStructSize)); LOGDEBUG(10, ("\thwndOwner = %lx\n",(p16)->hwndOwner)); LOGDEBUG(10, ("\thInstance = %lx\n",(p16)->hInstance)); LOGDEBUG(10, ("\tlpstrFilter = %lx\n",(p16)->lpstrFilter)); LOGDEBUG(10, ("\tlpstrCustomFilter= %lx\n",(p16)->lpstrCustomFilter)); LOGDEBUG(10, ("\tnMaxCustFilter = %lx\n",(p16)->nMaxCustFilter)); LOGDEBUG(10, ("\tnFilterIndex = %lx\n",(p16)->nFilterIndex)); LOGDEBUG(10, ("\tlpstrFile = %lx\n",(p16)->lpstrFile)); LOGDEBUG(10, ("\tnMaxFile = %lx\n",(p16)->nMaxFile)); LOGDEBUG(10, ("\tlpstrFileTitle = %lx\n",(p16)->lpstrFileTitle)); LOGDEBUG(10, ("\tnMaxFileTitle = %lx\n",(p16)->nMaxFileTitle)); LOGDEBUG(10, ("\tlpstrInitialDir = %lx\n",(p16)->lpstrInitialDir)); LOGDEBUG(10, ("\tlpstrTitle = %lx\n",(p16)->lpstrTitle)); LOGDEBUG(10, ("\tFlags = %lx\n",(p16)->Flags)); LOGDEBUG(10, ("\tnFileOffset = %lx\n",(p16)->nFileOffset)); LOGDEBUG(10, ("\tnFileExtension = %lx\n",(p16)->nFileExtension)); LOGDEBUG(10, ("\tlpstrDefExt = %lx\n",(p16)->lpstrDefExt)); LOGDEBUG(10, ("\tlCustData = %lx\n",(p16)->lCustData)); LOGDEBUG(10, ("\tlpfnHook = %lx\n",(p16)->lpfnHook)); LOGDEBUG(10, ("\tlpTemplateName = %lx\n",(p16)->lpTemplateName)); } } void WCDDumpOPENFILENAME32(OPENFILENAME *p32) { if (fLogFilter & FILTER_COMMDLG) { LOGDEBUG(10, ("OPENFILENAME32:\n")); LOGDEBUG(10, ("\tlStructSize = %x\n",(p32)->lStructSize)); LOGDEBUG(10, ("\thwndOwner = %lx\n",(p32)->hwndOwner)); LOGDEBUG(10, ("\thInstance = %lx\n",(p32)->hInstance)); LOGDEBUG(10, ("\tlpstrFilter = %s\n",(p32)->lpstrFilter)); LOGDEBUG(10, ("\tlpstrCustomFilter= %s\n",(p32)->lpstrCustomFilter)); LOGDEBUG(10, ("\tnMaxCustFilter = %lx\n",(p32)->nMaxCustFilter)); LOGDEBUG(10, ("\tnFilterIndex = %lx\n",(p32)->nFilterIndex)); LOGDEBUG(10, ("\tlpstrFile = %s\n",(p32)->lpstrFile)); LOGDEBUG(10, ("\tnMaxFile = %lx\n",(p32)->nMaxFile)); LOGDEBUG(10, ("\tlpstrFileTitle = %s\n",(p32)->lpstrFileTitle)); LOGDEBUG(10, ("\tnMaxFileTitle = %lx\n",(p32)->nMaxFileTitle)); LOGDEBUG(10, ("\tlpstrInitialDir = %s\n",(p32)->lpstrInitialDir)); LOGDEBUG(10, ("\tlpstrTitle = %s\n",(p32)->lpstrTitle)); LOGDEBUG(10, ("\tFlags = %lx\n",(p32)->Flags)); LOGDEBUG(10, ("\tnFileOffset = %lx\n",(p32)->nFileOffset)); LOGDEBUG(10, ("\tnFileExtension = %lx\n",(p32)->nFileExtension)); LOGDEBUG(10, ("\tlpstrDefExt = %s\n",(p32)->lpstrDefExt)); LOGDEBUG(10, ("\tlCustData = %lx\n",(p32)->lCustData)); LOGDEBUG(10, ("\tlpfnHook = %lx\n",(p32)->lpfnHook)); LOGDEBUG(10, ("\tlpTemplateName = %lx\n",(p32)->lpTemplateName)); } } void WCDDumpPRINTDLGData16(PPRINTDLGDATA16 p16) { if (fLogFilter & FILTER_COMMDLG) { LOGDEBUG(10, ("PRINTDLGData16:\n")); LOGDEBUG(10, ("\tlStructSize = %x\n",(p16)->lStructSize)); LOGDEBUG(10, ("\thwndOwner = %lx\n",(p16)->hwndOwner)); LOGDEBUG(10, ("\thDevMode = %lx\n",(p16)->hDevMode)); LOGDEBUG(10, ("\thDevNames = %lx\n",(p16)->hDevNames)); LOGDEBUG(10, ("\thDC = %lx\n",(p16)->hDC)); LOGDEBUG(10, ("\tFlags = %lx\n",(p16)->Flags)); LOGDEBUG(10, ("\tnFromPage = %d\n",(p16)->nFromPage)); LOGDEBUG(10, ("\tnToPage = %d\n",(p16)->nToPage)); LOGDEBUG(10, ("\tnMinPage = %d\n",(p16)->nMinPage)); LOGDEBUG(10, ("\tnMaxPage = %d\n",(p16)->nMaxPage)); LOGDEBUG(10, ("\tnCopies = %d\n",(p16)->nCopies)); LOGDEBUG(10, ("\thInstance = %lx\n",(p16)->hInstance)); LOGDEBUG(10, ("\tlCustData = %lx\n",(p16)->lCustData)); LOGDEBUG(10, ("\tlpfnPrintHook = %lx\n",(p16)->lpfnPrintHook)); LOGDEBUG(10, ("\tlpfnSetupHook = %lx\n",(p16)->lpfnSetupHook)); LOGDEBUG(10, ("\tlpPrintTemplateName = %lx\n",(p16)->lpPrintTemplateName)); LOGDEBUG(10, ("\tlpSetupTemplateName = %lx\n",(p16)->lpSetupTemplateName)); LOGDEBUG(10, ("\thPrintTemplate = %lx\n",(p16)->hPrintTemplate)); LOGDEBUG(10, ("\thSetupTemplate = %lx\n",(p16)->hSetupTemplate)); } } void WCDDumpPRINTDLGData32(PRINTDLG *p32) { if (fLogFilter & FILTER_COMMDLG) { LOGDEBUG(10, ("PRINTDLGData32:\n")); LOGDEBUG(10, ("\tlStructSize = %x\n",(p32)->lStructSize)); LOGDEBUG(10, ("\thwndOwner = %lx\n",(p32)->hwndOwner)); LOGDEBUG(10, ("\thDevMode = %lx\n",(p32)->hDevMode)); LOGDEBUG(10, ("\thDevNames = %lx\n",(p32)->hDevNames)); LOGDEBUG(10, ("\thDC = %lx\n",(p32)->hDC)); LOGDEBUG(10, ("\tFlags = %lx\n",(p32)->Flags)); LOGDEBUG(10, ("\tnFromPage = %d\n",(p32)->nFromPage)); LOGDEBUG(10, ("\tnToPage = %d\n",(p32)->nToPage)); LOGDEBUG(10, ("\tnMinPage = %d\n",(p32)->nMinPage)); LOGDEBUG(10, ("\tnMaxPage = %d\n",(p32)->nMaxPage)); LOGDEBUG(10, ("\tnCopies = %d\n",(p32)->nCopies)); LOGDEBUG(10, ("\thInstance = %lx\n",(p32)->hInstance)); LOGDEBUG(10, ("\tlCustData = %lx\n",(p32)->lCustData)); LOGDEBUG(10, ("\tlpfnPrintHook = %lx\n",(p32)->lpfnPrintHook)); LOGDEBUG(10, ("\tlpfnSetupHook = %lx\n",(p32)->lpfnSetupHook)); LOGDEBUG(10, ("\tlpPrintTemplateName = %lx\n",(p32)->lpPrintTemplateName)); LOGDEBUG(10, ("\tlpSetupTemplateName = %lx\n",(p32)->lpSetupTemplateName)); LOGDEBUG(10, ("\thPrintTemplate = %lx\n",(p32)->hPrintTemplate)); LOGDEBUG(10, ("\thSetupTemplate = %lx\n",(p32)->hSetupTemplate)); } } #endif // DEBUG