AddPrinterDriver API哪位老大能给个详细的sample
AddPrinterDriver API哪位老大能给个详细的sample 问题点数:0、回复次数:7Top
1 楼chinahu3000()回复于 2003-08-02 14:17:13 得分 0
upTop
2 楼taianmonkey()回复于 2003-08-02 14:26:36 得分 0
/*---------------------------------------------------------------
THIS CODE AND INFORMATION 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.
Copyright (C) 2001 Microsoft Corporation. All rights reserved.
DrvSrv.cpp
Defines the entry point and exported functions for the DLL application.
This DLL exports:
Install
This is the RunDLL32 entry point included just to support RunDLL32
InstallDriver
This is the function that does all the work
The exported functions are exported via .DEF file so that they
can be called easily from Visual Basic and RunDLL32.
History:
4/37/2001 Wrote it. -jcd
5/2/2001 1rst Publication -jcd
---------------------------------------------------------------*/
#include "stdafx.h"
#include "windows.h"
#include "winspool.h"
#include "DrvSrv.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
/*
Function: Install
RunDll32 entry point per:
Q164787 INFO: The Windows 95 Rundll and Rundll32 Interface
Remarks:
usage: RunDLL32 drvsrv,Install "\\[server]\[share]"
*/
void CALLBACK Install(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
InstallDriver(lpszCmdLine);
}
/*
Function: StripQuotes
Parameters:
IN/OUT str - the string from which leading and trailing quotes are to be
removed.
Remarks:
This code assumes that if the first char is not a quote, the string
should be left alone.
The work is performed by moving the char's of the string forward to
overwrite the leading quote.
It trims any trailing quote by overwritting the quote char with a
NULL terminator.
Worst case, the string length shrinks by a count of 2 chars.
A string with a leading quote but no trailing quote is valid.
*/
void StripQuotes(char *str)
{
int end;
// if leading quotes, then we have work to do
if (str[0] == '"')
{
// strip leading quote
lstrcpy(str, &str[1]);
// look for trailing quote and strip it too if necessary
end = lstrlen(str)-1;
if (str[end] == '"')
str[end] = 0;
}
}
/*
Function: TrimToServer
Parameters:
IN/OUT pszUNC - the UNC path
Remarks:
This function assumes the string is of the form "\\xxxx\ssss".
It truncates pszUNC to the form "\\xxx"
*/
void TrimToServer(char *pszUNC)
{
int ServerLen = strcspn(&pszUNC[2], "\\");
pszUNC[ServerLen + 2] = '\0';
}
/*
Function: GetDriverInfo
Parameters:
IN pszUNC - the UNC path to the printer share on a Windows NT or 2000 print server
OUT ppInfo - pointer to a pointer variable that receives the info
Remarks:
Caller must free the buffer at *ppInfo by using "delete (char *) *ppInfo;"
*/
BOOL GetDriverInfo(char *pszUNC, DRIVER_INFO_3 **ppInfo)
{
HANDLE hPrinter = INVALID_HANDLE_VALUE;
DRIVER_INFO_3 *pDI3 = NULL;
DWORD dwError = 0;
char *pEnv = NULL; // We'll never use this on 9x - must always be NULL
DWORD cbNeeded;
if (!OpenPrinter(pszUNC, &hPrinter, NULL))
{
// hmm, path to alleged printer must be wrong
// or if this somehow got executed on NT, the user account
// does not have access to the printer and/or we needed the
// third parameter.
goto bail;
}
// We expect the following call to fail so it can tell us
// how big the buffer should be.
GetPrinterDriver(hPrinter, pEnv, 3, (LPBYTE)NULL, 0, &cbNeeded);
dwError = GetLastError();
if (dwError != ERROR_INSUFFICIENT_BUFFER)
{
// OK, this is bad. We know the path is valid to somthing
// since we succeeded with OpenPrinter.
// But it sure isn't a printer share, or something worse.
goto bail;
}
// we know how big now, proceed
pDI3 = (DRIVER_INFO_3 *)new char[cbNeeded];
if (!GetPrinterDriver(hPrinter, pEnv, 3, (LPBYTE)pDI3, cbNeeded, &cbNeeded))
{
// This time if it fails, its for good.
// It really can't be an insufficient buffer error. We've done that already.
// Could have been a network error.
// System might be unstable.
// Something happened to the printer install.
// ...
// But we are done.
goto bail;
}
// Now we have the goods, send them back to the caller.
*ppInfo = pDI3;
pDI3 = NULL; // We do not own the buffer anymore.
// Done with the printer or the printer share
ClosePrinter(hPrinter);
return TRUE;
bail:
delete ((char *) pDI3); // delete by the same datatype as allocated
ClosePrinter(hPrinter);
return FALSE;
}
Top
3 楼taianmonkey()回复于 2003-08-02 14:27:45 得分 0
/*
Function: GetDriverServerPath9x
Parameters:
IN pszUNC - the UNC path to the printer share on Windows NT or 2000
OUT pszDest - pointer to a string buffer to receive the path.
IN cChar - size of pszDest string buffer in characters.
Remarks:
The function combines the "known" path to the driver files on NT/2000
with the name of the NT/2000 print server passed in by pszUNC.
Nominally, we should have needed to use GetPrinterDriverDirectory but
on Windows 9x, this function works only on the local machine.
print$ is the invisible share used for printer driver files.
Win40 is the "Environment" directory that correlates to the
"Windows 4.0" environment string that means Windows 9x.
0 is the directory that represents the driver architecture for 9x print
drivers.
A function customized for Windows NT/2000 would need to be written if
this technique would be used on such a client. Fortunately, with NT
Printer Connections, all of this is unnecessary. Just Call
AddPrinterConnection().
*/
BOOL GetDriverServerPath9x(const char *pszUNC, char *pszDest, const int cChar)
{
ZeroMemory(pszDest, cChar);
lstrcpyn(pszDest, pszUNC, cChar);
TrimToServer(pszDest);
lstrcat(pszDest, "\\print$\\Win40\\0"); // always this way for 9x clients
return TRUE;
}
/*
Function: DuplicateFile
Parameters:
IN pszFile - the filename to be duplicated
IN pszDestPath - the destination path to write the copy
IN pszSrcPath - the source path to the existing file
IN fOverwrite - the whether to try to overwrite the file
Remarks:
This function combines the CopyFile operation with the Full path
creation work to provide a simple interface for replicating a file by
name from one place to another.
Very handy for copying down driver files from a share.
*/
BOOL DuplicateFile(const char *pszFile, const char *pszDestPath, const char *pszSrcPath, const BOOL fOverwrite)
{
char szSrc[MAX_PATH];
char szDest[MAX_PATH];
lstrcpy(szSrc, pszSrcPath);
lstrcat(szSrc, "\\");
lstrcat(szSrc, pszFile);
lstrcpy(szDest, pszDestPath);
lstrcat(szDest, "\\");
lstrcat(szDest, pszFile);
return CopyFile(szSrc, szDest, !fOverwrite);
}
/*
Function: ReferenceFileName
Parameters:
IN pszPath - the path containing the file name
Remarks:
A handy utility for getting a string pointer to a filename in a path
when it is not necessary to isolate the filename from the path in the
string buffer.
Used for calls to DuplicateFile.
*/
const char *ReferenceFileName(const char *pszPath)
{
/* look for the leading backslash before the filename
if NULL is returned, there isn't one and the pszPath
is the filename.
if we found the backslash, adjust the pointer to the start
of the filename.
*/
const char *pszFile = strrchr(pszPath, '\\');
if (!pszFile)
/* Note that we pass through NULL here if we are given NULL */
pszFile = pszPath;
else
pszFile++;
return pszFile;
}
/*
Function: CopyDriverFiles
Parameters:
IN pDrvInfo - the driver info structure that contains the list of files
IN pszDest - destination path for the driver files
IN pszSrc - source path for the driver files
Returns: TRUE if all of the drive files were copied.
Remarks:
Copies driver files listed in a DRIVER_INFO_3 structure from pszDest
to pszSrc. The path parameters should not contain trailing backslashes.
If there is a file listed in a field of DRIVER_INFO_3,
we try to copy it.
If it exists, we copy over it. The assumption being this is the right
thing to do because the file is compatible with the one overwritten.
If it exists and is in use, the copy will fail and so will we.
This function behaves conservatively for failures. If copying of one
file fails for any reason, it quits and returns FALSE.
The function could be modified to check for the case where the copy
failed because the driver file already existed and is in use. If the
file is compatible, we could use it and allow things to proceed.
*/
BOOL CopyDriverFiles(const DRIVER_INFO_3 *pDrvInfo, const char *pszDest, const char *pszSrc)
{
const char *pszFile;
char *pszDepFiles;
/* Copy the driver */
pszFile = ReferenceFileName(pDrvInfo->pDriverPath);
if (pszFile)
{
if (!DuplicateFile(pszFile, pszDest, pszSrc, TRUE))
goto bail;
}
/* Copy the configuration file */
pszFile = ReferenceFileName(pDrvInfo->pConfigFile);
if (pszFile)
{
if (!DuplicateFile(pszFile, pszDest, pszSrc, TRUE))
goto bail;
}
/* Copy the datafile */
pszFile = ReferenceFileName(pDrvInfo->pDataFile);
if (pszFile)
{
if (!DuplicateFile(pszFile, pszDest, pszSrc, TRUE))
goto bail;
}
/* Copy the help file */
pszFile = ReferenceFileName(pDrvInfo->pHelpFile);
if (pszFile)
{
if (!DuplicateFile(pszFile, pszDest, pszSrc, TRUE))
goto bail;
}
/* Copy the Dependent files */
/* The pDrvInfo->pDependentFiles is a double NULL terminated list of
filenames. We creep down the list as we reach the end of each filename
string until we find the end of the list when we hit the double
terminator.
*/
pszDepFiles = pDrvInfo->pDependentFiles;
while (pszDepFiles && *pszDepFiles != 0)
{
pszFile = ReferenceFileName(pszDepFiles);
if (pszFile)
{
if (!DuplicateFile(pszFile, pszDest, pszSrc, TRUE))
goto bail;
}
/* go to next file in the list */
pszDepFiles += lstrlen(pszDepFiles)+1;
}
return TRUE;
bail:
return FALSE;
}
Top
4 楼taianmonkey()回复于 2003-08-02 14:28:10 得分 0
/*
Function: IsDriverInstalled
Parameters:
IN pDriverName - the name of the driver installation.
Returns: TRUE if we find this driver installation by name on this machine.
Remarks:
Checks for a package of driver fils installed by the name of
pDriverName.
If the function has trouble looking for installed printer drivers, it
fails and returns FALSE.
*/
BOOL IsDriverInstalled(const char *pDriverName)
{
DRIVER_INFO_1 *pDI = NULL;
char *pEnv = NULL; // We'll never use this on 9x - must always be NULL
DWORD cbNeeded;
DWORD cReturned;
BOOL fFound = FALSE;
DWORD i=0;
// We expect the following call to fail so it can tell us
// how big the buffer should be.
EnumPrinterDrivers(NULL, pEnv, 1, (LPBYTE)NULL, 0, &cbNeeded, &cReturned);
// we know how big now, proceed
pDI = (DRIVER_INFO_1 *)new char[cbNeeded];
if (!EnumPrinterDrivers(NULL, pEnv, 1, (LPBYTE)pDI, cbNeeded, &cbNeeded, &cReturned))
{
// This is bad.
goto bail;
}
/* Now we have the goods, look for the driver installation.
If we find it, return TRUE.
If we do not find it, we have already assumed it is not installed.
*/
for (i=0; i < cReturned && !fFound; i++)
{
if (lstrcmpi(pDI[i].pName, pDriverName) == 0)
fFound = TRUE;
}
delete ((char *) pDI); // delete by the same datatype as allocated
return fFound;
bail:
delete ((char *) pDI); // delete by the same datatype as allocated
return FALSE;
}
/*
Function: InstallDriver
Parameters:
IN pPrinterUNC - the UNC path to the printer share on a Windows NT or 2000
Remarks:
Call this function with a string that is a UNC path to the printer
share. Example: "\\spos\flamingo.pcl"
The shared printer must have the appropriate Windows 95/98/98SE or
Millenium drivers installed via the sharing dialog's Additional Drivers
feature. This is otherwise known as Point and Print in a mixed Windows
NT/2000 and Windows 9x network.
As written, this code takes the tactic that it is desireable to
overwrite any existing driver files of the same name. If it cannot for
some reason, it choses not to do a partial install and fails. If the
driver files by "driver name" are already installed, it fails.
Visual Basic declaration:
Declare Function InstallDriver Lib "drvsrv.dll" ( _
ByVal szPrintUNC As String _
) As Boolean
*/
DRVSRV_API BOOL WINAPI InstallDriver(const char *pPrinterUNC)
{
char *pEnv = NULL;
char szServedPrinter[MAX_PATH];
char szSource[MAX_PATH];
char szDestination[MAX_PATH];
DWORD cbNeeded;
DRIVER_INFO_3 *pDI3 = NULL;
/* We are going to work on the string so it is good form to
make a copy of our IN parameter.
*/
lstrcpy(szServedPrinter, pPrinterUNC);
StripQuotes(szServedPrinter);
// Get information for the printer drivers that are served.
if (!GetDriverInfo(szServedPrinter, &pDI3))
{
// Either the UNC path for the printer share inpServerPrinter
// is bogus, or something much more sinister has occured.
return FALSE;
}
// Check for existing driver
if (IsDriverInstalled(pDI3->pName))
{
// Already installed, don't bother to update
delete ((char *) pDI3); // delete by the same datatype as allocated
return FALSE;
}
// Copy the driver files to the place indicated by Windows
if (!GetPrinterDriverDirectory(NULL, pEnv, 1, (LPBYTE)szDestination, sizeof(szDestination), &cbNeeded) ||
!GetDriverServerPath9x(szServedPrinter, szSource, sizeof(szSource)))
{
delete ((char *) pDI3); // delete by the same datatype as allocated
return FALSE;
}
/* Now that we have what to copy, from where to get them, and where to put
them, do the copy.
*/
if (!CopyDriverFiles(pDI3, szDestination, szSource))
{
delete ((char *) pDI3); // delete by the same datatype as allocated
return FALSE;
}
/* Tweak Driver Information as necessary
We change cVersion because it is typically zero when it comes from
NT but it is arbitrarily and typically 1K on Windows 9x.
Note that this is not the release version of the driver files that one
finds in the file properties dialog.
*/
pDI3->cVersion = 1024;
// Install the Driver files
if (!AddPrinterDriver(NULL, 3, (LPBYTE)pDI3))
{
delete ((char *) pDI3); // delete by the same datatype as allocated
return FALSE;
}
// Done
delete (char*) pDI3;
return TRUE;
}
Top
5 楼chinahu3000()回复于 2003-08-04 09:45:20 得分 0
老大,好像不行,那个GetDriverInfo是可以,但是我是要去安装,以前没有那个Driver的,而且不同的Drive ::pDI3 = (DRIVER_INFO_3 *)new char[cbNeeded];cbNeeded
不一的,我总是没法用AddPrinterDriverTop
6 楼chinahu3000()回复于 2003-08-05 13:04:34 得分 0
upTop
7 楼chinahu3000()回复于 2003-08-06 08:35:17 得分 0
upTop




