Listing A 	VB5, VB6
Take Control of a Printer. Some tasks require you to have administrative privileges, such as pausing, resuming, or purging a print queue. The best you can do in these cases is try, and report the success of failure of your efforts. A printer object wrapper might even offer a CanAdminister property that simply attempts an OpenPrinter call with PRINTER_ACCESS_ADMINISTER specified for DesiredAccess. Such a property would be useful in determining the enabled state of associated UI functions.


Private Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _
(ByVal pPrinterName As String, phPrn As Long, pDefault As Any) As Long
Private Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrn As Long) _
As Long
Private Declare Function SetPrinter Lib "winspool.drv" Alias "SetPrinterA" _
(ByVal hPrinter As Long, ByVal Level As Long, pPrinter As Any, _
ByVal Command As Long) As Long

' Printer control codes
Private Const PRINTER_CONTROL_PAUSE		  As Long = 1
Private Const PRINTER_CONTROL_RESUME		 As Long = 2
Private Const PRINTER_CONTROL_PURGE		  As Long = 3

Private Enum PrinterControlCodes
	pcPause = PRINTER_CONTROL_PAUSE
	pcResume = PRINTER_CONTROL_RESUME
	pcPurge = PRINTER_CONTROL_PURGE
End Enum

Private Function SendControl(ByVal ControlCode As PrinterControlCodes) As _
Boolean
	Dim hPrn As Long
	Dim pd As PRINTER_DEFAULTS
	
	' Get handle to printer.
	pd.pDesiredAccess = PRINTER_ACCESS_ADMINISTER
	Call OpenPrinter(m_DevName, hPrn, pd)
	If hPrn Then
		' Attempt to send control code
		SendControl = CBool(SetPrinter(hPrn, 0, ByVal 0&, ControlCode))
		Call ClosePrinter(hPrn)
		Call Me.Refresh
	End If
End Function




Listing B	VB5, VB6
Set the Default System Printer. This can be an interesting exercise, for those who thrive on minutiae. Three different approaches are required, based on what operating system your find yourself running in. The NT4 approach beckons[hearkens?? back to the days of WIN.INI by grabbing a piece of the registry, mapped to that former bedrock of a system file, for this purpose.


Private Sub DefaultPrinterSet9x()
	Dim hPrn As Long
	Dim BytesNeeded As Long
	Dim Buffer() As Byte
	Dim BytesUsed As Long
	Dim Attributes As Long
	
	' Get handle to printer.
	Call OpenPrinter(m_DevName, hPrn, ByVal 0&)
	If hPrn Then
		' Call once to get proper buffer size.
		Call GetPrinter(hPrn, 2, ByVal 0&, 0, BytesNeeded)
		If Err.LastDllError = ERROR_INSUFFICIENT_BUFFER Then
			' Size buffer and get printer data.
			ReDim Buffer(0 To BytesNeeded - 1) As Byte
			If GetPrinter(hPrn, 2, Buffer(0), BytesNeeded, BytesUsed) Then
				' Set default printer attribute for this printer...
				' Attributes is the 14th element in structure
				Const AttribOffset As Long = 13 * 4&
				Call CopyMemory(Attributes, Buffer(AttribOffset), 4&)
				Attributes = Attributes Or PRINTER_ATTRIBUTE_DEFAULT
				Call CopyMemory(Buffer(AttribOffset), Attributes, 4&)
				' Send back updated structure.
				If SetPrinter(hPrn, 2, Buffer(0), 0) Then
					' Alert all other running applications,
					' giving each 1/2 second to react.
					Call SettingChangeAlert(500)
				End If
			End If
		End If
		Call ClosePrinter(hPrn)
	End If
End Sub

Private Sub DefaultPrinterSetNT(ByVal MajorVersion As Long)
	Dim os As OSVERSIONINFO
	Dim BufSize As Long
	Dim pPrinterName As Long
	Dim Result As String
	Dim comma As Long

	' Use either SetDefaultPrinter (2k+) or WIN.INI (NT4).
	If MajorVersion >= 5 Then
		' Almost so easy as to be boring. <g>
		Call SetDefaultPrinter(m_DevName)

	Else ' (NT4 or less)
		' Create satisfactory buffer.
		BufSize = 1024
		Result = Space$(BufSize)
		' In NT, the old WIN.INI [PrinterPorts] section is mapped to
		' HKCU\Software\Microsoft\Windows NT\CurrentVersion\PrinterPorts
		' and we can just use GetProfileString to extract! :-)
		' Returns: "driver name,port,timeout1,timeout2"
		If GetProfileString("PrinterPorts", ByVal m_DevName, "", Result, _
BufSize) Then
			' Find 2nd comma and truncate
			comma = InStr(Result, ",")
			comma = InStr(comma + 1, Result, ",")
			If comma Then
				Result = Left$(Result, comma - 1)
				' Prepend devname and write to registry.
				Result = m_DevName & "," & Result
				Call WriteProfileString("Windows", "device", Result)
				' Alert all other running applications,
				' giving each 1/2 second to react.
				Call SettingChangeAlert(500)
			End If
		End If
	End If
End Sub

Private Sub SettingChangeAlert(Optional ByVal Delay As Long = 500)
	' Send out alert to notify all other running applications
	' that a system setting has been updated.
	Call SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, _
		0, 0, SMTO_NORMAL, Delay, ByVal 0&)
