mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
255807f768
Fix Clang-Cl
'...\printerdrivers.c(97,98): warning: variable 'cbBuf' is uninitialized when used here [-Wuninitialized]'
Addendum to 62c4b82
.
CORE-14306
1151 lines
38 KiB
C
1151 lines
38 KiB
C
/*
|
|
* PROJECT: ReactOS Local Spooler
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: Functions for printer driver information
|
|
* COPYRIGHT: Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
|
|
* Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#include <strsafe.h>
|
|
|
|
typedef struct {
|
|
WCHAR src[MAX_PATH+MAX_PATH];
|
|
WCHAR dst[MAX_PATH+MAX_PATH];
|
|
DWORD srclen;
|
|
DWORD dstlen;
|
|
DWORD copyflags;
|
|
BOOL lazy;
|
|
} apd_data_t;
|
|
|
|
static const WCHAR backslashW[] = {'\\',0};
|
|
static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
|
|
static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
|
|
static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
|
|
static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
|
|
static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
|
|
static const WCHAR emptyW[] = {0};
|
|
static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
|
|
'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
|
|
'c','o','n','t','r','o','l','\\',
|
|
'P','r','i','n','t','\\',
|
|
'E','n','v','i','r','o','n','m','e','n','t','s','\\',
|
|
'%','s','\\','D','r','i','v','e','r','s','%','s',0 };
|
|
static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
|
|
static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
|
|
|
|
static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
|
|
|
|
static const WCHAR spoolW[] = {'\\','s','p','o','o','l',0};
|
|
static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0};
|
|
static const WCHAR ia64_envnameW[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
|
|
static const WCHAR ia64_subdirW[] = {'i','a','6','4',0};
|
|
static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
|
|
static const WCHAR version3_subdirW[] = {'\\','3',0};
|
|
static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
|
|
static const WCHAR version0_subdirW[] = {'\\','0',0};
|
|
static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
|
|
static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
|
|
static const WCHAR x64_subdirW[] = {'x','6','4',0};
|
|
static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
|
|
static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
|
|
static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
|
|
static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
|
|
|
|
static PRINTENV_T env_ia64 = {ia64_envnameW, ia64_subdirW, 3, version3_regpathW, version3_subdirW};
|
|
|
|
static PRINTENV_T env_x86 = {x86_envnameW, x86_subdirW, 3, version3_regpathW, version3_subdirW};
|
|
|
|
static PRINTENV_T env_x64 = {x64_envnameW, x64_subdirW, 3, version3_regpathW, version3_subdirW};
|
|
|
|
static PRINTENV_T env_win40 = {win40_envnameW, win40_subdirW, 0, version0_regpathW, version0_subdirW};
|
|
|
|
static PPRINTENV_T all_printenv[] = {&env_x86, &env_x64, &env_ia64, &env_win40};
|
|
|
|
static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
|
|
sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
|
|
sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
|
|
0, sizeof(DRIVER_INFO_8W)};
|
|
|
|
static WCHAR wszScratchPad[MAX_PATH] = L"";
|
|
|
|
static WCHAR wszLocalSplFile[MAX_PATH] = L"";
|
|
static WCHAR wszPrintUiFile[MAX_PATH] = L"";
|
|
static WCHAR wszDriverPath[MAX_PATH] = L"";
|
|
|
|
BOOL
|
|
InitializePrinterDrivers(VOID)
|
|
{
|
|
WCHAR szSysDir[MAX_PATH];
|
|
DWORD cbBuf;
|
|
|
|
if (wszLocalSplFile[0] && wszPrintUiFile[0])
|
|
return TRUE;
|
|
|
|
if (!GetSystemDirectoryW(szSysDir, _countof(szSysDir)))
|
|
{
|
|
ERR("GetSystemDirectoryW failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
StringCbCopyW(wszLocalSplFile, sizeof(wszLocalSplFile), szSysDir);
|
|
StringCbCatW(wszLocalSplFile, sizeof(wszLocalSplFile), L"\\localspl.dll");
|
|
|
|
StringCbCopyW(wszPrintUiFile, sizeof(wszPrintUiFile), szSysDir);
|
|
StringCbCatW(wszPrintUiFile, sizeof(wszPrintUiFile), L"\\printui.dll");
|
|
|
|
if (!LocalGetPrinterDriverDirectory(NULL, (PWSTR)wszCurrentEnvironment, 1, (PBYTE)szSysDir, (DWORD)sizeof(szSysDir), &cbBuf))
|
|
{
|
|
ERR("LocalGetPrinterDriverDirectory failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
StringCbCopyW(wszDriverPath, sizeof(wszDriverPath), szSysDir);
|
|
StringCbCatW(wszDriverPath, sizeof(wszDriverPath), version3_subdirW);
|
|
StringCbCatW(wszDriverPath, sizeof(wszDriverPath), backslashW);
|
|
|
|
// HAX! need to get it from the Reg Key L"Driver"!
|
|
StringCbCatW(wszDriverPath, sizeof(wszDriverPath), L"UniDrv.dll");
|
|
|
|
FIXME("DriverPath : %S\n",wszDriverPath);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Local Constants
|
|
static DWORD dwDriverInfo1Offsets[] = {
|
|
FIELD_OFFSET(DRIVER_INFO_1W, pName),
|
|
MAXDWORD
|
|
};
|
|
|
|
static DWORD dwDriverInfo2Offsets[] = {
|
|
FIELD_OFFSET(DRIVER_INFO_2W, pName),
|
|
FIELD_OFFSET(DRIVER_INFO_2W, pEnvironment),
|
|
FIELD_OFFSET(DRIVER_INFO_2W, pDriverPath),
|
|
FIELD_OFFSET(DRIVER_INFO_2W, pDataFile),
|
|
FIELD_OFFSET(DRIVER_INFO_2W, pConfigFile),
|
|
MAXDWORD
|
|
};
|
|
|
|
static DWORD dwDriverInfo3Offsets[] = {
|
|
FIELD_OFFSET(DRIVER_INFO_3W, pName),
|
|
FIELD_OFFSET(DRIVER_INFO_3W, pEnvironment),
|
|
FIELD_OFFSET(DRIVER_INFO_3W, pDriverPath),
|
|
FIELD_OFFSET(DRIVER_INFO_3W, pDataFile),
|
|
FIELD_OFFSET(DRIVER_INFO_3W, pConfigFile),
|
|
FIELD_OFFSET(DRIVER_INFO_3W, pHelpFile),
|
|
FIELD_OFFSET(DRIVER_INFO_3W, pDependentFiles),
|
|
FIELD_OFFSET(DRIVER_INFO_3W, pMonitorName),
|
|
FIELD_OFFSET(DRIVER_INFO_3W, pDefaultDataType),
|
|
MAXDWORD
|
|
};
|
|
|
|
static DWORD dwDriverInfo4Offsets[] = {
|
|
FIELD_OFFSET(DRIVER_INFO_4W, pName),
|
|
FIELD_OFFSET(DRIVER_INFO_4W, pEnvironment),
|
|
FIELD_OFFSET(DRIVER_INFO_4W, pDriverPath),
|
|
FIELD_OFFSET(DRIVER_INFO_4W, pDataFile),
|
|
FIELD_OFFSET(DRIVER_INFO_4W, pConfigFile),
|
|
FIELD_OFFSET(DRIVER_INFO_4W, pHelpFile),
|
|
FIELD_OFFSET(DRIVER_INFO_4W, pDependentFiles),
|
|
FIELD_OFFSET(DRIVER_INFO_4W, pMonitorName),
|
|
FIELD_OFFSET(DRIVER_INFO_4W, pDefaultDataType),
|
|
FIELD_OFFSET(DRIVER_INFO_4W, pszzPreviousNames),
|
|
MAXDWORD
|
|
};
|
|
|
|
static DWORD dwDriverInfo5Offsets[] = {
|
|
FIELD_OFFSET(DRIVER_INFO_5W, pName),
|
|
FIELD_OFFSET(DRIVER_INFO_5W, pEnvironment),
|
|
FIELD_OFFSET(DRIVER_INFO_5W, pDriverPath),
|
|
FIELD_OFFSET(DRIVER_INFO_5W, pDataFile),
|
|
FIELD_OFFSET(DRIVER_INFO_5W, pConfigFile),
|
|
MAXDWORD
|
|
};
|
|
|
|
static DWORD dwDriverInfo6Offsets[] = {
|
|
FIELD_OFFSET(DRIVER_INFO_6W, pName),
|
|
FIELD_OFFSET(DRIVER_INFO_6W, pEnvironment),
|
|
FIELD_OFFSET(DRIVER_INFO_6W, pDriverPath),
|
|
FIELD_OFFSET(DRIVER_INFO_6W, pDataFile),
|
|
FIELD_OFFSET(DRIVER_INFO_6W, pConfigFile),
|
|
FIELD_OFFSET(DRIVER_INFO_6W, pHelpFile),
|
|
FIELD_OFFSET(DRIVER_INFO_6W, pDependentFiles),
|
|
FIELD_OFFSET(DRIVER_INFO_6W, pMonitorName),
|
|
FIELD_OFFSET(DRIVER_INFO_6W, pDefaultDataType),
|
|
FIELD_OFFSET(DRIVER_INFO_6W, pszzPreviousNames),
|
|
FIELD_OFFSET(DRIVER_INFO_6W, pszMfgName),
|
|
FIELD_OFFSET(DRIVER_INFO_6W, pszOEMUrl),
|
|
FIELD_OFFSET(DRIVER_INFO_6W, pszHardwareID),
|
|
FIELD_OFFSET(DRIVER_INFO_6W, pszProvider),
|
|
MAXDWORD
|
|
};
|
|
|
|
static DWORD dwDriverInfo8Offsets[] = {
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pName),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pEnvironment),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pDriverPath),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pDataFile),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pConfigFile),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pHelpFile),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pDependentFiles),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pMonitorName),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pDefaultDataType),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pszzPreviousNames),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pszMfgName),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pszOEMUrl),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pszHardwareID),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pszProvider),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pszPrintProcessor),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pszVendorSetup),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pszzColorProfiles),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pszInfPath),
|
|
FIELD_OFFSET(DRIVER_INFO_8W, pszzCoreDriverDependencies),
|
|
MAXDWORD
|
|
};
|
|
|
|
static void
|
|
ToMultiSz(LPWSTR pString)
|
|
{
|
|
while (*pString)
|
|
{
|
|
if (*pString == '|')
|
|
*pString = '\0';
|
|
pString++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
_LocalGetPrinterDriverLevel1(PLOCAL_PRINTER pPrinter, PDRIVER_INFO_1W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
|
|
{
|
|
DWORD n;
|
|
PCWSTR pwszStrings[1];
|
|
|
|
/* This value is only here to send something, I have not verified if it is actually correct */
|
|
pwszStrings[0] = pPrinter->pwszPrinterDriver;
|
|
|
|
// Calculate the string lengths.
|
|
if (!ppDriverInfo)
|
|
{
|
|
for (n = 0; n < _countof(pwszStrings); ++n)
|
|
{
|
|
*pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
|
|
}
|
|
|
|
*pcbNeeded += sizeof(DRIVER_INFO_1W);
|
|
return;
|
|
}
|
|
|
|
// Finally copy the structure and advance to the next one in the output buffer.
|
|
*ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo1Offsets, *ppDriverInfoEnd);
|
|
(*ppDriverInfo)++;
|
|
}
|
|
|
|
static void
|
|
_LocalGetPrinterDriverLevel2(PLOCAL_PRINTER pPrinter, PDRIVER_INFO_2W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
|
|
{
|
|
DWORD n;
|
|
PCWSTR pwszStrings[5];
|
|
|
|
pwszStrings[0] = pPrinter->pwszPrinterDriver; // pName
|
|
pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
|
|
pwszStrings[2] = wszDriverPath; // pDriverPath
|
|
pwszStrings[3] = wszLocalSplFile; // pDataFile
|
|
pwszStrings[4] = wszPrintUiFile; // pConfigFile
|
|
|
|
// Calculate the string lengths.
|
|
if (!ppDriverInfo)
|
|
{
|
|
for (n = 0; n < _countof(pwszStrings); ++n)
|
|
{
|
|
if (pwszStrings[n])
|
|
{
|
|
*pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
*pcbNeeded += sizeof(DRIVER_INFO_2W);
|
|
return;
|
|
}
|
|
|
|
(*ppDriverInfo)->cVersion = 3;
|
|
|
|
// Finally copy the structure and advance to the next one in the output buffer.
|
|
*ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo2Offsets, *ppDriverInfoEnd);
|
|
(*ppDriverInfo)++;
|
|
}
|
|
|
|
static void
|
|
_LocalGetPrinterDriverLevel3(PLOCAL_PRINTER pPrinter, PDRIVER_INFO_3W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
|
|
{
|
|
DWORD n;
|
|
PCWSTR pwszStrings[9];
|
|
|
|
pwszStrings[0] = pPrinter->pwszPrinterDriver; // pName
|
|
pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
|
|
pwszStrings[2] = wszDriverPath; // pDriverPath
|
|
pwszStrings[3] = wszLocalSplFile; // pDataFile
|
|
pwszStrings[4] = wszPrintUiFile; // pConfigFile
|
|
pwszStrings[5] = L""; // pHelpFile
|
|
pwszStrings[6] = L"localspl.dll|printui.dll|"; // pDependentFiles, | is separator and terminator!
|
|
pwszStrings[7] = NULL;
|
|
if (pPrinter->pPort && pPrinter->pPort->pPrintMonitor)
|
|
{
|
|
pwszStrings[7] = pPrinter->pPort->pPrintMonitor->pwszName;
|
|
}
|
|
pwszStrings[8] = pPrinter->pwszDefaultDatatype;
|
|
|
|
|
|
// Calculate the string lengths.
|
|
if (!ppDriverInfo)
|
|
{
|
|
for (n = 0; n < _countof(pwszStrings); ++n)
|
|
{
|
|
if (pwszStrings[n])
|
|
{
|
|
*pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
*pcbNeeded += sizeof(DRIVER_INFO_3W);
|
|
return;
|
|
}
|
|
|
|
(*ppDriverInfo)->cVersion = 3;
|
|
|
|
// Finally copy the structure and advance to the next one in the output buffer.
|
|
*ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo3Offsets, *ppDriverInfoEnd);
|
|
ToMultiSz((*ppDriverInfo)->pDependentFiles);
|
|
(*ppDriverInfo)++;
|
|
}
|
|
|
|
static void
|
|
_LocalGetPrinterDriverLevel4(PLOCAL_PRINTER pPrinter, PDRIVER_INFO_4W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
|
|
{
|
|
DWORD n;
|
|
PCWSTR pwszStrings[10];
|
|
|
|
pwszStrings[0] = pPrinter->pwszPrinterDriver; // pName
|
|
pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
|
|
pwszStrings[2] = wszDriverPath; // pDriverPath
|
|
pwszStrings[3] = wszLocalSplFile; // pDataFile
|
|
pwszStrings[4] = wszPrintUiFile; // pConfigFile
|
|
pwszStrings[5] = L""; // pHelpFile
|
|
pwszStrings[6] = L"localspl.dll|printui.dll|"; // pDependentFiles, | is separator and terminator!
|
|
pwszStrings[7] = NULL;
|
|
if (pPrinter->pPort && pPrinter->pPort->pPrintMonitor)
|
|
{
|
|
pwszStrings[7] = pPrinter->pPort->pPrintMonitor->pwszName;
|
|
}
|
|
pwszStrings[8] = pPrinter->pwszDefaultDatatype;
|
|
pwszStrings[9] = NULL; // pszzPreviousNames
|
|
|
|
// Calculate the string lengths.
|
|
if (!ppDriverInfo)
|
|
{
|
|
for (n = 0; n < _countof(pwszStrings); ++n)
|
|
{
|
|
if (pwszStrings[n])
|
|
{
|
|
*pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
*pcbNeeded += sizeof(DRIVER_INFO_4W);
|
|
return;
|
|
}
|
|
|
|
(*ppDriverInfo)->cVersion = 3;
|
|
|
|
// Finally copy the structure and advance to the next one in the output buffer.
|
|
*ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo4Offsets, *ppDriverInfoEnd);
|
|
ToMultiSz((*ppDriverInfo)->pDependentFiles);
|
|
(*ppDriverInfo)++;
|
|
}
|
|
|
|
static void
|
|
_LocalGetPrinterDriverLevel5(PLOCAL_PRINTER pPrinter, PDRIVER_INFO_5W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
|
|
{
|
|
DWORD n;
|
|
PCWSTR pwszStrings[5];
|
|
|
|
pwszStrings[0] = pPrinter->pwszPrinterDriver; // pName
|
|
pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
|
|
pwszStrings[2] = wszDriverPath; // pDriverPath UniDrv.dll
|
|
pwszStrings[3] = wszLocalSplFile; // pDataFile.ppd
|
|
pwszStrings[4] = wszPrintUiFile; // pConfigFile UniDrvUI.dll
|
|
|
|
// Calculate the string lengths.
|
|
if (!ppDriverInfo)
|
|
{
|
|
for (n = 0; n < _countof(pwszStrings); ++n)
|
|
{
|
|
if (pwszStrings[n])
|
|
{
|
|
*pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
*pcbNeeded += sizeof(DRIVER_INFO_5W);
|
|
return;
|
|
}
|
|
|
|
(*ppDriverInfo)->cVersion = 3;
|
|
// Driver attributes, like UMPD/KMPD.
|
|
(*ppDriverInfo)->dwDriverAttributes = 0; // UMPD/KMPD, So where are they?
|
|
// Number of times the configuration file for this driver has been upgraded or downgraded since the last spooler restart.
|
|
(*ppDriverInfo)->dwConfigVersion = 1;
|
|
// Number of times the driver file for this driver has been upgraded or downgraded since the last spooler restart.
|
|
(*ppDriverInfo)->dwDriverVersion = 1;
|
|
|
|
// Finally copy the structure and advance to the next one in the output buffer.
|
|
*ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo5Offsets, *ppDriverInfoEnd);
|
|
(*ppDriverInfo)++;
|
|
}
|
|
|
|
|
|
static void
|
|
_LocalGetPrinterDriverLevel6(PLOCAL_PRINTER pPrinter, PDRIVER_INFO_6W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
|
|
{
|
|
DWORD n;
|
|
PCWSTR pwszStrings[14];
|
|
|
|
StringCbCopyW(wszScratchPad, sizeof(wszPrintProviderInfo[1]), wszPrintProviderInfo[1]); // Provider Name
|
|
|
|
pwszStrings[0] = pPrinter->pwszPrinterDriver; // pName
|
|
pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
|
|
pwszStrings[2] = wszDriverPath; // pDriverPath
|
|
pwszStrings[3] = wszLocalSplFile; // pDataFile
|
|
pwszStrings[4] = wszPrintUiFile; // pConfigFile
|
|
pwszStrings[5] = L""; // pHelpFile
|
|
pwszStrings[6] = L"localspl.dll|printui.dll|"; // pDependentFiles, | is separator and terminator!
|
|
pwszStrings[7] = NULL;
|
|
if (pPrinter->pPort && pPrinter->pPort->pPrintMonitor)
|
|
{
|
|
pwszStrings[7] = pPrinter->pPort->pPrintMonitor->pwszName;
|
|
}
|
|
pwszStrings[8] = pPrinter->pwszDefaultDatatype;
|
|
pwszStrings[9] = NULL; // pszzPreviousNames
|
|
pwszStrings[10] = NULL; // pszMfgName
|
|
pwszStrings[11] = NULL; // pszOEMUrl
|
|
pwszStrings[12] = NULL; // pszHardwareID
|
|
pwszStrings[13] = wszScratchPad;
|
|
|
|
// Calculate the string lengths.
|
|
if (!ppDriverInfo)
|
|
{
|
|
for (n = 0; n < _countof(pwszStrings); ++n)
|
|
{
|
|
if (pwszStrings[n])
|
|
{
|
|
*pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
*pcbNeeded += sizeof(DRIVER_INFO_6W);
|
|
return;
|
|
}
|
|
|
|
(*ppDriverInfo)->cVersion = 3;
|
|
|
|
// Finally copy the structure and advance to the next one in the output buffer.
|
|
*ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo6Offsets, *ppDriverInfoEnd);
|
|
ToMultiSz((*ppDriverInfo)->pDependentFiles);
|
|
(*ppDriverInfo)++;
|
|
}
|
|
|
|
static void
|
|
_LocalGetPrinterDriverLevel8(PLOCAL_PRINTER pPrinter, PDRIVER_INFO_8W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
|
|
{
|
|
DWORD n;
|
|
PCWSTR pwszStrings[19];
|
|
|
|
StringCbCopyW(wszScratchPad, sizeof(wszPrintProviderInfo[1]), wszPrintProviderInfo[1]); // Provider Name
|
|
|
|
pwszStrings[0] = pPrinter->pwszPrinterDriver; // pName
|
|
pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
|
|
pwszStrings[2] = wszDriverPath; // pDriverPath
|
|
pwszStrings[3] = wszLocalSplFile; // pDataFile
|
|
pwszStrings[4] = wszPrintUiFile; // pConfigFile
|
|
pwszStrings[5] = L""; // pHelpFile
|
|
pwszStrings[6] = L"localspl.dll|printui.dll|"; // pDependentFiles, | is separator and terminator!
|
|
pwszStrings[7] = NULL;
|
|
if (pPrinter->pPort && pPrinter->pPort->pPrintMonitor)
|
|
{
|
|
pwszStrings[7] = pPrinter->pPort->pPrintMonitor->pwszName;
|
|
}
|
|
pwszStrings[8] = pPrinter->pwszDefaultDatatype;
|
|
pwszStrings[9] = NULL; // pszzPreviousNames
|
|
pwszStrings[10] = NULL; // pszMfgName
|
|
pwszStrings[11] = NULL; // pszOEMUrl
|
|
pwszStrings[12] = NULL; // pszHardwareID
|
|
pwszStrings[13] = wszScratchPad;
|
|
pwszStrings[14] = NULL;
|
|
if ( pPrinter->pPrintProcessor )
|
|
{
|
|
pwszStrings[14] = pPrinter->pPrintProcessor->pwszName;
|
|
}
|
|
pwszStrings[15] = NULL; // pszVendorSetup
|
|
pwszStrings[16] = NULL; // pszzColorProfiles
|
|
pwszStrings[17] = NULL; // pszInfPath
|
|
pwszStrings[18] = NULL; // pszzCoreDriverDependencies
|
|
|
|
// Calculate the string lengths.
|
|
if (!ppDriverInfo)
|
|
{
|
|
for (n = 0; n < _countof(pwszStrings); ++n)
|
|
{
|
|
if (pwszStrings[n])
|
|
{
|
|
*pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
*pcbNeeded += sizeof(DRIVER_INFO_8W);
|
|
return;
|
|
}
|
|
|
|
(*ppDriverInfo)->cVersion = 3;
|
|
|
|
// Finally copy the structure and advance to the next one in the output buffer.
|
|
*ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo8Offsets, *ppDriverInfoEnd);
|
|
ToMultiSz((*ppDriverInfo)->pDependentFiles);
|
|
(*ppDriverInfo)++;
|
|
}
|
|
|
|
typedef void (*PLocalPrinterDriverLevelFunc)(PLOCAL_PRINTER, PVOID, PBYTE*, PDWORD);
|
|
|
|
static const PLocalPrinterDriverLevelFunc pfnPrinterDriverLevels[] = {
|
|
NULL,
|
|
(PLocalPrinterDriverLevelFunc)&_LocalGetPrinterDriverLevel1,
|
|
(PLocalPrinterDriverLevelFunc)&_LocalGetPrinterDriverLevel2,
|
|
(PLocalPrinterDriverLevelFunc)&_LocalGetPrinterDriverLevel3,
|
|
(PLocalPrinterDriverLevelFunc)&_LocalGetPrinterDriverLevel4,
|
|
(PLocalPrinterDriverLevelFunc)&_LocalGetPrinterDriverLevel5,
|
|
(PLocalPrinterDriverLevelFunc)&_LocalGetPrinterDriverLevel6,
|
|
NULL,
|
|
(PLocalPrinterDriverLevelFunc)&_LocalGetPrinterDriverLevel8
|
|
};
|
|
|
|
BOOL WINAPI LocalGetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
|
|
{
|
|
DWORD dwErrorCode;
|
|
PBYTE pEnd = &pDriverInfo[cbBuf];
|
|
PLOCAL_HANDLE pHandle;
|
|
PLOCAL_PRINTER_HANDLE pPrinterHandle;
|
|
|
|
TRACE("LocalGetPrinterDriver(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
|
|
|
|
// Check if this is a printer handle.
|
|
pHandle = (PLOCAL_HANDLE)hPrinter;
|
|
if (pHandle->HandleType != HandleType_Printer)
|
|
{
|
|
dwErrorCode = ERROR_INVALID_HANDLE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
|
|
|
|
// Only support 8 levels and not 7
|
|
if (Level < 1 || Level == 7 || Level > 8)
|
|
{
|
|
// The caller supplied an invalid level.
|
|
dwErrorCode = ERROR_INVALID_LEVEL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Count the required buffer size.
|
|
*pcbNeeded = 0;
|
|
|
|
pfnPrinterDriverLevels[Level](pPrinterHandle->pPrinter, NULL, NULL, pcbNeeded);
|
|
|
|
// Check if the supplied buffer is large enough.
|
|
if (cbBuf < *pcbNeeded)
|
|
{
|
|
ERR("Insuffisient Buffer size\n");
|
|
dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Copy over the information.
|
|
pEnd = &pDriverInfo[*pcbNeeded];
|
|
|
|
pfnPrinterDriverLevels[Level](pPrinterHandle->pPrinter, &pDriverInfo, &pEnd, NULL);
|
|
|
|
dwErrorCode = ERROR_SUCCESS;
|
|
|
|
Cleanup:
|
|
SetLastError(dwErrorCode);
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
|
}
|
|
|
|
BOOL WINAPI LocalGetPrinterDriverEx(
|
|
HANDLE hPrinter,
|
|
LPWSTR pEnvironment,
|
|
DWORD Level,
|
|
LPBYTE pDriverInfo,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded,
|
|
DWORD dwClientMajorVersion,
|
|
DWORD dwClientMinorVersion,
|
|
PDWORD pdwServerMajorVersion,
|
|
PDWORD pdwServerMinorVersion )
|
|
{
|
|
FIXME("LocalGetPrinterDriverEx(%p, %lu, %lu, %p, %lu, %p, %lu, %lu, %p, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, dwClientMajorVersion, dwClientMinorVersion, pdwServerMajorVersion, pdwServerMinorVersion);
|
|
//// HACK-plement
|
|
return LocalGetPrinterDriver( hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded );
|
|
}
|
|
|
|
BOOL WINAPI
|
|
LocalEnumPrinterDrivers(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
|
|
{
|
|
DWORD dwErrorCode;
|
|
PSKIPLIST_NODE pNode;
|
|
PBYTE pEnd;
|
|
PLOCAL_PRINTER pPrinter;
|
|
|
|
FIXME("LocalEnumPrinterDrivers(%S, %S, %lu, %p, %lu, %p, %p)\n", pName, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned);
|
|
|
|
// Only support 8 levels and not 7
|
|
if (Level < 1 || Level == 7 || Level > 8)
|
|
{
|
|
// The caller supplied an invalid level.
|
|
dwErrorCode = ERROR_INVALID_LEVEL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Count the required buffer size.
|
|
*pcbNeeded = 0;
|
|
|
|
// Count the required buffer size and the number of printers.
|
|
for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0])
|
|
{
|
|
pPrinter = (PLOCAL_PRINTER)pNode->Element;
|
|
|
|
pfnPrinterDriverLevels[Level](pPrinter, NULL, NULL, pcbNeeded);
|
|
}
|
|
|
|
// Check if the supplied buffer is large enough.
|
|
if (cbBuf < *pcbNeeded)
|
|
{
|
|
dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Copy over the Printer information.
|
|
pEnd = &pDriverInfo[*pcbNeeded];
|
|
|
|
for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0])
|
|
{
|
|
pPrinter = (PLOCAL_PRINTER)pNode->Element;
|
|
|
|
pfnPrinterDriverLevels[Level](pPrinter, &pDriverInfo, &pEnd, NULL);
|
|
(*pcReturned)++;
|
|
}
|
|
|
|
dwErrorCode = ERROR_SUCCESS;
|
|
|
|
Cleanup:
|
|
SetLastError(dwErrorCode);
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
|
}
|
|
|
|
/******************************************************************
|
|
* Return the number of bytes for an multi_sz string.
|
|
* The result includes all \0s
|
|
* (specifically the extra \0, that is needed as multi_sz terminator).
|
|
*/
|
|
static int multi_sz_lenW(const WCHAR *str)
|
|
{
|
|
const WCHAR *ptr = str;
|
|
if (!str) return 0;
|
|
do
|
|
{
|
|
ptr += lstrlenW(ptr) + 1;
|
|
} while (*ptr);
|
|
|
|
return (ptr - str + 1) * sizeof(WCHAR);
|
|
}
|
|
|
|
|
|
/******************************************************************
|
|
* validate_envW [internal]
|
|
*
|
|
* validate the user-supplied printing-environment
|
|
*
|
|
* PARAMS
|
|
* env [I] PTR to Environment-String or NULL
|
|
*
|
|
* RETURNS
|
|
* Success: PTR to printenv_t
|
|
* Failure: NULL and ERROR_INVALID_ENVIRONMENT
|
|
*
|
|
* NOTES
|
|
* An empty string is handled the same way as NULL.
|
|
*
|
|
*/
|
|
PPRINTENV_T validate_envW(LPCWSTR env)
|
|
{
|
|
PPRINTENV_T result = NULL;
|
|
unsigned int i;
|
|
|
|
TRACE("(%s)\n", debugstr_w(env));
|
|
if (env && env[0])
|
|
{
|
|
for (i = 0; i < ARRAYSIZE(all_printenv); i++)
|
|
{
|
|
if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
|
|
{
|
|
result = all_printenv[i];
|
|
break;
|
|
}
|
|
}
|
|
if (result == NULL)
|
|
{
|
|
FIXME("unsupported Environment: %s\n", debugstr_w(env));
|
|
SetLastError(ERROR_INVALID_ENVIRONMENT);
|
|
}
|
|
/* on win9x, only "Windows 4.0" is allowed, but we ignore this */
|
|
}
|
|
else
|
|
{
|
|
result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
|
|
}
|
|
|
|
TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
|
|
return result;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* open_driver_reg [internal]
|
|
*
|
|
* opens the registry for the printer drivers depending on the given input
|
|
* variable pEnvironment
|
|
*
|
|
* RETURNS:
|
|
* Success: the opened hkey
|
|
* Failure: NULL
|
|
*/
|
|
HKEY open_driver_reg(LPCWSTR pEnvironment)
|
|
{
|
|
HKEY retval = NULL;
|
|
LPWSTR buffer;
|
|
const PRINTENV_T * env;
|
|
|
|
TRACE("(%s)\n", debugstr_w(pEnvironment));
|
|
|
|
env = validate_envW(pEnvironment);
|
|
if (!env) return NULL;
|
|
|
|
buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
|
|
(lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
|
|
|
|
if (buffer)
|
|
{
|
|
wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
|
|
RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
|
|
HeapFree(GetProcessHeap(), 0, buffer);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* LocalGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
|
|
*
|
|
* Return the PATH for the Print-Processors
|
|
*
|
|
* PARAMS
|
|
* pName [I] Servername or NULL (this computer)
|
|
* pEnvironment [I] Printing-Environment or NULL (Default)
|
|
* level [I] Structure-Level (must be 1)
|
|
* pPPInfo [O] PTR to Buffer that receives the Result
|
|
* cbBuf [I] Size of Buffer at pPPInfo
|
|
* pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
|
|
*
|
|
* RETURNS
|
|
* Success: TRUE
|
|
* Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
|
|
*
|
|
* Native Values returned in pPPInfo on Success for this computer:
|
|
*| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
|
|
*| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
|
|
*| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
|
|
*
|
|
* "%winsysdir%" is the Value from GetSystemDirectoryW()
|
|
*
|
|
*/
|
|
BOOL WINAPI LocalGetPrinterDriverDirectory(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pDriverDirectory, DWORD cbBuf, PDWORD pcbNeeded)
|
|
{
|
|
DWORD needed;
|
|
const PRINTENV_T * env = NULL;
|
|
WCHAR * const dir = (WCHAR *)pDriverDirectory;
|
|
|
|
FIXME("LocalGetPrinterDriverDirectory(%S, %S, %lu, %p, %lu, %p)\n", pName, pEnvironment, Level, pDriverDirectory, cbBuf, pcbNeeded);
|
|
|
|
if (pName != NULL && pName[0])
|
|
{
|
|
FIXME("server %s not supported\n", debugstr_w(pName));
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
env = validate_envW(pEnvironment);
|
|
if (!env) return FALSE; /* pEnvironment invalid or unsupported */
|
|
|
|
/* GetSystemDirectoryW returns number of WCHAR including the '\0' */
|
|
needed = GetSystemDirectoryW(NULL, 0);
|
|
/* add the Size for the Subdirectories */
|
|
needed += lstrlenW(spoolW);
|
|
needed += lstrlenW(driversW);
|
|
needed += lstrlenW(env->subdir);
|
|
needed *= sizeof(WCHAR); /* return-value is size in Bytes */
|
|
|
|
*pcbNeeded = needed;
|
|
|
|
if (needed > cbBuf)
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (dir == NULL)
|
|
{
|
|
/* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
GetSystemDirectoryW( dir, cbBuf / sizeof(WCHAR) );
|
|
/* add the Subdirectories */
|
|
lstrcatW( dir, spoolW );
|
|
CreateDirectoryW( dir, NULL );
|
|
lstrcatW( dir, driversW );
|
|
CreateDirectoryW( dir, NULL );
|
|
lstrcatW( dir, env->subdir );
|
|
CreateDirectoryW( dir, NULL );
|
|
|
|
FIXME( "=> %s\n", debugstr_w( dir ) );
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************************************************
|
|
* apd_copyfile [internal]
|
|
*
|
|
* Copy a file from the driverdirectory to the versioned directory
|
|
*
|
|
* RETURNS
|
|
* Success: TRUE
|
|
* Failure: FALSE
|
|
*
|
|
*/
|
|
static BOOL apd_copyfile( WCHAR *pathname, WCHAR *file_part, apd_data_t *apd )
|
|
{
|
|
WCHAR *srcname;
|
|
BOOL res;
|
|
|
|
apd->src[apd->srclen] = '\0';
|
|
apd->dst[apd->dstlen] = '\0';
|
|
|
|
if (!pathname || !pathname[0]) {
|
|
/* nothing to copy */
|
|
return TRUE;
|
|
}
|
|
|
|
if (apd->copyflags & APD_COPY_FROM_DIRECTORY)
|
|
srcname = pathname;
|
|
else
|
|
{
|
|
srcname = apd->src;
|
|
lstrcatW( srcname, file_part );
|
|
}
|
|
lstrcatW( apd->dst, file_part );
|
|
|
|
FIXME("%s => %s\n", debugstr_w(srcname), debugstr_w(apd->dst));
|
|
|
|
/* FIXME: handle APD_COPY_NEW_FILES */
|
|
res = CopyFileW(srcname, apd->dst, FALSE);
|
|
FIXME("got %d with %u\n", res, GetLastError());
|
|
|
|
return apd->lazy || res;
|
|
}
|
|
|
|
/******************************************************************
|
|
* driver_load [internal]
|
|
*
|
|
* load a driver user interface dll
|
|
*
|
|
* On failure, NULL is returned
|
|
*
|
|
*/
|
|
|
|
static HMODULE driver_load(const PRINTENV_T * env, LPWSTR dllname)
|
|
{
|
|
WCHAR fullname[MAX_PATH];
|
|
HMODULE hui;
|
|
DWORD len;
|
|
|
|
FIXME("(%p, %s)\n", env, debugstr_w(dllname));
|
|
|
|
/* build the driverdir */
|
|
len = sizeof(fullname) - (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
|
|
|
|
if (!LocalGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1, (LPBYTE) fullname, len, &len))
|
|
{
|
|
/* Should never fail */
|
|
SetLastError(ERROR_BUFFER_OVERFLOW);
|
|
return NULL;
|
|
}
|
|
|
|
lstrcatW(fullname, env->versionsubdir);
|
|
lstrcatW(fullname, backslashW);
|
|
lstrcatW(fullname, dllname);
|
|
|
|
hui = LoadLibraryW(fullname);
|
|
FIXME("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
|
|
|
|
return hui;
|
|
}
|
|
|
|
static inline WCHAR *get_file_part( WCHAR *name )
|
|
{
|
|
WCHAR *ptr = wcsrchr( name, '\\' );
|
|
if (ptr) return ptr + 1;
|
|
return name;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* myAddPrinterDriverEx [internal]
|
|
*
|
|
* Install a Printer Driver with the Option to upgrade / downgrade the Files
|
|
* and a special mode with lazy error checking.
|
|
*
|
|
*/
|
|
BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
|
|
{
|
|
const PRINTENV_T *env;
|
|
apd_data_t apd;
|
|
DRIVER_INFO_8W di;
|
|
BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
|
|
HMODULE hui;
|
|
WCHAR *file;
|
|
HKEY hroot;
|
|
HKEY hdrv;
|
|
DWORD disposition;
|
|
DWORD len;
|
|
LONG lres;
|
|
BOOL res;
|
|
|
|
/* we need to set all entries in the Registry, independent from the Level of
|
|
DRIVER_INFO, that the caller supplied */
|
|
|
|
ZeroMemory(&di, sizeof(di));
|
|
if (pDriverInfo && (level < ARRAYSIZE(di_sizeof)))
|
|
{
|
|
memcpy(&di, pDriverInfo, di_sizeof[level]);
|
|
}
|
|
|
|
/* dump the most used infos */
|
|
FIXME("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
|
|
FIXME("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
|
|
FIXME("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
|
|
FIXME("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
|
|
FIXME("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
|
|
FIXME("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
|
|
FIXME("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
|
|
/* dump only the first of the additional Files */
|
|
FIXME("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
|
|
|
|
|
|
/* check environment */
|
|
env = validate_envW(di.pEnvironment);
|
|
if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
|
|
|
|
/* fill the copy-data / get the driverdir */
|
|
len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
|
|
if (!LocalGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1, (LPBYTE) apd.src, len, &len))
|
|
{
|
|
/* Should never fail */
|
|
return FALSE;
|
|
}
|
|
memcpy(apd.dst, apd.src, len);
|
|
lstrcatW(apd.src, backslashW);
|
|
apd.srclen = lstrlenW(apd.src);
|
|
lstrcatW(apd.dst, env->versionsubdir);
|
|
lstrcatW(apd.dst, backslashW);
|
|
apd.dstlen = lstrlenW(apd.dst);
|
|
apd.copyflags = dwFileCopyFlags;
|
|
apd.lazy = lazy;
|
|
CreateDirectoryW(apd.src, NULL);
|
|
CreateDirectoryW(apd.dst, NULL);
|
|
|
|
hroot = open_driver_reg(env->envname);
|
|
if (!hroot)
|
|
{
|
|
ERR("Can't create Drivers key\n");
|
|
return FALSE;
|
|
}
|
|
|
|
/* Fill the Registry for the Driver */
|
|
if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE | KEY_QUERY_VALUE, NULL,
|
|
&hdrv, &disposition)) != ERROR_SUCCESS)
|
|
{
|
|
ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
|
|
RegCloseKey(hroot);
|
|
SetLastError(lres);
|
|
return FALSE;
|
|
}
|
|
RegCloseKey(hroot);
|
|
|
|
/* Verified with the Adobe PS Driver, that w2k does not use di.Version */
|
|
RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (const BYTE*) &env->driverversion,
|
|
sizeof(DWORD));
|
|
|
|
file = get_file_part( di.pDriverPath );
|
|
RegSetValueExW( hdrv, driverW, 0, REG_SZ, (LPBYTE)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
|
|
apd_copyfile( di.pDriverPath, file, &apd );
|
|
|
|
file = get_file_part( di.pDataFile );
|
|
RegSetValueExW( hdrv, data_fileW, 0, REG_SZ, (LPBYTE)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
|
|
apd_copyfile( di.pDataFile, file, &apd );
|
|
|
|
file = get_file_part( di.pConfigFile );
|
|
RegSetValueExW( hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
|
|
apd_copyfile( di.pConfigFile, file, &apd );
|
|
|
|
/* settings for level 3 */
|
|
if (di.pHelpFile)
|
|
{
|
|
file = get_file_part( di.pHelpFile );
|
|
RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (LPBYTE)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
|
|
apd_copyfile( di.pHelpFile, file, &apd );
|
|
}
|
|
else
|
|
RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW) );
|
|
|
|
if (di.pDependentFiles && *di.pDependentFiles)
|
|
{
|
|
WCHAR *reg, *reg_ptr, *in_ptr;
|
|
reg = reg_ptr = HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di.pDependentFiles ) );
|
|
|
|
for (in_ptr = di.pDependentFiles; *in_ptr; in_ptr += lstrlenW( in_ptr ) + 1)
|
|
{
|
|
file = get_file_part( in_ptr );
|
|
len = lstrlenW( file ) + 1;
|
|
memcpy( reg_ptr, file, len * sizeof(WCHAR) );
|
|
reg_ptr += len;
|
|
apd_copyfile( in_ptr, file, &apd );
|
|
}
|
|
*reg_ptr = 0;
|
|
|
|
RegSetValueExW( hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)reg, (reg_ptr - reg + 1) * sizeof(WCHAR) );
|
|
HeapFree( GetProcessHeap(), 0, reg );
|
|
}
|
|
else
|
|
RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
|
|
|
|
/* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
|
|
if (di.pMonitorName)
|
|
RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
|
|
(lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
|
|
else
|
|
RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
|
|
|
|
if (di.pDefaultDataType)
|
|
RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
|
|
(lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
|
|
else
|
|
RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
|
|
|
|
/* settings for level 4 */
|
|
if (di.pszzPreviousNames)
|
|
RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
|
|
multi_sz_lenW(di.pszzPreviousNames));
|
|
else
|
|
RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
|
|
|
|
if (level > 5) FIXME("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
|
|
|
|
RegCloseKey(hdrv);
|
|
|
|
//
|
|
// Locate driver and send the event.
|
|
//
|
|
|
|
hui = driver_load(env, di.pConfigFile);
|
|
|
|
pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
|
|
|
|
if (hui && pDrvDriverEvent)
|
|
{
|
|
/* Support for DrvDriverEvent is optional */
|
|
TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
|
|
/* MSDN: level for DRIVER_INFO is 1 to 3 */
|
|
res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
|
|
TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
|
|
}
|
|
FreeLibrary(hui);
|
|
|
|
FIXME("=> TRUE with %u\n", GetLastError());
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* AddPrinterDriverEx [exported through PRINTPROVIDOR]
|
|
*
|
|
* Install a Printer Driver with the Option to upgrade / downgrade the Files
|
|
*
|
|
* PARAMS
|
|
* pName [I] Servername or NULL (local Computer)
|
|
* level [I] Level for the supplied DRIVER_INFO_*W struct
|
|
* pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
|
|
* dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
|
|
*
|
|
* RESULTS
|
|
* Success: TRUE
|
|
* Failure: FALSE
|
|
*
|
|
*/
|
|
BOOL WINAPI LocalAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
|
|
{
|
|
LONG lres;
|
|
|
|
TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
|
|
|
|
lres = copy_servername_from_name(pName, NULL);
|
|
|
|
if (lres)
|
|
{
|
|
FIXME("server %s not supported\n", debugstr_w(pName));
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES)
|
|
{
|
|
TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
|
|
}
|
|
|
|
return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
|
|
}
|
|
|
|
BOOL WINAPI LocalAddPrinterDriver(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
|
|
{
|
|
LONG lres;
|
|
|
|
TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo);
|
|
|
|
lres = copy_servername_from_name(pName, NULL);
|
|
|
|
if (lres)
|
|
{
|
|
FIXME("server %s not supported\n", debugstr_w(pName));
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return FALSE;
|
|
}
|
|
|
|
// Should be APD_COPY_NEW_FILES. Cheap wine.
|
|
|
|
return myAddPrinterDriverEx(level, pDriverInfo, APD_COPY_NEW_FILES, TRUE);
|
|
}
|