/*++ * * WOW v1.0 * * Copyright (c) 1991, Microsoft Corporation * * WSHELL.C * WOW32 16-bit SHELL API support * * History: * 14-April-1992 Chandan Chauhan (ChandanC) * Created. * --*/ #include "precomp.h" #pragma hdrstop #include #include "wowshlp.h" MODNAME(wshell.c); LONG WOWRegDeleteKey( IN HKEY hKey, IN LPCTSTR lpszSubKey ); #ifndef WIN16_HKEY_CLASSES_ROOT #define WIN16_HKEY_CLASSES_ROOT 1 #endif #ifndef WIN16_ERROR_SUCCESS #define WIN16_ERROR_SUCCESS 0L #define WIN16_ERROR_BADDB 1L #define WIN16_ERROR_BADKEY 2L #define WIN16_ERROR_CANTOPEN 3L #define WIN16_ERROR_CANTREAD 4L #define WIN16_ERROR_CANTWRITE 5L #define WIN16_ERROR_OUTOFMEMORY 6L #define WIN16_ERROR_INVALID_PARAMETER 7L #define WIN16_ERROR_ACCESS_DENIED 8L #endif // // Flags for DROPALIAS's dwFlags member // #define ALLOC_H32 0x0001L #define ALLOC_H16 0x0002L ULONG FASTCALL WS32DoEnvironmentSubst(PVDMFRAME pFrame) { // // This is an undocumented shell.dll API used by ProgMan // and Norton AntiVirus for Windows (part of Norton // Desktop for Windows), probably among others. // Since it's not in the Win32 shellapi.h, we have a // copy of the prototype here, copied from // \nt\private\windows\shell\library\expenv.c. // ULONG ul; register PDOENVIRONMENTSUBST16 parg16; PSZ psz; WORD cch; PSZ pszExpanded; DWORD cchExpanded; GETARGPTR(pFrame, sizeof(DOENVIRONMENTSUBST16), parg16); GETPSZPTR(parg16->vpsz, psz); cch = FETCHWORD(parg16->cch); LOGDEBUG(0,("WS32DoEnvironmentSubst input: '%s'\n", psz)); // // DoEnvironmentSubst makes its substitution in an allocated // buffer of cch characters. If the substution is too long // to fit, the original string is left untouched and the // low word of the return is FALSE, the high word is the // value of cch. If it fits, the string is overlaid and // the low word of the return is TRUE, and the high word // is the length (strlen()-style) of the expanded string. // if (!(pszExpanded = malloc_w(cch * sizeof(*psz)))) { goto Fail; } cchExpanded = ExpandEnvironmentStrings( psz, // source pszExpanded, // dest. cch // dest. size ); if (cchExpanded <= (DWORD)cch) { // // Succeeded, copy expanded string to caller's buffer. // cchExpanded includes null terminator, our return // code doesn't. // RtlCopyMemory(psz, pszExpanded, cchExpanded); LOGDEBUG(0,("WS32DoEnvironmentSubst output: '%s'\n", psz)); WOW32ASSERT((cchExpanded - 1) == strlen(psz)); FLUSHVDMPTR(parg16->vpsz, (USHORT)cchExpanded, psz); ul = MAKELONG((WORD)(cchExpanded - 1), TRUE); } else { Fail: ul = MAKELONG((WORD)cch, FALSE); LOGDEBUG(0,("WS32DoEnvironmentSubst failing!!!\n")); } if (pszExpanded) { free_w(pszExpanded); } FREEPSZPTR(psz); FREEARGPTR(parg16); RETURN(ul); } ULONG FASTCALL WS32RegOpenKey(PVDMFRAME pFrame) { ULONG ul; register PREGOPENKEY16 parg16; HKEY hkResult = 0; HKEY hkey; PSZ psz; PSZ psz1 = NULL; PHKEY lp; GETARGPTR(pFrame, sizeof(REGOPENKEY16), parg16); GETPSZPTR(parg16->f2, psz); GETOPTPTR(parg16->f3, 0, lp); hkey = (HKEY)FETCHDWORD(parg16->f1); if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) { hkey = (HKEY)HKEY_CLASSES_ROOT; } if (!hkey) { if (psz) { psz1 = Remove_Classes (psz); } ul = DPM_RegOpenKey ( HKEY_CLASSES_ROOT, psz1, &hkResult ); if ((psz1) && (psz1 != psz)) { free_w (psz1); } } else { ul = DPM_RegOpenKey ( hkey, psz, &hkResult ); } if(lp) { STOREDWORD(*lp, hkResult); FLUSHVDMPTR(parg16->f3, 4, lp); } ul = ConvertToWin31Error(ul); FREEOPTPTR(lp); FREEPSZPTR(psz); FREEARGPTR(parg16); RETURN(ul); } ULONG FASTCALL WS32RegCreateKey(PVDMFRAME pFrame) { ULONG ul; register PREGCREATEKEY16 parg16; PSZ psz; PSZ psz1 = NULL; HKEY hkResult = 0; HKEY hkey; PHKEY lp; GETARGPTR(pFrame, sizeof(REGCREATEKEY16), parg16); GETPSZPTR(parg16->f2, psz); GETOPTPTR(parg16->f3, 0, lp); hkey = (HKEY)FETCHDWORD(parg16->f1); if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) { hkey = (HKEY)HKEY_CLASSES_ROOT; } if (!hkey) { if (psz) { psz1 = Remove_Classes (psz); } ul = DPM_RegCreateKey ( HKEY_CLASSES_ROOT, psz1, &hkResult ); if ((psz1) && (psz1 != psz)) { free_w (psz1); } } else { ul = DPM_RegCreateKey ( hkey, psz, &hkResult ); } if(lp) { STOREDWORD(*lp, hkResult); FLUSHVDMPTR(parg16->f3, 4, lp); } ul = ConvertToWin31Error(ul); FREEOPTPTR(lp); FREEPSZPTR(psz); FREEARGPTR(parg16); RETURN(ul); } ULONG FASTCALL WS32RegCloseKey(PVDMFRAME pFrame) { ULONG ul; register PREGCLOSEKEY16 parg16; HKEY hkey; GETARGPTR(pFrame, sizeof(REGCLOSEKEY16), parg16); hkey = (HKEY)FETCHDWORD(parg16->f1); if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) { hkey = (HKEY)HKEY_CLASSES_ROOT; } ul = DPM_RegCloseKey ( hkey ); ul = ConvertToWin31Error(ul); FREEARGPTR(parg16); RETURN(ul); } ULONG FASTCALL WS32RegDeleteKey(PVDMFRAME pFrame) { ULONG ul; register PREGDELETEKEY16 parg16; HKEY hkey; PSZ psz; PSZ psz1 = NULL; GETARGPTR(pFrame, sizeof(REGDELETEKEY16), parg16); GETPSZPTR(parg16->f2, psz); hkey = (HKEY)FETCHDWORD(parg16->f1); if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) { hkey = (HKEY)HKEY_CLASSES_ROOT; } // // Fail any attempt to RegDeleteKey(something, NULL), // with ERROR_BADKEY as Win3.1 does. // if ((!psz) || (*psz == '\0')) { ul = ERROR_BADKEY; } else { if (!hkey) { psz1 = Remove_Classes (psz); ul = WOWRegDeleteKey ( HKEY_CLASSES_ROOT, psz1 ); if ((psz1) && (psz1 != psz)) { free_w (psz1); } } else { ul = WOWRegDeleteKey ( hkey, psz ); } } ul = ConvertToWin31Error(ul); FREEPSZPTR(psz); FREEARGPTR(parg16); RETURN(ul); } LONG APIENTRY WOWRegDeleteKey( HKEY hKey, LPCSTR lpszSubKey ) /*++ Routine Description: There is a significant difference between the Win3.1 and Win32 behavior of RegDeleteKey when the key in question has subkeys. The Win32 API does not allow you to delete a key with subkeys, while the Win3.1 API deletes a key and all its subkeys. This routine is a recursive worker that enumerates the subkeys of a given key, applies itself to each one, then deletes itself. It specifically does not attempt to deal rationally with the case where the caller may not have access to some of the subkeys of the key to be deleted. In this case, all the subkeys which the caller can delete will be deleted, but the api will still return ERROR_ACCESS_DENIED. Arguments: hKey - Supplies a handle to an open registry key. lpszSubKey - Supplies the name of a subkey which is to be deleted along with all of its subkeys. Return Value: ERROR_SUCCESS - entire subtree successfully deleted. ERROR_ACCESS_DENIED - given subkey could not be deleted. --*/ { DWORD i; HKEY Key; LONG Status; DWORD ClassLength=0; DWORD SubKeys; DWORD MaxSubKey; DWORD MaxClass; DWORD Values; DWORD MaxValueName; DWORD MaxValueData; DWORD SecurityLength; FILETIME LastWriteTime; LPTSTR NameBuffer; // // First open the given key so we can enumerate its subkeys // Status = DPM_RegOpenKeyEx(hKey, lpszSubKey, 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &Key); if (Status != ERROR_SUCCESS) { // // possibly we have delete access, but not enumerate/query. // So go ahead and try the delete call, but don't worry about // any subkeys. If we have any, the delete will fail anyway. // return(DPM_RegDeleteKey(hKey,lpszSubKey)); } // // Use RegQueryInfoKey to determine how big to allocate the buffer // for the subkey names. // Status = DPM_RegQueryInfoKey(Key, NULL, &ClassLength, 0, &SubKeys, &MaxSubKey, &MaxClass, &Values, &MaxValueName, &MaxValueData, &SecurityLength, &LastWriteTime); if ((Status != ERROR_SUCCESS) && (Status != ERROR_MORE_DATA) && (Status != ERROR_INSUFFICIENT_BUFFER)) { DPM_RegCloseKey(Key); return(Status); } NameBuffer = malloc_w(MaxSubKey + 1); if (NameBuffer == NULL) { DPM_RegCloseKey(Key); return(ERROR_NOT_ENOUGH_MEMORY); } // // Enumerate subkeys and apply ourselves to each one. // i=0; do { Status = DPM_RegEnumKey(Key, i, NameBuffer, MaxSubKey+1); if (Status == ERROR_SUCCESS) { Status = WOWRegDeleteKey(Key,NameBuffer); } if (Status != ERROR_SUCCESS) { // // Failed to delete the key at the specified index. Increment // the index and keep going. We could probably bail out here, // since the api is going to fail, but we might as well keep // going and delete everything we can. // ++i; } } while ( (Status != ERROR_NO_MORE_ITEMS) && (i < SubKeys) ); free_w(NameBuffer); DPM_RegCloseKey(Key); return(DPM_RegDeleteKey(hKey,lpszSubKey)); } // This is a Win 9x API. It doesn't need some of the thunking required by // the Win 3.1 Regxxx() API's. ie. WIN16_HKEY_CLASSES_ROOT conversion & // ConvertToWin31Error(). // Since this was brought over from the interpreted thunk code, it doesn't // require any special thunking for any of the parameters until an issue is // identified -- at which time this comment should be removed. ULONG FASTCALL WS32RegDeleteValue(PVDMFRAME pFrame) { ULONG ul; register PREGDELETEVALUE3216 parg16; HKEY hkey; PSZ lpszValueName; GETARGPTR(pFrame, sizeof(REGDELETEVALUE3216), parg16); hkey = (HKEY)FETCHDWORD(parg16->hKey); GETPSZPTR(parg16->lpszValue, lpszValueName); ul = DPM_RegDeleteValue (hkey, lpszValueName); FREEPSZPTR(lpszValueName); FREEARGPTR(parg16); RETURN(ul); } // This is a Win 9x API. It doesn't need some of the thunking required by // the Win 3.1 Regxxx() API's. ie. WIN16_HKEY_CLASSES_ROOT conversion & // ConvertToWin31Error(). // Since this was brought over from the interpreted thunk code, it doesn't // require any special thunking for any of the parameters until an issue is // identified -- at which time this comment should be removed. ULONG FASTCALL WS32RegFlushKey(PVDMFRAME pFrame) { ULONG ul; register PREGFLUSHKEY3216 parg16; HKEY hkey; GETARGPTR(pFrame, sizeof(REGFLUSHKEY3216), parg16); hkey = (HKEY)FETCHDWORD(parg16->hKey); ul = DPM_RegFlushKey (hkey); FREEARGPTR(parg16); RETURN(ul); } // This is a Win 9x API. It doesn't need some of the thunking required by // the Win 3.1 Regxxx() API's. ie. WIN16_HKEY_CLASSES_ROOT conversion & // ConvertToWin31Error(). // Since this was brought over from the interpreted thunk code, it doesn't // require any special thunking for any of the parameters until an issue is // identified -- at which time this comment should be removed. ULONG FASTCALL WS32RegLoadKey(PVDMFRAME pFrame) { ULONG ul; register PREGLOADKEY3216 parg16; HKEY hkey; PSZ lpszSubKey, lpszFile; GETARGPTR(pFrame, sizeof(REGLOADKEY3216), parg16); hkey = (HKEY)FETCHDWORD(parg16->hKey); GETPSZPTR(parg16->lpszSubkey, lpszSubKey); GETPSZPTR(parg16->lpszFileName, lpszFile); ul = DPM_RegLoadKey (hkey, lpszSubKey, lpszFile); FREEPSZPTR(lpszSubKey); FREEPSZPTR(lpszFile); FREEARGPTR(parg16); RETURN(ul); } // This is a Win 9x API. It doesn't need some of the thunking required by // the Win 3.1 Regxxx() API's. ie. WIN16_HKEY_CLASSES_ROOT conversion & // ConvertToWin31Error(). // Since this was brought over from the interpreted thunk code, it doesn't // require any special thunking for any of the parameters until an issue is // identified -- at which time this comment should be removed. ULONG FASTCALL WS32RegUnLoadKey(PVDMFRAME pFrame) { ULONG ul; register PREGUNLOADKEY3216 parg16; HKEY hkey; PSZ lpszSubKey; GETARGPTR(pFrame, sizeof(REGUNLOADKEY3216), parg16); hkey = (HKEY)FETCHDWORD(parg16->hKey); GETPSZPTR(parg16->lpszSubkey, lpszSubKey); ul = DPM_RegUnLoadKey (hkey, lpszSubKey); FREEPSZPTR(lpszSubKey); FREEARGPTR(parg16); RETURN(ul); } // This is a Win 9x API. It doesn't need some of the thunking required by // the Win 3.1 Regxxx() API's. ie. WIN16_HKEY_CLASSES_ROOT conversion & // ConvertToWin31Error(). // Since this was brought over from the interpreted thunk code, it doesn't // require any special thunking for any of the parameters until an issue is // identified -- at which time this comment should be removed. ULONG FASTCALL WS32RegSaveKey(PVDMFRAME pFrame) { ULONG ul; register PREGSAVEKEY3216 parg16; HKEY hkey; PSZ lpszFile; LPSECURITY_ATTRIBUTES lpSecurityAttributes; GETARGPTR(pFrame, sizeof(REGSAVEKEY3216), parg16); hkey = (HKEY)FETCHDWORD(parg16->hKey); GETPSZPTR(parg16->lpszFile, lpszFile); GETOPTPTR(parg16->lpSA, sizeof(SECURITY_ATTRIBUTES), lpSecurityAttributes); ul = DPM_RegSaveKey (hkey, lpszFile, lpSecurityAttributes); FREEPSZPTR(lpszFile); FREEOPTPTR(lpSecurityAttributes); FREEARGPTR(parg16); RETURN(ul); } ULONG FASTCALL WS32RegSetValue(PVDMFRAME pFrame) { register PREGSETVALUE16 parg16; ULONG ul; CHAR szZero[] = { '0', '\0' }; HKEY hkey; PSZ psz2; PSZ psz1 = NULL; LPBYTE lpszData = NULL; GETARGPTR(pFrame, sizeof(REGSETVALUE16), parg16); // Do what Win 3.1 does if(parg16->f3 != REG_SZ) { FREEARGPTR(parg16); return(WIN16_ERROR_INVALID_PARAMETER); } GETOPTPTR(parg16->f2, 0, psz2); // Windows 3.1 API reference says that cb (f5) is ignored. // Ergo, remove it from this call and use 1 in its place // (1 being the smallest size of a sz string) if(parg16->f4) { GETOPTPTR(parg16->f4, 1, lpszData); } // Quattro Pro 6.0 Install passes lpszData == NULL // In Win3.1, if(!lpszData || *lpszData == '\0') the value is set to 0 if(!lpszData) { lpszData = szZero; } hkey = (HKEY)FETCHDWORD(parg16->f1); if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) { hkey = (HKEY)HKEY_CLASSES_ROOT; } if (!hkey) { if (psz2) { psz1 = Remove_Classes (psz2); } ul = DPM_RegSetValue (HKEY_CLASSES_ROOT, psz1, REG_SZ, lpszData, lstrlen(lpszData)); if ((psz1) && (psz1 != psz2)) { free_w (psz1); } } else { ul = DPM_RegSetValue (hkey, psz2, REG_SZ, lpszData, lstrlen(lpszData)); } ul = ConvertToWin31Error(ul); FREEOPTPTR(psz2); FREEOPTPTR(lpszData); FREEARGPTR(parg16); RETURN(ul); } // This is a Win 9x API. It doesn't need some of the thunking required by // the Win 3.1 Regxxx() API's. ie. WIN16_HKEY_CLASSES_ROOT conversion & // ConvertToWin31Error(). // Since this was brought over from the interpreted thunk code, it doesn't // require any special thunking for any of the parameters until an issue is // identified -- at which time this comment should be removed. ULONG FASTCALL WS32RegSetValueEx(PVDMFRAME pFrame) { register PREGSETVALUEEX3216 parg16; ULONG ul; HKEY hkey; PSZ lpszValueName; LPBYTE lpData; GETARGPTR(pFrame, sizeof(REGSETVALUE3216), parg16); hkey = (HKEY)FETCHDWORD(parg16->hKey); GETOPTPTR(parg16->lpszValue, 0, lpszValueName); GETOPTPTR(parg16->lpBuffer, parg16->cbBuffer, lpData); ul = DPM_RegSetValueEx(hkey, lpszValueName, parg16->dwReserved, parg16->dwType, lpData, parg16->cbBuffer); FREEOPTPTR(lpszValueName); FREEOPTPTR(lpData); FREEARGPTR(parg16); RETURN(ul); } ULONG FASTCALL WS32RegQueryValue(PVDMFRAME pFrame) { ULONG ul; register PREGQUERYVALUE16 parg16; HKEY hkey; PSZ psz1 = NULL; PSZ psz2; LPBYTE lpszData; LPDWORD lpcbValue; DWORD cbValue; #define QUERYBUFFERSIZE 128 DWORD cbOriginalValue; BYTE cbBuffer[QUERYBUFFERSIZE]; LPBYTE lpByte = NULL; BOOL fAllocated = FALSE; GETARGPTR(pFrame, sizeof(REGQUERYVALUE16), parg16); GETOPTPTR(parg16->f2, 0, psz2); GETOPTPTR(parg16->f3, 0, lpszData); GETOPTPTR(parg16->f4, 0, lpcbValue); if ( lpcbValue == NULL ) { // Prevent us from dying just in case! FREEOPTPTR(psz2); FREEOPTPTR(lpszData); FREEOPTPTR(lpcbValue); FREEARGPTR(parg16); return( WIN16_ERROR_INVALID_PARAMETER ); } cbOriginalValue = cbValue = FETCHDWORD(*lpcbValue); #ifdef FE_SB // for Lotus 123 by v-kenich 94.Aug.27 // Lotus doesn't set value to *lpcb in one case // in other case set 80 // so when not set, assume 80 and set 80 in this field if (CURRENTPTD()->dwWOWCompatFlagsFE & WOWCF_FE_FORCEREGQRYLEN) { if (cbValue > 80) { cbOriginalValue = cbValue = 80; } } #endif // FE_SB // Fix MSTOOLBR.DLL unintialized cbValue by forcing it to be less than 64K // Win 3.1 Registry values are always less than 64K. cbOriginalValue &= 0x0000FFFF; if ( lpszData == NULL ) { lpByte = NULL; } else { lpByte = cbBuffer; if ( cbOriginalValue > QUERYBUFFERSIZE ) { lpByte = malloc_w(cbOriginalValue); if ( lpByte == NULL ) { FREEOPTPTR(psz2); FREEOPTPTR(lpszData); FREEOPTPTR(lpcbValue); FREEARGPTR(parg16); RETURN( WIN16_ERROR_OUTOFMEMORY ); } fAllocated = TRUE; } } hkey = (HKEY)FETCHDWORD(parg16->f1); if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) { hkey = (HKEY)HKEY_CLASSES_ROOT; } if (!hkey) { if (psz2) { psz1 = Remove_Classes (psz2); } hkey = HKEY_CLASSES_ROOT; } else { psz1 = psz2; } ul = DPM_RegQueryValue ( hkey, psz1, lpByte, &cbValue ); if (ul == ERROR_SUCCESS) { if ( lpszData ) { memcpy( lpszData, lpByte, cbValue ); } } else { if ( ul == ERROR_MORE_DATA ) { // // We need to allocate more // if ( fAllocated ) { free_w( lpByte ); } lpByte = malloc_w( cbValue ); if ( lpByte == NULL ) { if ((psz1) && (psz1 != psz2)) { // If we did some key name copying, then free that buffer free_w (psz1); } FREEOPTPTR(psz2); FREEOPTPTR(lpszData); FREEOPTPTR(lpcbValue); FREEARGPTR(parg16); RETURN(WIN16_ERROR_OUTOFMEMORY); } fAllocated = TRUE; ul = DPM_RegQueryValue( hkey, psz1, lpByte, &cbValue ); cbValue = cbOriginalValue; if ( lpszData ) { memcpy( lpszData, lpByte, cbValue ); } } } if ((psz1) && (psz1 != psz2)) { // If we did some key name copying, then free that buffer free_w (psz1); } if ( fAllocated ) { // If we've allocated memory for the output buffer, then free it free_w (lpByte); } STOREDWORD(*lpcbValue, cbValue); FLUSHVDMPTR(parg16->f4, 4, lpcbValue); if ( lpszData != NULL ) { FLUSHVDMPTR(parg16->f3, (USHORT)cbValue, lpszData); } ul = ConvertToWin31Error(ul); FREEOPTPTR(psz2); FREEOPTPTR(lpszData); FREEOPTPTR(lpcbValue); FREEARGPTR(parg16); RETURN(ul); } // This is a Win 9x API. It doesn't need some of the thunking required by // the Win 3.1 Regxxx() API's. ie. WIN16_HKEY_CLASSES_ROOT conversion & // ConvertToWin31Error(). // Since this was brought over from the interpreted thunk code, it doesn't // require any special thunking for any of the parameters until an issue is // identified -- at which time this comment should be removed. ULONG FASTCALL WS32RegQueryValueEx(PVDMFRAME pFrame) { ULONG ul; register PREGQUERYVALUEEX3216 parg16; HKEY hkey; PSZ lpszValueName; LPBYTE lpData; LPDWORD lpReserved, lpType, lpcbData; GETARGPTR(pFrame, sizeof(REGQUERYVALUE3216), parg16); hkey = (HKEY)FETCHDWORD(parg16->hKey); GETOPTPTR(parg16->lpszValue, 0, lpszValueName); GETOPTPTR(parg16->vpdwReserved, sizeof(DWORD), lpReserved); GETOPTPTR(parg16->vpdwType, sizeof(DWORD), lpType); GETOPTPTR(parg16->cbBuffer, sizeof(DWORD), lpcbData); GETOPTPTR(parg16->lpBuffer, *lpcbData, lpData); ul = DPM_RegQueryValueEx (hkey, lpszValueName, lpReserved, lpType, lpData, lpcbData); FREEOPTPTR(lpszValueName); FREEOPTPTR(lpReserved); FREEOPTPTR(lpType); FREEOPTPTR(lpData); FREEOPTPTR(lpcbData); FREEARGPTR(parg16); RETURN(ul); } ULONG FASTCALL WS32RegEnumKey(PVDMFRAME pFrame) { ULONG ul; register PREGENUMKEY16 parg16; HKEY hkey; LPBYTE lpszName; GETARGPTR(pFrame, sizeof(REGENUMKEY16), parg16); GETOPTPTR(parg16->f3, parg16->f4, lpszName); hkey = (HKEY)FETCHDWORD(parg16->f1); if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) { hkey = (HKEY)HKEY_CLASSES_ROOT; } ul = DPM_RegEnumKey ( hkey, parg16->f2, lpszName, parg16->f4 ); FLUSHVDMPTR(parg16->f3, (USHORT)parg16->f4, lpszName); ul = ConvertToWin31Error(ul); FREEOPTPTR(lpszName); FREEARGPTR(parg16); RETURN(ul); } // This is a Win 9x API. It doesn't need some of the thunking required by // the Win 3.1 Regxxx() API's. ie. WIN16_HKEY_CLASSES_ROOT conversion & // ConvertToWin31Error(). // Since this was brought over from the interpreted thunk code, it doesn't // require any special thunking for any of the parameters until an issue is // identified -- at which time this comment should be removed. ULONG FASTCALL WS32RegEnumValue(PVDMFRAME pFrame) { ULONG ul; register PREGENUMVALUE3216 parg16; HKEY hkey; PSZ lpszValueName; LPBYTE lpData; LPDWORD lpcbValueName, lpReserved, lpType, lpcbData; GETARGPTR(pFrame, sizeof(REGENUMVALUE3216), parg16); hkey = (HKEY)FETCHDWORD(parg16->hKey); GETOPTPTR(parg16->lpcchValue, sizeof(DWORD), lpcbValueName); GETOPTPTR(parg16->lpszValue, *lpcbValueName, lpszValueName); GETOPTPTR(parg16->lpdwReserved, sizeof(DWORD), lpReserved); GETOPTPTR(parg16->lpdwType, sizeof(DWORD), lpType); GETOPTPTR(parg16->lpcbData, sizeof(DWORD), lpcbData); GETOPTPTR(parg16->lpbData, *lpcbData, lpData); ul = DPM_RegEnumValue (hkey, parg16->iValue, lpszValueName, lpcbValueName, lpReserved, lpType, lpData, lpcbData); FREEOPTPTR(lpszValueName); FREEOPTPTR(lpcbValueName); FREEOPTPTR(lpReserved); FREEOPTPTR(lpType); FREEOPTPTR(lpData); FREEOPTPTR(lpcbData); FREEARGPTR(parg16); RETURN(ul); } ULONG FASTCALL WS32DragAcceptFiles(PVDMFRAME pFrame) { ULONG ul=0; register PDRAGACCEPTFILES16 parg16; GETARGPTR(pFrame, sizeof(DRAGACCEPTFILES16), parg16); DragAcceptFiles(HWND32(parg16->f1),(BOOL)parg16->f2); FREEARGPTR(parg16); RETURN(ul); } ULONG FASTCALL WS32DragQueryFile(PVDMFRAME pFrame) { ULONG ul = 0l; register PDRAGQUERYFILE16 parg16; LPSTR lpFile; HANDLE hdfs32; GETARGPTR(pFrame, sizeof(DRAGQUERYFILE16), parg16); if (hdfs32 = HDROP32(parg16->f1)) { GETOPTPTR(parg16->f3, parg16->f4, lpFile); ul = DragQueryFileAorW (hdfs32, INT32(parg16->f2), lpFile, parg16->f4, TRUE,TRUE); if ((lpFile != NULL) && (parg16->f2 != -1)) { FLUSHVDMPTR(parg16->f3, parg16->f4, lpFile); } FREEOPTPTR(lpFile); } FREEARGPTR(parg16); RETURN(ul); } ULONG FASTCALL WS32DragFinish(PVDMFRAME pFrame) { register PDRAGFINISH16 parg16; HDROP h32; GETARGPTR(pFrame, sizeof(PDRAGFINISH16), parg16); // // freehdrop16, frees the alias and returns the corresponding h32 // if (h32 = FREEHDROP16(parg16->f1)) { DragFinish(h32); } FREEARGPTR(parg16); return 0; } ULONG FASTCALL WS32ShellAbout (PVDMFRAME pFrame) { ULONG ul; register PSHELLABOUT16 parg16; PSZ psz2; PSZ psz3; GETARGPTR(pFrame, sizeof(SHELLABOUT16), parg16); GETPSZPTR(parg16->f2, psz2); GETPSZPTR(parg16->f3, psz3); ul = GETINT16(ShellAbout ( HWND32(parg16->f1), psz2, psz3, HICON32(parg16->f4) )); FREEPSZPTR(psz2); FREEPSZPTR(psz3); FREEARGPTR(parg16); RETURN(ul); } // NOTE : The return value can be instance handle or the handle of a // DDE server. So, take this information into account while debugging // the effect of the return value from this API. ChandanC 4/24/92. // You would notice that I am treating the return value as HINSTANCE. // ULONG FASTCALL WS32ShellExecute (PVDMFRAME pFrame) { ULONG ul; register PSHELLEXECUTE16 parg16; PSZ psz2; PSZ psz3; PSZ psz4; PSZ psz5; GETARGPTR(pFrame, sizeof(SHELLEXECUTE16), parg16); GETPSZPTR(parg16->f2, psz2); GETPSZPTR(parg16->f3, psz3); GETPSZPTR(parg16->f4, psz4); GETPSZPTR(parg16->f5, psz5); UpdateDosCurrentDirectory( DIR_DOS_TO_NT); ul = GETHINST16(WOWShellExecute ( HWND32(parg16->f1), psz2, psz3, psz4, psz5, parg16->f6, (LPVOID) W32ShellExecuteCallBack )); FREEPSZPTR(psz2); FREEPSZPTR(psz3); FREEPSZPTR(psz4); FREEPSZPTR(psz5); FREEARGPTR(parg16); RETURN(ul); } /* * This is an equivalent of a nasty win'95 style hack that prevents us from * launching things from winexec that are lfn-based * Unfortunate as it is -- this alone can't save us in all the cases -- it * just allows for a fix to ole-based method (another method should be * employed to fix winexec) * * The code was stolen from base/client/process.c * with win95's method being to try CreateProcess instead of SearchPath within * the inner loop. * * Parameters: * lpstrParsed -- destination string which upon successful return will contain * 1. Short path for an exe file * 2. The rest of the cmdline in an appropriate order * lpszCmdLine -- command line for an app with parameters * cchParsed -- character count for the lpstrParsed string * * fConvert -- if TRUE, path is going to be converted to its short * form, if FALSE -- it is going to be quoted for winexec * not to stumble upon it. * */ ULONG WS32ParseCmdLine( PBYTE lpstrParsed, LPSZ lpszCmdLine, ULONG cchstrParsed, BOOL fConvert) { int cb = 0; BOOL fQuote = FALSE; // was there a quote ? PCHAR psz = lpszCmdLine; // original ptr to the command line CHAR szFileName[MAX_PATH];// exe filename in its final form (from szCmd) CHAR szCmd[MAX_PATH]; // command that is being built from lpszCmdLine PCHAR pszCmd = szCmd; CHAR c; DWORD dwLength, dwLengthFileName, dwLengthCmdTail; DWORD dwError = ERROR_SUCCESS; WOW32ASSERTMSGF(lstrlen(lpszCmdLine) < sizeof(szCmd)/sizeof(szCmd[0]), ("WOW::WS32ParseCmdLine -- cmd line too long\n")); c = *psz; while(TRUE) { if ('\"' == c) { fQuote = !fQuote; // state variable -- flip quoting } else { // now check for space chars // the condition here is: if it is outside of a quote -- then // space is a delimiter. Another condition is an end of a string if (((' ' == c || '\t' == c) && !fQuote) || ('\0' == c)) { // delimiter -- now try for a file search *pszCmd = '\0'; dwLengthFileName = DPM_SearchPath(NULL, szCmd, ".exe", sizeof(szFileName)/sizeof(szFileName[0]), szFileName, NULL); // return value is length in chars if (!dwLengthFileName || dwLengthFileName > sizeof(szFileName)/sizeof(szFileName[0])) { // oops -- we have found none // so remember the error dwError = ERROR_FILE_NOT_FOUND; if ('\0' == c) { break; // end of the string } } else { // szFileName is what we need dwError = ERROR_SUCCESS; break; } } *pszCmd++ = c; // copy the character over and continue cb++; if(cb > sizeof(szCmd)/sizeof(szCmd[0])) { dwError = ERROR_INSUFFICIENT_BUFFER; break; } } // now move to the next char c = *++psz; } if (ERROR_SUCCESS != dwError) { return(dwError); } dwLengthCmdTail = strlen(psz); // now // psz points to a delimiter char that we have terminated our search on. // the part before this char -- is exe filename // the part after this char -- cmdline tail if (fConvert) { // now we go converting first dwLength = DPM_GetShortPathName(szFileName, lpstrParsed, cchstrParsed); if (!dwLength || dwLength > cchstrParsed-1) { LOGDEBUG(0, ("WS32ParseCmdLine: Can't convert to the short name\n")); WOW32ASSERT(FALSE); return(GetLastError()); } if (dwLength + dwLengthCmdTail > cchstrParsed - 1) { LOGDEBUG(0, ("WS32ParseCmdLine: Buffer too short for cmdline tail\n")); WOW32ASSERT(FALSE); return(ERROR_INSUFFICIENT_BUFFER); } } else { // now here we just insert quotes around the filename -- unless there // already were some quotes surrounding it if (dwLengthFileName + 2 > cchstrParsed - 1) { LOGDEBUG(0, ("WS32ParseCmdLine: Buffer too short for quoted filename\n")); WOW32ASSERT(FALSE); return(ERROR_INSUFFICIENT_BUFFER); } *lpstrParsed++ = '\"'; lstrcpyn(lpstrParsed, szFileName, dwLengthFileName+1); lstrcat(lpstrParsed, "\""); } lstrcat(lpstrParsed, psz); return(ERROR_SUCCESS); } extern DWORD demSetCurrentDirectoryGetDrive(LPSTR lpDirectoryName, PUINT pDriveNum); extern DWORD demLFNGetCurrentDirectory(UINT DriveNum, LPSTR lpDirectoryName); WORD W32ShellExecuteCallBack (LPSZ lpszCmdLine, WORD fuCmdShow, LPSZ lpszNewDir) { PBYTE lpstr16; PARM16 Parm16; ULONG ul = 0; VPVOID vpstr16; CHAR szCurrentDirectory[MAX_PATH]; UINT Drive; DWORD dwStatus; BOOL fRestoreDir; // what +5 is doing here ? The reasoning is like this : // generated short path could never be longer than the original (long path) // ULONG cchstr16 = lstrlen(lpszCmdLine) + 5; UpdateDosCurrentDirectory(DIR_NT_TO_DOS); // we're given a current directory here -- // so we see if this matches our current directory // demSetCurrentDirectoryLong( dwStatus = demLFNGetCurrentDirectory(0, szCurrentDirectory); fRestoreDir = NT_SUCCESS(dwStatus); dwStatus = demSetCurrentDirectoryGetDrive(lpszNewDir, &Drive); if (NT_SUCCESS(dwStatus)) { DosWowSetDefaultDrive((UCHAR)Drive); } if (vpstr16 = malloc16 (cchstr16)) { // .exe, remember ? GETMISCPTR (vpstr16, lpstr16); if (lpstr16) { // we cannot simply copy the command line here -- although memory // that was allocated is going to be sufficient. // Problem is that winexec will choke when the program name // is denoted as Long File Name -- which is the case with new Office // applications. The rule should be -- whatever comes into land16 // should be in a form of a short file name. // mind you that vpstr16 is big enough for both the long and // short name -- so this code requires no memory realloc // now we need to have ul = WS32ParseCmdLine(lpstr16, lpszCmdLine, cchstr16, TRUE); if (ERROR_SUCCESS != ul) { WOW32ASSERTMSGF(FALSE, ("WS32ParseCmdLine failed: 0x%lx\n", ul)); lstrcpy (lpstr16, lpszCmdLine); } Parm16.WndProc.wParam = fuCmdShow; Parm16.WndProc.lParam = vpstr16; CallBack16(RET_WINEXEC, &Parm16, 0, &ul); FREEMISCPTR (lpstr16); } free16(vpstr16); } if (fRestoreDir) { dwStatus = demSetCurrentDirectoryGetDrive(szCurrentDirectory, &Drive); if (NT_SUCCESS(dwStatus)) { DosWowSetDefaultDrive((UCHAR)Drive); } } return (LOWORD(ul)); } ULONG FASTCALL WS32FindExecutable (PVDMFRAME pFrame) { ULONG ul; register PFINDEXECUTABLE16 parg16; PSZ psz1; PSZ psz2; PSZ psz3; GETARGPTR(pFrame, sizeof(FINDEXECUTABLE16), parg16); GETPSZPTR(parg16->f1, psz1); GETPSZPTR(parg16->f2, psz2); GETPSZPTRNOLOG(parg16->f3, psz3); ul = (ULONG) FindExecutable ( psz1, psz2, psz3 ); LOGDEBUG(11,(" returns @%08lx: \"%.80s\"\n", FETCHDWORD(parg16->f3), psz3)); FLUSHVDMPTR(parg16->f3, strlen(psz3)+1, psz3); // This is for success condition. if (ul > 32) { ul = GETHINST16 (ul); } FREEPSZPTR(psz1); FREEPSZPTR(psz2); FREEPSZPTR(psz3); FREEARGPTR(parg16); RETURN(ul); } ULONG FASTCALL WS32ExtractIcon (PVDMFRAME pFrame) { ULONG ul; register PEXTRACTICON16 parg16; PSZ psz; UINT Id; GETARGPTR(pFrame, sizeof(EXTRACTICON16), parg16); GETPSZPTR(parg16->f2, psz); Id = (parg16->f3 == (WORD)0xffff) ? (UINT)(SHORT)parg16->f3 : (UINT)parg16->f3; ul = (ULONG) ExtractIcon (HMODINST32(parg16->f1), psz, Id); // This is for success condition. if ((Id != (UINT)(-1)) && ul > 1) { ul = GETHICON16(ul); } FREEPSZPTR(psz); FREEARGPTR(parg16); RETURN(ul); } // // This routine convert the Win 32 registry error codes to Win 31 // error codes. // ULONG ConvertToWin31Error(ULONG ul) { LOGDEBUG(3, ("WOW::ConvertToWin31Error: Ret value from NT = %08lx\n", ul)); switch (ul) { case ERROR_SUCCESS: return(WIN16_ERROR_SUCCESS); case ERROR_BADDB: return(WIN16_ERROR_BADDB); case ERROR_BADKEY: return(WIN16_ERROR_BADKEY); case ERROR_CANTOPEN: return(WIN16_ERROR_CANTOPEN); case ERROR_CANTREAD: return(WIN16_ERROR_CANTREAD); case ERROR_CANTWRITE: return(WIN16_ERROR_CANTWRITE); case ERROR_OUTOFMEMORY: return(WIN16_ERROR_OUTOFMEMORY); case ERROR_INVALID_PARAMETER: return(WIN16_ERROR_INVALID_PARAMETER); case ERROR_EA_ACCESS_DENIED: return(WIN16_ERROR_ACCESS_DENIED); case ERROR_MORE_DATA: return(WIN16_ERROR_INVALID_PARAMETER); case ERROR_FILE_NOT_FOUND: return(WIN16_ERROR_BADKEY); case ERROR_NO_MORE_ITEMS: return(WIN16_ERROR_BADKEY); default: LOGDEBUG(3, ("WOW::Registry Error Code unknown =%08lx : returning 8 (WIN16_ERROR_ACCESS_DENIED)\n", ul)); return (WIN16_ERROR_ACCESS_DENIED); } } LPSZ Remove_Classes (LPSZ psz) { LPSZ lpsz; LPSZ lpsz1; if (!WOW32_stricmp (".classes", psz)) { if (lpsz = malloc_w (1)) { *lpsz = '\0'; return (lpsz); } } else { if (*psz) { lpsz = WOW32_strchr (psz, '\\'); if (lpsz) { *lpsz = '\0'; if (!WOW32_stricmp (".classes", lpsz)) { *lpsz = '\\'; if (lpsz1 = malloc_w (strlen(lpsz+1)+1)) { strcpy (lpsz1, (lpsz+1)); return (lpsz1); } else { return (0); } } *lpsz = '\\'; return (psz); } else { return (psz); } } else { return (psz); } } return (psz); } //**************************************************************************** // DropFilesHandler - // takes either h16 or h32 as input. flInput identifies the type of the // handle and other operations to perform. return value varies but in most // cases it is the opposite to the 'input type'- ie returns h16 if h32 was // input and viceversa. // - nanduri //**************************************************************************** LPDROPALIAS glpDropAlias = NULL; LPDROPALIAS DropFilesFind(DWORD h, UINT fInput, LPDROPALIAS* ppPrev) { LPDROPALIAS lpT = glpDropAlias; LPDROPALIAS lpTPrev = NULL; WOW32ASSERT(h); WOW32ASSERT((!!(fInput & HDROP_H16)) ^ (!!(fInput & HDROP_H32))); while (NULL != lpT) { if (fInput & HDROP_H16) { if ((lpT->h16 & ~1) == (((HAND16)h) & ~1)) { break; } } else if (fInput & HDROP_H32) { if (lpT->h32 == (HANDLE)h) { break; } } lpTPrev = lpT; lpT = lpT->lpNext; } if (ppPrev) { *ppPrev = lpTPrev; } return(lpT); } DWORD DropFilesHandler(HAND16 h16, HANDLE h32, UINT flInput) { LPDROPALIAS lpT; LPDROPALIAS lpTprev; DWORD dwRet = 0; // assert if specified both or neither handle or flag WOW32ASSERT((h16) || (h32)); WOW32ASSERT((!!(flInput & HDROP_H32)) ^ (!!(flInput & HDROP_H16))); // find handle lpT = DropFilesFind(flInput & HDROP_H16 ? (DWORD)h16 : (DWORD)h32, flInput, &lpTprev); // // if not found, create the alias if requested // if (lpT == (LPDROPALIAS)NULL && (flInput & HDROP_ALLOCALIAS)) { if (lpT = malloc_w(sizeof(DROPALIAS))) { lpT->h16 = h16; lpT->h32 = h32; lpT->lpNext = glpDropAlias; lpT->dwFlags = 0; glpDropAlias = lpT; flInput |= HDROP_COPYDATA; } } // // if found - do the necessary operation. all (other) HDROP_* flags // have priority over HDROP_H16 and HDROP_H32 flags. // if (lpT) { if (flInput & HDROP_COPYDATA) { if (h32) { dwRet = (DWORD) (lpT->h16 = CopyDropFilesFrom32(h32)); lpT->dwFlags |= ALLOC_H16; } else { dwRet = (DWORD) (lpT->h32 = CopyDropFilesFrom16(h16)); lpT->dwFlags |= ALLOC_H32; } } else if (flInput & HDROP_FREEALIAS) { dwRet = (DWORD)lpT->h32; if (lpTprev) { lpTprev->lpNext = lpT->lpNext; } else { glpDropAlias = lpT->lpNext; } free_w(lpT); } else if (flInput & HDROP_H16) { dwRet = (DWORD)lpT->h32; } else if (flInput & HDROP_H32) { dwRet = (DWORD)lpT->h16; } } return (dwRet); } // // FindAndReleaseHDrop16 // Called from the 16-bit GlobalFree to see if we need to free alias // associated with this handle // The actual call is made through the wowddeglobalfree // Function frees 32-bit handle (or disposes of it using DragFinish // for consistency) but 16-bit handle is freed elsewere // BOOL FindAndReleaseHDrop16 (HAND16 h16) { LPDROPALIAS lpT; LPDROPALIAS lpTPrev; if (NULL != (lpT = DropFilesFind(h16, HDROP_H16, &lpTPrev))) { // found, now free 32-bit handle, but not 16-bit one // this assert will fire if we had not allocated 32-bit handle but // app tried to free the 16-bit equivalent instead LOGDEBUG(LOG_ALWAYS, ("HDrop16: removing handle 16:%lx 32:%lx\n", (DWORD)h16, (DWORD)lpT->h32)); if (lpT->dwFlags & ALLOC_H32) { LOGDEBUG(LOG_ALWAYS, ("HDROP16: h32 allocated through OLE\n")); WOWGLOBALFREE((HANDLE)lpT->h32); } else { // this handle was not allocated - but rather retrieved via old // style dropfiles mechanism LOGDEBUG(LOG_ALWAYS, ("HDrop16: h32 retrieved from shell\n")); DragFinish((HDROP)lpT->h32); } // now unlink if (NULL != lpTPrev) { lpTPrev->lpNext = lpT->lpNext; } else { glpDropAlias = lpT->lpNext; } // unmark 16-bit memory as being dde... W32UnMarkDDEHandle(h16); // free the list item free_w(lpT); } return(NULL != lpT); } //**************************************************************************** // CopyDropFilesStruct - // // returns h16. //**************************************************************************** HAND16 CopyDropFilesFrom32(HANDLE h32) { UINT cbSize; HAND16 hRet = 0; HAND16 hMem; VPVOID vp; // // the allocated 16bit handle and the corresponding 32bit handle // are freed in the shell api 'DragFinish' (if it is called by the app) // cbSize = GlobalSize((HANDLE)h32); if (vp = GlobalAllocLock16(GMEM_DDESHARE, cbSize, &hMem)) { LPDROPFILESTRUCT lpdfs32; PDROPFILESTRUCT16 lpdfs16; ULONG uIgnore; GETMISCPTR(vp, lpdfs16); if (lpdfs32 = (LPDROPFILESTRUCT)GlobalLock((HANDLE)h32)) { // // pFiles is a byte count to the beginning of the file. // lpdfs16->pFiles = sizeof(DROPFILESTRUCT16); lpdfs16->x = (SHORT) lpdfs32->pt.x; lpdfs16->y = (SHORT) lpdfs32->pt.y; lpdfs16->fNC = (SHORT) lpdfs32->fNC; if (lpdfs32->fWide) { RtlUnicodeToMultiByteN(((PCHAR)lpdfs16)+lpdfs16->pFiles, cbSize-lpdfs16->pFiles, &uIgnore, (PWSTR)(((PCHAR)lpdfs32)+lpdfs32->pFiles), cbSize-lpdfs32->pFiles); } else { // // Copy the files after each structure. // The offset from the beginning of the structure changes // (since the structures are differenly sized), but we // compensate by changes pFiles above. // RtlCopyMemory(lpdfs16+1, lpdfs32+1, GlobalSize((HANDLE)h32) - sizeof(DROPFILESTRUCT)); } GlobalUnlock((HANDLE)h32); hRet = hMem; // and before we return - mark this memory as being suspect for // stray mapping release // This function in wdde.c marks arena with GAH_PHANTOM flag // we will destroy the alias when the globalfree is called either // from 16-bit shell api DragFinish or from 16-bit ReleaseStgMedium W32MarkDDEHandle(hMem); } else { GlobalUnlockFree16(vp); } FREEMISCPTR(lpdfs16); } return (hRet); } /*--------------------------------------------------------------------------*/ /* */ /* CopyDropFilesFrom16() */ /* */ /*--------------------------------------------------------------------------*/ HANDLE CopyDropFilesFrom16(HAND16 h16) { HANDLE h32 = 0; ULONG cbSize16; UINT cbSize32; VPVOID vp; if (vp = GlobalLock16(h16, &cbSize16)) { LPDROPFILESTRUCT lpdfs32; PDROPFILESTRUCT16 lpdfs16; GETMISCPTR(vp, lpdfs16); cbSize32 = 2*sizeof(TCHAR) + sizeof(DROPFILESTRUCT) + (cbSize16 - sizeof(DROPFILESTRUCT16)); if (h32 = WOWGLOBALALLOC(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, cbSize32)){ lpdfs32 = (LPDROPFILESTRUCT)GlobalLock(h32); lpdfs32->pFiles = sizeof(DROPFILESTRUCT); lpdfs32->pt.x = (LONG) lpdfs16->x; lpdfs32->pt.y = (LONG) lpdfs16->y; lpdfs32->fNC = lpdfs16->fNC; lpdfs32->fWide = FALSE; RtlCopyMemory(lpdfs32+1, lpdfs16+1, cbSize16 - sizeof(DROPFILESTRUCT16)); GlobalUnlock(h32); } FREEMISCPTR(lpdfs16); GlobalUnlock16(h16); } return(h32); }