End Sub




Listing C 	VB5, VB6
Retrieving the Default System Printer's Name. You will need to take one of three different approaches to this problem, based on which operating system your application is running under. Interesting and contrary to this KB article, to date all Win32 operating systems respond correctly to the NT4 method of calling GetProfileString.
Option Explicit

' Win32 API declares
Private Declare Function EnumPrinters Lib "winspool.drv" Alias _
"EnumPrintersA" (ByVal Flags As Long, ByVal name As String, ByVal Level As _
Long, pPrinterEnum As Any, ByVal cdBuf As Long, pcbNeeded As Long, _
pcReturned As Long) As Long
Private Declare Function GetDefaultPrinter Lib "winspool.drv" Alias _
"GetDefaultPrinterA" (ByVal pszBuffer As String, pcchBuffer As Long) As Long
Private Declare Function GetProfileString Lib "kernel32" Alias _
"GetProfileStringA" (ByVal lpAppName As String, ByVal lpKeyName As Any, ByVal _
lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long) _
As _Long
Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" _
(lpVersionInformation As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function lstrlenA Lib "kernel32" (ByVal lpString As Long) As _
Long

' Some calls need to know OS
Private Type OSVERSIONINFO
	dwOSVersionInfoSize As Long
	dwMajorVersion As Long
	dwMinorVersion As Long
	dwBuildNumber As Long
	dwPlatformId As Long
	szCSDVersion As String * 128
End Type

' Structure returned by EnumPrinters, level 5
'	typedef struct _PRINTER_INFO_5 { // pri5
'		 LPTSTR	 pPrinterName;
'		 LPTSTR	 pPortName;
'		 DWORD	  Attributes;
'		 DWORD	  DeviceNotSelectedTimeout;
'		 DWORD	  TransmissionRetryTimeout;
'	} PRINTER_INFO_5;

' Platform ID constants
Private Const VER_PLATFORM_WIN32s As Long = &H0
Private Const VER_PLATFORM_WIN32_WINDOWS As Long = &H1
Private Const VER_PLATFORM_WIN32_NT As Long = &H2

' Used to indicate what to enumerate
Private Const PRINTER_ENUM_DEFAULT As Long = &H1

Public Function DefaultPrinterName() As String
	' HOWTO: Retrieve and Set the Default Printer in Windows
	' http://support.microsoft.com/support/kb/articles/q246/7/72.asp
	Dim Buffer() As Byte
	Dim BufSize As Long
	Dim pPrinterName As Long
	Dim Returned As Long
	Dim Result As String
	Dim os As OSVERSIONINFO

	' Get OS version info, so we know which way to fork.
	os.dwOSVersionInfoSize = Len(os)
	Call GetVersionEx(os)

	If os.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS Then  '95/98/ME
		' Determine how big the buffer needs to be.
		Call EnumPrinters(PRINTER_ENUM_DEFAULT, vbNullString, 5, ByVal 0&, 0, _
BufSize, Returned)
		If BufSize > 0 Then
			' Size buffer accordingly, and call again.
			ReDim Buffer(0 To BufSize - 1) As Byte
			If EnumPrinters(PRINTER_ENUM_DEFAULT, vbNullString, 5, Buffer(0), _
BufSize, BufSize, Returned) Then
				' A pointer to the default printer name is
				' returned at the beginning of the buffer.
				Call CopyMemory(pPrinterName, Buffer(0), 4)
				Result = PointerToStringA(pPrinterName)
			End If
		End If

	ElseIf os.dwPlatformId = VER_PLATFORM_WIN32_NT Then
		' Create satisfactory buffer.
		BufSize = 1024
		Result = Space$(BufSize)

		' Use either GetDefaultPrinter (2k+) or WIN.INI (NT4).
		If os.dwMajorVersion >= 5 Then
			If GetDefaultPrinter(Result, BufSize) Then
				' Truncate at first NULL
				Result = Left$(Result, InStr(Result, vbNullChar) - 1)
			End If
		Else 'NT4 or less
			' Look for default printer in WIN.INI
			' Returns: "printer name,driver name,port"
			If GetProfileString("Windows", ByVal "device", "", Result, BufSize) _
Then
				' Truncate buffer at end of name.
				Result = Left$(Result, InStr(Result, ",") - 1)
			End If
		End If
	End If

	' Return default printer name.
	DefaultPrinterName = Result
End Function

Private Function PointerToStringA(ByVal lpStringA As Long) As String
	Dim Buffer() As Byte
	Dim nLen As Long
	
	If lpStringA Then
		nLen = lstrlenA(ByVal lpStringA)
		If nLen Then
			ReDim Buffer(0 To (nLen - 1)) As Byte
			CopyMemory Buffer(0), ByVal lpStringA, nLen
			PointerToStringA = StrConv(Buffer, vbUnicode)
		End If
	End If
End Function


