You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1666 lines
48 KiB
1666 lines
48 KiB
// --------------------------------------------------------------------------------
|
|
// OERTUTIL.CPP
|
|
// --------------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "dllmain.h"
|
|
|
|
#undef BADSTRFUNCTIONS_H
|
|
#undef lstrcpyA
|
|
#undef lstrcpy
|
|
#define lstrcpy lstrcpyA
|
|
#include <BadStrFunctions.h>
|
|
|
|
#include "strconst.h"
|
|
#include <shlwapi.h>
|
|
#include <shlwapip.h>
|
|
#include <richedit.h>
|
|
#include <shlobj.h>
|
|
#include <shlobjp.h>
|
|
#include <mshtmhst.h>
|
|
#include "demand.h"
|
|
#include "hotwiz.h"
|
|
#include "unicnvrt.h"
|
|
#include "comctrlp.h"
|
|
|
|
int BrowseCallbackProcA(HWND hwnd, UINT msg, LPARAM lParam, LPARAM lpData);
|
|
int BrowseCallbackProcW(HWND hwnd, UINT msg, LPARAM lParam, LPARAM lpData);
|
|
|
|
typedef struct tagBROWSEFOLDERINFOA
|
|
{
|
|
LPCSTR psz;
|
|
BOOL fFileSysOnly;
|
|
} BROWSEFOLDERINFOA;
|
|
|
|
typedef struct tagBROWSEFOLDERINFOW
|
|
{
|
|
LPCWSTR pwsz;
|
|
BOOL fFileSysOnly;
|
|
} BROWSEFOLDERINFOW;
|
|
|
|
//// YST FIX
|
|
// This function returns unique and unpredictable path for temporary files.
|
|
// It fixes some security problem when hacker can run ActiveSetup in known directory, when user open attachment.
|
|
// For fix this we try to save temporery attachment file in unknown directory: in URL Cache dir.
|
|
// This function returns only directory name and user must create and remove file by self.
|
|
// it has also theoretical possibility to loose data at time
|
|
|
|
DWORD AthGetTempUniquePathW( DWORD nBufferLength, // size, in characters, of the buffer
|
|
LPWSTR pwszBuffer ) // pointer to buffer for temp. path
|
|
{
|
|
DWORD nRequired = 0;
|
|
CHAR szBuffer[MAX_PATH + 20];
|
|
LPWSTR pwszBufferToFree = NULL;
|
|
CHAR pszFilePath[MAX_PATH + 1];
|
|
CHAR szFileName[MAX_PATH];
|
|
LPSTR pszFile = NULL;
|
|
LPSTR pszExt = NULL;
|
|
|
|
|
|
Assert(pwszBuffer);
|
|
|
|
//1. Create unique temp file name
|
|
// Get Temp Dir
|
|
if(0 == GetTempPathA(ARRAYSIZE(szBuffer), szBuffer))
|
|
goto err;
|
|
|
|
if (0 == GetTempFileName(szBuffer, "wbk", 0, (LPSTR) pszFilePath))
|
|
{
|
|
err:
|
|
nRequired = 0;
|
|
*pwszBuffer = 0;
|
|
return(nRequired);
|
|
}
|
|
// Find the filename
|
|
pszFile = PathFindFileName(pszFilePath);
|
|
|
|
// Get the Extension
|
|
pszExt = PathFindExtension(pszFilePath);
|
|
|
|
// Copy fileName
|
|
if (pszExt && pszFile && pszExt >= pszFile)
|
|
StrCpyN(szFileName, pszFile, (DWORD) (min((pszExt - pszFile) + 1, ARRAYSIZE(szFileName))));
|
|
else
|
|
StrCpyN(szFileName, pszFile, ARRAYSIZE(szFileName));
|
|
|
|
|
|
// 2. Create bigus URL
|
|
wnsprintf(szBuffer, ARRAYSIZE(szBuffer), "http://%s.bogus", szFileName);
|
|
szBuffer[ARRAYSIZE(szBuffer) - 1] = 0;
|
|
|
|
// 3. Create bogus URL cache entry
|
|
szFileName[0] = 0;
|
|
if (!CreateUrlCacheEntry(szBuffer, 0, NULL, szFileName, 0))
|
|
goto err;
|
|
|
|
// DeleteUrlCacheEntry(szFileName);
|
|
|
|
// Find path for cache
|
|
pszFile = PathFindFileName(szFileName);
|
|
if(pszFile)
|
|
*pszFile = '\0';
|
|
|
|
pwszBufferToFree = PszToUnicode(CP_ACP, szFileName);
|
|
if (pwszBufferToFree)
|
|
{
|
|
nRequired = lstrlenW(pwszBufferToFree);
|
|
|
|
if ( nRequired < nBufferLength)
|
|
CopyMemory(pwszBuffer, pwszBufferToFree, (nRequired+1)*sizeof(WCHAR) );
|
|
else
|
|
{
|
|
nRequired = 0;
|
|
*pwszBuffer = 0;
|
|
}
|
|
}
|
|
else
|
|
*pwszBuffer = 0;
|
|
|
|
// Cleanup
|
|
MemFree(pwszBufferToFree);
|
|
DeleteFile(pszFilePath); // GetTempFileName creates file and we need to remove it
|
|
return nRequired;
|
|
}
|
|
|
|
|
|
/// END YST FIX
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// GenerateUniqueFileName
|
|
// --------------------------------------------------------------------------------
|
|
OESTDAPI_(HRESULT) GenerateUniqueFileName(LPCSTR pszDirectory, LPCSTR pszFileName, LPCSTR pszExtension,
|
|
LPSTR pszFilePath, ULONG cchMaxPath)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cchDirectory;
|
|
ULONG cchFileName;
|
|
ULONG cchExtension;
|
|
CHAR szUnique[10];
|
|
ULONG cchUnique;
|
|
ULONG cbEstimate;
|
|
HANDLE hTemp=INVALID_HANDLE_VALUE;
|
|
DWORD cUnique=0;
|
|
DWORD dwLastError;
|
|
LPCSTR pszSlash;
|
|
|
|
// Invalid Arg
|
|
Assert(pszDirectory && pszFileName && pszExtension && pszFilePath);
|
|
|
|
// Compute lengths
|
|
*szUnique = '\0';
|
|
cchDirectory = lstrlen(pszDirectory);
|
|
cchFileName = lstrlen(pszFileName);
|
|
cchExtension = lstrlen(pszExtension);
|
|
|
|
// Set pszSplashes
|
|
if ('\\' == *CharPrev(pszDirectory, pszDirectory + cchDirectory))
|
|
pszSlash = "";
|
|
else
|
|
pszSlash = "\\";
|
|
|
|
// Try to create the file
|
|
while(1)
|
|
{
|
|
// Compute length of unique post fix
|
|
cchUnique = lstrlen(szUnique);
|
|
|
|
// Do I have room + 1 (
|
|
cbEstimate = cchDirectory + cchFileName + cchExtension + cchUnique;
|
|
|
|
// Too Big
|
|
if (cbEstimate + 1 > cchMaxPath)
|
|
{
|
|
LengFail:
|
|
Assert(FALSE);
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
while(cbEstimate > (MAX_PATH - 4))
|
|
{
|
|
if((cchUnique + cchDirectory) >= (MAX_PATH - 7))
|
|
goto LengFail;
|
|
else if(cchFileName > 2)
|
|
{
|
|
pszFileName = CharNext(pszFileName);
|
|
cchFileName = lstrlen(pszFileName);
|
|
}
|
|
else if(cchExtension > 2)
|
|
{
|
|
pszExtension = CharNext(pszExtension);
|
|
cchExtension = lstrlen(pszExtension);
|
|
}
|
|
else
|
|
goto LengFail;
|
|
|
|
cbEstimate = cchDirectory + cchFileName + cchExtension + cchUnique;
|
|
}
|
|
// Build the file path
|
|
if (0 == cchUnique)
|
|
wnsprintf(pszFilePath, cchMaxPath, "%s%s%s%s", pszDirectory, pszSlash, pszFileName, pszExtension);
|
|
else
|
|
wnsprintf(pszFilePath, cchMaxPath, "%s%s%s (%s)%s", pszDirectory, pszSlash, pszFileName, szUnique, pszExtension);
|
|
|
|
// Open the File
|
|
hTemp = CreateFile(pszFilePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL , NULL);
|
|
if (INVALID_HANDLE_VALUE != hTemp)
|
|
{
|
|
// confirm that what we had is a file
|
|
CloseHandle(hTemp);
|
|
hTemp = INVALID_HANDLE_VALUE;
|
|
if (DeleteFile(pszFilePath))
|
|
{
|
|
hTemp = CreateFile(pszFilePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL , NULL);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Get the last error
|
|
dwLastError = GetLastError();
|
|
|
|
// If it didn't fail because ERROR_ALREADY_EXISTS, then fail
|
|
if (ERROR_ALREADY_EXISTS != dwLastError && ERROR_FILE_EXISTS != dwLastError)
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Increment cUnique
|
|
cUnique++;
|
|
|
|
// Format szUnique
|
|
wnsprintf(szUnique, ARRAYSIZE(szUnique), "%d", cUnique);
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
if (INVALID_HANDLE_VALUE != hTemp)
|
|
CloseHandle(hTemp);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CreateTempFile
|
|
// --------------------------------------------------------------------------------
|
|
OESTDAPI_(HRESULT) CreateTempFile(LPCSTR pszSuggest, LPCSTR pszExtension, LPSTR *ppszFilePath, HANDLE *phFile)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szTempDir[MAX_PATH];
|
|
WCHAR wszTempDir[MAX_PATH];
|
|
CHAR szFileName[MAX_PATH];
|
|
LPSTR pszFilePath=NULL;
|
|
LPSTR pszFile;
|
|
LPSTR pszExt;
|
|
ULONG cbAlloc;
|
|
|
|
// Invalid Arg
|
|
Assert(ppszFilePath && phFile);
|
|
|
|
// Init
|
|
*phFile = INVALID_HANDLE_VALUE;
|
|
|
|
// Create a temp file stream in URL cache
|
|
if(AthGetTempUniquePathW(ARRAYSIZE(wszTempDir), wszTempDir))
|
|
{
|
|
LPSTR pszAnsiStr = PszToANSI(CP_ACP, wszTempDir);
|
|
if (!pszAnsiStr)
|
|
goto exit;
|
|
StrCpyN(szTempDir, pszAnsiStr, ARRAYSIZE(szTempDir));
|
|
MemFree(pszAnsiStr);
|
|
}
|
|
// If cannot find URL cache try TEMP dir
|
|
else
|
|
{
|
|
DWORD nBufferLength = GetTempPath(ARRAYSIZE(szTempDir), szTempDir);
|
|
|
|
if (nBufferLength == 0 || nBufferLength > ARRAYSIZE(szTempDir))
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Compute Max Size of pszFilePath
|
|
cbAlloc = MAX_PATH + lstrlen(szTempDir);
|
|
if (pszSuggest)
|
|
cbAlloc += lstrlen(pszSuggest);
|
|
if (pszExtension)
|
|
cbAlloc += lstrlen(pszExtension);
|
|
|
|
// Allocate m_pszNeedFile
|
|
CHECKALLOC(pszFilePath = PszAllocA(cbAlloc + 1));
|
|
|
|
// Create a unique file path with suggested pszFileName and pszExtension
|
|
if (NULL != pszSuggest)
|
|
{
|
|
// Find the filename
|
|
pszFile = PathFindFileName(pszSuggest);
|
|
|
|
// Get the Extension
|
|
pszExt = PathFindExtension(pszSuggest);
|
|
|
|
// If no pszExtension, use extension from pszSuggest
|
|
if (NULL == pszExtension)
|
|
pszExtension = pszExt ? pszExt : (LPSTR)c_szDotDat;
|
|
|
|
// Copy fileName
|
|
if (pszExt && pszFile && pszExt >= pszFile)
|
|
StrCpyN(szFileName, pszFile, (DWORD) (min((pszExt - pszFile) - 1, ARRAYSIZE(szFileName))));
|
|
else
|
|
StrCpyN(szFileName, pszSuggest, ARRAYSIZE(szFileName));
|
|
|
|
// Fixup szTempDir
|
|
if (szTempDir[lstrlen(szTempDir) - 1] != '\\')
|
|
StrCatBuff(szTempDir, "\\", ARRAYSIZE(szTempDir));
|
|
|
|
// GenerateUniqueFileName
|
|
hr = GenerateUniqueFileName(szTempDir, szFileName, pszExtension, pszFilePath, cbAlloc);
|
|
}
|
|
|
|
// If no filename and no extension or suggested name failed, just use the windows function
|
|
if ((NULL == pszSuggest) || FAILED(hr))
|
|
{
|
|
hr = S_OK;
|
|
|
|
// Get Temp File Name
|
|
if (0 == GetTempFileName(szTempDir, "wbk", 0, pszFilePath))
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Open the File
|
|
*phFile = CreateFile(pszFilePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL , NULL);
|
|
if (INVALID_HANDLE_VALUE == *phFile)
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// SetReturn
|
|
*ppszFilePath = pszFilePath;
|
|
pszFilePath = NULL;
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pszFilePath);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// WriteStreamToFileHandle
|
|
// --------------------------------------------------------------------------------
|
|
OESTDAPI_(HRESULT) WriteStreamToFileHandle(IStream *pStream, HANDLE hFile, ULONG *pcbTotal)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cbRead;
|
|
ULONG cbTotal=0;
|
|
BYTE rgbBuffer[2048];
|
|
ULONG cbWrote;
|
|
|
|
// Invalid Arg
|
|
if(!pStream || !hFile || (hFile == INVALID_HANDLE_VALUE))
|
|
{
|
|
Assert(FALSE);
|
|
return(E_INVALIDARG);
|
|
}
|
|
|
|
// Dump pStream to hFile
|
|
while(1)
|
|
{
|
|
// Read a blob
|
|
CHECKHR(hr = pStream->Read(rgbBuffer, sizeof(rgbBuffer), &cbRead));
|
|
|
|
// Done
|
|
if (0 == cbRead)
|
|
break;
|
|
|
|
// Write to the file
|
|
if (0 == WriteFile(hFile, rgbBuffer, cbRead, &cbWrote, NULL))
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Count Bytes
|
|
cbTotal += cbWrote;
|
|
}
|
|
|
|
// Return Total
|
|
if (pcbTotal)
|
|
*pcbTotal = cbTotal;
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// DeleteTempFile
|
|
// --------------------------------------------------------------------------------
|
|
OESTDAPI_(HRESULT) DeleteTempFile(LPTEMPFILEINFO pTempFile)
|
|
{
|
|
// Locals
|
|
BOOL fDeleted;
|
|
DWORD dwAttributes;
|
|
|
|
// If NULL, assume the file has been deleted
|
|
if (NULL == pTempFile->pszFilePath)
|
|
return S_OK;
|
|
|
|
// Have we launched a process on this temp file which is still running?
|
|
if (pTempFile->hProcess && WAIT_OBJECT_0 != WaitForSingleObject(pTempFile->hProcess, 0))
|
|
return S_FALSE; // This file is probably still in use: won't delete
|
|
|
|
// First check if this is a file or a directory, then terminate it
|
|
dwAttributes = GetFileAttributes(pTempFile->pszFilePath);
|
|
if (0xFFFFFFFF != dwAttributes && (FILE_ATTRIBUTE_DIRECTORY & dwAttributes))
|
|
fDeleted = RemoveDirectory(pTempFile->pszFilePath);
|
|
else
|
|
fDeleted = DeleteFile(pTempFile->pszFilePath);
|
|
|
|
// Done
|
|
return fDeleted ? S_OK : S_FALSE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// AppendTempFileList
|
|
// --------------------------------------------------------------------------------
|
|
OESTDAPI_(HRESULT) AppendTempFileList(LPTEMPFILEINFO *ppHead, LPSTR pszFilePath, HANDLE hProcess)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPTEMPFILEINFO pTempFile, pInsertionPt;
|
|
|
|
// Allocate pTempFile
|
|
CHECKALLOC(pTempFile = (LPTEMPFILEINFO)g_pMalloc->Alloc(sizeof(TEMPFILEINFO)));
|
|
|
|
// Fill in the fields
|
|
ZeroMemory(pTempFile, sizeof(TEMPFILEINFO));
|
|
pTempFile->pszFilePath = pszFilePath;
|
|
pTempFile->hProcess = hProcess;
|
|
pTempFile->pNext = NULL;
|
|
|
|
// Insert new record at the end of the linked list
|
|
pInsertionPt = *ppHead;
|
|
if (NULL == pInsertionPt)
|
|
// Insert record into empty linked list
|
|
(*ppHead) = pTempFile;
|
|
else
|
|
{
|
|
// Insert record at end of linked list
|
|
while (NULL != pInsertionPt->pNext)
|
|
pInsertionPt = pInsertionPt->pNext;
|
|
|
|
pInsertionPt->pNext = pTempFile;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// DeleteTempFileOnShutdown
|
|
// --------------------------------------------------------------------------------
|
|
OESTDAPI_(VOID) DeleteTempFileOnShutdown(LPTEMPFILEINFO pTempFile)
|
|
{
|
|
LPTEMPFILEINFO pInsertionPt;
|
|
|
|
Assert(NULL != pTempFile && NULL == pTempFile->pNext);
|
|
|
|
// Enter global Critical Section
|
|
EnterCriticalSection(&g_csTempFileList);
|
|
|
|
// Insert new record at the end of the global linked list
|
|
pTempFile->pNext = NULL;
|
|
pInsertionPt = g_pTempFileHead;
|
|
if (NULL == pInsertionPt)
|
|
// Insert record into empty linked list
|
|
g_pTempFileHead = pTempFile;
|
|
else
|
|
{
|
|
// Insert record at end of linked list
|
|
while (NULL != pInsertionPt->pNext)
|
|
pInsertionPt = pInsertionPt->pNext;
|
|
|
|
pInsertionPt->pNext = pTempFile;
|
|
}
|
|
|
|
// Leave global Critical Section
|
|
LeaveCriticalSection(&g_csTempFileList);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// DeleteTempFileOnShutdownEx
|
|
// --------------------------------------------------------------------------------
|
|
OESTDAPI_(VOID) DeleteTempFileOnShutdownEx(LPSTR pszFilePath, HANDLE hProcess)
|
|
{
|
|
// Enter global Critical Section
|
|
EnterCriticalSection(&g_csTempFileList);
|
|
|
|
// Append to globa list
|
|
AppendTempFileList(&g_pTempFileHead, pszFilePath, hProcess);
|
|
|
|
// Enter global Critical Section
|
|
LeaveCriticalSection(&g_csTempFileList);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CleanupGlobalTempFiles
|
|
// --------------------------------------------------------------------------------
|
|
OESTDAPI_(VOID) CleanupGlobalTempFiles(void)
|
|
{
|
|
// Locals
|
|
LPTEMPFILEINFO pCurrent;
|
|
LPTEMPFILEINFO pNext;
|
|
|
|
// Enter global Critical Section
|
|
EnterCriticalSection(&g_csTempFileList);
|
|
|
|
// Init
|
|
pCurrent = g_pTempFileHead;
|
|
|
|
// Do the loop
|
|
while(pCurrent)
|
|
{
|
|
// Save Next
|
|
pNext = pCurrent->pNext;
|
|
|
|
// Delete the temp file
|
|
DeleteTempFile(pCurrent);
|
|
|
|
// Free file name
|
|
SafeMemFree(pCurrent->pszFilePath);
|
|
|
|
// Free pCurrent
|
|
g_pMalloc->Free(pCurrent);
|
|
|
|
// Goto Next
|
|
pCurrent = pNext;
|
|
}
|
|
|
|
// Null the head
|
|
g_pTempFileHead = NULL;
|
|
|
|
// Leave global Critical Section
|
|
LeaveCriticalSection(&g_csTempFileList);
|
|
}
|
|
|
|
// QFE 2522
|
|
#define EXT_SIZE 4
|
|
#define TMP_SIZE 10
|
|
|
|
// =====================================================================================
|
|
// FBuildTempPath
|
|
// =====================================================================================
|
|
BOOL FBuildTempPath(LPTSTR lpszOrigFile, LPTSTR lpszPath, ULONG cbMaxPath, BOOL fLink)
|
|
{
|
|
LPWSTR lpszOrigFileW = PszToUnicode(CP_ACP, lpszOrigFile);
|
|
LPWSTR lpszPathW = NULL;
|
|
BOOL result = FALSE;
|
|
|
|
if (!lpszOrigFileW)
|
|
return result;
|
|
|
|
MemAlloc((LPVOID *) &lpszPathW, sizeof(WCHAR) * cbMaxPath);
|
|
if (lpszPathW)
|
|
{
|
|
result = FBuildTempPathW(lpszOrigFileW, lpszPathW, cbMaxPath, fLink);
|
|
if (result)
|
|
WideCharToMultiByte(CP_ACP, 0, lpszPathW, -1, lpszPath, cbMaxPath, NULL, NULL);
|
|
}
|
|
|
|
MemFree(lpszOrigFileW);
|
|
MemFree(lpszPathW);
|
|
return result;
|
|
}
|
|
|
|
|
|
BOOL FBuildTempPathW(LPWSTR lpszOrigFile, LPWSTR lpszPath, ULONG cchMaxPath, BOOL fLink)
|
|
{
|
|
// Locals
|
|
INT i;
|
|
WCHAR *pszName,
|
|
*pszExt,
|
|
*pszOrigFileTemp = NULL,
|
|
szName[MAX_PATH],
|
|
szTempDir[MAX_PATH];
|
|
|
|
// Check Params
|
|
AssertSz(lpszOrigFile && lpszPath, "Null Parameter");
|
|
|
|
// Get Temp Path
|
|
if(!AthGetTempUniquePathW(ARRAYSIZE(szTempDir), szTempDir))
|
|
szTempDir[0] = L'\0';
|
|
|
|
int nTmp = lstrlenW(szTempDir);
|
|
if(nTmp >= (((int) cchMaxPath) - TMP_SIZE - EXT_SIZE - 1))
|
|
{
|
|
StrCpyNW(szTempDir, L"\\", ARRAYSIZE(szTempDir));
|
|
nTmp = lstrlenW(szTempDir);
|
|
}
|
|
|
|
DWORD cchSize = (lstrlenW(lpszOrigFile) + 1);
|
|
if (!MemAlloc((LPVOID *) &pszOrigFileTemp, sizeof(WCHAR) * cchSize) ||
|
|
(lpszOrigFile == NULL))
|
|
return(FALSE);
|
|
|
|
StrCpyNW(pszOrigFileTemp, lpszOrigFile, cchSize);
|
|
|
|
// Get the file name and extension
|
|
pszName = PathFindFileNameW(pszOrigFileTemp);
|
|
Assert(!FIsEmptyW(pszName));
|
|
|
|
pszExt = PathFindExtensionW(pszOrigFileTemp);
|
|
|
|
if(nTmp + lstrlenW(pszName) + lstrlenW(pszExt)> (((int) cchMaxPath) - TMP_SIZE)) // QFE 2522
|
|
{
|
|
if(nTmp + lstrlenW(pszExt) > (((int) cchMaxPath) - TMP_SIZE))
|
|
pszExt[0] = L'\0';
|
|
|
|
// Truncate anything that won't fit in the buffer passed in
|
|
if(lstrlenW(pszName) >= ((int) cchMaxPath) - (nTmp + lstrlenW(pszExt) + TMP_SIZE + 1))
|
|
*(pszName + ((int) cchMaxPath) - (nTmp + lstrlenW(pszExt) + TMP_SIZE + 1)) = '\0';
|
|
}
|
|
|
|
if (*pszExt != 0)
|
|
{
|
|
Assert(*pszExt == L'.');
|
|
*pszExt = 0;
|
|
StrCpyNW(szName, pszName, ARRAYSIZE(szName));
|
|
*pszExt = L'.';
|
|
}
|
|
else
|
|
{
|
|
StrCpyNW(szName, pszName, ARRAYSIZE(szName));
|
|
}
|
|
|
|
if (fLink)
|
|
pszExt = (LPWSTR)c_szLnkExt;
|
|
|
|
// Make first attemp file name
|
|
Assert (szTempDir[lstrlenW(szTempDir)-1] == L'\\');
|
|
Assert(cchMaxPath >= (ULONG)(lstrlenW(szTempDir) + lstrlenW(szName) + lstrlenW(pszExt) + TMP_SIZE));
|
|
|
|
StrCpyNW(lpszPath, szTempDir, cchMaxPath);
|
|
StrCatBuffW(lpszPath, szName, cchMaxPath);
|
|
StrCatBuffW(lpszPath, pszExt, cchMaxPath);
|
|
|
|
// If it doesn't exist, were done
|
|
if (PathFileExistsW(lpszPath) == FALSE)
|
|
{
|
|
MemFree(pszOrigFileTemp);
|
|
return(TRUE);
|
|
}
|
|
|
|
// Loop to find a temp name that doesn't exist
|
|
for (i=1; i<100 ;i++)
|
|
{
|
|
// Build new path
|
|
wnsprintfW(lpszPath, cchMaxPath, L"%s%s (%d)%s", szTempDir, szName, i, pszExt);
|
|
|
|
// If it doesn't exist, were done
|
|
if (PathFileExistsW(lpszPath) == FALSE)
|
|
{
|
|
MemFree(pszOrigFileTemp);
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
// Done
|
|
MemFree(pszOrigFileTemp);
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
void FreeTempFileList(LPTEMPFILEINFO pTempFileHead)
|
|
{
|
|
// Locals
|
|
LPTEMPFILEINFO pCurrent;
|
|
LPTEMPFILEINFO pNext;
|
|
|
|
// Init
|
|
pCurrent = pTempFileHead;
|
|
|
|
// Do the loop
|
|
while(pCurrent)
|
|
{
|
|
// Save Next
|
|
pNext = pCurrent->pNext;
|
|
|
|
// If not deleted, append to global file list
|
|
if (S_FALSE == DeleteTempFile(pCurrent))
|
|
{
|
|
// MSOERT maintains a list of global temp files to be killed on shutdown
|
|
DeleteTempFileOnShutdown(pCurrent);
|
|
}
|
|
|
|
// Otherwise, delete this node
|
|
else
|
|
{
|
|
// Free file name
|
|
SafeMemFree(pCurrent->pszFilePath);
|
|
|
|
// Free pCurrent
|
|
g_pMalloc->Free(pCurrent);
|
|
}
|
|
|
|
// Goto Next
|
|
pCurrent = pNext;
|
|
}
|
|
}
|
|
|
|
|
|
DWORD CALLBACK EditStreamInCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG FAR *pcb)
|
|
{
|
|
AssertSz(dwCookie, "Houston, we have a problem...");
|
|
((LPSTREAM)dwCookie)->Read(pbBuff, cb, (ULONG *)pcb);
|
|
#ifdef DEBUG
|
|
// validate for the richedit bug...
|
|
// if we put a \r in the richedit as the last char without a \n
|
|
// ie not a \r\n pair, it bithces and faults...
|
|
if(*pcb && *pcb<cb)
|
|
AssertSz(pbBuff[(*pcb)-1]!='\r', "is this the richedit bug??");
|
|
#endif
|
|
return NOERROR;
|
|
}
|
|
|
|
DWORD CALLBACK EditStreamOutCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG FAR *pcb)
|
|
{
|
|
return ((LPSTREAM)dwCookie)->Write(pbBuff, cb, (ULONG *)pcb);
|
|
}
|
|
|
|
|
|
HRESULT RicheditStreamIn(HWND hwndRE, LPSTREAM pstm, ULONG uSelFlags)
|
|
{
|
|
EDITSTREAM es;
|
|
|
|
if(!pstm)
|
|
return E_INVALIDARG;
|
|
|
|
if(!IsWindow(hwndRE))
|
|
return E_INVALIDARG;
|
|
|
|
HrRewindStream(pstm);
|
|
|
|
es.dwCookie = (DWORD_PTR)pstm;
|
|
es.pfnCallback=(EDITSTREAMCALLBACK)EditStreamInCallback;
|
|
SendMessage(hwndRE, EM_STREAMIN, uSelFlags, (LPARAM)&es);
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT RicheditStreamOut(HWND hwndRE, LPSTREAM pstm, ULONG uSelFlags)
|
|
{
|
|
EDITSTREAM es;
|
|
|
|
if(!pstm)
|
|
return E_INVALIDARG;
|
|
|
|
if(!IsWindow(hwndRE))
|
|
return E_INVALIDARG;
|
|
|
|
es.dwCookie = (DWORD_PTR)pstm;
|
|
es.pfnCallback=(EDITSTREAMCALLBACK)EditStreamOutCallback;
|
|
SendMessage(hwndRE, EM_STREAMOUT, uSelFlags, (LPARAM)&es);
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
HRESULT ShellUtil_GetSpecialFolderPath(DWORD dwSpecialFolder, LPSTR rgchPath)
|
|
{
|
|
LPITEMIDLIST pidl = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (SHGetSpecialFolderLocation(NULL, dwSpecialFolder, &pidl)==S_OK)
|
|
{
|
|
if (SHGetPathFromIDList(pidl, rgchPath))
|
|
hr = S_OK;
|
|
|
|
SHFree(pidl);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
* CenterDialog
|
|
*
|
|
* Purpose:
|
|
* This function centers a dialog with respect to its parent
|
|
* dialog.
|
|
*
|
|
* Parameters:
|
|
* hwndDlg hwnd of the dialog to center
|
|
*/
|
|
VOID CenterDialog(HWND hwndDlg)
|
|
{
|
|
HWND hwndOwner;
|
|
RECT rc;
|
|
RECT rcDlg;
|
|
RECT rcOwner;
|
|
RECT rcWork;
|
|
INT x;
|
|
INT y;
|
|
INT nAdjust;
|
|
|
|
// Get the working area rectangle
|
|
SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0);
|
|
|
|
// Get the owner window and dialog box rectangles.
|
|
// The window rect of the destop window is in trouble on multimonitored
|
|
// macs. GetWindow only gets the main screen.
|
|
if (hwndOwner = GetParent(hwndDlg))
|
|
GetWindowRect(hwndOwner, &rcOwner);
|
|
else
|
|
rcOwner = rcWork;
|
|
|
|
GetWindowRect(hwndDlg, &rcDlg);
|
|
rc = rcOwner;
|
|
|
|
// Offset the owner and dialog box rectangles so that
|
|
// right and bottom values represent the width and
|
|
// height, and then offset the owner again to discard
|
|
// space taken up by the dialog box.
|
|
OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
|
|
OffsetRect(&rc, -rc.left, -rc.top);
|
|
OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
|
|
|
|
// The new position is the sum of half the remaining
|
|
// space and the owner's original position.
|
|
// But not less than Zero - jefbai
|
|
|
|
x= rcOwner.left + (rc.right / 2);
|
|
y= rcOwner.top + (rc.bottom / 2);
|
|
|
|
// Make sure the dialog doesn't go off the right edge of the screen
|
|
nAdjust = rcWork.right - (x + rcDlg.right);
|
|
if (nAdjust < 0)
|
|
x += nAdjust;
|
|
|
|
//$ Raid 5128: Make sure the left edge is visible
|
|
if (x < rcWork.left)
|
|
x = rcWork.left;
|
|
|
|
// Make sure the dialog doesn't go off the bottom edge of the screen
|
|
nAdjust = rcWork.bottom - (y + rcDlg.bottom);
|
|
if (nAdjust < 0)
|
|
y += nAdjust;
|
|
|
|
//$ Raid 5128: Make sure the top edge is visible
|
|
if (y < rcWork.top)
|
|
y = rcWork.top;
|
|
SetWindowPos(hwndDlg, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
}
|
|
|
|
|
|
void SetIntlFont(HWND hwnd)
|
|
{
|
|
HFONT hfont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
|
|
if (hfont == NULL)
|
|
hfont = (HFONT)GetStockObject(SYSTEM_FONT);
|
|
if (hfont != NULL)
|
|
SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
|
|
}
|
|
|
|
|
|
|
|
// See whether entire string will fit in *prc; if not, compute number of chars
|
|
// that will fit, including ellipses. Returns length of string in *pcchDraw.
|
|
//
|
|
BOOL NeedsEllipses(HDC hdc, LPCTSTR pszText, RECT FAR* prc, int FAR* pcchDraw, int cxEllipses)
|
|
{
|
|
int cchText;
|
|
int cxRect;
|
|
int ichMin, ichMax, ichMid;
|
|
SIZE siz;
|
|
#if !defined(UNICODE) // && defined(DBCS)
|
|
LPCTSTR lpsz;
|
|
#endif
|
|
|
|
cxRect = prc->right - prc->left;
|
|
|
|
cchText = lstrlen(pszText);
|
|
|
|
if (cchText == 0)
|
|
{
|
|
*pcchDraw = cchText;
|
|
return FALSE;
|
|
}
|
|
|
|
GetTextExtentPoint32(hdc, pszText, cchText, &siz);
|
|
|
|
if (siz.cx <= cxRect)
|
|
{
|
|
*pcchDraw = cchText;
|
|
return FALSE;
|
|
}
|
|
|
|
cxRect -= cxEllipses;
|
|
|
|
// If no room for ellipses, always show first character.
|
|
//
|
|
ichMax = 1;
|
|
if (cxRect > 0)
|
|
{
|
|
// Binary search to find character that will fit
|
|
ichMin = 0;
|
|
ichMax = cchText;
|
|
while (ichMin < ichMax)
|
|
{
|
|
// Be sure to round up, to make sure we make progress in
|
|
// the loop if ichMax == ichMin + 1.
|
|
//
|
|
ichMid = (ichMin + ichMax + 1) / 2;
|
|
|
|
GetTextExtentPoint32(hdc, &pszText[ichMin], ichMid - ichMin, &siz);
|
|
|
|
if (siz.cx < cxRect)
|
|
{
|
|
ichMin = ichMid;
|
|
cxRect -= siz.cx;
|
|
}
|
|
else if (siz.cx > cxRect)
|
|
{
|
|
ichMax = ichMid - 1;
|
|
}
|
|
else
|
|
{
|
|
// Exact match up up to ichMid: just exit.
|
|
//
|
|
ichMax = ichMid;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Make sure we always show at least the first character...
|
|
//
|
|
if (ichMax < 1)
|
|
ichMax = 1;
|
|
}
|
|
|
|
#if !defined(UNICODE) // && defined(DBCS)
|
|
// b#8934
|
|
lpsz = &pszText[ichMax];
|
|
while ( lpsz-- > pszText )
|
|
{
|
|
if (!IsDBCSLeadByte(*lpsz))
|
|
break;
|
|
}
|
|
ichMax += ( (&pszText[ichMax] - lpsz) & 1 ) ? 0: 1;
|
|
#endif
|
|
|
|
*pcchDraw = ichMax;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
#define CCHELLIPSES 3
|
|
#define CCHLABELMAX MAX_PATH
|
|
|
|
|
|
void IDrawText(HDC hdc, LPCTSTR pszText, RECT FAR* prc, BOOL fEllipses, int cyChar)
|
|
{
|
|
int cchText,
|
|
cxEllipses;
|
|
RECT rc;
|
|
TCHAR ach[CCHLABELMAX + CCHELLIPSES];
|
|
SIZE sze;
|
|
|
|
// REVIEW: Performance idea:
|
|
// We could cache the currently selected text color
|
|
// so we don't have to set and restore it each time
|
|
// when the color is the same.
|
|
//
|
|
if (!pszText)
|
|
return;
|
|
|
|
if (IsRectEmpty(prc))
|
|
return;
|
|
|
|
|
|
rc = *prc;
|
|
|
|
if(fEllipses)
|
|
{
|
|
GetTextExtentPoint32(hdc, g_szEllipsis, lstrlen(g_szEllipsis), &sze);
|
|
cxEllipses=sze.cx;
|
|
}
|
|
|
|
if ((fEllipses) &&
|
|
NeedsEllipses(hdc, pszText, &rc, &cchText, cxEllipses))
|
|
{
|
|
// In some cases cchText was comming back bigger than
|
|
// ARRYASIZE(ach), so we need to make sure we don't overflow the buffer
|
|
|
|
// if cchText is too big for the buffer, truncate it down to size
|
|
if (cchText >= ARRAYSIZE(ach) - CCHELLIPSES)
|
|
cchText = ARRAYSIZE(ach) - CCHELLIPSES - 1;
|
|
|
|
memcpy(ach, pszText, cchText * sizeof(TCHAR));
|
|
StrCpyN(ach + cchText, g_szEllipsis, (ARRAYSIZE(ach) - cchText));
|
|
|
|
pszText = ach;
|
|
cchText += CCHELLIPSES;
|
|
}
|
|
else
|
|
{
|
|
cchText = lstrlen(pszText);
|
|
}
|
|
|
|
// Center vertically in case the bitmap (to the left) is larger than
|
|
// the height of one line
|
|
if (cyChar)
|
|
rc.top += (rc.bottom - rc.top - cyChar) / 2;
|
|
ExtTextOut(hdc, rc.left, rc.top, 0, prc, pszText, cchText, NULL);
|
|
}
|
|
|
|
|
|
BOOL FIsHTMLFile(LPSTR pszFile)
|
|
{
|
|
int cch;
|
|
|
|
if(pszFile==NULL)
|
|
return FALSE;
|
|
|
|
cch = lstrlen(pszFile);
|
|
|
|
if ((cch > 4 && lstrcmpi(&pszFile[cch-4], ".htm")==0) ||
|
|
(cch > 5 && lstrcmpi(&pszFile[cch-5], ".html")==0))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL FIsHTMLFileW(LPWSTR pwszFile)
|
|
{
|
|
int cch;
|
|
|
|
if(pwszFile==NULL)
|
|
return FALSE;
|
|
|
|
cch = lstrlenW(pwszFile);
|
|
|
|
if ((cch > 4 && StrCmpIW(&pwszFile[cch-4], L".htm")==0) ||
|
|
(cch > 5 && StrCmpIW(&pwszFile[cch-5], L".html")==0))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL GetExePath(LPCTSTR szExe, TCHAR *szPath, DWORD cch, BOOL fDirOnly)
|
|
{
|
|
BOOL fRet;
|
|
HKEY hkey;
|
|
DWORD dwType, cb;
|
|
TCHAR sz[MAX_PATH], szT[MAX_PATH];
|
|
|
|
Assert(szExe != NULL);
|
|
Assert(szPath != NULL);
|
|
|
|
fRet = FALSE;
|
|
|
|
wnsprintf(sz, ARRAYSIZE(sz), c_szPathFileFmt, c_szAppPaths, szExe);
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, sz, 0, KEY_QUERY_VALUE, &hkey))
|
|
{
|
|
cb = sizeof(szT);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, fDirOnly ? c_szRegPath : NULL, 0, &dwType, (LPBYTE)szT, &cb) && cb)
|
|
{
|
|
if (dwType == REG_EXPAND_SZ)
|
|
{
|
|
cb = ExpandEnvironmentStrings(szT, szPath, cch);
|
|
if (cb != 0 && cb <= cch)
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
Assert(dwType == REG_SZ);
|
|
StrCpyN(szPath, szT, cch);
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
|
|
int MessageBoxInstW(HINSTANCE hInst, HWND hwndOwner, LPWSTR pwszTitle, LPWSTR pwsz1, LPWSTR pwsz2, UINT fuStyle,
|
|
PFLOADSTRINGW pfLoadStringW, PFMESSAGEBOXW pfMessageBoxW)
|
|
{
|
|
WCHAR wszTitle[CCHMAX_STRINGRES];
|
|
WCHAR wszText[2 * CCHMAX_STRINGRES + 2];
|
|
int cch;
|
|
|
|
Assert(pwsz1);
|
|
Assert(pwszTitle != NULL);
|
|
|
|
if (!(fuStyle & MB_ICONEXCLAMATION) &&
|
|
!(fuStyle & MB_ICONWARNING) &&
|
|
!(fuStyle & MB_ICONINFORMATION) &&
|
|
!(fuStyle & MB_ICONASTERISK) &&
|
|
//!(fuStyle & MB_ICONQUESTION) && // BUG: 18105
|
|
!(fuStyle & MB_ICONSTOP) &&
|
|
!(fuStyle & MB_ICONERROR) &&
|
|
!(fuStyle & MB_ICONHAND))
|
|
{
|
|
if (fuStyle & MB_OK)
|
|
fuStyle |= MB_ICONINFORMATION;
|
|
else if (fuStyle & MB_YESNO || fuStyle & MB_YESNOCANCEL || fuStyle & MB_OKCANCEL)
|
|
fuStyle |= MB_ICONEXCLAMATION; // BUG 18105 MB_ICONQUESTION;
|
|
else if (fuStyle & MB_RETRYCANCEL || fuStyle & MB_ABORTRETRYIGNORE)
|
|
fuStyle |= MB_ICONWARNING;
|
|
else
|
|
fuStyle |= MB_ICONWARNING;
|
|
}
|
|
|
|
if (IS_INTRESOURCE(pwszTitle))
|
|
{
|
|
// its a string resource id
|
|
cch = pfLoadStringW(hInst, PtrToUlong(pwszTitle), wszTitle, ARRAYSIZE(wszTitle));
|
|
if (cch == 0)
|
|
return(0);
|
|
|
|
pwszTitle = wszTitle;
|
|
}
|
|
|
|
if (!(IS_INTRESOURCE(pwsz1)))
|
|
{
|
|
// its a pointer to a string
|
|
Assert(lstrlenW(pwsz1) < CCHMAX_STRINGRES);
|
|
if (NULL == StrCpyNW(wszText, pwsz1, ARRAYSIZE(wszText)))
|
|
return(0);
|
|
|
|
cch = lstrlenW(wszText);
|
|
}
|
|
else
|
|
{
|
|
// its a string resource id
|
|
cch = pfLoadStringW(hInst, PtrToUlong(pwsz1), wszText, ARRAYSIZE(wszText)-2);
|
|
if (cch == 0)
|
|
return(0);
|
|
}
|
|
|
|
if (pwsz2)
|
|
{
|
|
// there's another string that we need to append to the
|
|
// first string...
|
|
wszText[cch++] = L'\n';
|
|
wszText[cch++] = L'\n';
|
|
|
|
if (!(IS_INTRESOURCE(pwsz2)))
|
|
{
|
|
// its a pointer to a string
|
|
Assert(lstrlenW(pwsz2) < CCHMAX_STRINGRES);
|
|
if (NULL == StrCpyNW(&wszText[cch], pwsz2, (ARRAYSIZE(wszText) - cch)))
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
int cchTemp = ARRAYSIZE(wszText) - cch;
|
|
Assert(cchTemp > 0);
|
|
if (0 == pfLoadStringW(hInst, PtrToUlong(pwsz2), &wszText[cch], cchTemp))
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
return(pfMessageBoxW(hwndOwner, wszText, pwszTitle, MB_SETFOREGROUND | fuStyle));
|
|
}
|
|
|
|
int MessageBoxInst(HINSTANCE hInst, HWND hwndOwner, LPTSTR pszTitle, LPTSTR psz1, LPTSTR psz2, UINT fuStyle)
|
|
{
|
|
TCHAR szTitle[CCHMAX_STRINGRES];
|
|
TCHAR szText[2 * CCHMAX_STRINGRES + 2];
|
|
int cch;
|
|
|
|
Assert(psz1);
|
|
Assert(pszTitle != NULL);
|
|
|
|
if (!(fuStyle & MB_ICONEXCLAMATION) &&
|
|
!(fuStyle & MB_ICONWARNING) &&
|
|
!(fuStyle & MB_ICONINFORMATION) &&
|
|
!(fuStyle & MB_ICONASTERISK) &&
|
|
//!(fuStyle & MB_ICONQUESTION) && // BUG: 18105
|
|
!(fuStyle & MB_ICONSTOP) &&
|
|
!(fuStyle & MB_ICONERROR) &&
|
|
!(fuStyle & MB_ICONHAND))
|
|
{
|
|
if (fuStyle & MB_OK)
|
|
fuStyle |= MB_ICONINFORMATION;
|
|
else if (fuStyle & MB_YESNO || fuStyle & MB_YESNOCANCEL || fuStyle & MB_OKCANCEL)
|
|
fuStyle |= MB_ICONEXCLAMATION; // BUG 18105 MB_ICONQUESTION;
|
|
else if (fuStyle & MB_RETRYCANCEL || fuStyle & MB_ABORTRETRYIGNORE)
|
|
fuStyle |= MB_ICONWARNING;
|
|
else
|
|
fuStyle |= MB_ICONWARNING;
|
|
}
|
|
|
|
if (IS_INTRESOURCE(pszTitle))
|
|
{
|
|
// its a string resource id
|
|
cch = LoadString(hInst, PtrToUlong(pszTitle), szTitle, ARRAYSIZE(szTitle));
|
|
if (cch == 0)
|
|
return(0);
|
|
|
|
pszTitle = szTitle;
|
|
}
|
|
|
|
if (!(IS_INTRESOURCE(psz1)))
|
|
{
|
|
// its a pointer to a string
|
|
// Assert(lstrlen(psz1) < CCHMAX_STRINGRES);
|
|
// if (NULL == StrCpyN(szText, psz1, ARRAYSIZE(szText)))
|
|
// return(0);
|
|
|
|
if (NULL == StrCpyN(szText, psz1, ARRAYSIZE(szText) - 1))
|
|
return(0);
|
|
|
|
szText[ARRAYSIZE(szText) - 1] = '\0';
|
|
cch = lstrlen(szText);
|
|
}
|
|
else
|
|
{
|
|
// its a string resource id
|
|
cch = LoadString(hInst, PtrToUlong(psz1), szText, ARRAYSIZE(szText)-1);
|
|
if (cch == 0)
|
|
return(0);
|
|
}
|
|
|
|
// check that we have enough room for the '\n's and at least one byte of data
|
|
if (psz2 && (cch < (ARRAYSIZE(szText) - 4)))
|
|
{
|
|
// there's another string that we need to append to the
|
|
// first string...
|
|
szText[cch++] = '\n';
|
|
szText[cch++] = '\n';
|
|
|
|
if (!(IS_INTRESOURCE(psz2)))
|
|
{
|
|
// its a pointer to a string
|
|
// Assert(lstrlen(psz2) < CCHMAX_STRINGRES);
|
|
|
|
if (NULL == StrCpyN(&szText[cch], psz2, (ARRAYSIZE(szText)-1)-cch))
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
int cchTemp = ARRAYSIZE(szText) - cch;
|
|
Assert(cchTemp > 0);
|
|
if (0 == LoadString(hInst, PtrToUlong(psz2), &szText[cch], cchTemp))
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
return(MessageBox(hwndOwner, szText, pszTitle, MB_SETFOREGROUND | fuStyle));
|
|
}
|
|
|
|
BOOL BrowseForFolder(HINSTANCE hInst, HWND hwnd, TCHAR *pszDir, int cch, int idsText, BOOL fFileSysOnly)
|
|
{
|
|
LPITEMIDLIST plist;
|
|
BROWSEINFO bi;
|
|
BROWSEFOLDERINFOA bfi;
|
|
BOOL fRet = FALSE;
|
|
CHAR *psz = NULL,
|
|
szTemp[MAX_PATH];
|
|
CHAR szRes[256];
|
|
|
|
Assert(pszDir != NULL);
|
|
Assert(cch >= MAX_PATH);
|
|
|
|
LoadString(hInst, idsText, szRes, ARRAYSIZE(szRes));
|
|
|
|
bfi.psz = pszDir;
|
|
bfi.fFileSysOnly = fFileSysOnly;
|
|
|
|
bi.hwndOwner = hwnd;
|
|
bi.pidlRoot = NULL;
|
|
bi.pszDisplayName = szTemp;
|
|
bi.lpszTitle = szRes;
|
|
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT;
|
|
bi.lpfn = BrowseCallbackProcA;
|
|
bi.lParam = (LPARAM)&bfi;
|
|
plist = SHBrowseForFolder(&bi);
|
|
|
|
if (plist != NULL)
|
|
{
|
|
fRet = SHGetPathFromIDList(plist, pszDir);
|
|
SHFree(plist);
|
|
}
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
BOOL SHGetPathFromIDListAthW(LPCITEMIDLIST pidl, LPWSTR pwszPath)
|
|
{
|
|
CHAR pszPath[MAX_PATH];
|
|
BOOL fSucceeded = FALSE;
|
|
|
|
fSucceeded = SHGetPathFromIDListW(pidl, pwszPath);
|
|
|
|
if (!fSucceeded)
|
|
{
|
|
fSucceeded = SHGetPathFromIDListA(pidl, pszPath);
|
|
if (fSucceeded)
|
|
fSucceeded = (0 != MultiByteToWideChar(CP_ACP, 0, pszPath, -1, pwszPath, MAX_PATH));
|
|
}
|
|
|
|
return fSucceeded;
|
|
}
|
|
|
|
LPITEMIDLIST SHBrowseForFolderAthW(LPBROWSEINFOW pbiW)
|
|
{
|
|
LPITEMIDLIST pidl = NULL;
|
|
LPSTR pszTitle = NULL;
|
|
CHAR szDisplay[MAX_PATH];
|
|
BROWSEINFOA biA;
|
|
|
|
Assert(pbiW);
|
|
|
|
if((IsPlatformWinNT() == S_OK) && g_rOSVersionInfo.dwMajorVersion >= 5)
|
|
pidl = SHBrowseForFolderW(pbiW); // this is only for NT5
|
|
else
|
|
{
|
|
pszTitle = PszToANSI(CP_ACP, pbiW->lpszTitle);
|
|
if (!pszTitle)
|
|
goto exit;
|
|
|
|
biA = *((BROWSEINFOA*)pbiW);
|
|
biA.lpszTitle = pszTitle;
|
|
biA.pszDisplayName = szDisplay;
|
|
|
|
pidl = SHBrowseForFolderA(&biA);
|
|
if (pidl)
|
|
{
|
|
if (0 == MultiByteToWideChar(CP_ACP, 0, biA.pszDisplayName, -1, pbiW->pszDisplayName, MAX_PATH))
|
|
{
|
|
SHFree(pidl);
|
|
pidl = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
MemFree(pszTitle);
|
|
return pidl;
|
|
}
|
|
|
|
|
|
BOOL BrowseForFolderW(HINSTANCE hInst, HWND hwnd, WCHAR *pwszDir, int cch, int idsText, BOOL fFileSysOnly)
|
|
{
|
|
LPITEMIDLIST plist;
|
|
BROWSEINFOW bi;
|
|
BROWSEFOLDERINFOW bfi;
|
|
BOOL fRet = FALSE;
|
|
WCHAR *pwsz = NULL,
|
|
wszTemp[MAX_PATH];
|
|
CHAR szRes[256];
|
|
|
|
Assert(pwszDir != NULL);
|
|
Assert(cch >= MAX_PATH);
|
|
|
|
// Don't have access to all wrappers in msoert so
|
|
// must do conversion ourselves for LoadStringW
|
|
LoadString(hInst, idsText, szRes, ARRAYSIZE(szRes));
|
|
pwsz = PszToUnicode(CP_ACP, szRes);
|
|
if (!pwsz)
|
|
goto exit;
|
|
|
|
bfi.pwsz = pwszDir;
|
|
bfi.fFileSysOnly = fFileSysOnly;
|
|
|
|
bi.hwndOwner = hwnd;
|
|
bi.pidlRoot = NULL;
|
|
bi.pszDisplayName = wszTemp;
|
|
bi.lpszTitle = pwsz;
|
|
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT;
|
|
bi.lpfn = BrowseCallbackProcW;
|
|
bi.lParam = (LPARAM)&bfi;
|
|
plist = SHBrowseForFolderAthW(&bi);
|
|
|
|
if (plist != NULL)
|
|
{
|
|
fRet = SHGetPathFromIDListAthW(plist, pwszDir);
|
|
SHFree(plist);
|
|
}
|
|
|
|
exit:
|
|
MemFree(pwsz);
|
|
return(fRet);
|
|
}
|
|
|
|
int BrowseCallbackProcW(HWND hwnd, UINT msg, LPARAM lParam, LPARAM lpData)
|
|
{
|
|
BOOL fRet;
|
|
UINT type;
|
|
WCHAR wsz[MAX_PATH];
|
|
BROWSEFOLDERINFOW *pbfi;
|
|
|
|
switch (msg)
|
|
{
|
|
case BFFM_INITIALIZED:
|
|
pbfi = (BROWSEFOLDERINFOW *)lpData;
|
|
Assert(pbfi != NULL);
|
|
SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, (LPARAM)pbfi->pwsz);
|
|
break;
|
|
|
|
case BFFM_SELCHANGED:
|
|
pbfi = (BROWSEFOLDERINFOW *)lpData;
|
|
Assert(pbfi != NULL);
|
|
fRet = SHGetPathFromIDListAthW((LPITEMIDLIST)lParam, wsz);
|
|
if (fRet)
|
|
{
|
|
if (L':' == wsz[1] && L'\\' == wsz[2])
|
|
{
|
|
wsz[3] = 0;
|
|
if (S_OK == IsPlatformWinNT())
|
|
type = GetDriveTypeW(wsz);
|
|
else
|
|
{
|
|
// Since we can't fail in this function, we need to do some kind
|
|
// of conversion that doesn't require memory allocations, etc.
|
|
// Since drives always must be ansi, can do the conversion in this
|
|
// really ugly way.
|
|
CHAR szDir[] = "a:\\";
|
|
AssertSz(0 == ((LPSTR)wsz)[1], "The char is not a unicode ANSI char");
|
|
*szDir = *((LPSTR)wsz);
|
|
type = GetDriveType(szDir);
|
|
}
|
|
if (pbfi->fFileSysOnly)
|
|
fRet = (type == DRIVE_FIXED);
|
|
else
|
|
fRet = (type == DRIVE_FIXED || type == DRIVE_REMOVABLE || type == DRIVE_REMOTE);
|
|
}
|
|
else
|
|
{
|
|
fRet = !pbfi->fFileSysOnly;
|
|
}
|
|
}
|
|
|
|
SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM)fRet);
|
|
break;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
int BrowseCallbackProcA(HWND hwnd, UINT msg, LPARAM lParam, LPARAM lpData)
|
|
{
|
|
BOOL fRet;
|
|
UINT type;
|
|
CHAR sz[MAX_PATH];
|
|
BROWSEFOLDERINFOA *pbfi;
|
|
|
|
switch (msg)
|
|
{
|
|
case BFFM_INITIALIZED:
|
|
pbfi = (BROWSEFOLDERINFOA *)lpData;
|
|
Assert(pbfi != NULL);
|
|
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)pbfi->psz);
|
|
break;
|
|
|
|
case BFFM_SELCHANGED:
|
|
pbfi = (BROWSEFOLDERINFOA *)lpData;
|
|
Assert(pbfi != NULL);
|
|
fRet = SHGetPathFromIDList((LPITEMIDLIST)lParam, sz);
|
|
if (fRet)
|
|
{
|
|
// Only reason to do this check is to see if we have
|
|
// some funky chars in the filename. This will protect us
|
|
// from selecting files with non-ANSI chars in them.
|
|
if (PathFileExists(sz))
|
|
{
|
|
if (':' == sz[1] && '\\' == sz[2])
|
|
{
|
|
sz[3] = 0;
|
|
type = GetDriveType(sz);
|
|
|
|
if (pbfi->fFileSysOnly)
|
|
fRet = (type == DRIVE_FIXED);
|
|
else
|
|
fRet = (type == DRIVE_FIXED || type == DRIVE_REMOVABLE || type == DRIVE_REMOTE);
|
|
}
|
|
else
|
|
{
|
|
fRet = !pbfi->fFileSysOnly;
|
|
}
|
|
}
|
|
else
|
|
fRet = FALSE;
|
|
}
|
|
|
|
SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM)fRet);
|
|
break;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
HRESULT IsPlatformWinNT(void)
|
|
{
|
|
return (g_rOSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
void UpdateRebarBandColors(HWND hwndRebar)
|
|
{
|
|
REBARBANDINFO rbbi;
|
|
UINT i;
|
|
UINT cBands;
|
|
|
|
// First find the band with the toolbar
|
|
cBands = (UINT) SendMessage(hwndRebar, RB_GETBANDCOUNT, 0, 0);
|
|
ZeroMemory(&rbbi, sizeof(rbbi));
|
|
rbbi.cbSize = sizeof(REBARBANDINFO);
|
|
rbbi.fMask = RBBIM_ID;
|
|
|
|
for (i = 0; i < cBands; i++)
|
|
{
|
|
SendMessage(hwndRebar, RB_GETBANDINFO, i, (LPARAM) &rbbi);
|
|
|
|
ZeroMemory(&rbbi, sizeof(rbbi));
|
|
rbbi.cbSize = sizeof(REBARBANDINFO);
|
|
rbbi.fMask = RBBIM_COLORS;
|
|
rbbi.clrFore = GetSysColor(COLOR_BTNTEXT);
|
|
rbbi.clrBack = GetSysColor(COLOR_BTNFACE);
|
|
|
|
SendMessage(hwndRebar, RB_SETBANDINFO, i, (LPARAM) (LPREBARBANDINFO) &rbbi);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
#define RGB_BUTTONTEXT (RGB(000,000,000)) // black
|
|
#define RGB_BUTTONSHADOW (RGB(128,128,128)) // dark grey
|
|
#define RGB_BUTTONFACE (RGB(192,192,192)) // bright grey
|
|
#define RGB_BUTTONHILIGHT (RGB(255,255,255)) // white
|
|
#define RGB_TRANSPARENT (RGB(255,000,255)) // pink
|
|
|
|
inline BOOL fIsNT5() { return((g_rOSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) && (g_rOSVersionInfo.dwMajorVersion >= 5)); }
|
|
inline BOOL fIsWhistler() { return((fIsNT5() && g_rOSVersionInfo.dwMinorVersion >=1) ||
|
|
((g_rOSVersionInfo.dwMajorVersion > 5) && (g_rOSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT))); }
|
|
|
|
|
|
/*
|
|
* This function loads an OE toolbar bitmap and maps 3D colors to the
|
|
* appropriate current scheme. We also map black and white so that we look
|
|
* good on high-contrast displays
|
|
*/
|
|
|
|
HIMAGELIST LoadMappedToolbarBitmap(HINSTANCE hInst, int idBitmap, int cx)
|
|
{
|
|
static const COLORMAP SysColorMap[] = {
|
|
{RGB_BUTTONTEXT, COLOR_BTNTEXT}, // black
|
|
{RGB_BUTTONSHADOW, COLOR_BTNSHADOW}, // dark grey
|
|
{RGB_BUTTONFACE, COLOR_BTNFACE}, // bright grey
|
|
{RGB_BUTTONHILIGHT, COLOR_BTNHIGHLIGHT},// white
|
|
};
|
|
|
|
#define NUM_DEFAULT_MAPS (sizeof(SysColorMap)/sizeof(COLORMAP))
|
|
COLORMAP DefaultColorMap[NUM_DEFAULT_MAPS];
|
|
|
|
HIMAGELIST himl;
|
|
HBITMAP hBmp;
|
|
BITMAP bm;
|
|
int cy=0;
|
|
|
|
/* Get system colors for the default color map */
|
|
for (int i=0; i < NUM_DEFAULT_MAPS; i++)
|
|
{
|
|
DefaultColorMap[i].from = SysColorMap[i].from;
|
|
DefaultColorMap[i].to = GetSysColor((int)SysColorMap[i].to);
|
|
}
|
|
|
|
if(!fIsWhistler())
|
|
hBmp = CreateMappedBitmap(hInst, idBitmap, 0, (COLORMAP *)&DefaultColorMap, NUM_DEFAULT_MAPS);
|
|
else
|
|
hBmp = CreateMappedBitmap(hInst, idBitmap, CMB_DIBSECTION, (COLORMAP *)&DefaultColorMap, NUM_DEFAULT_MAPS);
|
|
if (!hBmp)
|
|
return NULL;
|
|
|
|
if (GetObject(hBmp, sizeof(BITMAP), &bm))
|
|
cy = bm.bmHeight;
|
|
|
|
if(!fIsWhistler())
|
|
himl = ImageList_Create(cx, cy, ILC_COLORDDB|ILC_MASK, 4, 4);
|
|
else
|
|
himl = ImageList_Create(cx, cy, ILC_COLOR32|ILC_MASK, 4, 4);
|
|
if (!himl)
|
|
{
|
|
DeleteObject(hBmp);
|
|
return NULL;
|
|
}
|
|
|
|
// if(!fIsWhistler())
|
|
{
|
|
ImageList_AddMasked(himl, hBmp, RGB_TRANSPARENT);
|
|
ImageList_SetBkColor(himl, CLR_NONE);
|
|
}
|
|
DeleteObject(hBmp);
|
|
return himl;
|
|
}
|
|
|
|
|
|
|
|
HRESULT DoHotMailWizard(HWND hwndOwner, LPSTR pszUrl, LPSTR pszFriendly, RECT *prc, IUnknown *pUnkHost)
|
|
{
|
|
IHotWizard *pWiz=NULL;
|
|
HRESULT hr = S_OK;
|
|
LPWSTR pwszUrl = NULL,
|
|
pwszCaption = NULL;
|
|
IHotWizardHost *pHost = NULL;
|
|
|
|
if (pUnkHost)
|
|
IF_FAILEXIT(hr = pUnkHost->QueryInterface(IID_IHotWizardHost, (LPVOID *)&pHost));
|
|
|
|
// create and show the wizard
|
|
IF_FAILEXIT(hr = CoCreateInstance(CLSID_OEHotMailWizard, NULL, CLSCTX_INPROC_SERVER, IID_IHotWizard, (LPVOID*)&pWiz));
|
|
|
|
IF_NULLEXIT(pwszUrl = PszToUnicode(CP_ACP, pszUrl));
|
|
|
|
IF_NULLEXIT(pwszCaption = PszToUnicode(CP_ACP, pszFriendly));
|
|
|
|
IF_FAILEXIT(hr = pWiz->Show(hwndOwner, pwszUrl, pwszCaption, pHost, prc));
|
|
|
|
exit:
|
|
MemFree(pwszUrl);
|
|
MemFree(pwszCaption);
|
|
ReleaseObj(pWiz);
|
|
ReleaseObj(pHost);
|
|
return hr;
|
|
}
|
|
|
|
BOOL fGetBrowserUrlEncoding(LPDWORD pdwFlags)
|
|
{
|
|
DWORD dwUrlEncodingDisableUTF8;
|
|
DWORD dwSize = sizeof(dwUrlEncodingDisableUTF8);
|
|
BOOL fDefault = FALSE;
|
|
DWORD dwFlags = *pdwFlags;
|
|
BOOL fret = TRUE;
|
|
|
|
if (ERROR_SUCCESS == SHRegGetUSValue(c_szInternetSettingsPath, c_szUrlEncoding,
|
|
NULL, (LPBYTE) &dwUrlEncodingDisableUTF8, &dwSize,
|
|
FALSE, (LPVOID) &fDefault, sizeof(fDefault)))
|
|
{
|
|
if (!dwUrlEncodingDisableUTF8)
|
|
dwFlags |= DOCHOSTUIFLAG_URL_ENCODING_ENABLE_UTF8;
|
|
else
|
|
dwFlags |= DOCHOSTUIFLAG_URL_ENCODING_DISABLE_UTF8;
|
|
|
|
*pdwFlags = dwFlags;
|
|
}
|
|
else fret = FALSE;
|
|
|
|
return fret;
|
|
|
|
}
|