/* * comc.c - Shared routines. */ /* Headers **********/ #include "project.h" #pragma hdrstop #include "assoc.h" #pragma warning(disable:4001) /* "single line comment" warning */ #include "filetype.h" #pragma warning(default:4001) /* "single line comment" warning */ /* Global Constants *******************/ #pragma data_seg(DATA_SEG_READ_ONLY) PUBLIC_DATA const char g_cszWhiteSpace[] = " \t"; PUBLIC_DATA const char g_cszSlashes[] = "/\\"; PUBLIC_DATA const char g_cszPathSeparators[] = ":/\\"; PUBLIC_DATA const char g_cszEditFlags[] = "EditFlags"; #pragma data_seg() /* Module Constants *******************/ #pragma data_seg(DATA_SEG_READ_ONLY) PRIVATE_DATA CCHAR s_cszMIMETypeSubKeyFmt[] = "MIME\\Database\\Content Type\\%s"; PRIVATE_DATA CCHAR s_cszDefaultVerbSubKeyFmt[] = "%s\\Shell"; PRIVATE_DATA CCHAR s_cszShellOpenCmdSubKey[] = "Shell\\Open\\Command"; PRIVATE_DATA CCHAR s_cszContentType[] = "Content Type"; PRIVATE_DATA CCHAR s_cszExtension[] = "Extension"; PRIVATE_DATA const char s_cszAppCmdLineFmt[] = " %s"; PRIVATE_DATA const char s_cszQuotesAppCmdLineFmt[] = " \"%s\""; #pragma data_seg() /***************************** Private Functions *****************************/ /* ** GetMIMETypeStringValue() ** ** Retrieves the string for a registered MIME type's value. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL GetMIMETypeStringValue(PCSTR pcszMIMEType, PCSTR pcszValue, PSTR pszBuf, UINT ucBufLen) { BOOL bResult; DWORD dwValueType; DWORD dwcbLen = ucBufLen; /* GetMIMEValue() will verify parameters. */ bResult = (GetMIMEValue(pcszMIMEType, pcszValue, &dwValueType, (PBYTE)pszBuf, &dwcbLen) && dwValueType == REG_SZ); if (! bResult) { if (ucBufLen > 0) *pszBuf = '\0'; } ASSERT(! ucBufLen || IS_VALID_STRING_PTR(pszBuf, STR)); return(bResult); } /****************************** Public Functions *****************************/ PUBLIC_CODE BOOL DataCopy(PCBYTE pcbyteSrc, ULONG ulcbLen, PBYTE *ppbyteDest) { BOOL bResult; ASSERT(IS_VALID_READ_BUFFER_PTR(pcbyteSrc, CBYTE, ulcbLen)); ASSERT(IS_VALID_WRITE_PTR(ppbyteDest, PBYTE)); bResult = AllocateMemory(ulcbLen, ppbyteDest); if (bResult) CopyMemory(*ppbyteDest, pcbyteSrc, ulcbLen); else *ppbyteDest = NULL; ASSERT((bResult && IS_VALID_READ_BUFFER_PTR(*ppbyteDest, BYTE, ulcbLen)) || (! bResult && EVAL(! *ppbyteDest))); return(bResult); } PUBLIC_CODE BOOL StringCopy(PCSTR pcszSrc, PSTR *ppszCopy) { BOOL bResult; ASSERT(IS_VALID_STRING_PTR(pcszSrc, CSTR)); ASSERT(IS_VALID_WRITE_PTR(ppszCopy, PSTR)); /* (+ 1) for null terminator. */ bResult = DataCopy((PCBYTE)pcszSrc, lstrlen(pcszSrc) + 1, (PBYTE *)ppszCopy); ASSERT(! bResult || IS_VALID_STRING_PTR(*ppszCopy, STR)); return(bResult); } /* ** GetMIMETypeSubKey() ** ** Generates the HKEY_CLASSES_ROOT subkey for a MIME type. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL GetMIMETypeSubKey(PCSTR pcszMIMEType, PSTR pszSubKeyBuf, UINT ucSubKeyBufLen) { BOOL bResult; bResult = ((UINT)lstrlen(s_cszMIMETypeSubKeyFmt) + (UINT)lstrlen(pcszMIMEType) < ucSubKeyBufLen); if (bResult) EVAL((UINT)wsprintf(pszSubKeyBuf, s_cszMIMETypeSubKeyFmt, pcszMIMEType) < ucSubKeyBufLen); else { if (ucSubKeyBufLen > 0) *pszSubKeyBuf = '\0'; WARNING_OUT(("GetMIMETypeSubKey(): Given sub key buffer of length %u is too short to hold sub key for MIME type %s.", ucSubKeyBufLen, pcszMIMEType)); } ASSERT(! ucSubKeyBufLen || (IS_VALID_STRING_PTR(pszSubKeyBuf, STR) && (UINT)lstrlen(pszSubKeyBuf) < ucSubKeyBufLen)); ASSERT(bResult || ! ucSubKeyBufLen || ! *pszSubKeyBuf); return(bResult); } /* ** GetMIMEValue() ** ** Retrieves the data for a value of a MIME type. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL GetMIMEValue(PCSTR pcszMIMEType, PCSTR pcszValue, PDWORD pdwValueType, PBYTE pbyteValueBuf, PDWORD pdwcbValueBufLen) { BOOL bResult; char szMIMETypeSubKey[MAX_PATH_LEN]; ASSERT(IS_VALID_STRING_PTR(pcszMIMEType, CSTR)); ASSERT(! pcszValue || IS_VALID_STRING_PTR(pcszValue, CSTR)); ASSERT(IS_VALID_WRITE_PTR(pdwValueType, DWORD)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pbyteValueBuf, BYTE, *pdwcbValueBufLen)); bResult = (GetMIMETypeSubKey(pcszMIMEType, szMIMETypeSubKey, sizeof(szMIMETypeSubKey)) && GetRegKeyValue(HKEY_CLASSES_ROOT, szMIMETypeSubKey, pcszValue, pdwValueType, pbyteValueBuf, pdwcbValueBufLen) == ERROR_SUCCESS); return(bResult); } /* ** GetFileTypeValue() ** ** Retrieves the data for a value of the file class associated with an ** extension. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL GetFileTypeValue(PCSTR pcszExtension, PCSTR pcszSubKey, PCSTR pcszValue, PDWORD pdwValueType, PBYTE pbyteValueBuf, PDWORD pdwcbValueBufLen) { BOOL bResult = FALSE; ASSERT(IsValidExtension(pcszExtension)); ASSERT(! pcszSubKey || IS_VALID_STRING_PTR(pcszSubKey, CSTR)); ASSERT(! pcszValue || IS_VALID_STRING_PTR(pcszValue, CSTR)); ASSERT(IS_VALID_WRITE_PTR(pdwValueType, DWORD)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pbyteValueBuf, BYTE, *pdwcbValueBufLen)); if (EVAL(*pcszExtension)) { char szSubKey[MAX_PATH_LEN]; DWORD dwcbLen = sizeof(szSubKey); /* Get extension's file type. */ if (GetDefaultRegKeyValue(HKEY_CLASSES_ROOT, pcszExtension, szSubKey, &dwcbLen) == ERROR_SUCCESS && *szSubKey) { /* Any sub key to append? */ if (pcszSubKey) { /* Yes. */ /* (+ 1) for possible key separator. */ bResult = EVAL(lstrlen(szSubKey) + 1 + lstrlen(pcszSubKey) < sizeof(szSubKey)); if (bResult) { CatPath(szSubKey, pcszSubKey); ASSERT(lstrlen(szSubKey) < sizeof(szSubKey)); } } else /* No. */ bResult = TRUE; if (bResult) /* Get file type's value string. */ bResult = (GetRegKeyValue(HKEY_CLASSES_ROOT, szSubKey, pcszValue, pdwValueType, pbyteValueBuf, pdwcbValueBufLen) == ERROR_SUCCESS); } else TRACE_OUT(("GetFileTypeValue(): No file type registered for extension %s.", pcszExtension)); } else WARNING_OUT(("GetFileTypeValue(): No extension given.")); return(bResult); } /* ** GetMIMEFileTypeValue() ** ** Retrieves the data for a value of the file class associated with a MIME ** type. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL GetMIMEFileTypeValue(PCSTR pcszMIMEType, PCSTR pcszSubKey, PCSTR pcszValue, PDWORD pdwValueType, PBYTE pbyteValueBuf, PDWORD pdwcbValueBufLen) { BOOL bResult; char szExtension[MAX_PATH_LEN]; ASSERT(IS_VALID_STRING_PTR(pcszMIMEType, CSTR)); ASSERT(! pcszSubKey || IS_VALID_STRING_PTR(pcszSubKey, CSTR)); ASSERT(! pcszValue || IS_VALID_STRING_PTR(pcszValue, CSTR)); ASSERT(IS_VALID_WRITE_PTR(pdwValueType, DWORD)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pbyteValueBuf, BYTE, *pdwcbValueBufLen)); /* Get file name extension associated with MIME type. */ if (MIME_GetExtension(pcszMIMEType, szExtension, sizeof(szExtension))) bResult = GetFileTypeValue(szExtension, pcszSubKey, pcszValue, pdwValueType, pbyteValueBuf, pdwcbValueBufLen); else { bResult = FALSE; TRACE_OUT(("GetMIMEFileTypeValue(): No extension registered for MIME type %s.", pcszMIMEType)); } return(bResult); } /* ** MIME_IsExternalHandlerRegistered() ** ** Determines whether or not an external handler is registered for a MIME type. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL MIME_IsExternalHandlerRegistered(PCSTR pcszMIMEType) { BOOL bResult; DWORD dwValueType; char szOpenCmd[MAX_PATH_LEN]; DWORD dwcbOpenCmdLen = sizeof(szOpenCmd); /* GetMIMEFileTypeValue() will verify parameters. */ /* Look up the open command of the MIME type's associated file type. */ bResult = (GetMIMEFileTypeValue(pcszMIMEType, s_cszShellOpenCmdSubKey, NULL, &dwValueType, (PBYTE)szOpenCmd, &dwcbOpenCmdLen) && dwValueType == REG_SZ); TRACE_OUT(("MIME_IsExternalHandlerRegistered(): %s external handler is registered for MIME type %s.", bResult ? "An" : "No", pcszMIMEType)); return(bResult); } /* ** MIME_GetExtension() ** ** Determines the file name extension to be used when writing a file of a MIME ** type to the file system. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL MIME_GetExtension(PCSTR pcszMIMEType, PSTR pszExtensionBuf, UINT ucExtensionBufLen) { BOOL bResult = FALSE; ASSERT(IS_VALID_STRING_PTR(pcszMIMEType, CSTR)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszExtensionBuf, STR, ucExtensionBufLen)); if (EVAL(ucExtensionBufLen > 2)) { /* Leave room for possible leading period. */ if (GetMIMETypeStringValue(pcszMIMEType, s_cszExtension, pszExtensionBuf + 1, ucExtensionBufLen - 1)) { if (pszExtensionBuf[1]) { /* Prepend period if necessary. */ if (pszExtensionBuf[1] == PERIOD) /* (+ 1) for null terminator. */ MoveMemory(pszExtensionBuf, pszExtensionBuf + 1, lstrlen(pszExtensionBuf + 1) + 1); else pszExtensionBuf[0] = PERIOD; bResult = TRUE; } } } if (! bResult) { if (ucExtensionBufLen > 0) *pszExtensionBuf = '\0'; } if (bResult) TRACE_OUT(("MIME_GetExtension(): Extension %s registered as default extension for MIME type %s.", pszExtensionBuf, pcszMIMEType)); else TRACE_OUT(("MIME_GetExtension(): No default extension registered for MIME type %s.", pcszMIMEType)); ASSERT((bResult && IsValidExtension(pszExtensionBuf)) || (! bResult && (! ucExtensionBufLen || ! *pszExtensionBuf))); ASSERT(! ucExtensionBufLen || (UINT)lstrlen(pszExtensionBuf) < ucExtensionBufLen); return(bResult); } /* ** MIME_GetMIMETypeFromExtension() ** ** Determines the MIME type associated with a file extension. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL MIME_GetMIMETypeFromExtension(PCSTR pcszPath, PSTR pszMIMETypeBuf, UINT ucMIMETypeBufLen) { BOOL bResult; PCSTR pcszExtension; ASSERT(IS_VALID_STRING_PTR(pcszPath, CSTR)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszMIMETypeBuf, STR, ucMIMETypeBufLen)); pcszExtension = ExtractExtension(pcszPath); if (*pcszExtension) { DWORD dwcLen = ucMIMETypeBufLen; bResult = (GetRegKeyStringValue(HKEY_CLASSES_ROOT, pcszExtension, s_cszContentType, pszMIMETypeBuf, &dwcLen) == ERROR_SUCCESS); if (bResult) TRACE_OUT(("MIME_GetMIMETypeFromExtension(): MIME type for extension %s is %s.", pcszExtension, pszMIMETypeBuf)); else TRACE_OUT(("MIME_GetMIMETypeFromExtension(): No MIME type registered for extension %s.", pcszExtension)); } else { bResult = FALSE; TRACE_OUT(("MIME_GetMIMETypeFromExtension(): No extension in path %s.", pcszPath)); } if (! bResult) { if (ucMIMETypeBufLen > 0) *pszMIMETypeBuf = '\0'; } ASSERT(! ucMIMETypeBufLen || (IS_VALID_STRING_PTR(pszMIMETypeBuf, STR) && (UINT)lstrlen(pszMIMETypeBuf) < ucMIMETypeBufLen)); ASSERT(bResult || ! ucMIMETypeBufLen || ! *pszMIMETypeBuf); return(bResult); } /* ** CatPath() ** ** Appends a filename to a path string. ** ** Arguments: pszPath - path string that file name is to be appended to ** pcszSubPath - path to append ** ** Returns: void ** ** Side Effects: none ** ** N.b., truncates path to MAX_PATH_LEN characters in length. ** ** Examples: ** ** input path input file name output path ** ---------- --------------- ----------- ** c:\ foo c:\foo ** c: foo c:foo ** c:\foo\bar\ goo c:\foo\bar\goo ** c:\foo\bar\ \goo c:\foo\bar\goo ** c:\foo\bar\ goo\shoe c:\foo\bar\goo\shoe ** c:\foo\bar\ \goo\shoe\ c:\foo\bar\goo\shoe\ ** foo\bar\ goo foo\bar\goo ** ** foo foo ** foo foo ** fred bird fred\bird */ PUBLIC_CODE void CatPath(PSTR pszPath, PCSTR pcszSubPath) { PSTR pcsz; PSTR pcszLast; ASSERT(IS_VALID_STRING_PTR(pszPath, STR)); ASSERT(IS_VALID_STRING_PTR(pcszSubPath, CSTR)); /* (+ 1) for possible separator. */ /* (+ 1) for null terminator. */ ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszPath, STR, lstrlen(pszPath) + 1 + lstrlen(pcszSubPath) + 1)); /* Find last character in path string. */ for (pcsz = pcszLast = pszPath; *pcsz; pcsz = CharNext(pcsz)) pcszLast = pcsz; if (IS_SLASH(*pcszLast) && IS_SLASH(*pcszSubPath)) pcszSubPath++; else if (! IS_SLASH(*pcszLast) && ! IS_SLASH(*pcszSubPath)) { if (*pcszLast && *pcszLast != COLON && *pcszSubPath) *pcsz++ = '\\'; } lstrcpy(pcsz, pcszSubPath); ASSERT(IS_VALID_STRING_PTR(pszPath, STR)); return; } /* ** MyLStrCpyN() ** ** Like lstrcpy(), but the copy is limited to ucb bytes. The destination ** string is always null-terminated. ** ** Arguments: pszDest - pointer to destination buffer ** pcszSrc - pointer to source string ** ncb - maximum number of bytes to copy, including null ** terminator ** ** Returns: void ** ** Side Effects: none ** ** N.b., this function behaves quite differently than strncpy()! It does not ** pad out the destination buffer with null characters, and it always null ** terminates the destination string. */ PUBLIC_CODE void MyLStrCpyN(PSTR pszDest, PCSTR pcszSrc, int ncb) { ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszDest, STR, ncb)); ASSERT(IS_VALID_STRING_PTR(pcszSrc, CSTR)); ASSERT(ncb > 0); while (ncb > 1) { ncb--; *pszDest = *pcszSrc; if (*pcszSrc) { pszDest++; pcszSrc++; } else break; } if (ncb == 1) *pszDest = '\0'; ASSERT(IS_VALID_STRING_PTR(pszDest, STR)); ASSERT(lstrlen(pszDest) < ncb); ASSERT(lstrlen(pszDest) <= lstrlen(pcszSrc)); return; } PUBLIC_CODE COMPARISONRESULT MapIntToComparisonResult(int nResult) { COMPARISONRESULT cr; /* Any integer is valid input. */ if (nResult < 0) cr = CR_FIRST_SMALLER; else if (nResult > 0) cr = CR_FIRST_LARGER; else cr = CR_EQUAL; return(cr); } /* ** TrimWhiteSpace() ** ** Trims leading and trailing white space from a string in place. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE void TrimWhiteSpace(PSTR pszTrimMe) { ASSERT(IS_VALID_STRING_PTR(pszTrimMe, STR)); TrimString(pszTrimMe, g_cszWhiteSpace); /* TrimString() validates pszTrimMe on output. */ return; } /* ** TrimSlashes() ** ** Trims leading and trailing slashes from a string in place. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE void TrimSlashes(PSTR pszTrimMe) { ASSERT(IS_VALID_STRING_PTR(pszTrimMe, STR)); TrimString(pszTrimMe, g_cszSlashes); /* TrimString() validates pszTrimMe on output. */ return; } PUBLIC_CODE void TrimString(PSTR pszTrimMe, PCSTR pszTrimChars) { PSTR psz; PSTR pszStartMeat; ASSERT(IS_VALID_STRING_PTR(pszTrimMe, STR)); ASSERT(IS_VALID_STRING_PTR(pszTrimChars, CSTR)); if ( !pszTrimMe ) return; /* Trim leading characters. */ psz = pszTrimMe; while (*psz && strchr(pszTrimChars, *psz)) psz = CharNext(psz); pszStartMeat = psz; /* Trim trailing characters. */ if (*psz) { psz += lstrlen(psz); psz = CharPrev(pszStartMeat, psz); if (psz > pszStartMeat) { while (strchr(pszTrimChars, *psz)) psz = CharPrev(pszStartMeat, psz); psz = CharNext(psz); ASSERT(psz > pszStartMeat); *psz = '\0'; } } /* Relocate stripped string. */ if (pszStartMeat > pszTrimMe) /* (+ 1) for null terminator. */ MoveMemory(pszTrimMe, pszStartMeat, lstrlen(pszStartMeat) + 1); else ASSERT(pszStartMeat == pszTrimMe); ASSERT(IS_VALID_STRING_PTR(pszTrimMe, STR)); return; } /* ** ExtractFileName() ** ** Extracts the file name from a path name. ** ** Arguments: pcszPathName - path string from which to extract file name ** ** Returns: Pointer to file name in path string. ** ** Side Effects: none */ PUBLIC_CODE PCSTR ExtractFileName(PCSTR pcszPathName) { PCSTR pcszLastComponent; PCSTR pcsz; ASSERT(IS_VALID_STRING_PTR(pcszPathName, CSTR)); for (pcszLastComponent = pcsz = pcszPathName; *pcsz; pcsz = CharNext(pcsz)) { if (IS_SLASH(*pcsz) || *pcsz == COLON) pcszLastComponent = CharNext(pcsz); } ASSERT(IsValidPath(pcszLastComponent)); return(pcszLastComponent); } /* ** ExtractExtension() ** ** Extracts the extension from a name. ** ** Arguments: pcszName - name whose extension is to be extracted ** ** Returns: If the name contains an extension, a pointer to the period at ** the beginning of the extension is returned. If the name has ** no extension, a pointer to the name's null terminator is ** returned. ** ** Side Effects: none */ PUBLIC_CODE PCSTR ExtractExtension(PCSTR pcszName) { PCSTR pcszLastPeriod; ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR)); /* Make sure we have an isolated file name. */ pcszName = ExtractFileName(pcszName); pcszLastPeriod = NULL; while (*pcszName) { if (*pcszName == PERIOD) pcszLastPeriod = pcszName; pcszName = CharNext(pcszName); } if (! pcszLastPeriod) { /* Point at null terminator. */ pcszLastPeriod = pcszName; ASSERT(! *pcszLastPeriod); } else /* Point at period at beginning of extension. */ ASSERT(*pcszLastPeriod == PERIOD); ASSERT(! *pcszLastPeriod || IsValidExtension(pcszLastPeriod)); return(pcszLastPeriod); } /* ** SetRegKeyValue() ** ** Sets the data associated with a registry key's value. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE LONG SetRegKeyValue(HKEY hkeyParent, PCSTR pcszSubKey, PCSTR pcszValue, DWORD dwType, PCBYTE pcbyte, DWORD dwcb) { LONG lResult; HKEY hkeySubKey; ASSERT(IS_VALID_HANDLE(hkeyParent, KEY)); ASSERT(IS_VALID_STRING_PTR(pcszSubKey, CSTR)); ASSERT(IsValidRegistryValueType(dwType)); ASSERT(! pcszValue || IS_VALID_STRING_PTR(pcszValue, CSTR)); ASSERT(IS_VALID_READ_BUFFER_PTR(pcbyte, CBYTE, dwcb)); lResult = RegCreateKeyEx(hkeyParent, pcszSubKey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkeySubKey, NULL); if (lResult == ERROR_SUCCESS) { LONG lResultClose; lResult = RegSetValueEx(hkeySubKey, pcszValue, 0, dwType, pcbyte, dwcb); lResultClose = RegCloseKey(hkeySubKey); if (lResult == ERROR_SUCCESS) lResult = lResultClose; } return(lResult); } /* ** GetRegKeyValue() ** ** Retrieves the data from a registry key's value. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE LONG GetRegKeyValue(HKEY hkeyParent, PCSTR pcszSubKey, PCSTR pcszValue, PDWORD pdwValueType, PBYTE pbyteBuf, PDWORD pdwcbBufLen) { LONG lResult; HKEY hkeySubKey; ASSERT(IS_VALID_HANDLE(hkeyParent, KEY)); ASSERT(! pcszSubKey || IS_VALID_STRING_PTR(pcszSubKey, CSTR)); ASSERT(! pcszValue || IS_VALID_STRING_PTR(pcszValue, CSTR)); ASSERT(! pdwValueType || IS_VALID_WRITE_PTR(pdwValueType, DWORD)); ASSERT(! pbyteBuf || IS_VALID_WRITE_BUFFER_PTR(pbyteBuf, BYTE, *pdwcbBufLen)); lResult = RegOpenKeyEx(hkeyParent, pcszSubKey, 0, KEY_QUERY_VALUE, &hkeySubKey); if (lResult == ERROR_SUCCESS) { LONG lResultClose; lResult = RegQueryValueEx(hkeySubKey, pcszValue, NULL, pdwValueType, pbyteBuf, pdwcbBufLen); lResultClose = RegCloseKey(hkeySubKey); if (lResult == ERROR_SUCCESS) lResult = lResultClose; } return(lResult); } /* ** GetRegKeyStringValue() ** ** Retrieves the data from a registry key's string value. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE LONG GetRegKeyStringValue(HKEY hkeyParent, PCSTR pcszSubKey, PCSTR pcszValue, PSTR pszBuf, PDWORD pdwcbBufLen) { LONG lResult; DWORD dwValueType; /* GetRegKeyValue() will verify the parameters. */ lResult = GetRegKeyValue(hkeyParent, pcszSubKey, pcszValue, &dwValueType, (PBYTE)pszBuf, pdwcbBufLen); if (lResult == ERROR_SUCCESS && dwValueType != REG_SZ) lResult = ERROR_CANTREAD; return(lResult); } /* ** GetDefaultRegKeyValue() ** ** Retrieves the data from a registry key's default string value. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE LONG GetDefaultRegKeyValue(HKEY hkeyParent, PCSTR pcszSubKey, PSTR pszBuf, PDWORD pdwcbBufLen) { /* GetRegKeyStringValue() will verify the parameters. */ return(GetRegKeyStringValue(hkeyParent, pcszSubKey, NULL, pszBuf, pdwcbBufLen)); } /* ** FullyQualifyPath() ** ** Fully qualifies a path. ** ** Arguments: ** ** Returns: S_OK ** ** E_FILE_NOT_FOUND ** ** Side Effects: none */ PUBLIC_CODE HRESULT FullyQualifyPath(PCSTR pcszPath, PSTR pszFullyQualifiedPath, UINT ucFullyQualifiedPathBufLen) { HRESULT hr = E_FILE_NOT_FOUND; PSTR pszFileName; ASSERT(IS_VALID_STRING_PTR(pcszPath, CSTR)); /* Any path separators? */ if (! strpbrk(pcszPath, g_cszPathSeparators)) { /* No. Search for file. */ TRACE_OUT(("FullyQualifyPath(): Searching PATH for %s.", pcszPath)); if (SearchPath(NULL, pcszPath, NULL, ucFullyQualifiedPathBufLen, pszFullyQualifiedPath, &pszFileName) > 0) hr = S_OK; else TRACE_OUT(("FullyQualifyPath(): %s not found on PATH.", pcszPath)); } if (hr != S_OK && GetFullPathName(pcszPath, ucFullyQualifiedPathBufLen, pszFullyQualifiedPath, &pszFileName) > 0) hr = S_OK; if (hr == S_OK) TRACE_OUT(("FullyQualifyPath(): %s qualified as %s.", pcszPath, pszFullyQualifiedPath)); else { if (ucFullyQualifiedPathBufLen > 0) pszFullyQualifiedPath = '\0'; WARNING_OUT(("FullyQualifyPath(): Failed to qualify %s.", pcszPath)); } ASSERT((hr == S_OK && EVAL(IsFullPath(pszFullyQualifiedPath))) || (hr == E_FILE_NOT_FOUND && (! ucFullyQualifiedPathBufLen || ! *pszFullyQualifiedPath))); return(hr); } /* ** MyExecute() ** ** Calls CreateProcess() politely. ** ** Arguments: ** ** Returns: S_OK ** ** E_FAIL ** E_FILE_NOT_FOUND ** E_OUTOFMEMORY ** ** Side Effects: none */ PUBLIC_CODE HRESULT MyExecute(PCSTR pcszApp, PCSTR pcszArgs, DWORD dwInFlags) { HRESULT hr; char szFullApp[MAX_PATH_LEN]; ASSERT(IS_VALID_STRING_PTR(pcszApp, CSTR)); ASSERT(IS_VALID_STRING_PTR(pcszArgs, CSTR)); ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_ME_IN_FLAGS)); hr = FullyQualifyPath(pcszApp, szFullApp, sizeof(szFullApp)); if (hr == S_OK) { DWORD dwcbCmdLineLen; PSTR pszCmdLine; /* (+ 1) for null terminator. */ dwcbCmdLineLen = max(sizeof(s_cszAppCmdLineFmt), sizeof(s_cszQuotesAppCmdLineFmt)) + + lstrlen(pcszArgs) + 1; if (AllocateMemory(dwcbCmdLineLen * sizeof(*pszCmdLine), &pszCmdLine)) { PCSTR pcszFmt; STARTUPINFO si; PROCESS_INFORMATION pi; /* Execute URL via one-shot app. */ pcszFmt = (IS_FLAG_SET(dwInFlags, ME_IFL_QUOTE_ARGS) && strpbrk(pcszArgs, g_cszWhiteSpace) != NULL) ? s_cszQuotesAppCmdLineFmt : s_cszAppCmdLineFmt; EVAL((DWORD)wsprintf(pszCmdLine, pcszFmt, pcszArgs) < dwcbCmdLineLen); ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); /* Specify command line exactly as given to app. */ if (CreateProcess(szFullApp, pszCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); hr = S_OK; TRACE_OUT(("MyExecute(): CreateProcess() \"%s %s\" succeeded.", szFullApp, pszCmdLine)); } else { hr = E_FAIL; WARNING_OUT(("MyExecute(): CreateProcess() \"%s %s\" failed.", szFullApp, pszCmdLine)); } FreeMemory(pszCmdLine); pszCmdLine = NULL; } else hr = E_OUTOFMEMORY; } else WARNING_OUT(("MyExecute(): Unable to find app %s.", pcszApp)); return(hr); } PUBLIC_CODE BOOL GetClassDefaultVerb(PCSTR pcszClass, PSTR pszDefaultVerbBuf, UINT ucDefaultVerbBufLen) { BOOL bResult; char szDefaultVerbSubKey[MAX_PATH_LEN]; ASSERT(IS_VALID_STRING_PTR(pcszClass, CSTR)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszDefaultVerbBuf, STR, ucDefaultVerbBufLen)); ASSERT(lstrlen(pcszClass) > 0); if (sizeof(s_cszDefaultVerbSubKeyFmt) + lstrlen(pcszClass) < sizeof(szDefaultVerbSubKey)) { DWORD dwValueType; DWORD dwcbBufLen = ucDefaultVerbBufLen; EVAL(wsprintf(szDefaultVerbSubKey, s_cszDefaultVerbSubKeyFmt, pcszClass) < sizeof(szDefaultVerbSubKey)); bResult = (GetRegKeyValue(HKEY_CLASSES_ROOT, szDefaultVerbSubKey, NULL, &dwValueType, (PBYTE)pszDefaultVerbBuf, &dwcbBufLen) == ERROR_SUCCESS && dwValueType == REG_SZ && *pszDefaultVerbBuf); } else bResult = FALSE; if (! bResult) { if (ucDefaultVerbBufLen > 0) *pszDefaultVerbBuf = '\0'; } if (bResult) TRACE_OUT(("GetClassDefaultVerb(): Default verb for %s class is %s.", pcszClass, pszDefaultVerbBuf)); else TRACE_OUT(("GetClassDefaultVerb(): No default verb for %s class.", pcszClass)); ASSERT(! ucDefaultVerbBufLen || (IS_VALID_STRING_PTR(pszDefaultVerbBuf, STR) && EVAL((UINT)lstrlen(pszDefaultVerbBuf) < ucDefaultVerbBufLen))); ASSERT(bResult || ! ucDefaultVerbBufLen || ! *pszDefaultVerbBuf); return(bResult); } /* * APPCOMPAT: The need for this function should be obviated by a ShellExecuteEx() * flag indicating that the default verb, rather than the open verb, should be * executed. This is broken for folders, for compound document files, for * files whose extensions are registered without a file class, for files whose * extensions are not unregistered, etc. */ PUBLIC_CODE BOOL GetPathDefaultVerb(PCSTR pcszPath, PSTR pszDefaultVerbBuf, UINT ucDefaultVerbBufLen) { BOOL bResult = FALSE; PCSTR pcszExtension; char szClass[MAX_PATH_LEN]; DWORD dwcbLen = ucDefaultVerbBufLen; ASSERT(IsValidPath(pcszPath)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszDefaultVerbBuf, STR, ucDefaultVerbBufLen)); pcszExtension = ExtractExtension(pcszPath); bResult = (*pcszExtension && GetDefaultRegKeyValue(HKEY_CLASSES_ROOT, pcszExtension, szClass, &dwcbLen) == ERROR_SUCCESS && *szClass && GetClassDefaultVerb(szClass, pszDefaultVerbBuf, ucDefaultVerbBufLen)); if (! bResult) { if (ucDefaultVerbBufLen > 0) *pszDefaultVerbBuf = '\0'; } ASSERT(! ucDefaultVerbBufLen || (IS_VALID_STRING_PTR(pszDefaultVerbBuf, STR) && EVAL((UINT)lstrlen(pszDefaultVerbBuf) < ucDefaultVerbBufLen))); ASSERT(bResult || ! ucDefaultVerbBufLen || ! *pszDefaultVerbBuf); return(bResult); } /* ** ClassIsSafeToOpen() ** ** Determines whether or not a file class is known safe to open. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL ClassIsSafeToOpen(PCSTR pcszClass) { BOOL bSafe; DWORD dwValueType; DWORD dwEditFlags; DWORD dwcbLen = sizeof(dwEditFlags); ASSERT(IS_VALID_STRING_PTR(pcszClass, CSTR)); bSafe = (GetRegKeyValue(HKEY_CLASSES_ROOT, pcszClass, g_cszEditFlags, &dwValueType, (PBYTE)&dwEditFlags, &dwcbLen) == ERROR_SUCCESS && (dwValueType == REG_BINARY || dwValueType == REG_DWORD) && IS_FLAG_SET(dwEditFlags, FTA_OpenIsSafe)); TRACE_OUT(("ClassIsSafeToOpen(): Class %s %s safe to open.", pcszClass, bSafe ? "is" : "is not")); return(bSafe); } /* ** SetClassEditFlags() ** ** Sets or clears EditFlags for a file class. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL SetClassEditFlags(PCSTR pcszClass, DWORD dwFlags, BOOL bSet) { BOOL bResult = FALSE; DWORD dwValueType; DWORD dwEditFlags; DWORD dwcbLen = sizeof(dwEditFlags); ASSERT(IS_VALID_STRING_PTR(pcszClass, CSTR)); /* Get current file class flags. */ if (GetRegKeyValue(HKEY_CLASSES_ROOT, pcszClass, g_cszEditFlags, &dwValueType, (PBYTE)&dwEditFlags, &dwcbLen) != ERROR_SUCCESS || (dwValueType != REG_BINARY && dwValueType != REG_DWORD)) dwEditFlags = 0; /* Set or clear SafeOpen flag for file class. */ if (bSet) SET_FLAG(dwEditFlags, dwFlags); else CLEAR_FLAG(dwEditFlags, dwFlags); /* * N.b., we must set this as REG_BINARY because the base Win95 shell32.dll * only accepts REG_BINARY EditFlags. */ bResult = (SetRegKeyValue(HKEY_CLASSES_ROOT, pcszClass, g_cszEditFlags, REG_BINARY, (PCBYTE)&dwEditFlags, sizeof(dwEditFlags)) == ERROR_SUCCESS); if (bResult) TRACE_OUT(("SetClassEditFlags(): Class %s flags %lu %s.", pcszClass, dwFlags, bSet ? "set" : "cleared")); else WARNING_OUT(("SetClassEditFlags(): Failed to %s class %s flags %lu.", bSet ? "set" : "clear", pcszClass, dwFlags)); return(bResult); } #ifdef DEBUG PUBLIC_CODE BOOL IsFullPath(PCSTR pcszPath) { BOOL bResult = FALSE; char rgchFullPath[MAX_PATH_LEN]; if (IS_VALID_STRING_PTR(pcszPath, CSTR) && EVAL(lstrlen(pcszPath) < MAX_PATH_LEN)) { DWORD dwPathLen; PSTR pszFileName; dwPathLen = GetFullPathName(pcszPath, sizeof(rgchFullPath), rgchFullPath, &pszFileName); if (EVAL(dwPathLen > 0) && EVAL(dwPathLen < sizeof(rgchFullPath))) bResult = EVAL(! lstrcmpi(pcszPath, rgchFullPath)); } return(bResult); } #endif /* DEBUG */