1360 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1360 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /***************************************************************************
 | |
|  * UTILITIES.CPP
 | |
|  *
 | |
|  * Shared helper functions and routines.
 | |
|  *
 | |
|  *  Copyright ©1999-2004; Microsoft Corporation. All rights reserved.
 | |
|  *  Written by Microsoft Developer Support Office Integration (PSS DSOI)
 | |
|  * 
 | |
|  *  This code is provided via KB 311765 as a sample. It is not a formal
 | |
|  *  product and has not been tested with all containers or servers. Use it
 | |
|  *  for educational purposes only. See the EULA.TXT file included in the
 | |
|  *  KB download for full terms of use and restrictions.
 | |
|  *
 | |
|  *  THIS CODE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 | |
|  *  EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 | |
|  *  WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 | |
|  *
 | |
|  ***************************************************************************/
 | |
| #include "dsoframer.h"
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // Core Utility Functions
 | |
| //
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // Heap Allocation (Private Heap)
 | |
| //
 | |
| extern HANDLE v_hPrivateHeap;
 | |
| STDAPI_(LPVOID) DsoMemAlloc(DWORD cbSize)
 | |
| {
 | |
|     CHECK_NULL_RETURN(v_hPrivateHeap, NULL);
 | |
|     return HeapAlloc(v_hPrivateHeap, HEAP_ZERO_MEMORY, cbSize);
 | |
| }
 | |
| 
 | |
| STDAPI_(void) DsoMemFree(LPVOID ptr)
 | |
| {
 | |
|     if ((v_hPrivateHeap) && (ptr))
 | |
|         HeapFree(v_hPrivateHeap, 0, ptr);
 | |
| }
 | |
| 
 | |
| void * _cdecl operator new(size_t size){ return DsoMemAlloc(size);}
 | |
| void  _cdecl operator delete(void *ptr){ DsoMemFree(ptr); }
 | |
| int __cdecl _purecall(){__asm{int 3}; return 0;}
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // Global String Functions
 | |
| //
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoConvertToUnicodeEx
 | |
| //
 | |
| STDAPI DsoConvertToUnicodeEx(LPCSTR pszMbcsString, DWORD cbMbcsLen, LPWSTR pwszUnicode, DWORD cbUniLen, UINT uiCodePage)
 | |
