700 lines
19 KiB
C++
700 lines
19 KiB
C++
//
|
|
// Unicwrap.cpp
|
|
//
|
|
// Simple thunking layer for NT/9X.
|
|
//
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#define _NO_UNICWRAP_WRAPPERS_
|
|
#include "theapp.h"
|
|
#include "cstrinout.h"
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// WNET
|
|
//
|
|
|
|
DWORD WNetOpenEnumWrapW(DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCEW lpNetResource, LPHANDLE lphEnum)
|
|
{
|
|
ASSERT(sizeof(NETRESOURCEA)==sizeof(NETRESOURCEW));
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
return WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetResource, lphEnum);
|
|
}
|
|
else
|
|
{
|
|
if (!lpNetResource)
|
|
{
|
|
return WNetOpenEnumA(dwScope, dwType, dwUsage, NULL, lphEnum);
|
|
}
|
|
else
|
|
{
|
|
CStrIn cstrLocalName(lpNetResource->lpLocalName);
|
|
CStrIn cstrRemoteName(lpNetResource->lpRemoteName);
|
|
CStrIn cstrComment(lpNetResource->lpComment);
|
|
CStrIn cstrProvider(lpNetResource->lpProvider);
|
|
|
|
NETRESOURCEA nrA;
|
|
CopyMemory(&nrA, lpNetResource, sizeof(nrA));
|
|
|
|
nrA.lpLocalName = cstrLocalName;
|
|
nrA.lpRemoteName = cstrRemoteName;
|
|
nrA.lpComment = cstrComment;
|
|
nrA.lpProvider = cstrProvider;
|
|
|
|
return WNetOpenEnumA(dwScope, dwType, dwUsage, &nrA, lphEnum);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DWORD WNetEnumResourceWrapW(HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
|
|
{
|
|
ASSERT((!*lpBufferSize && !lpBuffer) || (*lpBufferSize && lpBuffer));
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
return WNetEnumResourceW(hEnum, lpcCount, lpBuffer, lpBufferSize);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwRet;
|
|
LPVOID lpBufferA = NULL;
|
|
DWORD dwBufferSizeA = (*lpBufferSize) / 2;
|
|
|
|
if (dwBufferSizeA)
|
|
{
|
|
lpBufferA = malloc(dwBufferSizeA);
|
|
if (!lpBufferA)
|
|
return ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
dwRet = WNetEnumResourceA(hEnum, lpcCount, lpBufferA, &dwBufferSizeA);
|
|
|
|
if ((0 == dwRet) || (ERROR_MORE_DATA == dwRet))
|
|
{
|
|
if (lpBufferA)
|
|
{
|
|
LPNETRESOURCEW pnrW = (LPNETRESOURCEW)lpBuffer;
|
|
LPNETRESOURCEA pnrA = (LPNETRESOURCEA)lpBufferA;
|
|
LPWSTR pwszStrings = (LPWSTR)&pnrW[*lpcCount];
|
|
DWORD cchStrings = (*lpBufferSize - (DWORD)((LPBYTE)pwszStrings - (LPBYTE)pnrW)) / sizeof(WCHAR);
|
|
DWORD i;
|
|
|
|
// if cchStrings goes to 0 before all strings are copied, pwszStrings points
|
|
// one past the buffer length. this case shouldn't happen, but if it does
|
|
// we don't want to fault - reduce cchStrings by one so we point to valid memory.
|
|
//
|
|
cchStrings --;
|
|
for (i=0 ; i<*lpcCount ; i++)
|
|
{
|
|
ASSERT(sizeof(NETRESOURCEW) == sizeof(NETRESOURCEA));
|
|
CopyMemory(pnrW, pnrA, sizeof(NETRESOURCEA));
|
|
|
|
if (pnrA->lpLocalName)
|
|
{
|
|
DWORD cch = SHAnsiToUnicode(pnrA->lpLocalName, pwszStrings, cchStrings);
|
|
pnrW->lpLocalName = pwszStrings;
|
|
pwszStrings += cch;
|
|
cchStrings -= cch;
|
|
}
|
|
if (pnrA->lpRemoteName)
|
|
{
|
|
DWORD cch = SHAnsiToUnicode(pnrA->lpRemoteName, pwszStrings, cchStrings);
|
|
pnrW->lpRemoteName = pwszStrings;
|
|
pwszStrings += cch;
|
|
cchStrings -= cch;
|
|
}
|
|
if (pnrA->lpComment)
|
|
{
|
|
DWORD cch = SHAnsiToUnicode(pnrA->lpComment, pwszStrings, cchStrings);
|
|
pnrW->lpComment = pwszStrings;
|
|
pwszStrings += cch;
|
|
cchStrings -= cch;
|
|
}
|
|
if (pnrA->lpProvider)
|
|
{
|
|
DWORD cch = SHAnsiToUnicode(pnrA->lpProvider, pwszStrings, cchStrings);
|
|
pnrW->lpProvider = pwszStrings;
|
|
pwszStrings += cch;
|
|
cchStrings -= cch;
|
|
}
|
|
|
|
pnrW++;
|
|
pnrA++;
|
|
}
|
|
// (and null out that memory for the overflow case)
|
|
*pwszStrings = TEXTW('\0');
|
|
}
|
|
|
|
*lpBufferSize = dwBufferSizeA * 2 + 1;
|
|
}
|
|
|
|
if (lpBufferA)
|
|
{
|
|
free(lpBufferA);
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
return WN_NOT_SUPPORTED;
|
|
}
|
|
|
|
DWORD WNetGetUserWrapW(LPCWSTR lpName, LPWSTR lpUserName, LPDWORD lpnLength)
|
|
{
|
|
if (g_fRunningOnNT)
|
|
{
|
|
return WNetGetUserW(lpName, lpUserName, lpnLength);
|
|
}
|
|
else
|
|
{
|
|
CStrIn cstrName(lpName);
|
|
CStrOut cstrUserName(lpUserName, *lpnLength);
|
|
|
|
// *lpnLength is character count, so no adjustment needed on ERROR_MORE_DATA
|
|
return WNetGetUserA(cstrName, cstrUserName, lpnLength);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// RAS
|
|
//
|
|
|
|
// ras structure thunkers
|
|
|
|
class CRasDialParamsIn
|
|
{
|
|
public:
|
|
CRasDialParamsIn(LPRASDIALPARAMSW pRDP);
|
|
|
|
void Convert();
|
|
|
|
operator LPRASDIALPARAMSA() { return _pRDPW ? &_rdp : NULL; };
|
|
|
|
private:
|
|
|
|
RASDIALPARAMSA _rdp;
|
|
LPRASDIALPARAMSW _pRDPW;
|
|
};
|
|
|
|
CRasDialParamsIn::CRasDialParamsIn(LPRASDIALPARAMSW pRDP)
|
|
{
|
|
_pRDPW = pRDP;
|
|
_rdp.dwSize = sizeof(_rdp);
|
|
}
|
|
|
|
void CRasDialParamsIn::Convert()
|
|
{
|
|
if (_pRDPW)
|
|
{
|
|
_rdp.dwSize = sizeof(_rdp);
|
|
SHUnicodeToAnsi(_pRDPW->szEntryName, _rdp.szEntryName, ARRAYSIZE(_rdp.szEntryName));
|
|
SHUnicodeToAnsi(_pRDPW->szPhoneNumber, _rdp.szPhoneNumber, ARRAYSIZE(_rdp.szPhoneNumber));
|
|
SHUnicodeToAnsi(_pRDPW->szCallbackNumber, _rdp.szCallbackNumber, ARRAYSIZE(_rdp.szCallbackNumber));
|
|
SHUnicodeToAnsi(_pRDPW->szUserName, _rdp.szUserName, ARRAYSIZE(_rdp.szUserName));
|
|
SHUnicodeToAnsi(_pRDPW->szPassword, _rdp.szPassword, ARRAYSIZE(_rdp.szPassword));
|
|
SHUnicodeToAnsi(_pRDPW->szDomain, _rdp.szDomain, ARRAYSIZE(_rdp.szDomain));
|
|
}
|
|
}
|
|
|
|
class CRasDialParamsOut
|
|
{
|
|
public:
|
|
CRasDialParamsOut(LPRASDIALPARAMSW pRDP) { _pRDPW = pRDP; _rdp.dwSize = sizeof(_rdp); };
|
|
|
|
void Convert();
|
|
void NullOutBuffer();
|
|
|
|
operator LPRASDIALPARAMSA() { return _pRDPW ? &_rdp : NULL; };
|
|
|
|
private:
|
|
|
|
RASDIALPARAMSA _rdp;
|
|
LPRASDIALPARAMSW _pRDPW;
|
|
};
|
|
|
|
void CRasDialParamsOut::Convert()
|
|
{
|
|
if (_pRDPW)
|
|
{
|
|
ASSERT(_pRDPW->dwSize == sizeof(*_pRDPW));
|
|
SHAnsiToUnicode(_rdp.szEntryName, _pRDPW->szEntryName, ARRAYSIZE(_pRDPW->szEntryName));
|
|
SHAnsiToUnicode(_rdp.szPhoneNumber, _pRDPW->szPhoneNumber, ARRAYSIZE(_pRDPW->szPhoneNumber));
|
|
SHAnsiToUnicode(_rdp.szCallbackNumber, _pRDPW->szCallbackNumber, ARRAYSIZE(_pRDPW->szCallbackNumber));
|
|
SHAnsiToUnicode(_rdp.szUserName, _pRDPW->szUserName, ARRAYSIZE(_pRDPW->szUserName));
|
|
SHAnsiToUnicode(_rdp.szPassword, _pRDPW->szPassword, ARRAYSIZE(_pRDPW->szPassword));
|
|
SHAnsiToUnicode(_rdp.szDomain, _pRDPW->szDomain, ARRAYSIZE(_pRDPW->szDomain));
|
|
}
|
|
}
|
|
|
|
void CRasDialParamsOut::NullOutBuffer()
|
|
{
|
|
if (_pRDPW)
|
|
{
|
|
_pRDPW->szEntryName[0] = '\0';
|
|
_pRDPW->szPhoneNumber[0] = '\0';
|
|
_pRDPW->szCallbackNumber[0] = '\0';
|
|
_pRDPW->szUserName[0] = '\0';
|
|
_pRDPW->szPassword[0] = '\0';
|
|
_pRDPW->szDomain[0] = '\0';
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// ras function wrappers
|
|
//
|
|
|
|
// Use old size so we work downlevel
|
|
#define OLD_RASENTRYNAMEA_SIZE ((DWORD)(&((RASENTRYNAMEA*)NULL)->dwFlags))
|
|
|
|
DWORD RasEnumEntriesWrapW(LPCWSTR reserved, LPCWSTR pszPhoneBookPath, LPRASENTRYNAMEW pRasEntryNameW, LPDWORD pcb, LPDWORD pcEntries)
|
|
{
|
|
ASSERT(NULL==reserved && NULL==pszPhoneBookPath); // we don't thunk these, so make sure we don't call with them
|
|
ASSERT(!pRasEntryNameW || *pcb>0); // we're either requesting the size or we have a buffer
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
return RasEnumEntriesW(reserved, pszPhoneBookPath, pRasEntryNameW, pcb, pcEntries);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwRet = 0; // assume success
|
|
DWORD cbA = *pcb / 2; // inverse of below
|
|
LPRASENTRYNAMEA pRasEntryNameA = NULL;
|
|
|
|
// if we're requesting info, allocate an ansi buffer
|
|
if (pRasEntryNameW)
|
|
{
|
|
pRasEntryNameA = (LPRASENTRYNAMEA)malloc(cbA);
|
|
|
|
if (pRasEntryNameA)
|
|
{
|
|
pRasEntryNameA->dwSize = OLD_RASENTRYNAMEA_SIZE;
|
|
}
|
|
else
|
|
{
|
|
dwRet = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
if (0==dwRet)
|
|
{
|
|
dwRet = RasEnumEntriesA(NULL, NULL, pRasEntryNameA, &cbA, pcEntries);
|
|
|
|
// we successfully got info, thunk it back
|
|
if (0 == dwRet && pRasEntryNameA)
|
|
{
|
|
UINT i;
|
|
|
|
RASENTRYNAMEA* pRasEntryNameA2 = pRasEntryNameA;
|
|
|
|
for (i=0 ; i<*pcEntries ; i++)
|
|
{
|
|
pRasEntryNameW[i].dwSize = sizeof(pRasEntryNameW[i]);
|
|
SHAnsiToUnicode(pRasEntryNameA2->szEntryName, pRasEntryNameW[i].szEntryName, ARRAYSIZE(pRasEntryNameW[i].szEntryName));
|
|
pRasEntryNameA2 = (RASENTRYNAMEA*)((BYTE*)pRasEntryNameA2 + OLD_RASENTRYNAMEA_SIZE);
|
|
}
|
|
}
|
|
|
|
// allow room for thunking
|
|
*pcb = *pcEntries * sizeof(RASENTRYNAMEW);
|
|
}
|
|
|
|
if (pRasEntryNameA)
|
|
free(pRasEntryNameA);
|
|
|
|
return dwRet;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DWORD RasSetEntryDialParamsWrapW(LPCWSTR pszPhonebook, LPRASDIALPARAMSW lpRasDialParamsW, BOOL fRemovePassword)
|
|
{
|
|
ASSERT(NULL==pszPhonebook); // we don't thunk this
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
return RasSetEntryDialParamsW(pszPhonebook, lpRasDialParamsW, fRemovePassword);
|
|
}
|
|
else
|
|
{
|
|
CRasDialParamsIn rdp(lpRasDialParamsW);
|
|
|
|
rdp.Convert();
|
|
|
|
return RasSetEntryDialParamsA(NULL, rdp, fRemovePassword);
|
|
}
|
|
}
|
|
|
|
DWORD RasGetEntryDialParamsWrapW(LPCWSTR pszPhonebook, LPRASDIALPARAMSW lpRasDialParamsW, LPBOOL pfRemovePassword)
|
|
{
|
|
ASSERT(NULL==pszPhonebook); // we don't thunk this
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
return RasGetEntryDialParamsW(pszPhonebook, lpRasDialParamsW, pfRemovePassword);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwRet;
|
|
CRasDialParamsOut rdp(lpRasDialParamsW);
|
|
|
|
dwRet = RasGetEntryDialParamsA(NULL, rdp, pfRemovePassword);
|
|
|
|
if (ERROR_SUCCESS == dwRet)
|
|
{
|
|
rdp.Convert();
|
|
}
|
|
else
|
|
{
|
|
rdp.NullOutBuffer();
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
}
|
|
|
|
DWORD RnaGetDefaultAutodialConnectionWrap(LPWSTR szBuffer, DWORD cchBuffer, LPDWORD lpdwOptions)
|
|
{
|
|
ASSERT(0 < cchBuffer);
|
|
ASSERT(cchBuffer <= MAX_PATH); // largest string we thunk
|
|
|
|
if (!g_fRunningOnNT)
|
|
{
|
|
DWORD dwRet;
|
|
|
|
CStrOut cstroutBuffer(szBuffer, cchBuffer);
|
|
|
|
dwRet = RnaGetDefaultAutodialConnection(cstroutBuffer, cstroutBuffer.BufSize(), lpdwOptions);
|
|
|
|
cstroutBuffer.ConvertIncludingNul();
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
// NT doesn't have an implementation of this function
|
|
*lpdwOptions = 0;
|
|
szBuffer[0] = TEXT('\0');
|
|
|
|
return 0;
|
|
}
|
|
|
|
DWORD RnaSetDefaultAutodialConnectionWrap(LPWSTR szEntry, DWORD dwOptions)
|
|
{
|
|
ASSERT(lstrlen(szEntry) < MAX_PATH); // should be valid since we assert this on the Get...
|
|
|
|
if (!g_fRunningOnNT)
|
|
{
|
|
CStrIn cstrinEntry(szEntry);
|
|
return RnaSetDefaultAutodialConnection(cstrinEntry, dwOptions);
|
|
}
|
|
|
|
// NT doesn't have an implementation of this function
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// PropertySheet wrappers.
|
|
//
|
|
|
|
|
|
INT_PTR WINAPI PropertySheetWrapW(LPCPROPSHEETHEADERW ppshW)
|
|
{
|
|
INT_PTR iRet;
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
iRet = PropertySheetW(ppshW);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Warning! Warning! Warning!
|
|
//
|
|
// This code assumes that none of the strings in this struct are being
|
|
// used. If a string gets used then the structure will have to be
|
|
// converted. It also assumes that PROPSHEETHEADERW and
|
|
// PROPSHEETHEADERA are the same except for string types.
|
|
//
|
|
|
|
COMPILETIME_ASSERT(sizeof(PROPSHEETHEADERW) == sizeof(PROPSHEETHEADERA));
|
|
|
|
ASSERT(NULL == ppshW->pszIcon || !(ppshW->dwFlags & PSH_USEICONID) || IS_INTRESOURCE(ppshW->pszIcon));
|
|
ASSERT(NULL == ppshW->pszCaption || IS_INTRESOURCE(ppshW->pszCaption));
|
|
ASSERT(NULL == ppshW->pStartPage || !(ppshW->dwFlags & PSH_USEPSTARTPAGE) || IS_INTRESOURCE(ppshW->pStartPage));
|
|
ASSERT(NULL == ppshW->pszIcon || !(ppshW->dwFlags & PSH_USEICONID) || IS_INTRESOURCE(ppshW->pszIcon));
|
|
ASSERT(NULL == ppshW->pszbmWatermark || !(ppshW->dwFlags & PSH_USEHBMWATERMARK) || IS_INTRESOURCE(ppshW->pszbmWatermark));
|
|
ASSERT(NULL == ppshW->pszbmHeader || !(ppshW->dwFlags & PSH_USEHBMHEADER) || IS_INTRESOURCE(ppshW->pszbmHeader));
|
|
|
|
iRet = PropertySheetA((LPCPROPSHEETHEADERA)ppshW);
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
HPROPSHEETPAGE WINAPI CreatePropertySheetPageWrapW(LPCPROPSHEETPAGEW ppspW)
|
|
{
|
|
HPROPSHEETPAGE hpspRet;
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
hpspRet = CreatePropertySheetPageW(ppspW);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Warning! Warning! Warning!
|
|
//
|
|
// This code assumes that none of the strings in this struct are being
|
|
// used. If a string gets used then the structure will have to be
|
|
// converted. It also assumes that PROPSHEETPAGEW and
|
|
// PROPSHEETPAGEA are the same except for string types.
|
|
//
|
|
|
|
COMPILETIME_ASSERT(sizeof(PROPSHEETPAGEW) == sizeof(PROPSHEETPAGEA));
|
|
|
|
ASSERT(NULL == ppspW->pszTemplate || (ppspW->dwFlags & PSP_DLGINDIRECT) || IS_INTRESOURCE(ppspW->pszTemplate));
|
|
ASSERT(NULL == ppspW->pszIcon || !(ppspW->dwFlags & PSP_USEICONID) || IS_INTRESOURCE(ppspW->pszIcon));
|
|
ASSERT(NULL == ppspW->pszTitle || !(ppspW->dwFlags & PSP_USETITLE) || IS_INTRESOURCE(ppspW->pszTitle));
|
|
ASSERT(NULL == ppspW->pszHeaderTitle || !(ppspW->dwFlags & PSP_USEHEADERTITLE) || IS_INTRESOURCE(ppspW->pszHeaderTitle));
|
|
ASSERT(NULL == ppspW->pszHeaderSubTitle || !(ppspW->dwFlags & PSP_USEHEADERSUBTITLE) || IS_INTRESOURCE(ppspW->pszHeaderSubTitle));
|
|
|
|
hpspRet = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)ppspW);
|
|
}
|
|
|
|
return hpspRet;
|
|
}
|
|
|
|
//
|
|
// Miscelaneous APIs that aren't wrapped in shlwapi. Move to shlwapi?
|
|
//
|
|
|
|
UINT WINAPI GlobalGetAtomNameWrapW(ATOM nAtom, LPWSTR lpBuffer, int nSize)
|
|
{
|
|
UINT uRet;
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
uRet = GlobalGetAtomNameW(nAtom, lpBuffer, nSize);
|
|
}
|
|
else
|
|
{
|
|
CStrOut csoBuffer(lpBuffer, nSize);
|
|
|
|
uRet = GlobalGetAtomNameA(nAtom, csoBuffer, csoBuffer.BufSize());
|
|
}
|
|
|
|
return uRet;
|
|
}
|
|
|
|
BOOL WINAPI GetComputerNameWrapW(LPWSTR lpBuffer, LPDWORD pnSize)
|
|
{
|
|
BOOL fRet;
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
fRet = GetComputerNameW(lpBuffer, pnSize);
|
|
}
|
|
else
|
|
{
|
|
CStrOut csoBuffer(lpBuffer, *pnSize);
|
|
DWORD cch = csoBuffer.BufSize();
|
|
|
|
fRet = GetComputerNameA(csoBuffer, &cch);
|
|
|
|
if (fRet && pnSize)
|
|
{
|
|
*pnSize = csoBuffer.ConvertExcludingNul();
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
BOOL WINAPI SetComputerNameWrapW(LPCWSTR lpComputerName)
|
|
{
|
|
BOOL fRet;
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
fRet = SetComputerNameW(lpComputerName);
|
|
}
|
|
else
|
|
{
|
|
CStrIn csiComputerName(lpComputerName);
|
|
|
|
fRet = SetComputerNameA(csiComputerName);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
UINT WINAPI GetDriveTypeWrapW(LPCWSTR lpRootPathName)
|
|
{
|
|
UINT uRet;
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
uRet = GetDriveTypeW(lpRootPathName);
|
|
}
|
|
else
|
|
{
|
|
CStrIn csiRootPathName(lpRootPathName);
|
|
|
|
uRet = GetDriveTypeA(csiRootPathName);
|
|
}
|
|
|
|
return uRet;
|
|
}
|
|
|
|
|
|
//
|
|
// Printer wrappers.
|
|
//
|
|
|
|
class CPrinterEnumIn
|
|
{
|
|
public:
|
|
CPrinterEnumIn(DWORD dwLevel, BYTE* pPrinterEnum, DWORD cbPrinterEnum, DWORD* ppsbNeeded, DWORD* pcPrinters);
|
|
~CPrinterEnumIn();
|
|
|
|
operator BYTE*() {return _pPrinterEnumA;}
|
|
operator DWORD() {return _cbPrinterEnumA;}
|
|
|
|
private:
|
|
void Convert(void);
|
|
void ConvertStruct(const PRINTER_INFO_5A* ppi5A, PRINTER_INFO_5W* ppi5W, LPWSTR* ppszCurrent, UINT* pcchCurrent);
|
|
void ConvertStructString(LPCSTR pszA, LPWSTR* ppszDst, LPWSTR* ppszW, UINT* pcchW);
|
|
|
|
private:
|
|
BYTE* _pPrinterEnum;
|
|
DWORD _cbPrinterEnum;
|
|
DWORD* _pcbNeeded;
|
|
DWORD* _pcPrinters;
|
|
|
|
BYTE* _pPrinterEnumA;
|
|
DWORD _cbPrinterEnumA;
|
|
};
|
|
|
|
CPrinterEnumIn::CPrinterEnumIn(DWORD dwLevel, BYTE* pPrinterEnum, DWORD cbPrinterEnum, DWORD* pcbNeeded, DWORD* pcPrinters)
|
|
{
|
|
ASSERT(5 == dwLevel); // only level supported.
|
|
|
|
_pPrinterEnum = pPrinterEnum;
|
|
_cbPrinterEnum = cbPrinterEnum;
|
|
_pcbNeeded = pcbNeeded;
|
|
_pcPrinters = pcPrinters;
|
|
|
|
if (_cbPrinterEnum)
|
|
{
|
|
_pPrinterEnumA = (BYTE*)LocalAlloc(LPTR, _cbPrinterEnum);
|
|
|
|
_cbPrinterEnumA = _pPrinterEnumA ? _cbPrinterEnum : 0;
|
|
}
|
|
else
|
|
{
|
|
_pPrinterEnumA = NULL;
|
|
_cbPrinterEnumA = 0;
|
|
}
|
|
}
|
|
|
|
CPrinterEnumIn::~CPrinterEnumIn()
|
|
{
|
|
Convert();
|
|
|
|
if (_pPrinterEnumA)
|
|
LocalFree(_pPrinterEnumA);
|
|
}
|
|
|
|
void CPrinterEnumIn::Convert()
|
|
{
|
|
if (!_pPrinterEnumA)
|
|
{
|
|
*_pcbNeeded *= 2;
|
|
}
|
|
else
|
|
{
|
|
UINT cchCurrent = _cbPrinterEnum > (sizeof(PRINTER_INFO_5) * *_pcPrinters) ?
|
|
(_cbPrinterEnum - (sizeof(PRINTER_INFO_5) * *_pcPrinters)) / sizeof(WCHAR) :
|
|
0;
|
|
|
|
LPWSTR pszCurrent = cchCurrent ? (LPWSTR)&(((PRINTER_INFO_5*)_pPrinterEnum)[*_pcPrinters]) : NULL;
|
|
|
|
for (UINT i = 0; i < *_pcPrinters; i++)
|
|
{
|
|
ConvertStruct(&((const PRINTER_INFO_5A*)_pPrinterEnumA)[i], &((PRINTER_INFO_5W*)_pPrinterEnum)[i], &pszCurrent, &cchCurrent);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void CPrinterEnumIn::ConvertStruct(const PRINTER_INFO_5A* ppi5A, PRINTER_INFO_5W* ppi5W, LPWSTR* ppszCurrent, UINT* pcchCurrent)
|
|
{
|
|
if (ppi5A->pPrinterName && *pcchCurrent)
|
|
{
|
|
ConvertStructString(ppi5A->pPrinterName, &ppi5W->pPrinterName, ppszCurrent, pcchCurrent);
|
|
}
|
|
|
|
if (ppi5A->pPortName && *pcchCurrent)
|
|
{
|
|
ConvertStructString(ppi5A->pPortName, &ppi5W->pPortName, ppszCurrent, pcchCurrent);
|
|
}
|
|
|
|
ppi5W->Attributes = ppi5A->Attributes;
|
|
ppi5W->DeviceNotSelectedTimeout = ppi5A->DeviceNotSelectedTimeout;
|
|
ppi5W->TransmissionRetryTimeout = ppi5A->TransmissionRetryTimeout;
|
|
|
|
return;
|
|
}
|
|
|
|
void CPrinterEnumIn::ConvertStructString(LPCSTR pszA, LPWSTR* ppszDst, LPWSTR* ppszW, UINT* pcchW)
|
|
{
|
|
UINT cch = MultiByteToWideChar(CP_ACP, 0, pszA, -1, *ppszW, *pcchW);
|
|
|
|
if (cch)
|
|
{
|
|
*ppszDst = *ppszW;
|
|
*pcchW -= cch;
|
|
*ppszW += cch;
|
|
}
|
|
else
|
|
{
|
|
*ppszDst = NULL;
|
|
*pcchW = 0;
|
|
*ppszW = NULL;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
BOOL EnumPrintersWrapW(DWORD dwFlags, LPWSTR pszName, DWORD dwLevel, BYTE* pPrinterEnum, DWORD cbPrinterEnum, DWORD* pcbNeeded, DWORD* pcPrinters)
|
|
{
|
|
BOOL fRet;
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
fRet = EnumPrintersW(dwFlags, pszName, dwLevel, pPrinterEnum, cbPrinterEnum, pcbNeeded, pcPrinters);
|
|
}
|
|
else
|
|
{
|
|
CStrIn strName(pszName);
|
|
CPrinterEnumIn cpeiPrinterEnum(dwLevel, pPrinterEnum, cbPrinterEnum, pcbNeeded, pcPrinters);
|
|
|
|
fRet = EnumPrintersA(dwFlags, strName, dwLevel, cpeiPrinterEnum, cpeiPrinterEnum, pcbNeeded, pcPrinters);
|
|
}
|
|
|
|
return fRet;
|
|
}
|