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);
|
|
}
|