| {
 | |
| 	DWORD cbRet;
 | |
| 	UINT iCode = CP_ACP;
 | |
| 
 | |
| 	if (IsValidCodePage(uiCodePage))
 | |
| 		iCode = uiCodePage;
 | |
| 
 | |
| 	CHECK_NULL_RETURN(pwszUnicode,    E_POINTER);
 | |
| 	pwszUnicode[0] = L'\0';
 | |
| 
 | |
| 	CHECK_NULL_RETURN(pszMbcsString,  E_POINTER);
 | |
| 	CHECK_NULL_RETURN(cbMbcsLen,      E_INVALIDARG);
 | |
| 	CHECK_NULL_RETURN(cbUniLen,       E_INVALIDARG);
 | |
| 
 | |
| 	cbRet = MultiByteToWideChar(iCode, 0, pszMbcsString, cbMbcsLen, pwszUnicode, cbUniLen);
 | |
| 	if (cbRet == 0)	return E_WIN32_LASTERROR;
 | |
| 
 | |
| 	pwszUnicode[cbRet] = L'\0';
 | |
| 	return S_OK;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoConvertToMBCSEx
 | |
| //
 | |
| STDAPI DsoConvertToMBCSEx(LPCWSTR pwszUnicodeString, DWORD cbUniLen, LPSTR pszMbcsString, DWORD cbMbcsLen, UINT uiCodePage)
 | |
| {
 | |
| 	DWORD cbRet;
 | |
| 	UINT iCode = CP_ACP;
 | |
| 
 | |
| 	if (IsValidCodePage(uiCodePage))
 | |
| 		iCode = uiCodePage;
 | |
| 
 | |
| 	CHECK_NULL_RETURN(pszMbcsString,     E_POINTER);
 | |
| 	pszMbcsString[0] = L'\0';
 | |
| 
 | |
| 	CHECK_NULL_RETURN(pwszUnicodeString, E_POINTER);
 | |
| 	CHECK_NULL_RETURN(cbMbcsLen,         E_INVALIDARG);
 | |
| 	CHECK_NULL_RETURN(cbUniLen,          E_INVALIDARG);
 | |
| 
 | |
| 	cbRet = WideCharToMultiByte(iCode, 0, pwszUnicodeString, -1, pszMbcsString, cbMbcsLen, NULL, NULL);
 | |
| 	if (cbRet == 0)	return E_WIN32_LASTERROR;
 | |
| 
 | |
| 	pszMbcsString[cbRet] = '\0';
 | |
| 	return S_OK;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoConvertToLPWSTR
 | |
| //
 | |
| //  Takes a MBCS string and returns a LPWSTR allocated on private heap.
 | |
| //
 | |
| STDAPI_(LPWSTR) DsoConvertToLPWSTR(LPCSTR pszMbcsString)
 | |
| {
 | |
| 	LPWSTR pwsz = NULL;
 | |
| 	UINT cblen, cbnew;
 | |
| 
 | |
| 	if ((pszMbcsString) && 
 | |
|         ((cblen = lstrlen(pszMbcsString)) > 0))
 | |
| 	{
 | |
| 		cbnew = ((cblen + 1) * sizeof(WCHAR));
 | |
| 		if ((pwsz = (LPWSTR)DsoMemAlloc(cbnew)) != NULL) 
 | |
| 		{
 | |
| 			if (FAILED(DsoConvertToUnicodeEx(pszMbcsString, cblen, pwsz, cbnew, GetACP())))
 | |
|             {
 | |
| 			    DsoMemFree(pwsz);
 | |
|                 pwsz = NULL;
 | |
|             }
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return pwsz;
 | |
| }
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoConvertToMBCS
 | |
| //
 | |
| //  Takes a WCHAR string and returns a LPSTR on the private heap.
 | |
| //
 | |
| STDAPI_(LPSTR) DsoConvertToMBCS(LPCWSTR pwszUnicodeString)
 | |
| {
 | |
| 	LPSTR psz = NULL;
 | |
| 	UINT cblen, cbnew;
 | |
| 
 | |
|     if ((pwszUnicodeString) && 
 | |
|         ((cblen = lstrlenW(pwszUnicodeString)) > 0))
 | |
| 	{
 | |
| 		cbnew = ((cblen + 1) * sizeof(WCHAR));
 | |
| 		if ((psz = (LPSTR)DsoMemAlloc(cbnew)) != NULL) 
 | |
| 		{
 | |
| 			if (FAILED(DsoConvertToMBCSEx(pwszUnicodeString, cblen, psz, cbnew, GetACP())))
 | |
|             {
 | |
| 			    DsoMemFree(psz); psz = NULL;
 | |
|             }
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return psz;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoConvertToBSTR
 | |
| //
 | |
| //  Takes a MBCS string and returns a BSTR. NULL is returned if the 
 | |
| //  function fails or the string is empty.
 | |
| //
 | |
| STDAPI_(BSTR) DsoConvertToBSTR(LPCSTR pszMbcsString)
 | |
| {
 | |
| 	BSTR bstr = NULL;
 | |
|     LPWSTR pwsz = DsoConvertToLPWSTR(pszMbcsString);
 | |
| 	if (pwsz)
 | |
| 	{
 | |
| 	    bstr = SysAllocString(pwsz);
 | |
| 	    DsoMemFree(pwsz);
 | |
|     }
 | |
| 	return bstr;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoConvertToLPOLESTR
 | |
| //
 | |
| //  Returns Unicode string in COM Task Memory (CoTaskMemAlloc).
 | |
| //
 | |
| STDAPI_(LPWSTR) DsoConvertToLPOLESTR(LPCWSTR pwszUnicodeString)
 | |
| {
 | |
| 	LPWSTR pwsz;
 | |
| 	UINT cblen;
 | |
| 
 | |
| 	CHECK_NULL_RETURN(pwszUnicodeString, NULL);
 | |
| 	cblen = lstrlenW(pwszUnicodeString);
 | |
| 
 | |
|     pwsz = (LPWSTR)CoTaskMemAlloc((cblen * sizeof(WCHAR)) + 2);
 | |
|     if (pwsz)
 | |
|     {
 | |
|         memcpy(pwsz, pwszUnicodeString, (cblen * sizeof(WCHAR)));
 | |
|         pwsz[cblen] = L'\0'; // Make sure it is NULL terminated.
 | |
|     }
 | |
| 
 | |
|     return pwsz;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoCopyString
 | |
| //
 | |
| //  Duplicates the string into private heap string.
 | |
| //
 | |
| STDAPI_(LPWSTR) DsoCopyString(LPCWSTR pwszString)
 | |
| {
 | |
| 	LPWSTR pwsz;
 | |
| 	UINT cblen;
 | |
| 
 | |
| 	CHECK_NULL_RETURN(pwszString, NULL);
 | |
| 	cblen = lstrlenW(pwszString);
 | |
| 
 | |
|     pwsz = (LPWSTR)DsoMemAlloc((cblen * sizeof(WCHAR)) + 2);
 | |
|     if (pwsz)
 | |
|     {
 | |
|         memcpy(pwsz, pwszString, (cblen * sizeof(WCHAR)));
 | |
|         pwsz[cblen] = L'\0'; // Make sure it is NULL terminated.
 | |
|     }
 | |
| 
 | |
|     return pwsz;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoCopyStringCat
 | |
| //
 | |
| STDAPI_(LPWSTR) DsoCopyStringCat(LPCWSTR pwszString1, LPCWSTR pwszString2)
 | |
| {return DsoCopyStringCatEx(pwszString1, 1, &pwszString2);}
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoCopyStringCatEx
 | |
| //
 | |
| //  Duplicates the string into private heap string and appends one or more
 | |
| //  strings to the end (concatenation). 
 | |
| //
 | |
| STDAPI_(LPWSTR) DsoCopyStringCatEx(LPCWSTR pwszBaseString, UINT cStrs, LPCWSTR *ppwszStrs)
 | |
| {
 | |
| 	LPWSTR pwsz;
 | |
| 	UINT i, cblenb, cblent;
 | |
|     UINT *pcblens;
 | |
| 
 | |
|  // We assume you have a base string to start with. If not, we return NULL...
 | |
|     if ((pwszBaseString == NULL) || 
 | |
|         ((cblenb = lstrlenW(pwszBaseString)) < 1))
 | |
|         return NULL;
 | |
| 
 | |
|  // If we have nothing to append, just do a plain copy...
 | |
|     if ((cStrs == 0) || (ppwszStrs == NULL))
 | |
|         return DsoCopyString(pwszBaseString);
 | |
| 
 | |
|  // Determine the size of the final string by finding the lengths
 | |
|  // of each. We create an array of sizes to use later on...
 | |
|     cblent = cblenb;
 | |
|     pcblens = new UINT[cStrs];
 | |
|     CHECK_NULL_RETURN(pcblens,  NULL);
 | |
| 
 | |
|     for (i = 0; i < cStrs; i++)
 | |
|     {
 | |
|         pcblens[i] =  lstrlenW(ppwszStrs[i]);
 | |
|         cblent += pcblens[i];
 | |
|     }
 | |
| 
 | |
|  // If we have data to append, create the new string and append the
 | |
|  // data by copying them in place. We expect UTF-16 Unicode strings
 | |
|  // for this to work, but this should be normal...
 | |
| 	if (cblent > cblenb)
 | |
|     {
 | |
| 	    pwsz = (LPWSTR)DsoMemAlloc(((cblent + 1) * sizeof(WCHAR)));
 | |
| 	    CHECK_NULL_RETURN(pwsz,   NULL);
 | |
| 
 | |
| 	    memcpy(pwsz, pwszBaseString, (cblenb * sizeof(WCHAR)));
 | |
|         cblent = cblenb;
 | |
| 
 | |
|         for (i = 0; i < cStrs; i++)
 | |
|         {
 | |
| 		    memcpy((pwsz + cblent), ppwszStrs[i], (pcblens[i] * sizeof(WCHAR)));
 | |
|             cblent += pcblens[i];
 | |
|         }
 | |
|     }
 | |
|     else pwsz = DsoCopyString(pwszBaseString);
 | |
| 
 | |
|     delete [] pcblens;
 | |
| 	return pwsz;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoCLSIDtoLPSTR
 | |
| //
 | |
| STDAPI_(LPSTR) DsoCLSIDtoLPSTR(REFCLSID clsid)
 | |
| {
 | |
| 	LPSTR psz = NULL;
 | |
| 	LPWSTR pwsz;
 | |
| 	if (SUCCEEDED(StringFromCLSID(clsid, &pwsz)))
 | |
| 	{
 | |
| 		psz = DsoConvertToMBCS(pwsz);
 | |
| 		CoTaskMemFree(pwsz);
 | |
| 	}
 | |
|     return psz;
 | |
| }
 | |
| 
 | |
| 
 | |
| ///////////////////////////////////////////////////////////////////////////////////
 | |
| // DsoCompareStringsEx
 | |
| //
 | |
| //  Calls CompareString API using Unicode version (if available on OS). Otherwise,
 | |
| //  we have to thunk strings down to MBCS to compare. This is fairly inefficient for
 | |
| //  Win9x systems that don't handle Unicode, but hey...this is only a sample.
 | |
| //
 | |
| STDAPI_(UINT) DsoCompareStringsEx(LPCWSTR pwsz1, INT cch1, LPCWSTR pwsz2, INT cch2)
 | |
| {
 | |
| 	UINT iret;
 | |
| 	LCID lcid = GetThreadLocale();
 | |
| 	UINT cblen1, cblen2;
 | |
| 
 | |
|  // Check that valid parameters are passed and then contain somethimg...
 | |
|     if ((pwsz1 == NULL) || (cch1 == 0) || 
 | |
|         ((cblen1 = ((cch1 > 0) ? cch1 : lstrlenW(pwsz1))) == 0))
 | |
| 		return CSTR_LESS_THAN;
 | |
| 
 | |
| 	if ((pwsz2 == NULL) || (cch2 == 0) || 
 | |
|         ((cblen2 = ((cch2 > 0) ? cch2 : lstrlenW(pwsz2))) == 0))
 | |
| 		return CSTR_GREATER_THAN;
 | |
| 
 | |
|  // If the string is of the same size, then we do quick compare to test for
 | |
|  // equality (this is slightly faster than calling the API, but only if we
 | |
|  // expect the calls to find an equal match)...
 | |
| 	if (cblen1 == cblen2)
 | |
| 	{
 | |
| 		for (iret = 0; iret < cblen1; iret++)
 | |
| 		{
 | |
| 			if (pwsz1[iret] == pwsz2[iret])
 | |
| 				continue;
 | |
| 
 | |
| 			if (((pwsz1[iret] >= 'A') && (pwsz1[iret] <= 'Z')) &&
 | |
| 				((pwsz1[iret] + ('a' - 'A')) == pwsz2[iret]))
 | |
| 				continue;
 | |
| 
 | |
| 			if (((pwsz2[iret] >= 'A') && (pwsz2[iret] <= 'Z')) &&
 | |
| 				((pwsz2[iret] + ('a' - 'A')) == pwsz1[iret]))
 | |
| 				continue;
 | |
| 
 | |
| 			break; // don't continue if we can't quickly match...
 | |
| 		}
 | |
| 
 | |
| 		// If we made it all the way, then they are equal...
 | |
| 		if (iret == cblen1)
 | |
| 			return CSTR_EQUAL;
 | |
| 	}
 | |
| 
 | |
|  // Now ask the OS to check the strings and give us its read. (We prefer checking
 | |
|  // in Unicode since this is faster and we may have strings that can't be thunked
 | |
|  // down to the local ANSI code page)...
 | |
| 	if (v_fUnicodeAPI)
 | |
| 	{
 | |
| 		iret = CompareStringW(lcid, NORM_IGNORECASE | NORM_IGNOREWIDTH, pwsz1, cblen1, pwsz2, cblen2);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 	 // If we are on Win9x, we don't have much of choice (thunk the call)...
 | |
| 		LPSTR psz1 = DsoConvertToMBCS(pwsz1);
 | |
| 		LPSTR psz2 = DsoConvertToMBCS(pwsz2);
 | |
| 		iret = CompareStringA(lcid, NORM_IGNORECASE, psz1, -1, psz2, -1);
 | |
| 		DsoMemFree(psz2);
 | |
| 		DsoMemFree(psz1);
 | |
| 	}
 | |
| 
 | |
| 	return iret;
 | |
| }
 | |
| 
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // URL Helpers
 | |
| //
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // General Functions (checks to see if we can recognize type)
 | |
| //
 | |
| STDAPI_(BOOL) LooksLikeUNC(LPCWSTR pwsz)
 | |
| {
 | |
| 	return ((pwsz) && (*pwsz == L'\\') && (*(pwsz + 1) == L'\\') && (*(pwsz + 2) != L'\\'));
 | |
| }
 | |
| 
 | |
| STDAPI_(BOOL) LooksLikeLocalFile(LPCWSTR pwsz)
 | |
| {
 | |
| 	return ((pwsz) && 
 | |
|         (((*pwsz > 64) && (*pwsz < 91)) || ((*pwsz > 96) && (*pwsz < 123))) &&
 | |
|         (*(pwsz + 1) == L':') && (*(pwsz + 2) == L'\\'));
 | |
| }
 | |
| 
 | |
| STDAPI_(BOOL) LooksLikeHTTP(LPCWSTR pwsz)
 | |
| {
 | |
| 	return ((pwsz) && ((*pwsz == L'H') || (*pwsz == L'h')) &&
 | |
| 		((*(pwsz + 1) == L'T') || (*(pwsz + 1) == L't')) &&
 | |
| 		((*(pwsz + 2) == L'T') || (*(pwsz + 2) == L't')) &&
 | |
| 		((*(pwsz + 3) == L'P') || (*(pwsz + 3) == L'p')) &&
 | |
| 		((*(pwsz + 4) == L':') || (((*(pwsz + 4) == L'S') || (*(pwsz + 4) == L's')) && (*(pwsz + 5) == L':'))));
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // GetTempPathForURLDownload
 | |
| //
 | |
| //  Constructs a temp path for a downloaded file. Note we scan the URL 
 | |
| //  to find the name of the file so we can use its exention for server 
 | |
| //  association (in case it is a non-docfile -- like RTF) and also 
 | |
| //  create our own subfolder to try and avoid name conflicts in temp
 | |
| //  folder itself. 
 | |
| //
 | |
| STDAPI_(BOOL) GetTempPathForURLDownload(WCHAR* pwszURL, WCHAR** ppwszLocalFile)
 | |
| {
 | |
| 	DWORD  dw;
 | |
| 	LPWSTR pwszTPath = NULL;
 | |
| 	LPWSTR pwszTFile = NULL;
 | |
| 	CHAR   szTmpPath[MAX_PATH];
 | |
| 
 | |
|  // Do a little parameter checking and find length of the URL...
 | |
| 	if (!(pwszURL) || ((dw = lstrlenW(pwszURL)) < 6) ||
 | |
| 		!(LooksLikeHTTP(pwszURL)) || !(ppwszLocalFile))
 | |
| 		return FALSE;
 | |
| 
 | |
| 	*ppwszLocalFile = NULL;
 | |
| 
 | |
| 	if (GetTempPath(MAX_PATH, szTmpPath))
 | |
| 	{
 | |
| 		DWORD dwtlen = lstrlen(szTmpPath);
 | |
| 		if (dwtlen > 0 && szTmpPath[dwtlen-1] != '\\')
 | |
| 			lstrcat(szTmpPath, "\\");
 | |
| 
 | |
| 		lstrcat(szTmpPath, "DsoFramer");
 | |
| 
 | |
| 		if (CreateDirectory(szTmpPath, NULL) || GetLastError() == ERROR_ALREADY_EXISTS)
 | |
| 		{
 | |
| 			lstrcat(szTmpPath, "\\");
 | |
| 			pwszTPath = DsoConvertToLPWSTR(szTmpPath);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (pwszTPath)
 | |
| 	{
 | |
| 		if (pwszTFile = DsoCopyString(pwszURL))
 | |
| 		{
 | |
| 			LPWSTR pwszT = pwszTFile;
 | |
| 			while (*(++pwszT))
 | |
| 				if (*pwszT == L'?'){*pwszT = L'\0'; break;}
 | |
| 
 | |
| 			while (*(--pwszT))
 | |
| 				if (*pwszT == L'/'){++pwszT; break;}
 | |
| 
 | |
| 			*ppwszLocalFile = DsoCopyStringCat(pwszTPath, pwszT);
 | |
| 
 | |
| 			DsoMemFree(pwszTFile);
 | |
| 		}
 | |
| 
 | |
| 		DsoMemFree(pwszTPath);
 | |
| 	}
 | |
| 
 | |
| 	return (BOOL)(*ppwszLocalFile);
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // URLDownloadFile
 | |
| //
 | |
| //  Does a simple URLMON download of file (no save back to server allowed),
 | |
| //  and no dependent files will be downloaded (just one temp file). 
 | |
| //
 | |
| STDAPI URLDownloadFile(LPUNKNOWN punk, WCHAR* pwszURL, WCHAR* pwszLocalFile)
 | |
| {
 | |
|     typedef HRESULT (WINAPI *PFN_URLDTFW)(LPUNKNOWN, LPCWSTR, LPCWSTR, DWORD, LPUNKNOWN);
 | |
|     static PFN_URLDTFW pfnURLDownloadToFileW = NULL;
 | |
|     HMODULE hUrlmon;
 | |
| 
 | |
|     if (pfnURLDownloadToFileW == NULL)
 | |
|     {
 | |
|         if (hUrlmon = LoadLibrary("URLMON.DLL"))
 | |
|             pfnURLDownloadToFileW = (PFN_URLDTFW)GetProcAddress(hUrlmon, "URLDownloadToFileW");
 | |
|     }
 | |
| 
 | |
|     if (pfnURLDownloadToFileW == NULL)
 | |
|         return E_UNEXPECTED;
 | |
| 
 | |
|     return pfnURLDownloadToFileW(punk, pwszURL, pwszLocalFile, 0, NULL);
 | |
| }
 | |
| 
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // OLE Conversion Functions
 | |
| //
 | |
| #define HIMETRIC_PER_INCH   2540      // number HIMETRIC units per inch
 | |
| #define PTS_PER_INCH        72        // number points (font size) per inch
 | |
| 
 | |
| #define MAP_PIX_TO_LOGHIM(x,ppli)   MulDiv(HIMETRIC_PER_INCH, (x), (ppli))
 | |
| #define MAP_LOGHIM_TO_PIX(x,ppli)   MulDiv((ppli), (x), HIMETRIC_PER_INCH)
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoHimetricToPixels
 | |
| //
 | |
| STDAPI_(void) DsoHimetricToPixels(LONG* px, LONG* py)
 | |
| {
 | |
|     HDC hdc = GetDC(NULL);
 | |
|     if (px) *px = MAP_LOGHIM_TO_PIX(*px, GetDeviceCaps(hdc, LOGPIXELSX));
 | |
|     if (py) *py = MAP_LOGHIM_TO_PIX(*py, GetDeviceCaps(hdc, LOGPIXELSY));
 | |
|     ReleaseDC(NULL, hdc);
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoPixelsToHimetric
 | |
| //
 | |
| STDAPI_(void) DsoPixelsToHimetric(LONG* px, LONG* py)
 | |
| {
 | |
|     HDC hdc = GetDC(NULL);
 | |
|     if (px) *px = MAP_PIX_TO_LOGHIM(*px, GetDeviceCaps(hdc, LOGPIXELSX));
 | |
|     if (py) *py = MAP_PIX_TO_LOGHIM(*py, GetDeviceCaps(hdc, LOGPIXELSY));
 | |
|     ReleaseDC(NULL, hdc);
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // GDI Helper Functions
 | |
| //
 | |
| STDAPI_(HBITMAP) DsoGetBitmapFromWindow(HWND hwnd)
 | |
| {
 | |
|     HBITMAP hbmpold, hbmp = NULL;
 | |
|     HDC hdcWin, hdcMem;
 | |
|     RECT rc;
 | |
|     INT x, y;
 | |
| 
 | |
|     if (!GetWindowRect(hwnd, &rc))
 | |
|         return NULL;
 | |
| 
 | |
|     x = (rc.right - rc.left); if (x < 0) x = 1;
 | |
|     y = (rc.bottom - rc.top); if (y < 0) y = 1;
 | |
| 
 | |
| 	hdcWin = GetDC(hwnd);
 | |
| 	hdcMem = CreateCompatibleDC(hdcWin);
 | |
| 
 | |
| 	hbmp = CreateCompatibleBitmap(hdcWin, x, y);
 | |
| 	hbmpold = (HBITMAP)SelectObject(hdcMem, hbmp);
 | |
| 
 | |
| 	BitBlt(hdcMem, 0,0, x, y, hdcWin, 0,0, SRCCOPY);
 | |
| 
 | |
| 	SelectObject(hdcMem, hbmpold);
 | |
| 	DeleteDC(hdcMem);
 | |
| 	ReleaseDC(hwnd, hdcWin);
 | |
| 
 | |
|     return hbmp;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // Windows Helper Functions
 | |
| //
 | |
| STDAPI_(BOOL) IsWindowChild(HWND hwndParent, HWND hwndChild)
 | |
| {
 | |
|     HWND hwnd;
 | |
| 
 | |
|     if ((hwndChild == NULL) || !IsWindow(hwndChild))
 | |
|         return FALSE;
 | |
| 
 | |
|     if (hwndParent == NULL)
 | |
|         return TRUE;
 | |
| 
 | |
|     if (!IsWindow(hwndParent))
 | |
|         return FALSE;
 | |
| 
 | |
|     hwnd = hwndChild;
 | |
| 
 | |
|     while (hwnd = GetParent(hwnd))
 | |
| 	    if (hwnd == hwndParent)
 | |
|             return TRUE;
 | |
| 
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoGetTypeInfoEx
 | |
| //
 | |
| //  Gets an ITypeInfo from the LIBID specified. Optionally can load and
 | |
| //  register the typelib from a module resource (if specified). Used to
 | |
| //  load our typelib on demand.
 | |
| //
 | |
| STDAPI DsoGetTypeInfoEx(REFGUID rlibid, LCID lcid, WORD wVerMaj, WORD wVerMin, HMODULE hResource, REFGUID rguid, ITypeInfo** ppti)
 | |
| {
 | |
| 	HRESULT     hr;
 | |
| 	ITypeLib*   ptlib;
 | |
| 
 | |
| 	CHECK_NULL_RETURN(ppti, E_POINTER);
 | |
|     *ppti = NULL;
 | |
| 
 | |
|  // Try to pull information from the registry...
 | |
|     hr = LoadRegTypeLib(rlibid, wVerMaj, wVerMin, lcid, &ptlib);
 | |
| 
 | |
|  // If that failed, and we have a resource module to load from,
 | |
|  // try loading it from the module...
 | |
|     if (FAILED(hr) && (hResource))
 | |
|     {
 | |
| 		LPWSTR pwszPath;
 | |
|         if (FGetModuleFileName(hResource, &pwszPath))
 | |
|         {
 | |
|          // Now, load the type library from module resource file...
 | |
| 			hr = LoadTypeLib(pwszPath, &ptlib);
 | |
| 
 | |
| 		 // Register library to make things easier next time...
 | |
| 			if (SUCCEEDED(hr))
 | |
|                 RegisterTypeLib(ptlib, pwszPath, NULL);
 | |
| 
 | |
| 			DsoMemFree(pwszPath);
 | |
| 		}
 | |
|     }
 | |
| 
 | |
|  // We have the typelib. Now get the requested typeinfo...
 | |
| 	if (SUCCEEDED(hr))
 | |
|         hr = ptlib->GetTypeInfoOfGuid(rguid, ppti);
 | |
| 
 | |
|  // Release the type library interface.
 | |
|     SAFE_RELEASE_INTERFACE(ptlib);
 | |
| 	return hr;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoDispatchInvoke
 | |
| //
 | |
| //  Wrapper for IDispatch::Invoke calls to event sinks, or late bound call
 | |
| //  to embedded object to get ambient property.
 | |
| //
 | |
| STDAPI DsoDispatchInvoke(LPDISPATCH pdisp, LPOLESTR pwszname, DISPID dspid, WORD wflags, DWORD cargs, VARIANT* rgargs, VARIANT* pvtret)
 | |
| {
 | |
|     HRESULT    hr = S_FALSE;
 | |
|     DISPID     dspidPut = DISPID_PROPERTYPUT;
 | |
|     DISPPARAMS dspparm = {NULL, NULL, 0, 0};
 | |
| 
 | |
| 	CHECK_NULL_RETURN(pdisp, E_POINTER);
 | |
| 
 | |
|     dspparm.rgvarg = rgargs;
 | |
|     dspparm.cArgs = cargs;
 | |
| 
 | |
| 	if ((wflags & DISPATCH_PROPERTYPUT) || (wflags & DISPATCH_PROPERTYPUTREF))
 | |
| 	{
 | |
| 		dspparm.rgdispidNamedArgs = &dspidPut;
 | |
| 		dspparm.cNamedArgs = 1;
 | |
| 	}
 | |
| 
 | |
| 	SEH_TRY
 | |
| 
 | |
| 	if (pwszname)
 | |
| 		hr = pdisp->GetIDsOfNames(IID_NULL, &pwszname, 1, LOCALE_USER_DEFAULT, &dspid);
 | |
| 
 | |
|     if (SUCCEEDED(hr))
 | |
|         hr = pdisp->Invoke(dspid, IID_NULL, LOCALE_USER_DEFAULT, (WORD)(DISPATCH_METHOD | wflags), &dspparm, pvtret, NULL, NULL);
 | |
| 
 | |
|     SEH_EXCEPT(hr)
 | |
| 
 | |
|     return hr;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // DsoReportError -- Report Error for both ComThreadError and DispError.
 | |
| //
 | |
| STDAPI DsoReportError(HRESULT hr, LPWSTR pwszCustomMessage, EXCEPINFO* peiDispEx)
 | |
| {
 | |
|     BSTR bstrSource, bstrDescription;
 | |
|     ICreateErrorInfo* pcerrinfo;
 | |
|     IErrorInfo* perrinfo;
 | |
|     CHAR szError[MAX_PATH];
 | |
|     UINT nID = 0;
 | |
| 
 | |
|  // Don't need to do anything unless this is an error.
 | |
|     if ((hr == S_OK) || SUCCEEDED(hr)) return hr;
 | |
| 
 | |
|  // Is this one of our custom errors (if so we will pull description from resource)...
 | |
|     if ((hr > DSO_E_ERR_BASE) && (hr < DSO_E_ERR_MAX))
 | |
|         nID = (hr & 0xFF);
 | |
| 
 | |
|  // Set the source name...
 | |
|     bstrSource = SysAllocString(L"DsoFramerControl");
 | |
| 
 | |
|  // Set the error description...
 | |
|     if (pwszCustomMessage)
 | |
|     {
 | |
|         bstrDescription = SysAllocString(pwszCustomMessage);
 | |
|     }
 | |
|     else if (((nID) && LoadString(v_hModule, nID, szError, sizeof(szError))) || 
 | |
|              (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, szError, sizeof(szError), NULL)))
 | |
|     {
 | |
|         bstrDescription = DsoConvertToBSTR(szError);
 | |
|     }
 | |
|     else bstrDescription = NULL;
 | |
|     
 | |
|  // Set ErrorInfo so that vtable clients can get rich error information...
 | |
| 	if (SUCCEEDED(CreateErrorInfo(&pcerrinfo)))
 | |
|     {
 | |
| 		pcerrinfo->SetSource(bstrSource);
 | |
|         pcerrinfo->SetDescription(bstrDescription);
 | |
| 
 | |
| 		if (SUCCEEDED(pcerrinfo->QueryInterface(IID_IErrorInfo, (void**) &perrinfo)))
 | |
|         {
 | |
| 			SetErrorInfo(0, perrinfo);
 | |
| 			perrinfo->Release();
 | |
| 		}
 | |
| 		pcerrinfo->Release();
 | |
| 	}
 | |
| 
 | |
|  // Fill-in DispException Structure for late-boud clients...
 | |
|     if (peiDispEx)
 | |
|     {
 | |
|         peiDispEx->scode = hr;
 | |
|         peiDispEx->bstrSource = SysAllocString(bstrSource);
 | |
|         peiDispEx->bstrDescription = SysAllocString(bstrDescription);
 | |
|     }
 | |
| 
 | |
|  // Free temp strings...
 | |
|     SAFE_FREEBSTR(bstrDescription);
 | |
|     SAFE_FREEBSTR(bstrSource);
 | |
| 
 | |
|  // We always return error passed (so caller can chain this in return call).
 | |
|     return hr;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // Variant Type Helpers (Fast Access to Variant Data)
 | |
| //
 | |
| VARIANT* __fastcall DsoPVarFromPVarRef(VARIANT* px)
 | |
| {return ((px->vt == (VT_VARIANT|VT_BYREF)) ? (px->pvarVal) : px);}
 | |
| 
 | |
| BOOL __fastcall DsoIsVarParamMissing(VARIANT* px)
 | |
| {return ((px->vt == VT_EMPTY) || ((px->vt & VT_ERROR) == VT_ERROR));}
 | |
| 
 | |
| LPWSTR __fastcall DsoPVarWStrFromPVar(VARIANT* px)
 | |
| {return ((px->vt == VT_BSTR) ? px->bstrVal : ((px->vt == (VT_BSTR|VT_BYREF)) ? *(px->pbstrVal) : NULL));}
 | |
| 
 | |
| SAFEARRAY* __fastcall DsoPVarArrayFromPVar(VARIANT* px)
 | |
| {return (((px->vt & (VT_BYREF|VT_ARRAY)) == (VT_BYREF|VT_ARRAY)) ? *(px->pparray) : (((px->vt & VT_ARRAY) == VT_ARRAY) ? px->parray : NULL));}
 | |
| 
 | |
| IUnknown* __fastcall DsoPVarUnkFromPVar(VARIANT* px)
 | |
| {return (((px->vt == VT_DISPATCH) || (px->vt == VT_UNKNOWN)) ? px->punkVal : (((px->vt == (VT_DISPATCH|VT_BYREF)) || (px->vt == (VT_UNKNOWN|VT_BYREF))) ? *(px->ppunkVal) : NULL));}
 | |
| 
 | |
| SHORT __fastcall DsoPVarShortFromPVar(VARIANT* px, SHORT fdef)
 | |
| {return (((px->vt & 0xFF) != VT_I2) ? fdef : ((px->vt & VT_BYREF) == VT_BYREF) ? *(px->piVal) : px->iVal);}
 | |
| 
 | |
| LONG __fastcall DsoPVarLongFromPVar(VARIANT* px, LONG fdef)
 | |
| {return (((px->vt & 0xFF) != VT_I4) ? (LONG)DsoPVarShortFromPVar(px, (SHORT)fdef) : ((px->vt & VT_BYREF) == VT_BYREF) ? *(px->plVal) : px->lVal);}
 | |
| 
 | |
| BOOL __fastcall DsoPVarBoolFromPVar(VARIANT* px, BOOL fdef)
 | |
| {return (((px->vt & 0xFF) != VT_BOOL) ? (BOOL)DsoPVarLongFromPVar(px, (LONG)fdef) : ((px->vt & VT_BYREF) == VT_BYREF) ? (BOOL)(*(px->pboolVal)) : (BOOL)(px->boolVal));}
 | |
| 
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // Win32 Unicode API wrappers
 | |
| //
 | |
| //  This project is not compiled to Unicode in order for it to run on Win9x
 | |
| //  machines. However, in order to try to keep the code language/locale neutral 
 | |
| //  we use these wrappers to call the Unicode API functions when supported,
 | |
| //  and thunk down strings to local code page if must run MBCS API.
 | |
| //
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // FFileExists
 | |
| //
 | |
| //  Returns TRUE if the given file exists. Does not handle URLs.
 | |
| //
 | |
| STDAPI_(BOOL) FFileExists(WCHAR* wzPath)
 | |
| {
 | |
|     DWORD dw = 0xFFFFFFFF;
 | |
|     if (v_fUnicodeAPI)
 | |
|     {
 | |
|         dw = GetFileAttributesW(wzPath);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 		LPSTR psz = DsoConvertToMBCS(wzPath);
 | |
|         if (psz) dw = GetFileAttributesA(psz);
 | |
| 		DsoMemFree(psz);
 | |
| 	}
 | |
|     return (dw != 0xFFFFFFFF);
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // FOpenLocalFile
 | |
| //
 | |
| //  Returns TRUE if the file can be opened with the access required.
 | |
| //  Use the handle for ReadFile/WriteFile operations as normal.
 | |
| //
 | |
| STDAPI_(BOOL) FOpenLocalFile(WCHAR* wzFilePath, DWORD dwAccess, DWORD dwShareMode, DWORD dwCreate, HANDLE* phFile)
 | |
| {
 | |
|     CHECK_NULL_RETURN(phFile, FALSE);
 | |
|     *phFile = INVALID_HANDLE_VALUE;
 | |
|     if (v_fUnicodeAPI)
 | |
|     {
 | |
| 	    *phFile = CreateFileW(wzFilePath, dwAccess, dwShareMode, NULL, dwCreate, FILE_ATTRIBUTE_NORMAL, NULL);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         LPSTR psz = DsoConvertToMBCS(wzFilePath);
 | |
|         if (psz) *phFile = CreateFileA(psz, dwAccess, dwShareMode, NULL, dwCreate, FILE_ATTRIBUTE_NORMAL, NULL);
 | |
|         DsoMemFree(psz);
 | |
|     }
 | |
|     return (*phFile != INVALID_HANDLE_VALUE);
 | |
| }
 | |
| 
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // FPerformShellOp
 | |
| //
 | |
| //  This function started as a wrapper for SHFileOperation, but that 
 | |
| //  shell function had an enormous performance hit, especially on Win9x
 | |
| //  and NT4. To speed things up we removed the shell32 call and are
 | |
| //  using the kernel32 APIs instead. The only drawback is we can't
 | |
| //  handle multiple files, but that is not critical for this project.
 | |
| //
 | |
| STDAPI_(BOOL) FPerformShellOp(DWORD dwOp, WCHAR* wzFrom, WCHAR* wzTo)
 | |
| {
 | |
| 	BOOL f = FALSE;
 | |
|     if (v_fUnicodeAPI)
 | |
|     {
 | |
| 		switch (dwOp)
 | |
| 		{
 | |
| 		case FO_COPY:		f = CopyFileW(wzFrom, wzTo, FALSE);	break;
 | |
| 		case FO_MOVE: 
 | |
| 		case FO_RENAME:		f = MoveFileW(wzFrom, wzTo);		break;
 | |
| 		case FO_DELETE:		f = DeleteFileW(wzFrom);			break;
 | |
| 		}
 | |
| 	}
 | |
|     else
 | |
|     {
 | |
| 	    LPSTR pszFrom = DsoConvertToMBCS(wzFrom);
 | |
| 	    LPSTR pszTo = DsoConvertToMBCS(wzTo);
 | |
| 
 | |
| 		switch (dwOp)
 | |
| 		{
 | |
| 		case FO_COPY:		f = CopyFileA(pszFrom, pszTo, FALSE); break;
 | |
| 		case FO_MOVE:
 | |
| 		case FO_RENAME:		f = MoveFileA(pszFrom, pszTo);		break;
 | |
| 		case FO_DELETE:		f = DeleteFileA(pszFrom);			break;
 | |
| 		}
 | |
| 
 | |
| 	    if (pszFrom) DsoMemFree(pszFrom);
 | |
| 	    if (pszTo) DsoMemFree(pszTo);
 | |
|     }
 | |
| 
 | |
| 	return f;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // FGetModuleFileName
 | |
| //
 | |
| //  Handles Unicode/ANSI paths from a module handle.
 | |
| //
 | |
| STDAPI_(BOOL) FGetModuleFileName(HMODULE hModule, WCHAR** wzFileName)
 | |
| {
 | |
|     LPWSTR pwsz;
 | |
|     DWORD dw;
 | |
| 
 | |
|     CHECK_NULL_RETURN(wzFileName, FALSE);
 | |
|     *wzFileName = NULL;
 | |
| 
 | |
|     pwsz = (LPWSTR)DsoMemAlloc((MAX_PATH * sizeof(WCHAR)));
 | |
|     CHECK_NULL_RETURN(pwsz, FALSE);
 | |
| 
 | |
|     if (v_fUnicodeAPI)
 | |
|     {
 | |
|         dw = GetModuleFileNameW(hModule, pwsz, MAX_PATH);
 | |
|         if (dw == 0)
 | |
|         {
 | |
|             DsoMemFree(pwsz);
 | |
|             return FALSE;
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         dw = GetModuleFileNameA(hModule, (LPSTR)pwsz, MAX_PATH);
 | |
|         if (dw == 0)
 | |
|         {
 | |
|             DsoMemFree(pwsz);
 | |
|             return FALSE;
 | |
|         }
 | |
| 
 | |
|         LPWSTR pwsz2 = DsoConvertToLPWSTR((LPSTR)pwsz);
 | |
|         if (pwsz2 == NULL)
 | |
|         {
 | |
|             DsoMemFree(pwsz);
 | |
|             return FALSE;
 | |
|         }
 | |
| 
 | |
|         DsoMemFree(pwsz);
 | |
|         pwsz = pwsz2;
 | |
|     }
 | |
| 
 | |
|     *wzFileName = pwsz;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // FIsIECacheFile
 | |
| //
 | |
| //  Determines if file came from IE Cache (treat as read-only).
 | |
| //
 | |
| STDAPI_(BOOL) FIsIECacheFile(LPWSTR pwszFile)
 | |
| {
 | |
|     BOOL fIsCacheFile = FALSE;
 | |
|     LPWSTR pwszTmpCache = NULL;
 | |
|     BYTE rgbuffer[MAX_PATH * sizeof(WCHAR)];
 | |
|     HKEY hk;
 | |
| 
 | |
|     if (RegOpenKey(HKEY_CURRENT_USER, 
 | |
|         "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", &hk) == ERROR_SUCCESS)
 | |
|     {
 | |
|         DWORD dwT, dwS; dwT = MAX_PATH; 
 | |
|         memset(rgbuffer, 0, (MAX_PATH * sizeof(WCHAR)));
 | |
| 
 | |
|         if (v_fUnicodeAPI)
 | |
|         {
 | |
|             if ((RegQueryValueExA(hk, "Cache", 0, &dwT, rgbuffer, &dwS) == ERROR_SUCCESS) && 
 | |
|                 (dwT == REG_SZ) && (dwS > 1))
 | |
|                 pwszTmpCache = DsoConvertToLPWSTR((LPSTR)rgbuffer);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if ((RegQueryValueExW(hk, L"Cache", 0, &dwT, rgbuffer, &dwS) == ERROR_SUCCESS) && 
 | |
|                 (dwT == REG_SZ) && (dwS > 1))
 | |
|                 pwszTmpCache = DsoCopyString((LPWSTR)rgbuffer);
 | |
|         }
 | |
| 
 | |
|         RegCloseKey(hk);
 | |
| 
 | |
|         if (pwszTmpCache)
 | |
|         {
 | |
|             dwS = lstrlenW(pwszTmpCache);
 | |
|             dwT = lstrlenW(pwszFile);
 | |
|             fIsCacheFile = ((dwS < dwT) && 
 | |
|                 (DsoCompareStringsEx(pwszTmpCache, dwS, pwszFile, dwS) == CSTR_EQUAL));
 | |
|             DsoMemFree(pwszTmpCache);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return fIsCacheFile;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // FDrawText
 | |
| //
 | |
| //  This is used by the control for drawing the caption in the titlebar.
 | |
| //  Since a custom caption could contain Unicode characters only printable
 | |
| //  on Unicode OS, we should try to use the Unicode version when available.
 | |
| //
 | |
| STDAPI_(BOOL) FDrawText(HDC hdc, WCHAR* pwsz, LPRECT prc, UINT fmt)
 | |
| {
 | |
| 	BOOL f;
 | |
|     if (v_fUnicodeAPI)
 | |
|     {
 | |
|         f = (BOOL)DrawTextW(hdc, pwsz, -1, prc, fmt);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 		LPSTR psz = DsoConvertToMBCS(pwsz);
 | |
| 		f = (BOOL)DrawTextA(hdc, psz, -1, prc, fmt);
 | |
| 		DsoMemFree(psz);
 | |
|     }
 | |
| 	return f;
 | |
| }
 | |
| 
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // FSetRegKeyValue
 | |
| //
 | |
| //  We use this for registration when dealing with the file path, since
 | |
| //  that path may have Unicode characters on some systems. Win9x boxes
 | |
| //  will have to be converted to ANSI.
 | |
| //
 | |
| STDAPI_(BOOL) FSetRegKeyValue(HKEY hk, WCHAR* pwsz)
 | |
| {
 | |
| 	LONG lret;
 | |
|     if (v_fUnicodeAPI)
 | |
|     {
 | |
|         lret = RegSetValueExW(hk, NULL, 0, REG_SZ, (BYTE*)pwsz, (lstrlenW(pwsz) * sizeof(WCHAR)));
 | |
|     }
 | |
|     else
 | |
| 	{
 | |
| 		LPSTR psz = DsoConvertToMBCS(pwsz);
 | |
| 		lret = RegSetValueExA(hk, NULL, 0, REG_SZ, (BYTE*)psz, lstrlen(psz));
 | |
| 		DsoMemFree(psz);
 | |
| 	}
 | |
| 	return (lret == ERROR_SUCCESS);
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // FOpenPrinter
 | |
| //
 | |
| //  Open the specified printer by name.
 | |
| //
 | |
| STDAPI_(BOOL) FOpenPrinter(LPCWSTR pwszPrinter, LPHANDLE phandle)
 | |
| {
 | |
| 	BOOL fRet = FALSE;
 | |
|     DWORD dwLastError = 0;
 | |
|     if (v_fUnicodeAPI)
 | |
|     {
 | |
|         PRINTER_DEFAULTSW prtdef; 
 | |
|         memset(&prtdef, 0, sizeof(PRINTER_DEFAULTSW));
 | |
|         prtdef.DesiredAccess = PRINTER_ACCESS_USE;
 | |
|         fRet = OpenPrinterW((LPWSTR)pwszPrinter, phandle, &prtdef);
 | |
|     }
 | |
|     else
 | |
| 	{
 | |
| 		LPSTR psz = DsoConvertToMBCS(pwszPrinter);
 | |
|         fRet = OpenPrinterA(psz, phandle, NULL);
 | |
|         if (!fRet) dwLastError = GetLastError();
 | |
| 		DsoMemFree(psz);
 | |
| 	}
 | |
|     if (dwLastError) SetLastError(dwLastError);
 | |
| 	return fRet;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // FGetPrinterSettings
 | |
| //
 | |
| //  Returns the default device, port name, and DEVMODE structure for the
 | |
| //  printer passed. Handles Unicode translation of DEVMODE if on Win9x.
 | |
| //
 | |
| STDAPI_(BOOL) FGetPrinterSettings(HANDLE hprinter, LPWSTR *ppwszProcessor, LPWSTR *ppwszDevice, LPWSTR *ppwszOutput, LPDEVMODEW *ppdvmode, DWORD *pcbSize)
 | |
| {
 | |
| 	BOOL fRet = FALSE;
 | |
|     DWORD dwLastError = 0;
 | |
|     DWORD cbNeed, cbAlloc = 0;
 | |
| 
 | |
|     if ((ppwszProcessor == NULL) || (ppwszDevice == NULL) || (ppwszOutput == NULL) ||
 | |
|         (ppdvmode == NULL) || (pcbSize == NULL))
 | |
|         return FALSE;
 | |
| 
 | |
|     *ppwszProcessor = NULL; *ppwszDevice = NULL; *ppwszOutput = NULL;
 | |
|     *ppdvmode = NULL; *pcbSize = 0;
 | |
| 
 | |
|     if (v_fUnicodeAPI) // Use Unicode API if possible (much easier)...
 | |
|     {
 | |
| 		GetPrinterW(hprinter, 2, NULL, 0, &cbAlloc);
 | |
|         PRINTER_INFO_2W *pinfo = (PRINTER_INFO_2W*)DsoMemAlloc(++cbAlloc);
 | |
|         if (pinfo)
 | |
|         {
 | |
|             fRet = GetPrinterW(hprinter, 2, (BYTE*)pinfo, cbAlloc, &cbNeed);
 | |
|             if (fRet)
 | |
|             {
 | |
|                 *ppwszProcessor = DsoConvertToLPWSTR("winspool");
 | |
|                 *ppwszDevice = DsoCopyString(pinfo->pDriverName);
 | |
|                 *ppwszOutput = DsoCopyString(pinfo->pPortName);
 | |
| 
 | |
|                 if (pinfo->pDevMode) // If we have the devmode, just need to copy it...
 | |
|                 {
 | |
|                     DWORD cbData = (pinfo->pDevMode->dmSize) + (pinfo->pDevMode->dmDriverExtra);
 | |
|                     *ppdvmode = (DEVMODEW*)DsoMemAlloc(cbData);
 | |
|                     if (*ppdvmode)
 | |
|                     {
 | |
|                         memcpy(*ppdvmode, pinfo->pDevMode, cbData);
 | |
|                         *pcbSize = cbData;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else dwLastError = GetLastError();
 | |
| 
 | |
|             DsoMemFree(pinfo);
 | |
|         }
 | |
|         else dwLastError = ERROR_NOT_ENOUGH_MEMORY;   
 | |
|     }
 | |
|     else
 | |
| 	{
 | |
| 		GetPrinterA(hprinter, 2, NULL, 0, &cbAlloc);
 | |
|         PRINTER_INFO_2A *pinfo = (PRINTER_INFO_2A*)DsoMemAlloc(++cbAlloc);
 | |
|         if (pinfo)
 | |
|         {
 | |
|             fRet = GetPrinterA(hprinter, 2, (BYTE*)pinfo, cbAlloc, &cbNeed);
 | |
|             if (fRet)
 | |
|             {
 | |
|                 *ppwszProcessor = DsoConvertToLPWSTR("winspool");
 | |
|                 *ppwszDevice = DsoConvertToLPWSTR(pinfo->pDriverName);
 | |
|                 *ppwszOutput = DsoConvertToLPWSTR(pinfo->pPortName);
 | |
| 
 | |
|                 if (pinfo->pDevMode) // For Win9x API, we have to convert the DEVMODEA
 | |
|                 {                    // into DEVMODEW so we have Unicode names for TARGETDEVICE...
 | |
|                     DWORD cbData = sizeof(DEVMODEW) + 
 | |
|                                 ((pinfo->pDevMode->dmSize > sizeof(DEVMODEA)) ? (pinfo->pDevMode->dmSize - sizeof(DEVMODEA)) : 0) +
 | |
|                                   pinfo->pDevMode->dmDriverExtra;
 | |
| 
 | |
|                     *ppdvmode = (DEVMODEW*)DsoMemAlloc(cbData);
 | |
|                     if (*ppdvmode)
 | |
|                     {
 | |
|                         DsoConvertToUnicodeEx(
 | |
|                             (LPSTR)(pinfo->pDevMode->dmDeviceName), CCHDEVICENAME,
 | |
|                             (LPWSTR)((*ppdvmode)->dmDeviceName), CCHDEVICENAME, 0);
 | |
| 
 | |
|                         // The rest of the copy depends on the default size of the DEVMODE.
 | |
|                         // Just check the size and convert the form name if it exists...
 | |
| 		                if (pinfo->pDevMode->dmSize <= FIELD_OFFSET(DEVMODEA, dmFormName))
 | |
|                         {
 | |
|                             memcpy(&((*ppdvmode)->dmSpecVersion), 
 | |
|                                    &(pinfo->pDevMode->dmSpecVersion),
 | |
|                                    pinfo->pDevMode->dmSize - CCHDEVICENAME);
 | |
| 		                }
 | |
| 		                else 
 | |
|                         {
 | |
| 			                memcpy(&((*ppdvmode)->dmSpecVersion), 
 | |
|                                    &(pinfo->pDevMode->dmSpecVersion),
 | |
| 				                   FIELD_OFFSET(DEVMODEA, dmFormName) -
 | |
| 					               FIELD_OFFSET(DEVMODEA, dmSpecVersion));
 | |
| 
 | |
|                             DsoConvertToUnicodeEx(
 | |
|                                 (LPSTR)(pinfo->pDevMode->dmFormName), CCHFORMNAME,
 | |
|                                 (LPWSTR)((*ppdvmode)->dmFormName), CCHFORMNAME, 0);
 | |
| 
 | |
| 			                if (pinfo->pDevMode->dmSize > FIELD_OFFSET(DEVMODEA, dmLogPixels))
 | |
| 				                memcpy(&((*ppdvmode)->dmLogPixels),
 | |
|                                        &(pinfo->pDevMode->dmLogPixels),
 | |
| 					                   pinfo->pDevMode->dmSize - FIELD_OFFSET(DEVMODEA, dmLogPixels));
 | |
| 		                }
 | |
|             
 | |
|                         (*ppdvmode)->dmSize = (WORD)((pinfo->pDevMode->dmSize > sizeof(DEVMODEA)) ?
 | |
|                                                    (sizeof(DEVMODEW) + (pinfo->pDevMode->dmSize - sizeof(DEVMODEA))) :
 | |
|                                                     sizeof(DEVMODEW));
 | |
| 
 | |
|                         memcpy((((BYTE*)(*ppdvmode)) + ((*ppdvmode)->dmSize)),
 | |
|                                (((BYTE*)(pinfo->pDevMode)) + (pinfo->pDevMode->dmSize)),
 | |
|                                pinfo->pDevMode->dmDriverExtra);
 | |
| 
 | |
|                         *pcbSize = cbData;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else dwLastError = GetLastError();
 | |
| 
 | |
|             DsoMemFree(pinfo);
 | |
|         }
 | |
|         else dwLastError = ERROR_NOT_ENOUGH_MEMORY;
 | |
| 	}
 | |
|     if (dwLastError) SetLastError(dwLastError);
 | |
| 	return fRet;
 | |
| }
 | |
| 
 | |
| 
 | |
| ///////////////////////////////////////////////////////////////////////////////////
 | |
| // DsoGetFileFromUser
 | |
| //
 | |
| //  Displays the Open/Save dialog using Unicode version if available. Returns the
 | |
| //  path as a unicode BSTR regardless of OS.
 | |
| //
 | |
| STDAPI DsoGetFileFromUser(HWND hwndOwner, LPCWSTR pwzTitle, DWORD dwFlags, 
 | |
|        LPCWSTR pwzFilter, DWORD dwFiltIdx, LPCWSTR pwszDefExt, LPCWSTR pwszCurrentItem, BOOL fShowSave,
 | |
|        BSTR *pbstrFile, BOOL *pfReadOnly)
 | |
| {
 | |
| 	BYTE buffer[MAX_PATH * sizeof(WCHAR)];
 | |
| 	BOOL fSuccess;
 | |
| 	DWORD dw;
 | |
| 
 | |
|  // Make sure they pass a *bstr...
 | |
|     CHECK_NULL_RETURN(pbstrFile,  E_POINTER);
 | |
|     *pbstrFile = NULL;
 | |
| 
 | |
| 	buffer[0] = 0; buffer[1] = 0;
 | |
| 
 | |
|  // See if we have Unicode function to call. If so, we use OPENFILENAMEW and 
 | |
|  // get the file path in Unicode, returned as BSTR...
 | |
| 	 if (v_fUnicodeAPI)
 | |
| 	{
 | |
| 		OPENFILENAMEW ofnw;
 | |
| 		memset(&ofnw,  0,   sizeof(OPENFILENAMEW));
 | |
| 	    ofnw.lStructSize  = sizeof(OPENFILENAMEW);
 | |
| 	    ofnw.hwndOwner    = hwndOwner;
 | |
| 	    ofnw.lpstrFilter  = pwzFilter;
 | |
| 	    ofnw.nFilterIndex = dwFiltIdx;
 | |
|         ofnw.lpstrDefExt  = pwszDefExt;
 | |
| 	    ofnw.lpstrTitle   = pwzTitle;
 | |
| 	    ofnw.lpstrFile    = (LPWSTR)&buffer[0];
 | |
| 	    ofnw.nMaxFile     = MAX_PATH;
 | |
| 	    ofnw.Flags        = dwFlags;
 | |
| 
 | |
| 		if (pwszCurrentItem)
 | |
| 		{
 | |
| 			dw = lstrlenW(pwszCurrentItem);
 | |
| 			if ((dw) && (dw < MAX_PATH))
 | |
| 			{
 | |
| 				memcpy(ofnw.lpstrFile, pwszCurrentItem,  dw * sizeof(WCHAR));
 | |
| 				ofnw.lpstrFile[dw] = L'\0';
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (fShowSave)
 | |
| 			fSuccess = GetSaveFileNameW(&ofnw);
 | |
| 		else
 | |
| 			fSuccess = GetOpenFileNameW(&ofnw);
 | |
| 
 | |
| 		if (fSuccess)
 | |
|         {
 | |
| 			*pbstrFile = SysAllocString((LPWSTR)&buffer[0]);
 | |
|             if (pfReadOnly) *pfReadOnly = (ofnw.Flags & OFN_READONLY);
 | |
|         }
 | |
| 	}
 | |
| 	else
 | |
| 	{ // If not, then we use OPENFILENAMEA and thunk down our params to
 | |
| 	  // the MBCS of the system, and then thunk back the Unicode for the return...
 | |
| 		OPENFILENAMEA ofn;
 | |
| 		memset(&ofn,  0,   sizeof(OPENFILENAMEA));
 | |
| 	    ofn.lStructSize  = sizeof(OPENFILENAMEA);
 | |
| 	    ofn.hwndOwner    = hwndOwner;
 | |
| 	    ofn.lpstrFilter  = DsoConvertToMBCS(pwzFilter);
 | |
| 	    ofn.nFilterIndex = dwFiltIdx;
 | |
|         ofn.lpstrDefExt  = DsoConvertToMBCS(pwszDefExt);
 | |
| 	    ofn.lpstrTitle   = DsoConvertToMBCS(pwzTitle);
 | |
| 	    ofn.lpstrFile    = (LPSTR)&buffer[0];
 | |
| 	    ofn.nMaxFile     = MAX_PATH;
 | |
| 	    ofn.Flags        = dwFlags;
 | |
| 
 | |
| 		if (pwszCurrentItem)
 | |
| 			DsoConvertToMBCSEx(pwszCurrentItem, lstrlenW(pwszCurrentItem), (LPSTR)&buffer[0], MAX_PATH, GetACP());
 | |
| 
 | |
| 		if (fShowSave)
 | |
| 			fSuccess = GetSaveFileNameA(&ofn);
 | |
| 		else
 | |
| 			fSuccess = GetOpenFileNameA(&ofn);
 | |
| 
 | |
| 
 | |
| 		if (fSuccess)
 | |
|         {
 | |
| 			*pbstrFile = DsoConvertToBSTR((LPCSTR)&buffer[0]);
 | |
|             if (pfReadOnly) *pfReadOnly = (ofn.Flags & OFN_READONLY);
 | |
|         }
 | |
| 
 | |
|         DsoMemFree((void*)(ofn.lpstrDefExt));
 | |
|         DsoMemFree((void*)(ofn.lpstrFilter));
 | |
|         DsoMemFree((void*)(ofn.lpstrTitle));
 | |
| 	}
 | |
| 
 | |
|  // If we got a string, then success. All other errors (even user cancel) should
 | |
|  // be treated as a general failure (feel free to change this for more full function).
 | |
|     return ((*pbstrFile == NULL) ? E_FAIL : S_OK);
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////////////////////////////
 | |
| // DsoGetOleInsertObjectFromUser
 | |
| //
 | |
| //  Displays the OLE InsertObject dialog using Unicode version if available.
 | |
| //
 | |
| STDAPI DsoGetOleInsertObjectFromUser(HWND hwndOwner, LPCWSTR pwzTitle, DWORD dwFlags, 
 | |
|         BOOL fDocObjectOnly, BOOL fAllowControls, BSTR *pbstrResult, UINT *ptype)
 | |
| {
 | |
| 	BYTE buffer[MAX_PATH * sizeof(WCHAR)];
 | |
|     LPCLSID lpNewExcludeList = NULL;
 | |
| 	int nNewExcludeCount = 0;
 | |
| 	int nNewExcludeLen = 0;
 | |
| 
 | |
|  // Make sure they pass a *bstr...
 | |
|     CHECK_NULL_RETURN(pbstrResult,  E_POINTER);
 | |
|     *pbstrResult = NULL;
 | |
| 
 | |
|  // To limit list to just those marked as DocObject servers, you have to enum
 | |
|  // the registry and create an exclude list for OLE dialog. Exclude all except
 | |
|  // those that are marked DocObject under their ProgID.
 | |
|     if (fDocObjectOnly)
 | |
|     {
 | |
| 	    HKEY hkCLSID;
 | |
| 	    HKEY hkItem;
 | |
| 	    HKEY hkDocObject;
 | |
| 	    DWORD dwIndex = 0;
 | |
| 	    CHAR szName[MAX_PATH+1];
 | |
| 
 | |
| 	    if (RegOpenKeyEx(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ|KEY_ENUMERATE_SUB_KEYS, &hkCLSID) == ERROR_SUCCESS)
 | |
| 	    {
 | |
| 		    while (RegEnumKey(hkCLSID, dwIndex++, szName, MAX_PATH) == ERROR_SUCCESS)
 | |
| 		    {
 | |
| 			    if (RegOpenKeyEx(hkCLSID, szName, 0, KEY_READ, &hkItem) == ERROR_SUCCESS)
 | |
| 			    {
 | |
| 					if ((RegOpenKeyEx(hkItem, "DocObject", 0, KEY_READ, &hkDocObject) != ERROR_SUCCESS))
 | |
| 					{
 | |
| 						CLSID clsid;
 | |
| 						LPWSTR pwszClsid = DsoConvertToLPWSTR(szName);
 | |
| 						if ((pwszClsid) && SUCCEEDED(CLSIDFromString(pwszClsid, &clsid)))
 | |
| 						{
 | |
| 							if (lpNewExcludeList == NULL)
 | |
| 							{
 | |
| 								nNewExcludeCount = 0;
 | |
| 								nNewExcludeLen = 16;
 | |
| 								lpNewExcludeList = new CLSID[nNewExcludeLen];
 | |
| 							}
 | |
| 							if (nNewExcludeCount == nNewExcludeLen)
 | |
| 							{
 | |
| 								LPCLSID lpOldList = lpNewExcludeList;
 | |
| 								nNewExcludeLen <<= 2;
 | |
| 								lpNewExcludeList = new CLSID[nNewExcludeLen];
 | |
| 								memcpy(lpNewExcludeList, lpOldList, sizeof(CLSID) * nNewExcludeCount);
 | |
| 								delete [] lpOldList;
 | |
| 							}
 | |
| 
 | |
| 							lpNewExcludeList[nNewExcludeCount] = clsid;
 | |
| 							nNewExcludeCount++;
 | |
| 						}
 | |
| 						SAFE_FREESTRING(pwszClsid);
 | |
|                         RegCloseKey(hkDocObject);
 | |
| 					}
 | |
| 				    
 | |
| 				    RegCloseKey(hkItem);
 | |
| 			    }
 | |
| 		    }
 | |
| 		    RegCloseKey(hkCLSID);
 | |
| 	    }
 | |
|     }
 | |
| 	buffer[0] = 0; buffer[1] = 0;
 | |
| 
 | |
|  // See if we have Unicode function to call...
 | |
| 	if (v_fUnicodeAPI)
 | |
| 	{
 | |
| 	    OLEUIINSERTOBJECTW oidlg = {0};
 | |
| 	    oidlg.cbStruct = sizeof(OLEUIINSERTOBJECTW);
 | |
| 	    oidlg.dwFlags = dwFlags;
 | |
| 	    oidlg.hWndOwner = hwndOwner;
 | |
| 	    oidlg.lpszCaption = pwzTitle;
 | |
| 	    oidlg.lpszFile = (LPWSTR)buffer;
 | |
| 	    oidlg.cchFile = MAX_PATH;
 | |
| 		oidlg.lpClsidExclude = lpNewExcludeList;
 | |
| 		oidlg.cClsidExclude = nNewExcludeCount;
 | |
| 
 | |
| 		if (OleUIInsertObjectW(&oidlg) == OLEUI_OK)
 | |
| 		{
 | |
| 			if ((oidlg.dwFlags & IOF_SELECTCREATENEW) && (oidlg.clsid != GUID_NULL))
 | |
| 			{
 | |
| 				LPOLESTR posz;
 | |
| 				if (SUCCEEDED(ProgIDFromCLSID(oidlg.clsid, &posz)))
 | |
| 				{
 | |
| 					*pbstrResult = SysAllocString(posz);
 | |
| 					CoTaskMemFree(posz);
 | |
| 				}
 | |
|                 if (ptype) *ptype = IOF_SELECTCREATENEW;
 | |
| 			}
 | |
| 			else if ((oidlg.dwFlags & IOF_SELECTCREATEFROMFILE) && (buffer[0] != 0))
 | |
| 			{
 | |
| 				*pbstrResult = SysAllocString((LPWSTR)buffer);
 | |
|                 if (ptype) *ptype = IOF_SELECTCREATEFROMFILE;
 | |
| 			}
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	    OLEUIINSERTOBJECTA oidlg = {0};
 | |
| 	    oidlg.cbStruct = sizeof(OLEUIINSERTOBJECTA);
 | |
| 	    oidlg.dwFlags = dwFlags;
 | |
| 	    oidlg.hWndOwner = hwndOwner;
 | |
| 	    oidlg.lpszCaption = DsoConvertToMBCS(pwzTitle);
 | |
| 	    oidlg.lpszFile = (LPSTR)buffer;
 | |
| 	    oidlg.cchFile = MAX_PATH;
 | |
| 		oidlg.lpClsidExclude = lpNewExcludeList;
 | |
| 		oidlg.cClsidExclude = nNewExcludeCount;
 | |
| 
 | |
| 		if (OleUIInsertObjectA(&oidlg) == OLEUI_OK)
 | |
| 		{
 | |
| 			if ((oidlg.dwFlags & IOF_SELECTCREATENEW) && (oidlg.clsid != GUID_NULL))
 | |
| 			{
 | |
| 				LPOLESTR posz;
 | |
| 				if (SUCCEEDED(ProgIDFromCLSID(oidlg.clsid, &posz)))
 | |
| 				{
 | |
| 					*pbstrResult = SysAllocString(posz);
 | |
| 					CoTaskMemFree(posz);
 | |
| 				}
 | |
|                 if (ptype) *ptype = IOF_SELECTCREATENEW;
 | |
| 			}
 | |
| 			else if ((oidlg.dwFlags & IOF_SELECTCREATEFROMFILE) && (buffer[0] != 0))
 | |
| 			{
 | |
| 				*pbstrResult = DsoConvertToBSTR((LPSTR)buffer);
 | |
|                 if (ptype) *ptype = IOF_SELECTCREATEFROMFILE;
 | |
| 			}
 | |
|         }
 | |
| 
 | |
|         DsoMemFree((void*)(oidlg.lpszCaption));
 | |
|     }
 | |
| 
 | |
|     if (lpNewExcludeList)
 | |
| 		delete [] lpNewExcludeList;
 | |
| 
 | |
|  // If we got a string, then success. All other errors (even user cancel) should
 | |
|  // be treated as a general failure (feel free to change this for more full function).
 | |
|     return ((*pbstrResult == NULL) ? E_FAIL : S_OK);
 | |
| }
 | 
