/*++ Copyright (c) 1996 Microsoft Corporation Module Name: print.c Abstract: This module contains the print specific WINFAX API functions. Author: Wesley Witt (wesw) 29-Nov-1996 Revision History: --*/ #include "faxapi.h" #pragma hdrstop LPWSTR Platforms[] = { L"Windows NT x86", L"Windows NT R4000", L"Windows NT Alpha_AXP", L"Windows NT PowerPC" }; LPWSTR AddFaxTag( LPWSTR TagStr, LPCWSTR FaxTag, LPCWSTR Value ) { if (!Value) { return TagStr; } wcscat( TagStr, FaxTag ); wcscat( TagStr, Value ); return TagStr; } BOOL IsPrinterFaxPrinter( LPWSTR PrinterName ) { HANDLE hPrinter = NULL; PRINTER_DEFAULTS PrinterDefaults; SYSTEM_INFO SystemInfo; DWORD Size; DWORD Rval = FALSE; LPDRIVER_INFO_2 DriverInfo = NULL; PrinterDefaults.pDatatype = NULL; PrinterDefaults.pDevMode = NULL; PrinterDefaults.DesiredAccess = PRINTER_READ; if (!OpenPrinter( PrinterName, &hPrinter, &PrinterDefaults )) { DebugPrint(( L"OpenPrinter() failed, ec=%d", GetLastError() )); return FALSE; } GetSystemInfo( &SystemInfo ); Size = 4096; DriverInfo = (LPDRIVER_INFO_2) MemAlloc( Size ); if (!DriverInfo) { DebugPrint(( L"Memory allocation failed, size=%d", Size )); SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto exit; } Rval = GetPrinterDriver( hPrinter, Platforms[SystemInfo.wProcessorArchitecture], 2, (LPBYTE) DriverInfo, Size, &Size ); if (!Rval) { DebugPrint(( L"GetPrinterDriver() failed, ec=%d", GetLastError() )); goto exit; } if (_tcscmp( DriverInfo->pName, FAX_DRIVER_NAME ) == 0) { Rval = TRUE; } else { Rval = FALSE; } exit: MemFree( DriverInfo ); ClosePrinter( hPrinter ); return Rval; } PVOID MyGetJob( HANDLE hPrinter, DWORD level, DWORD jobId ) /*++ Routine Description: Wrapper function for spooler API GetJob Arguments: hPrinter - Handle to the printer object level - Level of JOB_INFO structure interested jobId - Specifies the job ID Return Value: Pointer to a JOB_INFO structure, NULL if there is an error --*/ { PBYTE pJobInfo = NULL; DWORD cbNeeded; if (!GetJob(hPrinter, jobId, level, NULL, 0, &cbNeeded) && GetLastError() == ERROR_INSUFFICIENT_BUFFER && (pJobInfo = MemAlloc(cbNeeded)) && GetJob(hPrinter, jobId, level, pJobInfo, cbNeeded, &cbNeeded)) { return pJobInfo; } MemFree(pJobInfo); return NULL; } LPWSTR GetCpField( HKEY hKey, LPWSTR SubKey ) /*++ Routine Description: Retrieves the data for a coverpage field from the registry. Arguments: hKey - Registry handle SubKey - Subkey name Return Value: Pointer to the coverpage field data. --*/ { LONG rVal; DWORD RegSize; DWORD RegType; LPBYTE Buffer; rVal = RegQueryValueEx( hKey, SubKey, 0, &RegType, NULL, &RegSize ); if (rVal != ERROR_SUCCESS) { return NULL; } Buffer = (LPBYTE) MemAlloc( RegSize ); if (!Buffer) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } rVal = RegQueryValueEx( hKey, SubKey, 0, &RegType, Buffer, &RegSize ); if (rVal != ERROR_SUCCESS) { MemFree( Buffer ); return NULL; } return (LPWSTR) Buffer; } BOOL GetCpFields( PCOVERPAGEFIELDS CpFields ) /*++ Routine Description: Initializes the coverpage field structure and fills in the sender information from the registry. Arguments: CpFields - Pointer to a coverpage field structure. Return Value: TRUE for success. FALSE for failure. --*/ { HKEY hKey; LONG rVal; rVal = RegOpenKey( HKEY_CURRENT_USER, REGKEY_FAX_USERINFO, &hKey ); if (rVal != ERROR_SUCCESS) { return FALSE; } ZeroMemory( CpFields, sizeof(COVERPAGEFIELDS) ); CpFields->ThisStructSize = sizeof(COVERPAGEFIELDS); // // sender fields // CpFields->SdrName = GetCpField( hKey, REGVAL_FULLNAME ); CpFields->SdrFaxNumber = GetCpField( hKey, REGVAL_FAX_NUMBER ); CpFields->SdrCompany = GetCpField( hKey, REGVAL_COMPANY ); CpFields->SdrAddress = GetCpField( hKey, REGVAL_ADDRESS ); CpFields->SdrTitle = GetCpField( hKey, REGVAL_TITLE ); CpFields->SdrDepartment = GetCpField( hKey, REGVAL_DEPT ); CpFields->SdrOfficeLocation = GetCpField( hKey, REGVAL_OFFICE ); CpFields->SdrHomePhone = GetCpField( hKey, REGVAL_HOME_PHONE ); CpFields->SdrOfficePhone = GetCpField( hKey, REGVAL_OFFICE_PHONE ); RegCloseKey( hKey ); return TRUE; } VOID FreeCpFields( PCOVERPAGEFIELDS CpFields ) /*++ Routine Description: Frees all memory associated with a coverpage field structure. Arguments: CpFields - Pointer to a coverpage field structure. Return Value: None. --*/ { DWORD i; LPBYTE *p; for (i = 0; i < NUM_INSERTION_TAGS; i++) { p = (LPBYTE *) ((ULONG_PTR)CpFields + sizeof(LPTSTR)*(i+1)); if (p && *p) MemFree( *p ); } } BOOL WINAPI FaxPrintCoverPageW( IN const FAX_CONTEXT_INFO *FaxContextInfo, IN const FAX_COVERPAGE_INFOW *CoverPageInfo ) /*++ Routine Description: Prints a coverpage into the printer DC provided. Arguments: FaxContextInfo - contains servername, Printer DC CoverPageInfo - Cover page information Return Value: TRUE for success. FALSE for failure. --*/ { WCHAR CpName[MAX_PATH]; WCHAR Buffer[MAX_PATH]; LPWSTR p; COVERPAGEFIELDS CpFields = {0}; COVDOCINFO CovDocInfo; DWORD DateTimeLen; DWORD cch; LPWSTR s; DWORD ec = 0; LPCWSTR *src; LPCWSTR *dst; DWORD i; // // do a little argument validation // if (CoverPageInfo == NULL || CoverPageInfo->SizeOfStruct != sizeof(FAX_COVERPAGE_INFOW) || FaxContextInfo == NULL || FaxContextInfo->hDC == NULL || FaxContextInfo->SizeOfStruct != sizeof (FAX_CONTEXT_INFOW) ) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } if (!ValidateCoverpage(CoverPageInfo->CoverPageName, FaxContextInfo->ServerName, CoverPageInfo->UseServerCoverPage, CpName)) { return FALSE; } // // get the coverpage fields // GetCpFields( &CpFields ); // // fixup the recipient name // if (CoverPageInfo->RecName) { if (CoverPageInfo->RecName[0] == '\'') { wcscpy( Buffer, &CoverPageInfo->RecName[1] ); Buffer[wcslen(Buffer)-1] = 0; } else { wcscpy( Buffer, CoverPageInfo->RecName ); } } else { Buffer[0] = 0; } // // fill in the coverpage fields with the // data that the caller passed in // CpFields.RecName = StringDup( Buffer ); CpFields.RecFaxNumber = StringDup( CoverPageInfo->RecFaxNumber ); if (CpFields.RecFaxNumber) { p = wcsrchr( (LPWSTR) CpFields.RecFaxNumber, L'@' ); if (p) { wcscpy( (LPWSTR) CpFields.RecFaxNumber, p+1 ); } } CpFields.Subject = StringDup( CoverPageInfo->Subject ); CpFields.Note = StringDup( CoverPageInfo->Note ? CoverPageInfo->Note : L"" ); CpFields.NumberOfPages = StringDup( _itow( CoverPageInfo->PageCount, Buffer, 10 ) ); for (i = 0; i <= ((LPBYTE)&CoverPageInfo->SdrOfficePhone-(LPBYTE)&CoverPageInfo->RecCompany)/sizeof(LPCWSTR); i++) { src = (LPCWSTR *) ((LPBYTE)&CoverPageInfo->RecCompany + (i*sizeof(LPCWSTR))); dst = (LPCWSTR *) ((LPBYTE)&CpFields.RecCompany + (i*sizeof(LPCWSTR))); if (*dst) { MemFree ( (LPBYTE) *dst ) ; } *dst = (LPCWSTR) StringDup( *src ); } // // the time the fax was sent // GetLocalTime((LPSYSTEMTIME)&CoverPageInfo->TimeSent); DateTimeLen = sizeof(Buffer); s = Buffer; GetDateFormat( LOCALE_USER_DEFAULT, 0, &CoverPageInfo->TimeSent, NULL, s, DateTimeLen ); cch = wcslen( s ); s += cch; if (++cch < DateTimeLen) { *s++ = ' '; DateTimeLen -= cch; GetTimeFormat( LOCALE_USER_DEFAULT, 0, &CoverPageInfo->TimeSent, NULL, s, DateTimeLen ); } CpFields.TimeSent = StringDup( Buffer ); // // start the coverpage on a new page // StartPage( FaxContextInfo->hDC ); // // print the cover page // ec = PrintCoverPage( FaxContextInfo->hDC, &CpFields, CpName, &CovDocInfo ); // // end the page // EndPage( FaxContextInfo->hDC ); FreeCpFields( &CpFields ); if (ec != 0) { SetLastError( ec ); return FALSE; } return TRUE; } BOOL WINAPI FaxPrintCoverPageA( IN const FAX_CONTEXT_INFOA *FaxContextInfo, IN const FAX_COVERPAGE_INFOA *CoverPageInfo ) /*++ Routine Description: Prints a coverpage into the printer DC provided. Arguments: FaxContextInfo - fax Printer context info (hdc, etc.) CoverPageInfo - Cover page information Return Value: TRUE for success. FALSE for failure. --*/ { // // assume all fields between Subject and RecName are LPCTSTR's // #define COUNT_CP_FIELDS ((LPBYTE) &CoverPageInfoW.Subject - (LPBYTE)&CoverPageInfoW.RecName)/sizeof(LPCTSTR) BOOL Rval; FAX_COVERPAGE_INFOW CoverPageInfoW = {0}; FAX_CONTEXT_INFOW ContextInfoW = {0}; LPWSTR ServerName = NULL; LPWSTR *d; LPSTR *s; DWORD i; if (!FaxContextInfo || !CoverPageInfo || FaxContextInfo->SizeOfStruct != sizeof(FAX_CONTEXT_INFOA) || CoverPageInfo->SizeOfStruct != sizeof(FAX_COVERPAGE_INFOA)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } ContextInfoW.SizeOfStruct = sizeof(FAX_CONTEXT_INFOW); ContextInfoW.hDC = FaxContextInfo->hDC; if (FaxContextInfo->ServerName[0] != (CHAR)'\0') { ServerName = AnsiStringToUnicodeString( FaxContextInfo->ServerName ); wcscpy(ContextInfoW.ServerName,ServerName); } CoverPageInfoW.SizeOfStruct = sizeof(FAX_COVERPAGE_INFOW); CoverPageInfoW.UseServerCoverPage = CoverPageInfo->UseServerCoverPage; CoverPageInfoW.PageCount = CoverPageInfo->PageCount; CoverPageInfoW.CoverPageName = AnsiStringToUnicodeString( CoverPageInfo->CoverPageName ); for (i=0;i<=COUNT_CP_FIELDS;i++) { d = (LPWSTR*) ((ULONG_PTR)&CoverPageInfoW.RecName + i*sizeof(LPCWSTR)); s = (LPSTR *) ((LPBYTE)&CoverPageInfo->RecName + i*sizeof(LPSTR)); DebugPrint(( TEXT(" source: 0x%08x --> dest: 0x%08x \n"), s, d)); *d = AnsiStringToUnicodeString( *s ); } CoverPageInfoW.TimeSent = CoverPageInfo->TimeSent; CoverPageInfoW.PageCount = CoverPageInfo->PageCount; Rval = FaxPrintCoverPageW( &ContextInfoW, &CoverPageInfoW ); if (CoverPageInfoW.CoverPageName) { MemFree( (LPBYTE) CoverPageInfoW.CoverPageName ); } if (ServerName) { MemFree( (LPBYTE) ServerName ); } for (i = 0; i < COUNT_CP_FIELDS; i++) { d = (LPWSTR *)((ULONG_PTR)&CoverPageInfoW.RecName + i*sizeof(LPWSTR)); if (d && *d)MemFree( (LPBYTE)*d ); } return Rval; } BOOL WINAPI FaxStartPrintJobW( IN LPCWSTR PrinterName, IN const FAX_PRINT_INFOW *PrintInfo, OUT LPDWORD FaxJobId, OUT PFAX_CONTEXT_INFO FaxContextInfo ) /*++ Routine Description: Starts a print job for the specified printer. This function provides functionality beyond what the caller can provide by using StartDoc(). This function disables the display of the fax send wizard and also passes along the information that would otherwise be gathered by the fax wizard ui. Arguments: PrinterName - Fax printer name (must be a fax printer) PrintInfo - Fax print information FaxJobId - Job id of the resulting print job FaxContextInfo - context information including hdc Return Value: TRUE for success. FALSE for failure. --*/ { HANDLE hPrinter = NULL; PDEVMODE DevMode = NULL; PDMPRIVATE DevModePrivate = NULL; DOCINFO DocInfo; PJOB_INFO_2 JobInfo = NULL; PPRINTER_INFO_2 PrinterInfo = NULL; DWORD dwNeeded = 0; HDC hDC = NULL; INT JobId = 0; LPWSTR FaxTags = NULL; LONG Size; LPWSTR FaxPrinterName; // // do a little argument validation // if (PrintInfo == NULL || PrintInfo->SizeOfStruct != sizeof(FAX_PRINT_INFOW) || !FaxJobId || !FaxContextInfo) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } if (PrintInfo->OutputFileName == NULL && (PrintInfo->RecipientNumber == NULL || PrintInfo->RecipientNumber[0] == 0)) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } if (PrintInfo->DrProfileName && PrintInfo->DrEmailAddress) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } // // if no printer specified, assume they want a local fax printer // if (!PrinterName) { FaxPrinterName = GetFaxPrinterName(); if (!FaxPrinterName) { SetLastError(ERROR_INVALID_PRINTER_NAME); return FALSE; } } else { FaxPrinterName = (LPWSTR) PrinterName; } // // verify that the printer is a fax printer, the only type allowed // if (!IsPrinterFaxPrinter( FaxPrinterName )) { SetLastError( ERROR_INVALID_PRINTER_NAME ); return FALSE; } // // open the printer for normal access (this should always work) // if (!OpenPrinter( FaxPrinterName, &hPrinter, NULL )) { goto error_exit; } // // get the fax server's name if the fax printer isn't local // if (!GetPrinter(hPrinter,2,(LPBYTE)PrinterInfo,0,&dwNeeded)) { PrinterInfo = MemAlloc( dwNeeded ); if (!PrinterInfo) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto error_exit; } } if (!GetPrinter(hPrinter,2,(LPBYTE)PrinterInfo,dwNeeded,&dwNeeded)) { goto error_exit; } if (PrinterInfo->pServerName) wcscpy(FaxContextInfo->ServerName,PrinterInfo->pServerName); else FaxContextInfo->ServerName[0] = 0; // // get the required size for the DEVMODE // Size = DocumentProperties( NULL, hPrinter, NULL, NULL, NULL, 0 ); if (Size <= 0) { goto error_exit; } // // allocate memory for the DEVMODE // DevMode = (PDEVMODE) MemAlloc( Size ); if (!DevMode) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); goto error_exit; } // // get the default document properties // if (DocumentProperties( NULL, hPrinter, NULL, DevMode, NULL, DM_OUT_BUFFER ) != IDOK) { goto error_exit; } // // be sure we are dealing with the correct DEVMODE // if (DevMode->dmDriverExtra < sizeof(DMPRIVATE)) { goto error_exit; } // // set the private DEVMODE pointer // DevModePrivate = (PDMPRIVATE) ((LPBYTE) DevMode + DevMode->dmSize); // // set the necessary stuff in the DEVMODE // DevModePrivate->sendCoverPage = FALSE; DevModePrivate->flags |= FAXDM_NO_WIZARD; DevModePrivate->flags &= ~FAXDM_DRIVER_DEFAULT; // // create the device context // hDC = CreateDC( L"WINSPOOL", FaxPrinterName, NULL, DevMode ); if (!hDC) { goto error_exit; } // // set the document information // DocInfo.cbSize = sizeof(DOCINFO); DocInfo.lpszDocName = PrintInfo->DocName; DocInfo.lpszOutput = PrintInfo->OutputFileName; DocInfo.lpszDatatype = NULL; DocInfo.fwType = 0; // // start the print job // JobId = StartDoc( hDC, &DocInfo ); if (JobId <= 0) { goto error_exit; } if (PrintInfo->OutputFileName == NULL) { // // HACK HACK -> pause the print job // if (FaxJobId && *FaxJobId == 0xffffffff) { SetJob( hPrinter, JobId, 0, NULL, JOB_CONTROL_PAUSE ); } // // allocate memory for the fax tags // FaxTags = (LPWSTR) MemAlloc( 4096 ); if (!FaxTags) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return FALSE; } // // set the job tags // this is how we communicate the information to // the print driver that would otherwise be // provided by the fax print wizard // JobInfo = MyGetJob( hPrinter, 2, JobId ); if (!JobInfo) { goto error_exit; } AddFaxTag( FaxTags, FAXTAG_RECIPIENT_NUMBER, PrintInfo->RecipientNumber ); AddFaxTag( FaxTags, FAXTAG_RECIPIENT_NAME, PrintInfo->RecipientName ); AddFaxTag( FaxTags, FAXTAG_SENDER_NAME, PrintInfo->SenderName ); AddFaxTag( FaxTags, FAXTAG_SENDER_NAME, PrintInfo->SenderName ); AddFaxTag( FaxTags, FAXTAG_SENDER_COMPANY, PrintInfo->SenderCompany ); AddFaxTag( FaxTags, FAXTAG_SENDER_DEPT, PrintInfo->SenderDept ); AddFaxTag( FaxTags, FAXTAG_BILLING_CODE, PrintInfo->SenderBillingCode ); if (PrintInfo->DrProfileName) { AddFaxTag( FaxTags, FAXTAG_PROFILE_NAME, PrintInfo->DrProfileName ); AddFaxTag( FaxTags, FAXTAG_EMAIL_NAME, L"inbox" ); } else if (PrintInfo->DrEmailAddress) { AddFaxTag( FaxTags, FAXTAG_PROFILE_NAME, PrintInfo->DrEmailAddress ); AddFaxTag( FaxTags, FAXTAG_EMAIL_NAME, L"email" ); } // // set these fields or the spooler will // return ACCESS_DENIED for a non-admin client // JobInfo->Position = JOB_POSITION_UNSPECIFIED; JobInfo->pDevMode = NULL; // // set our new fax tags // JobInfo->pParameters = FaxTags; if (!SetJob( hPrinter, JobId, 2, (LPBYTE) JobInfo, 0 )) { goto error_exit; } } // // clean up and return to the caller // ClosePrinter( hPrinter); MemFree( PrinterInfo); MemFree( DevMode ); MemFree( FaxTags ); MemFree( JobInfo ); if (!PrinterName) { MemFree (FaxPrinterName); } if (FaxJobId) { *FaxJobId = JobId; } FaxContextInfo->hDC = hDC; return TRUE; error_exit: if (hPrinter) { ClosePrinter( hPrinter); } if (PrinterInfo) { MemFree( PrinterInfo); } if (JobId) { EndDoc( hDC ); } if (hDC) { DeleteDC( hDC ); } if (DevMode) { MemFree( DevMode ); } if (FaxTags) { MemFree( FaxTags ); } if (JobInfo) { MemFree( JobInfo ); } if (!PrinterName) { MemFree (FaxPrinterName); } return FALSE; } BOOL WINAPI FaxStartPrintJobA( IN LPCSTR PrinterName, IN const FAX_PRINT_INFOA *PrintInfo, OUT LPDWORD JobId, OUT FAX_CONTEXT_INFOA *FaxContextInfo ) /*++ Routine Description: Starts a print job for the specified printer. This function provides functionality beyond what the caller can provide by using StartDoc(). This function disables the display of the fax send wizard and also passes along the information that would otherwise be gathered by the fax wizard ui. Arguments: PrinterName - Fax printer name (must be a fax printer) PrintInfo - Fax print information FaxJobId - Job id of the resulting print job FaxContextInfo - device context information (hdc, etc.) Return Value: TRUE for success. FALSE for failure. --*/ { BOOL Rval; FAX_PRINT_INFOW PrintInfoW; FAX_CONTEXT_INFOW ContextInfoW; LPSTR ServerName; LPWSTR PrinterNameW = NULL; if (!PrintInfo || !JobId || !FaxContextInfo || (PrintInfo->SizeOfStruct != sizeof(FAX_PRINT_INFOA))) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (PrinterName) { PrinterNameW = AnsiStringToUnicodeString( PrinterName ); } ZeroMemory( &ContextInfoW, sizeof(FAX_CONTEXT_INFOW) ); ContextInfoW.SizeOfStruct = sizeof(FAX_CONTEXT_INFOW) ; ZeroMemory( &PrintInfoW, sizeof(FAX_PRINT_INFOW) ); PrintInfoW.SizeOfStruct = sizeof(FAX_PRINT_INFOW); PrintInfoW.DocName = AnsiStringToUnicodeString( PrintInfo->DocName ); PrintInfoW.RecipientName = AnsiStringToUnicodeString( PrintInfo->RecipientName ); PrintInfoW.RecipientNumber = AnsiStringToUnicodeString( PrintInfo->RecipientNumber ); PrintInfoW.SenderName = AnsiStringToUnicodeString( PrintInfo->SenderName ); PrintInfoW.SenderCompany = AnsiStringToUnicodeString( PrintInfo->SenderCompany ); PrintInfoW.SenderDept = AnsiStringToUnicodeString( PrintInfo->SenderDept ); PrintInfoW.SenderBillingCode = AnsiStringToUnicodeString( PrintInfo->SenderBillingCode ); PrintInfoW.DrProfileName = AnsiStringToUnicodeString( PrintInfo->DrProfileName ); PrintInfoW.DrEmailAddress = AnsiStringToUnicodeString( PrintInfo->DrEmailAddress ); PrintInfoW.OutputFileName = AnsiStringToUnicodeString( PrintInfo->OutputFileName ); Rval = FaxStartPrintJobW( (LPWSTR) PrinterNameW, &PrintInfoW, JobId, &ContextInfoW ); MemFree( (LPBYTE) PrinterNameW ); MemFree( (LPBYTE) PrintInfoW.DocName ); MemFree( (LPBYTE) PrintInfoW.RecipientName ); MemFree( (LPBYTE) PrintInfoW.RecipientNumber ); MemFree( (LPBYTE) PrintInfoW.SenderName ); MemFree( (LPBYTE) PrintInfoW.SenderCompany ); MemFree( (LPBYTE) PrintInfoW.SenderDept ); MemFree( (LPBYTE) PrintInfoW.SenderBillingCode ); ServerName = UnicodeStringToAnsiString( ContextInfoW.ServerName); if (ServerName) { strcpy(FaxContextInfo->ServerName,ServerName); } else FaxContextInfo->ServerName[0] = 0; FaxContextInfo->SizeOfStruct = sizeof(FAX_CONTEXT_INFOA); FaxContextInfo->hDC = ContextInfoW.hDC; MemFree( (LPBYTE) ServerName ); return Rval; } BOOL ValidateCoverpage( LPCWSTR CoverPageName, LPCWSTR ServerName, BOOL ServerCoverpage, LPWSTR ResolvedName ) /*++ Routine Description: This routine tries to validate that that coverpage specified by the user actually exists where they say it does, and that it is indeed a coverpage (or a resolvable link to one) Please see the SDK for documentation on the rules for how server coverpages work, etc. Arguments: CoverpageName - contains name of coverpage ServerName - name of the server, if any (can be null) ServerCoverpage - indicates if this coverpage is on the server, or in the server location for coverpages locally ResolvedName - a pointer to buffer (should be MAX_PATH large at least) to receive the resolved coverpage name. If NULL, then this param is ignored Return Value: TRUE if coverpage can be used. FALSE if the coverpage is invalid or cannot be used. --*/ { LPWSTR p; DWORD ec = 0; WCHAR CpDir[MAX_PATH]; WCHAR Buffer[MAX_PATH]; if (!CoverPageName) { ec = ERROR_INVALID_PARAMETER; goto exit; } wcsncpy(CpDir,CoverPageName,MAX_PATH); p = wcschr(CpDir, L'\\' ); if (p) { // // the coverpage file name contains a path so just use it. // if (GetFileAttributes( CpDir ) == 0xffffffff) { ec = ERROR_FILE_NOT_FOUND; goto exit; } } else { // // the coverpage file name does not contain // a path so we must construct a full path name // if (ServerCoverpage) { if (!ServerName || ServerName[0] == 0) ec = GetServerCpDir( NULL, CpDir, sizeof(CpDir) ); else ec = GetServerCpDir( ServerName, CpDir, sizeof(CpDir) ); } else { ec = GetClientCpDir( CpDir, sizeof(CpDir) ); } if (!ec) { ec = ERROR_FILE_NOT_FOUND; goto exit; } ec = 0; ConcatenatePaths(CpDir, CoverPageName); if (wcschr( CpDir, '.' ) == NULL) { wcscat( CpDir, CP_FILENAME_EXT ); } if (GetFileAttributes( CpDir ) == 0xffffffff) { p = wcschr( CpDir, '.' ); if (p) { wcscpy( p, CP_SHORTCUT_EXT ); if (GetFileAttributes( CpDir ) == 0xffffffff) { ec = ERROR_FILE_NOT_FOUND; goto exit; } } else { ec = ERROR_FILE_NOT_FOUND; goto exit; } } } // // if the file is really a shortcut, then resolve it // if (IsCoverPageShortcut( CpDir )) { if (!ResolveShortcut( CpDir, Buffer )) { DebugPrint(( TEXT("Cover page file is really a link, but resolution is not possible") )); ec = ERROR_FILE_NOT_FOUND; goto exit; } else { if (ResolvedName) { wcscpy(ResolvedName,Buffer); } } } else { if (ResolvedName) { wcscpy( ResolvedName, CpDir ); } } exit: if (ec) { SetLastError(ec); return FALSE; } return TRUE; }