Function to Set Default Printer

Environment: Windows NT4 SP3; Developed with Visual C++ 6 SP3


SetPrinter is a simple DLL COM that enables you to programmatically set the default printer:


  • The problem that I faced is that if you
    attempt to specify the default printer from an application,
    that printer is not actually realized as the default printer by
    Windows immediately.


You can resolve this problem by doing the following:



  • First, install the driver printer on your machine;
  • If You work on Windows 2000, you must use ‘SetDefaultPrinter’ followed by the printer’s name.
  • If You work on Windows 98 or Windows NT 4 you must first call the OpenPrinter function
    in order to retrieve the printer handle. Then you need to call the
    GetPrinter function twice in order to obtain the printer informations.
    You then need to call the WriteProfileString function (Windows NT)
  • Finally, you must notify all windows of this new Windows setting as follows:


    lResult = SendMessageTimeout(HWND_BROADCAST,
    WM_SETTINGCHANGE,
    0L, 0L,
    SMTO_NORMAL,
    1000,
    NULL);


Or instead of going through all of that, you can use my COM component and its DPSetDefaultPrinter method.
Here is the code for that method so that you can see all that needs to take place to perform a seemingly very
simple task.


STDMETHODIMP CCustomPrinter::DPSetDefaultPrinter(BSTR pPrinterName, int *Result)
{
USES_CONVERSION;

BOOL bFlag;
OSVERSIONINFO osv;
DWORD dwNeeded = 0;
HANDLE hPrinter = NULL;
PRINTER_INFO_2 *ppi2 = NULL;
LPTSTR pBuffer = NULL;
LONG lResult;

// What version of Windows are you running?
osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osv);

if (!pPrinterName)
*Result = 0;
return S_FALSE;
// If Windows 95 or 98, use SetPrinter…
if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
// Open this printer so you can get information about it…
bFlag = OpenPrinter((char*)OLE2CA(pPrinterName), &hPrinter, NULL);
if (!bFlag || !hPrinter)
*Result = 0;
return S_FALSE;
// The first GetPrinter() tells you how big our buffer should
// be in order to hold ALL of PRINTER_INFO_2. Note that this will
// usually return FALSE. This only means that the buffer (the 3rd
// parameter) was not filled in. You don’t want it filled in here…
GetPrinter(hPrinter, 2, 0, 0, &dwNeeded);
if (dwNeeded == 0)
{
ClosePrinter(hPrinter);
*Result = 0;
return S_FALSE;
}

// Allocate enough space for PRINTER_INFO_2…
ppi2 = (PRINTER_INFO_2 *)GlobalAlloc(GPTR, dwNeeded);
if (!ppi2)
{
ClosePrinter(hPrinter);
*Result = 0;
return S_FALSE;
}

// The second GetPrinter() will fill in all the current information
// so that all you need to do is modify what you’re interested in…
bFlag = GetPrinter(hPrinter, 2, (LPBYTE)ppi2, dwNeeded, &dwNeeded);
if (!bFlag)
{
ClosePrinter(hPrinter);
GlobalFree(ppi2);
*Result = 0;
return S_FALSE;
}

// Set default printer attribute for this printer…
ppi2->Attributes |= PRINTER_ATTRIBUTE_DEFAULT;
bFlag = SetPrinter(hPrinter, 2, (LPBYTE)ppi2, 0);
if (!bFlag)
{
ClosePrinter(hPrinter);
GlobalFree(ppi2);
*Result = 0;
return S_FALSE;
}

// Tell all open applications that this change occurred.
// Allow each application 1 second to handle this message.
lResult = SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0L,
(LPARAM)(LPCTSTR)”windows”, SMTO_NORMAL, 1000, NULL);
}

// If Windows NT, use the SetDefaultPrinter API for Windows 2000,
// or WriteProfileString for version 4.0 and earlier…
else if (osv.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
#if(WINVER >= 0x0500)
if (osv.dwMajorVersion >= 5) // Windows 2000 or later…
{
bFlag = SetDefaultPrinter(pPrinterName);
if (!bFlag)
*Result = 0;
return S_FALSE;
}

else // NT4.0 or earlier…
#endif
{
// Open this printer so you can get information about it…
bFlag = OpenPrinter((char*)OLE2CA(pPrinterName), &hPrinter, NULL);
if (!bFlag || !hPrinter)
*Result = 0;
return S_FALSE;

// The first GetPrinter() tells you how big our buffer should
// be in order to hold ALL of PRINTER_INFO_2. Note that this will
// usually return FALSE. This only means that the buffer (the 3rd
// parameter) was not filled in. You don’t want it filled in here…
GetPrinter(hPrinter, 2, 0, 0, &dwNeeded);
if (dwNeeded == 0)
{
ClosePrinter(hPrinter);
*Result = 0;
return S_FALSE;
}

// Allocate enough space for PRINTER_INFO_2…
ppi2 = (PRINTER_INFO_2 *)GlobalAlloc(GPTR, dwNeeded);
if (!ppi2)
{
ClosePrinter(hPrinter);
*Result = 0;
return S_FALSE;
}

// The second GetPrinter() fills in all the current

// information…
bFlag = GetPrinter(hPrinter, 2, (LPBYTE)ppi2, dwNeeded, &dwNeeded);
if ((!bFlag) || (!ppi2->pDriverName) || (!ppi2->pPortName))
{
ClosePrinter(hPrinter);
GlobalFree(ppi2);
*Result = 0;
return S_FALSE;
}

// Allocate buffer big enough for concatenated string.
// String will be in form “printername,drivername,portname”…
pBuffer = (LPTSTR)GlobalAlloc(GPTR,
lstrlen((char*)OLE2CA(pPrinterName)) +
lstrlen(ppi2->pDriverName) +
lstrlen(ppi2->pPortName) + 3);
if (!pBuffer)
{
ClosePrinter(hPrinter);
GlobalFree(ppi2);
*Result = 0;
return S_FALSE;
}

// Build string in form “printername,drivername,portname”…
lstrcpy(pBuffer, (char*)OLE2CA(pPrinterName)); lstrcat(pBuffer, “,”);
lstrcat(pBuffer, ppi2->pDriverName); lstrcat(pBuffer, “,”);
lstrcat(pBuffer, ppi2->pPortName);

// Set the default printer in Win.ini and registry…
bFlag = WriteProfileString(“windows”, “device”, pBuffer);
if (!bFlag)
{
ClosePrinter(hPrinter);
GlobalFree(ppi2);
GlobalFree(pBuffer);
*Result = 0;
return S_FALSE;
}
}

// Tell all open applications that this change occurred.
// Allow each app 1 second to handle this message.
lResult = SendMessageTimeout(HWND_BROADCAST,
WM_SETTINGCHANGE,
0L, 0L,
SMTO_NORMAL,
1000,
NULL);
}

// Cleanup…
if (hPrinter)
ClosePrinter(hPrinter);
if (ppi2)
GlobalFree(ppi2);
if (pBuffer)
GlobalFree(pBuffer);

*Result = 1;
return S_OK;

}

Installation


  • On each machine where you want to use the SetPrinter component, you must register the DLL as follows:
    regsvr32 <path>SetPrinter.dll;


Downloads


Download SetPrinter project code – 40 Kb

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read