You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1359 lines
38 KiB
1359 lines
38 KiB
// oleInst.cpp : Implementation of COleInstall
|
|
#include "stdafx.h"
|
|
#include <strsafe.h>
|
|
#include "prnsec.h"
|
|
|
|
#include "oleprn.h"
|
|
#include "oleInst.h"
|
|
#include "printer.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COleInstall
|
|
|
|
const TCHAR * const g_szWindowClassName = TEXT("Ole Install Control");
|
|
const TCHAR * const g_fmtSpoolSSPipe = TEXT("\\\\%s\\PIPE\\SPOOLSS");
|
|
const DWORD cdwSucessExitCode = 0xFFFFFFFF;
|
|
|
|
typedef DWORD (*pfnPrintUIEntry)(HWND,HINSTANCE,LPCTSTR,UINT);
|
|
|
|
OleInstallData::OleInstallData (
|
|
LPTSTR pPrinterUncName,
|
|
LPTSTR pPrinterUrl,
|
|
HWND hwnd,
|
|
BOOL bRPC)
|
|
:m_lCount (2),
|
|
m_pPrinterUncName (NULL),
|
|
m_pPrinterUrl (NULL),
|
|
m_pszTempWebpnpFile (NULL),
|
|
m_hwnd (hwnd),
|
|
m_bValid (FALSE),
|
|
m_bRPC(bRPC)
|
|
{
|
|
if (AssignString (m_pPrinterUncName, pPrinterUncName)
|
|
&& AssignString (m_pPrinterUrl, pPrinterUrl))
|
|
m_bValid = TRUE;
|
|
}
|
|
|
|
OleInstallData::~OleInstallData ()
|
|
{
|
|
if (m_pszTempWebpnpFile) {
|
|
DeleteFile (m_pszTempWebpnpFile);
|
|
LocalFree (m_pszTempWebpnpFile);
|
|
}
|
|
|
|
LocalFree (m_pPrinterUncName);
|
|
LocalFree (m_pPrinterUrl);
|
|
}
|
|
|
|
|
|
COleInstall::COleInstall()
|
|
: m_hwnd (NULL),
|
|
m_pPrinterUncName (NULL),
|
|
m_pPrinterUrl (NULL),
|
|
m_pThreadData (NULL)
|
|
|
|
{
|
|
DisplayUIonDisallow(FALSE); // We don't want IE displaying UI.
|
|
}
|
|
|
|
COleInstall::~COleInstall()
|
|
{
|
|
if(m_hwnd)
|
|
{
|
|
if (m_pThreadData) {
|
|
m_pThreadData->m_hwnd = NULL;
|
|
}
|
|
|
|
::DestroyWindow(m_hwnd);
|
|
m_hwnd = NULL;
|
|
}
|
|
|
|
|
|
LocalFree (m_pPrinterUncName);
|
|
LocalFree (m_pPrinterUrl);
|
|
|
|
if (m_pThreadData) {
|
|
if (InterlockedDecrement (& (m_pThreadData->m_lCount)) == 0) {
|
|
delete (m_pThreadData);
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
COleInstall::OnDraw(
|
|
ATL_DRAWINFO& di)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
BOOL
|
|
COleInstall::UpdateUI (
|
|
OleInstallData *pData,
|
|
UINT message,
|
|
WPARAM wParam)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
if (pData->m_hwnd) {
|
|
::SendMessage (pData->m_hwnd, message, wParam, NULL);
|
|
bRet = TRUE;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL
|
|
COleInstall::UpdateProgress (
|
|
OleInstallData *pData,
|
|
DWORD dwProgress)
|
|
{
|
|
return UpdateUI (pData, WM_ON_PROGRESS, dwProgress);
|
|
}
|
|
|
|
BOOL
|
|
COleInstall::UpdateError (
|
|
OleInstallData *pData)
|
|
{
|
|
return UpdateUI (pData, WM_INSTALL_ERROR, GetLastError ());
|
|
}
|
|
|
|
HRESULT
|
|
COleInstall::InitWin (BOOL bRPC)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
DWORD dwThreadId;
|
|
HANDLE hThread = NULL;
|
|
WNDCLASS wc;
|
|
|
|
// Create Window Class
|
|
if (!::GetClassInfo(_Module.GetModuleInstance(), g_szWindowClassName, &wc))
|
|
{
|
|
wc.style = 0;
|
|
wc.lpfnWndProc = COleInstall::WndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = _Module.GetModuleInstance();
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = NULL;
|
|
wc.hbrBackground = NULL;
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = g_szWindowClassName;
|
|
|
|
if (!RegisterClass(&wc)) {
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
m_hwnd = CreateWindow(g_szWindowClassName,
|
|
NULL, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
|
|
_Module.GetModuleInstance(), this);
|
|
|
|
if (m_hwnd) {
|
|
|
|
m_pThreadData = new OleInstallData (m_pPrinterUncName,
|
|
m_pPrinterUrl,
|
|
m_hwnd,
|
|
bRPC);
|
|
|
|
if (m_pThreadData && m_pThreadData->m_bValid) {
|
|
|
|
if (hThread = ::CreateThread (NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE) &COleInstall::WorkingThread,
|
|
m_pThreadData,
|
|
0,
|
|
&dwThreadId)) {
|
|
CloseHandle (hThread);
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
COleInstall::WorkingThread(
|
|
void * param)
|
|
{
|
|
OleInstallData * pThreadData = (OleInstallData *) param;
|
|
BOOL bRet = FALSE;
|
|
|
|
if (pThreadData) {
|
|
bRet = StartInstall (pThreadData);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
COleInstall::StartInstall(
|
|
OleInstallData *pThreadData)
|
|
{
|
|
HANDLE hServer = NULL;
|
|
PRINTER_DEFAULTS pd = {NULL, NULL, SERVER_ALL_ACCESS};
|
|
BOOL bRet = FALSE;
|
|
|
|
CPrinter Printer;
|
|
HANDLE hPrinter;
|
|
PPRINTER_INFO_2 pPrinterInfo2 = NULL;
|
|
LPTSTR lpszPrinterURL = NULL;
|
|
|
|
// Working thread
|
|
if (!UpdateProgress (pThreadData, 0))
|
|
goto Cleanup;
|
|
|
|
//
|
|
// Check if we are to try RPC or HTTP
|
|
//
|
|
if (pThreadData->m_bRPC)
|
|
{
|
|
// Check RPC connections at first
|
|
if (::AddPrinterConnection( (BSTR)pThreadData->m_pPrinterUncName))
|
|
{
|
|
UpdateProgress (pThreadData, 50);
|
|
if (CheckAndSetDefaultPrinter ())
|
|
{
|
|
UpdateProgress (pThreadData, 100);
|
|
bRet = TRUE;
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Install using HTTP
|
|
//
|
|
// Since http installation always requires
|
|
// administrator privilidge, We have to do a access check before we
|
|
// try to down load the cab file
|
|
|
|
if (!OpenPrinter (NULL, &hServer, &pd))
|
|
{
|
|
// If this fails and it is because we do not have access, we should send a better error
|
|
// message to the local user telling them that the do not have the ability to create
|
|
// printers on the local machine
|
|
|
|
if (GetLastError() == ERROR_ACCESS_DENIED)
|
|
{
|
|
SetLastError(ERROR_LOCAL_PRINTER_ACCESS);
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
else
|
|
ClosePrinter (hServer);
|
|
|
|
//
|
|
// Try the local CAB installation instead of downloading the cab, etc.
|
|
// Need admin privaleges.
|
|
//
|
|
if ( NULL != (lpszPrinterURL = RemoveURLVars( pThreadData->m_pPrinterUrl )) &&
|
|
Printer.Open( lpszPrinterURL, &hPrinter ) )
|
|
{
|
|
|
|
LPTSTR lpszInfName = NULL;
|
|
LPTSTR lpszPrinterName = NULL;
|
|
|
|
pPrinterInfo2 = Printer.GetPrinterInfo2();
|
|
if ((pPrinterInfo2 == NULL) && (GetLastError () == ERROR_ACCESS_DENIED))
|
|
{
|
|
if (!ConfigurePort( NULL, pThreadData->m_hwnd, lpszPrinterURL ))
|
|
{
|
|
bRet = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
pPrinterInfo2 = Printer.GetPrinterInfo2();
|
|
}
|
|
|
|
if ( (NULL != pPrinterInfo2) &&
|
|
(NULL != (lpszInfName = GetNTPrint())) &&
|
|
(NULL != (lpszPrinterName = CreatePrinterBaseName(lpszPrinterURL, pPrinterInfo2->pPrinterName))) )
|
|
{
|
|
|
|
LPTSTR lpszCmd = NULL;
|
|
DWORD dwLength = 0;
|
|
TCHAR szCmdString[] = _TEXT("/if /x /b \"%s\" /r \"%s\" /m \"%s\" /n \"%s\" /f %s /q");
|
|
HMODULE hPrintUI = NULL;
|
|
pfnPrintUIEntry PrintUIEntry;
|
|
|
|
dwLength = lstrlen( szCmdString ) +
|
|
lstrlen( lpszPrinterName ) +
|
|
lstrlen( pPrinterInfo2->pPortName ) +
|
|
lstrlen( pPrinterInfo2->pDriverName ) +
|
|
lstrlen( pThreadData->m_pPrinterUncName ) +
|
|
lstrlen( lpszInfName ) + 1;
|
|
|
|
if ( (lpszCmd = (LPTSTR)LocalAlloc( LPTR, dwLength*sizeof(TCHAR) )) &&
|
|
(hPrintUI = LoadLibraryFromSystem32( TEXT("printui.dll") )) )
|
|
{
|
|
|
|
StringCchPrintf( lpszCmd,
|
|
dwLength,
|
|
szCmdString,
|
|
lpszPrinterName,
|
|
pPrinterInfo2->pPortName,
|
|
pPrinterInfo2->pDriverName,
|
|
pThreadData->m_pPrinterUncName,
|
|
lpszInfName );
|
|
|
|
if ( PrintUIEntry = (pfnPrintUIEntry)GetProcAddress(hPrintUI, "PrintUIEntryW") )
|
|
{
|
|
if ( ERROR_SUCCESS == (*PrintUIEntry)( NULL,
|
|
0,
|
|
lpszCmd,
|
|
SW_HIDE ) )
|
|
{
|
|
UpdateProgress (pThreadData, 50);
|
|
if (CheckAndSetDefaultPrinter ())
|
|
{
|
|
UpdateProgress (pThreadData, 100);
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( lpszCmd )
|
|
LocalFree( lpszCmd );
|
|
|
|
if ( hPrintUI )
|
|
FreeLibrary( hPrintUI );
|
|
}
|
|
if ( lpszInfName )
|
|
LocalFree( lpszInfName );
|
|
|
|
if ( lpszPrinterName )
|
|
LocalFree( lpszPrinterName );
|
|
}
|
|
|
|
if ( lpszPrinterURL )
|
|
LocalFree(lpszPrinterURL);
|
|
|
|
if ( bRet )
|
|
goto Cleanup;
|
|
|
|
if (UpdateProgress (pThreadData, 25))
|
|
{
|
|
|
|
// Step two, the Local CAB install failed so download a driver and install
|
|
if (GetHttpPrinterFile (pThreadData, pThreadData->m_pPrinterUrl))
|
|
{
|
|
|
|
if (UpdateProgress (pThreadData, 60))
|
|
{
|
|
|
|
if (InstallHttpPrinter (pThreadData))
|
|
{
|
|
|
|
if (UpdateProgress (pThreadData, 90))
|
|
{
|
|
|
|
if (CheckAndSetDefaultPrinter ())
|
|
{
|
|
UpdateProgress (pThreadData, 100);
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
if (!bRet)
|
|
{
|
|
UpdateError (pThreadData);
|
|
}
|
|
|
|
// Cleanup the ThreadData
|
|
if (InterlockedDecrement (& (pThreadData->m_lCount)) == 0)
|
|
{
|
|
delete (pThreadData);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
LRESULT CALLBACK
|
|
COleInstall::WndProc(
|
|
HWND hWnd,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
COleInstall *ptc = (COleInstall *)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
|
|
switch(uMsg)
|
|
{
|
|
case WM_CREATE:
|
|
{
|
|
ptc = (COleInstall *)((CREATESTRUCT *)lParam)->lpCreateParams;
|
|
::SetWindowLongPtr(hWnd, GWLP_USERDATA, (UINT_PTR) ptc);
|
|
}
|
|
break;
|
|
|
|
case WM_ON_PROGRESS:
|
|
if (ptc)
|
|
ptc->Fire_OnProgress ((long) wParam);
|
|
break;
|
|
|
|
case WM_INSTALL_ERROR:
|
|
if (ptc)
|
|
ptc->Fire_InstallError ((long) wParam);
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
// ignore late messages
|
|
if(ptc)
|
|
{
|
|
MSG msg;
|
|
|
|
while(PeekMessage(&msg, hWnd, WM_ON_PROGRESS, WM_INSTALL_ERROR, PM_REMOVE));
|
|
::SetWindowLongPtr (hWnd, GWLP_USERDATA, NULL);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
COleInstall::InstallPrinter(
|
|
BSTR bstrUncName,
|
|
BSTR bstrUrl)
|
|
{
|
|
HRESULT hr = bstrUncName && bstrUrl ? S_OK : E_POINTER;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// When using an ATL string conversion Macro, spedcify the USES_CONVERSION macro
|
|
// to avoid compiler error
|
|
USES_CONVERSION;
|
|
|
|
hr = AssignString(m_pPrinterUncName, OLE2T(bstrUncName)) && AssignString(m_pPrinterUrl, OLE2T(bstrUrl)) ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CanIInstallRPC(m_pPrinterUncName); // Determine whether to use RPC or HTTP.
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BOOL bRPC = hr == S_OK;
|
|
LPTSTR lpszDisplay = NULL;
|
|
LPTSTR lpszTemp = NULL;
|
|
DWORD cchSize = 0;
|
|
|
|
if (bRPC)
|
|
{
|
|
cchSize = lstrlen(m_pPrinterUncName) + 1;
|
|
lpszDisplay = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * cchSize);
|
|
hr = lpszDisplay ? S_OK : E_OUTOFMEMORY;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = StringCchCopy(lpszDisplay, cchSize, m_pPrinterUncName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If it's a URL printer name, we need to remove any variables embedded in the
|
|
// URL and also decode it to remove those ~-escaped characters.
|
|
//
|
|
lpszTemp = RemoveURLVars(m_pPrinterUrl);
|
|
hr = lpszTemp ? S_OK : E_OUTOFMEMORY;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// This call is to ask for the required size for this decoding. It has to fail and
|
|
// return ERROR_INSUFFICIENT_BUFFER, otherwise, something is wrong.
|
|
//
|
|
hr = DecodePrinterName(lpszTemp, NULL, &cchSize) ? E_FAIL : GetLastErrorAsHResultAndFail();
|
|
|
|
if (FAILED(hr) && HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
lpszDisplay = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * cchSize);
|
|
hr = lpszDisplay ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = DecodePrinterName(lpszTemp, lpszDisplay, &cchSize) ? S_OK : GetLastErrorAsHResultAndFail();
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = PromptUser(bRPC ? AddPrinterConnection : AddWebPrinterConnection, lpszDisplay);
|
|
}
|
|
|
|
LocalFree(lpszTemp);
|
|
LocalFree(lpszDisplay);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
hr = InitWin(bRPC);
|
|
}
|
|
else if (hr == S_FALSE)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
COleInstall::OpenPrintersFolder()
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (FAILED(hr = CanIOpenPrintersFolder()))
|
|
return hr; // We allow JAVALOW/JAVAMEDIUM to open the printers folder
|
|
|
|
LPITEMIDLIST pidl = NULL;
|
|
HWND hwnd = GetDesktopWindow ();
|
|
|
|
hr = SHGetSpecialFolderLocation( hwnd, CSIDL_PRINTERS, &pidl );
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SHELLEXECUTEINFO ei = {0};
|
|
|
|
ei.cbSize = sizeof(SHELLEXECUTEINFO);
|
|
ei.fMask = SEE_MASK_IDLIST;
|
|
ei.hwnd = hwnd;
|
|
ei.lpIDList = (LPVOID)pidl;
|
|
ei.nShow = SW_SHOWNORMAL;
|
|
|
|
if (!ShellExecuteEx(&ei))
|
|
hr = E_FAIL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Private Member Functions
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL
|
|
COleInstall::SyncExecute(
|
|
LPTSTR pszFileName,
|
|
int nShow)
|
|
{
|
|
SHELLEXECUTEINFO shellExeInfo;
|
|
DWORD dwErrorCode;
|
|
BOOL bRet = FALSE;
|
|
HWND hWndForeground, hWndParent, hWndOwner, hWndLastPopup;
|
|
|
|
//
|
|
// We need to get the window handle of the current process to pass to the installation code,
|
|
// otherwise any UI (e.g. driver signing pop ups) won't have focus of the IE frame.
|
|
//
|
|
|
|
// get the foreground window first
|
|
hWndForeground = ::GetForegroundWindow();
|
|
|
|
// climb up to the top parent in case it's a child window...
|
|
hWndParent = hWndForeground;
|
|
while( hWndParent = ::GetParent(hWndParent) ) {
|
|
hWndForeground = hWndParent;
|
|
}
|
|
|
|
// get the owner in case the top parent is owned
|
|
hWndOwner = ::GetWindow(::GetParent(hWndForeground), GW_OWNER);
|
|
if( hWndOwner ) {
|
|
hWndForeground = hWndOwner;
|
|
}
|
|
|
|
// get the last popup of the owner window
|
|
hWndLastPopup = ::GetLastActivePopup(hWndForeground);
|
|
|
|
ZeroMemory (&shellExeInfo, sizeof (SHELLEXECUTEINFO));
|
|
shellExeInfo.cbSize = sizeof (SHELLEXECUTEINFO);
|
|
shellExeInfo.hwnd = hWndLastPopup;
|
|
shellExeInfo.lpVerb = TEXT ("open");
|
|
shellExeInfo.lpFile = pszFileName;
|
|
shellExeInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
|
shellExeInfo.nShow = nShow;
|
|
|
|
if (ShellExecuteEx (&shellExeInfo) &&
|
|
(UINT_PTR) shellExeInfo.hInstApp > 32) {
|
|
|
|
// Wait until it is done
|
|
if (!WaitForSingleObject (shellExeInfo.hProcess , INFINITE) &&
|
|
GetExitCodeProcess (shellExeInfo.hProcess, &dwErrorCode)) {
|
|
|
|
if (dwErrorCode == cdwSucessExitCode) {
|
|
bRet = TRUE;
|
|
}
|
|
else {
|
|
if (!dwErrorCode) {
|
|
// This means that wpnpinst was terminated abnormally
|
|
// So we have to setup an customized error code here.
|
|
dwErrorCode = ERROR_WPNPINST_TERMINATED;
|
|
}
|
|
SetLastError (dwErrorCode);
|
|
}
|
|
}
|
|
|
|
if (shellExeInfo.hProcess) {
|
|
::CloseHandle(shellExeInfo.hProcess);
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
DWORD
|
|
COleInstall::GetWebpnpFile(
|
|
OleInstallData *pData,
|
|
LPTSTR pszURL,
|
|
LPTSTR *ppErrMsg)
|
|
{
|
|
HINTERNET hUrlWebpnp = NULL;
|
|
HINTERNET hHandle = NULL;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
DWORD dwSize = 0;
|
|
DWORD dwWritten = 0;
|
|
LPTSTR pszHeader = NULL;
|
|
BOOL bRet;
|
|
BOOL bRetry = TRUE;
|
|
DWORD dwRet = RET_OTHER_ERROR;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
DWORD dwLastError;
|
|
DWORD i;
|
|
BYTE buf[FILEBUFSIZE];
|
|
|
|
*ppErrMsg = NULL;
|
|
|
|
if (! (hHandle = InternetOpen (TEXT ("Internet Add Printer"),
|
|
INTERNET_OPEN_TYPE_PRECONFIG,
|
|
NULL, NULL, 0)))
|
|
goto Cleanup;
|
|
|
|
|
|
for (i = 0; bRetry ; i++) {
|
|
DWORD dwCode;
|
|
DWORD dwBufSize = sizeof (DWORD);
|
|
|
|
hUrlWebpnp = InternetOpenUrl (hHandle, pszURL, NULL, 0, 0, 0);
|
|
|
|
|
|
if (!HttpQueryInfo(hUrlWebpnp,
|
|
HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE,
|
|
&dwCode,
|
|
&dwBufSize,
|
|
NULL))
|
|
goto Cleanup;
|
|
|
|
switch (dwCode) {
|
|
case HTTP_STATUS_OK :
|
|
bRetry = FALSE;
|
|
break;
|
|
case HTTP_STATUS_SERVER_ERROR :
|
|
// Errors are returned by the server
|
|
// Try to get the error string
|
|
|
|
dwBufSize = 0;
|
|
bRet = HttpQueryInfo(hUrlWebpnp,
|
|
HTTP_QUERY_STATUS_TEXT,
|
|
NULL,
|
|
&dwBufSize,
|
|
NULL);
|
|
|
|
if (!bRet && GetLastError () == ERROR_INSUFFICIENT_BUFFER) {
|
|
if (!(pszHeader = (LPTSTR) LocalAlloc( LPTR, dwBufSize)))
|
|
goto Cleanup;
|
|
|
|
*ppErrMsg = pszHeader;
|
|
|
|
if (! HttpQueryInfo(hUrlWebpnp,
|
|
HTTP_QUERY_STATUS_TEXT,
|
|
pszHeader,
|
|
&dwBufSize,
|
|
NULL))
|
|
goto Cleanup;
|
|
|
|
dwRet = RET_SERVER_ERROR;
|
|
goto Cleanup;
|
|
}
|
|
else
|
|
goto Cleanup;
|
|
|
|
break;
|
|
case HTTP_STATUS_DENIED :
|
|
case HTTP_STATUS_PROXY_AUTH_REQ :
|
|
dwError = InternetErrorDlg(GetDesktopWindow(), hUrlWebpnp,
|
|
hUrlWebpnp? ERROR_SUCCESS : GetLastError(),
|
|
FLAGS_ERROR_UI_FILTER_FOR_ERRORS |
|
|
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS |
|
|
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA,
|
|
NULL);
|
|
|
|
switch (dwError) {
|
|
case ERROR_INTERNET_FORCE_RETRY:
|
|
if (i >= MAX_INET_RETRY) {
|
|
goto Cleanup;
|
|
}
|
|
break;
|
|
case ERROR_SUCCESS:
|
|
bRetry = FALSE;
|
|
break;
|
|
case ERROR_CANCELLED:
|
|
default:
|
|
goto Cleanup;
|
|
}
|
|
break;
|
|
default:
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
if (!UpdateProgress (pData, 35))
|
|
goto Cleanup;
|
|
|
|
if ( INVALID_HANDLE_VALUE ==
|
|
(hFile = GetTempFile(TEXT (".webpnp"), &(pData->m_pszTempWebpnpFile))))
|
|
goto Cleanup;
|
|
|
|
dwSize = FILEBUFSIZE;
|
|
while (dwSize == FILEBUFSIZE) {
|
|
if (! InternetReadFile (hUrlWebpnp, (LPVOID)buf, FILEBUFSIZE, &dwSize)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (! (pData->m_hwnd)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (! WriteFile (hFile, buf, dwSize, &dwWritten, NULL)) {
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
CloseHandle (hFile);
|
|
hFile = INVALID_HANDLE_VALUE;
|
|
|
|
dwRet = RET_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
dwLastError = GetLastError ();
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle (hFile);
|
|
if (hUrlWebpnp)
|
|
InternetCloseHandle (hUrlWebpnp);
|
|
if (hHandle)
|
|
InternetCloseHandle (hHandle);
|
|
|
|
SetLastError (dwLastError);
|
|
|
|
if (dwRet == RET_OTHER_ERROR && GetLastError () == ERROR_SUCCESS) {
|
|
SetLastError (ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
HANDLE
|
|
COleInstall::GetTempFile(
|
|
LPTSTR pExtension,
|
|
LPTSTR * ppFileName)
|
|
{
|
|
HANDLE hServer = NULL;
|
|
PRINTER_DEFAULTS prDefaults = {0}; // Used to test access rights to the printer
|
|
DWORD dwType = 0; // This is the type of the string
|
|
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
LPTSTR pszTempDir = NULL;
|
|
LPTSTR pszTempFname = NULL;
|
|
GUID guid = GUID_NULL;
|
|
LPOLESTR pszGUID = NULL;
|
|
|
|
DWORD dwAllocated = 0; // This is the total number of characters allocated (not byte-size).
|
|
DWORD dwTempLen = 0; // This is the new size of the string
|
|
DWORD dwTempSize = 0; // This is the Size of the return String
|
|
|
|
// First we want to open the local print server and ensure that we have access to it
|
|
prDefaults.pDatatype = NULL;
|
|
prDefaults.pDevMode = NULL;
|
|
prDefaults.DesiredAccess = SERVER_ACCESS_ADMINISTER;
|
|
|
|
*ppFileName = NULL;
|
|
|
|
// Open the local spooler to get a handle to it
|
|
if (!OpenPrinter( NULL, &hServer, &prDefaults)) {
|
|
hServer = NULL; // Open Printer returns NULL and not INVALID_HANDLE_VALUE for a failure
|
|
goto Cleanup; // OpenPrinter will SetLastError to the reason why we couldn't open
|
|
}
|
|
|
|
// Get the size of the buffer we will need to copy the printer data
|
|
if (ERROR_MORE_DATA !=
|
|
GetPrinterData( hServer, SPLREG_DEFAULT_SPOOL_DIRECTORY, &dwType, NULL, 0, &dwTempSize)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
// If it's something other than a simple string, set the error to a database error
|
|
if (dwType != REG_SZ) {
|
|
SetLastError(ERROR_BADDB);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Allocate memory for the directory string.
|
|
if (! (pszTempDir = (LPTSTR) LocalAlloc( LPTR, dwTempSize )))
|
|
goto Cleanup;
|
|
|
|
if (ERROR_SUCCESS !=
|
|
GetPrinterData( hServer, SPLREG_DEFAULT_SPOOL_DIRECTORY, &dwType, (LPBYTE)pszTempDir,
|
|
dwTempSize, &dwTempLen))
|
|
goto Cleanup; // For some reason we could not get the data
|
|
|
|
ClosePrinter(hServer);
|
|
hServer = NULL;
|
|
|
|
if ( FAILED( ::CoCreateGuid( &guid )))
|
|
goto Cleanup;
|
|
|
|
if ( FAILED( ::StringFromCLSID( guid, &pszGUID )))
|
|
goto Cleanup;
|
|
|
|
dwAllocated = lstrlen( pszTempDir ) + 1 + lstrlen( pszGUID ) + lstrlen ( pExtension ) + 1;
|
|
|
|
if (! (pszTempFname = (LPTSTR) LocalAlloc( LPTR, sizeof (TCHAR) * dwAllocated )) )
|
|
goto Cleanup;
|
|
|
|
if ( FAILED ( StringCchPrintf( pszTempFname,
|
|
dwAllocated,
|
|
TEXT("%s\\%s%s"),
|
|
pszTempDir,
|
|
pszGUID,
|
|
pExtension )))
|
|
goto Cleanup;
|
|
|
|
hFile = CreateFile( pszTempFname,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
if ( !hFile || hFile == INVALID_HANDLE_VALUE)
|
|
goto Cleanup;
|
|
|
|
LocalFree (pszTempDir);
|
|
::CoTaskMemFree(pszGUID);
|
|
|
|
*ppFileName = pszTempFname;
|
|
return hFile;
|
|
|
|
Cleanup:
|
|
if (pszTempDir)
|
|
LocalFree (pszTempDir);
|
|
|
|
if (pszTempFname)
|
|
LocalFree (pszTempFname);
|
|
|
|
if (pszGUID)
|
|
::CoTaskMemFree(pszGUID);
|
|
|
|
if (hServer)
|
|
ClosePrinter(hServer);
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
COleInstall::IsHttpPreferred(void)
|
|
{
|
|
DWORD dwVal;
|
|
DWORD dwType = REG_DWORD;
|
|
DWORD dwSize = sizeof (DWORD);
|
|
HKEY hHandle = NULL;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
if (ERROR_SUCCESS != RegOpenKey (HKEY_CURRENT_USER,
|
|
TEXT ("Printers\\Settings"),
|
|
&hHandle))
|
|
goto Cleanup;
|
|
|
|
if (ERROR_SUCCESS == RegQueryValueEx (hHandle,
|
|
TEXT ("PreferredConnection"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwVal,
|
|
&dwSize)) {
|
|
bRet = (dwVal == 0) ? TRUE : FALSE;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if (hHandle) {
|
|
RegCloseKey (hHandle);
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
BOOL
|
|
COleInstall::GetHttpPrinterFile(
|
|
OleInstallData *pData,
|
|
LPTSTR pbstrURL)
|
|
{
|
|
LPTSTR pszErrMsg = NULL;
|
|
BOOL bRet = FALSE;
|
|
DWORD dwError;
|
|
|
|
if (!pbstrURL) {
|
|
return FALSE;
|
|
}
|
|
|
|
switch (GetWebpnpFile(pData, pbstrURL, &pszErrMsg)) {
|
|
case RET_SUCCESS:
|
|
bRet = TRUE;
|
|
break;
|
|
|
|
case RET_SERVER_ERROR:
|
|
dwError = _ttol (pszErrMsg);
|
|
if (dwError == 0) {
|
|
// This is a server internal error
|
|
dwError = ERROR_INTERNAL_SERVER;
|
|
}
|
|
|
|
SetLastError (dwError);
|
|
|
|
break;
|
|
|
|
case RET_OTHER_ERROR:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (pszErrMsg) {
|
|
LocalFree (pszErrMsg);
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
BOOL
|
|
COleInstall::InstallHttpPrinter(
|
|
OleInstallData *pData)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
if (SyncExecute(pData->m_pszTempWebpnpFile, SW_SHOWNORMAL))
|
|
bRet = TRUE;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL
|
|
COleInstall::CheckAndSetDefaultPrinter()
|
|
{
|
|
DWORD dwSize = 0;
|
|
BOOL bRet = TRUE;
|
|
|
|
if (!GetDefaultPrinterW (NULL, &dwSize)) {
|
|
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
|
// No default printer is set
|
|
// We pass a NULL to SetDefaultPrinter to set the first printer in the device list to
|
|
// be the default one
|
|
bRet = SetDefaultPrinter (NULL);
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
HRESULT COleInstall::CanIOpenPrintersFolder(void) {
|
|
DWORD dwPolicy;
|
|
HRESULT hr = GetActionPolicy(URLACTION_JAVA_PERMISSIONS, dwPolicy );
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
hr = (dwPolicy == URLPOLICY_JAVA_MEDIUM ||
|
|
dwPolicy == URLPOLICY_JAVA_LOW ||
|
|
dwPolicy == URLPOLICY_ALLOW) ? S_OK : HRESULT_FROM_WIN32(ERROR_IE_SECURITY_DENIED);
|
|
}
|
|
|
|
if (FAILED(hr)) {
|
|
hr = GetActionPolicy(URLACTION_SHELL_INSTALL_DTITEMS, dwPolicy);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = dwPolicy == URLPOLICY_DISALLOW ? HRESULT_FROM_WIN32(ERROR_IE_SECURITY_DENIED) : S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
COleInstall::CanIInstallRPC(
|
|
IN LPTSTR lpszPrinterUNC
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Examine Secuiry Policies to determine whether we should install the printer or not
|
|
|
|
Arguments:
|
|
lpszPrinterUNC - The UNC of the printer that we want to install
|
|
|
|
Return Value:
|
|
S_OK - Install via RPC
|
|
S_FALSE - Install via Web Pnp
|
|
HRESULT_FROM_WIN32(ERROR_IE_SECURITY_DENIED) - IE security does not allow this action
|
|
Other HRESULT error code.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwPolicyJava;
|
|
DWORD dwPolicyDTI;
|
|
HRESULT hrRet = S_FALSE;
|
|
HRESULT hr = GetActionPolicy(URLACTION_JAVA_PERMISSIONS, dwPolicyJava);
|
|
|
|
_ASSERTE(lpszPrinterUNC);
|
|
|
|
//
|
|
// Before checking anything, we should check the HTTP install registry setting
|
|
// If it is don;t even check the other stuff.
|
|
//
|
|
if (IsHttpPreferred())
|
|
{
|
|
hr = S_FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// There is no JAVA Security Manager, or something went wrong,
|
|
// then we decide whether to use Web PnP instead or just fail.
|
|
hrRet = S_OK;
|
|
}
|
|
|
|
switch (dwPolicyJava)
|
|
{
|
|
case URLPOLICY_JAVA_LOW:
|
|
case URLPOLICY_JAVA_MEDIUM:
|
|
hr = S_OK;
|
|
break;
|
|
default: // We must do Web PnP
|
|
hr = GetActionPolicy(URLACTION_SHELL_INSTALL_DTITEMS, dwPolicyDTI );
|
|
|
|
if (FAILED(hr)) // Couldn't get the policy on installing Desk Top Items
|
|
goto Cleanup;
|
|
|
|
switch (dwPolicyDTI)
|
|
{
|
|
case URLPOLICY_ALLOW:
|
|
case URLPOLICY_QUERY:
|
|
hr = hrRet;
|
|
break;
|
|
case URLPOLICY_DISALLOW:
|
|
hr = HRESULT_FROM_WIN32(ERROR_IE_SECURITY_DENIED);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If it looks like we can install via RPC then check if the UNC is valid
|
|
//
|
|
if (S_OK == hr)
|
|
{
|
|
//
|
|
// Find ther Server name from the UNC
|
|
//
|
|
LPTSTR pszServer = NULL;
|
|
hr = GetServerNameFromUNC( lpszPrinterUNC, &pszServer );
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
hr = CheckServerForSpooler(pszServer);
|
|
}
|
|
|
|
if (pszServer)
|
|
LocalFree(pszServer);
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Name:
|
|
|
|
GetServerNameFromUNC
|
|
|
|
Description:
|
|
|
|
This returns the server name from the given UNC path
|
|
|
|
Arguments:
|
|
|
|
pszUNC - The UNC name,
|
|
ppszServerName - The server name.
|
|
|
|
Return Value:
|
|
|
|
An HRESULT.
|
|
|
|
--*/
|
|
HRESULT
|
|
COleInstall::GetServerNameFromUNC(
|
|
IN LPTSTR pszUNC,
|
|
OUT LPTSTR *ppszServerName
|
|
)
|
|
{
|
|
HRESULT hr = pszUNC && ppszServerName ? S_OK : S_FALSE;
|
|
PWSTR pszServer = NULL;
|
|
|
|
if (S_OK==hr)
|
|
{
|
|
hr = *pszUNC++ == L'\\' && *pszUNC++ == L'\\' ? S_OK : S_FALSE;
|
|
}
|
|
|
|
if (S_OK==hr)
|
|
{
|
|
hr = AssignString(pszServer, pszUNC) ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (S_OK==hr)
|
|
{
|
|
PWSTR pszSlash = wcschr(&pszServer[0], L'\\');
|
|
|
|
//
|
|
// If there was no second slash, then what we have is the server name.
|
|
//
|
|
if (pszSlash)
|
|
{
|
|
*pszSlash = L'\0';
|
|
}
|
|
|
|
*ppszServerName = pszServer;
|
|
pszServer = NULL;
|
|
}
|
|
|
|
LocalFree(pszServer);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
COleInstall::CheckServerForSpooler(
|
|
IN LPTSTR pszServerName
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
//
|
|
// Build a string with the Server Name and the name of the spooler
|
|
// named pipe
|
|
//
|
|
LPTSTR pszSpoolerPipe = NULL;
|
|
DWORD dwStrLen = lstrlen(pszServerName) + lstrlen(g_fmtSpoolSSPipe) + 1;
|
|
pszSpoolerPipe = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * dwStrLen);
|
|
hr = pszSpoolerPipe ? S_OK : E_OUTOFMEMORY;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = StringCchPrintf(pszSpoolerPipe, dwStrLen, g_fmtSpoolSSPipe, pszServerName);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Now try to connect to the pipe with Anonymous Access
|
|
//
|
|
HANDLE hSpoolerPipe = INVALID_HANDLE_VALUE;
|
|
hSpoolerPipe = CreateFile(pszSpoolerPipe, 0, 0, NULL, OPEN_EXISTING,
|
|
(FILE_ATTRIBUTE_NORMAL | SECURITY_ANONYMOUS), NULL);
|
|
if (hSpoolerPipe != INVALID_HANDLE_VALUE)
|
|
{
|
|
// Pipe Exists try RPC
|
|
hr = S_OK;
|
|
CloseHandle(hSpoolerPipe);
|
|
}
|
|
else
|
|
{
|
|
// Check to see if failure is ACCESS_DENIED
|
|
DWORD dwError = GetLastError();
|
|
if (ERROR_ACCESS_DENIED == dwError)
|
|
{
|
|
// The pipe exists, but we don't have permissions
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
|
|
if (pszSpoolerPipe)
|
|
LocalFree(pszSpoolerPipe);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
LPTSTR COleInstall::RemoveURLVars(IN LPTSTR lpszPrinter) {
|
|
_ASSERTE(lpszPrinter);
|
|
|
|
LPTSTR lpszStripped = NULL;
|
|
|
|
DWORD dwIndex = _tcscspn( lpszPrinter, TEXT("?") );
|
|
|
|
lpszStripped = (LPTSTR)LocalAlloc( LPTR, (dwIndex + 1) * sizeof(TCHAR) );
|
|
|
|
if (NULL == lpszStripped)
|
|
goto Cleanup;
|
|
|
|
_tcsncpy( lpszStripped, lpszPrinter, dwIndex );
|
|
|
|
lpszStripped[dwIndex] = NULL; // NULL terminate it.
|
|
|
|
Cleanup:
|
|
return lpszStripped;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
Function: GetNTPrint
|
|
|
|
Purpose: Returns a LPTSTR with the path to %windir%\inf\ntprint.inf
|
|
Caller must free the returned string.
|
|
|
|
*/
|
|
LPTSTR
|
|
COleInstall::GetNTPrint(void)
|
|
{
|
|
UINT uiSize = 0;
|
|
UINT uiAllocSize = 0;
|
|
PTCHAR pData = NULL;
|
|
LPTSTR lpszNTPrintInf = NULL;
|
|
LPCTSTR gcszNTPrint = _TEXT("\\inf\\ntprint.inf");
|
|
|
|
//
|
|
// Get %windir%
|
|
// If the return is 0 - the call failed.
|
|
//
|
|
if( !(uiSize = GetSystemWindowsDirectory( lpszNTPrintInf, 0 )))
|
|
goto Cleanup;
|
|
|
|
uiAllocSize += uiSize + _tcslen( gcszNTPrint ) + 1;
|
|
|
|
if( NULL == (lpszNTPrintInf = (LPTSTR)LocalAlloc( LPTR, uiAllocSize*sizeof(TCHAR) )))
|
|
goto Cleanup;
|
|
|
|
if ( GetSystemWindowsDirectory( lpszNTPrintInf, uiSize ) > uiSize )
|
|
{
|
|
LocalFree(lpszNTPrintInf);
|
|
lpszNTPrintInf = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Determine if we have a \ on the end remove it.
|
|
//
|
|
pData = &lpszNTPrintInf[ _tcslen(lpszNTPrintInf)-1 ];
|
|
if( *pData == _TEXT('\\') )
|
|
*pData = 0;
|
|
|
|
//
|
|
// Copy the inf\ntprint.inf string onto the end of the %windir%\ string.
|
|
//
|
|
StringCchCat( lpszNTPrintInf, uiAllocSize, gcszNTPrint );
|
|
|
|
Cleanup:
|
|
return lpszNTPrintInf;
|
|
}
|
|
|
|
//
|
|
// Creates the printer base name from the printerURL and printer name.
|
|
// Form is : "\\http://url\printer name"
|
|
//
|
|
LPTSTR
|
|
COleInstall::CreatePrinterBaseName(
|
|
LPCTSTR lpszPrinterURL,
|
|
LPCTSTR lpszPrinterName
|
|
)
|
|
{
|
|
LPTSTR lpszFullPrinterName = NULL;
|
|
PTCHAR pWhack = NULL,
|
|
pFriendlyName = NULL;
|
|
DWORD cchBufSize = 0;
|
|
|
|
//
|
|
// lpszPrinterName should be of the form "server\printer name"
|
|
// We need to get only the "printer name" part.
|
|
//
|
|
if( NULL != ( pFriendlyName = _tcsrchr( lpszPrinterName, _TEXT('\\') ))) {
|
|
//
|
|
// Move off the \
|
|
//
|
|
pFriendlyName++;
|
|
} else {
|
|
pFriendlyName = (PTCHAR)lpszPrinterName;
|
|
}
|
|
|
|
//
|
|
// Worst case size - the size of the two strings plus the "\\" plus "\" and
|
|
// a NULL terminator
|
|
//
|
|
cchBufSize = lstrlen(lpszPrinterURL) + lstrlen(pFriendlyName) + 4;
|
|
lpszFullPrinterName = (LPTSTR)LocalAlloc( LPTR, cchBufSize * sizeof(TCHAR) );
|
|
|
|
if( lpszFullPrinterName ){
|
|
StringCchCopy( lpszFullPrinterName, cchBufSize, _TEXT("\\\\") );
|
|
StringCchCat( lpszFullPrinterName, cchBufSize, lpszPrinterURL );
|
|
|
|
pWhack = _tcschr( lpszFullPrinterName, _TEXT('/') );
|
|
|
|
if( pWhack ) {
|
|
if( *(pWhack+1) == _TEXT('/') ) {
|
|
//
|
|
// We've got a //, find the next /
|
|
//
|
|
pWhack = _tcschr( pWhack+2, _TEXT('/') );
|
|
}
|
|
}
|
|
|
|
if( !pWhack ) {
|
|
pWhack = &lpszFullPrinterName[ lstrlen( lpszFullPrinterName ) ];
|
|
}
|
|
|
|
*pWhack++ = _TEXT('\\');
|
|
|
|
*pWhack = 0;
|
|
|
|
StringCchCat( lpszFullPrinterName, cchBufSize, pFriendlyName );
|
|
}
|
|
|
|
return lpszFullPrinterName;
|
|
}
|
|
|
|
|
|
/****************************************************************************************
|
|
** End of File (oleinst.cpp)
|
|
****************************************************************************************/
|