#include “BLICECTR.H”
BOOL PASCAL WaitForPrnPipeWithPriority(LPWSTR pszPipeName, HWND hMsgWnd, DWORD dwMessageNum, int nPri);
Description
Starts the Pipe Message Capture thread with desired thread priority. The thread receives messages from the Printer Driver through a named pipe, translates them to regular Window messages and sends them to the Window specified by hMsgWnd. This way the application can easily handle the pipe messages sent by the Printer Driver without directly dealing with the named pipe.
The WaitForPrnPipe function is non-blocking, it returns immediately after the Message Capture thread is created. To stop the Message Capture thread, the application should call EndWaitPrnPipe. The priority of the Message Capture thread can NOT be set using the deprecated SetListeningPriority function.
Parameters
LPWSTR pszPipeName - pointer to a NULL terminated UNICODE string that contains the pipe name, including the \\.\pipe\ prefix. To see how to construct the pipe name, refer to the Code Example section below.
HWND hMsgWnd - A Window handle. The BLICECTR.DLL will send window messages to this window. The message loop of the specified window should accept and handle the type of window messages that are specified in dwMessageNum.
DWORD dwMessageNum - Message number. The message number of the window message to send, if a pipe message arrives. Can be any unused number above WM_USER, e.g: WM_USER + 1000.
int nPri - sets the priority of the thread which waits for pipe messages. Valid values are the following:
THREAD_PRIORITY_LOWEST
THREAD_PRIORITY_BELOW_NORMAL
THREAD_PRIORITY_NORMAL
THREAD_PRIORITY_HIGHEST
THREAD_PRIORITY_ABOVE_NORMAL
THREAD_PRIORITY_ERROR_RETURN
THREAD_PRIORITY_TIME_CRITICAL
THREAD_PRIORITY_IDLE
Return value
TRUE if the message capture thread was started successfully, FALSE otherwise.
Programming Notes
The window that receives the messages must be created in the same process where the WaitForPrnPipeWithPriority function is called.
Code Example
C++ Example
GetSessionID(lpDevMode, &dwSessionID);
swprintf(szPipeName, L"\\\\.\\pipe\\%s%d", GetInterfaceName(lpDevMode),dwSessionID);
WaitForPrnPipeWithPriority(szPipeName, hWnd, WM_USER + 1000, THREAD_PRIORITY_TIME_CRITICAL);
C# example
//Black Ice Message Capture functions from blicectr.dll
//Messages reserved for use by the system.
public const int WM_USER = 0x0400;
//Base priority of 15 for NORMAL_PRIORITY_CLASS processes.
public const int THREAD_PRIORITY_TIME_CRITICAL = 15;
[DllImport("blicectr.dll", EntryPoint = "WaitForPrnPipeWithPriority", CharSet = CharSet.Unicode)]
private static extern int WaitForPrnPipeWithPriority(string pszPipeName, IntPtr hMsgWnd, int dwMessageNum, int nPri);
[DllImport("blicectr.dll", EntryPoint = "EndWaitPrnPipe", CharSet = CharSet.Unicode)]
private static extern int EndWaitPrnPipe(string pszPipeName);
//Locks a global memory object and returns a pointer to the first byte of the object's memory block.
[DllImport("kernel32.dll")]
static extern IntPtr GlobalLock(IntPtr hMem);
//Decrements the lock count associated with a memory object that was allocated with GMEM_MOVEABLE. This function has no effect on memory objects allocated with GMEM_FIXED.
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GlobalUnlock(IntPtr hMem);
//Frees the specified global memory object and invalidates its handle.
[DllImport("kernel32.dll")]
static extern IntPtr GlobalFree(IntPtr hMem);
//Retrieves the current size of the specified global memory object, in bytes.
[DllImport("kernel32.dll")]
static extern UIntPtr GlobalSize(IntPtr hMem);
//Printer Driver Messaging Interface structure for Printer Drivers 14.97 and earlier
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct TSPrnMessageV1
{
public uint dwMessage;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDocName;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szFileName;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szPrinterName;
public int nPageNumber;
[MarshalAsAttribute(UnmanagedType.Bool)]
public bool fAppendPage;
[MarshalAsAttribute(UnmanagedType.Bool)]
public bool fPortrait;
public uint dwOCRDataType;
};
//Printer Driver Messaging Interface structure for Printer Drivers version 14.98 and newer
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct TSPrnMessage
{
public TSPrnMessage(TSPrnMessageV1 v1)
{
dwMessage = v1.dwMessage;
szDocName = v1.szDocName;
szFileName = v1.szFileName;
szPrinterName = v1.szPrinterName;
nPageNumber = v1.nPageNumber;
fAppendPage = v1.fAppendPage;
fPortrait = v1.fPortrait;
dwJobID = 0;
if (dwMessage == BLACKICE_MESSAGE_STARTDOC || dwMessage == BLACKICE_MESSAGE_ENDDOC)
{
szOutputFileName = "";
szGroupFileName = v1.szFileName;
}
else if (dwMessage == BLACKICE_MESSAGE_STARTPAGE || dwMessage == BLACKICE_MESSAGE_ENDPAGE)
{
szOutputFileName = v1.szFileName;
szGroupFileName = "";
}
else
{
szOutputFileName = "";
szGroupFileName = "";
}
dwOCRDataType = v1.dwOCRDataType;
}
public uint dwMessage;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDocName;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szFileName;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szPrinterName;
public int nPageNumber;
[MarshalAsAttribute(UnmanagedType.Bool)]
public bool fAppendPage;
[MarshalAsAttribute(UnmanagedType.Bool)]
public bool fPortrait;
public uint dwJobID;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szOutputFileName;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szGroupFileName;
public uint dwOCRDataType;
};
// Printer Message identifiers
public const int BLACKICE_MESSAGE_STARTDOC = 0x00000001;
public const int BLACKICE_MESSAGE_STARTPAGE = 0x00000002;
public const int BLACKICE_MESSAGE_ENDPAGE = 0x00000003;
public const int BLACKICE_MESSAGE_ENDDOC = 0x00000004;
public const int BLACKICE_MESSAGE_ABORT = 0x00000005;
public const int BLACKICE_MESSAGE_ERROR = 0x00000006;
public const int BLACKICE_MESSAGE_DEVMODE = 0x00000007;
public const int BLACKICE_MESSAGE_MEMIMAGE = 0x00000008;
public const int BLACKICE_MESSAGE_OCR = 0x00000009;
public const int BLACKICE_MESSAGE_TEXT = 0x0000000A;
public const int BI_OCR_MEM_FORMAT_TEXT = 0x00000001;
public const int BI_OCR_MEM_FORMAT_HOCR_HEADER = 0x00000002;
public const int BI_OCR_MEM_FORMAT_HOCR_PAGE = 0x00000003;
public const int BI_OCR_MEM_FORMAT_HOCR_FOOTER = 0x00000004;
BiHelper class with GetPrinterSessionID and GetPrinterInterfaceName functions for WaitForPrnPipeWithPriority function
using System.Runtime.InteropServices;
class BiHelper
{
//Black Ice Devmode functions from BlackIceDEVMODE.dll
[DllImport("BlackIceDEVMODE.dll", EntryPoint = "LoadBlackIceDEVMODE", CharSet = CharSet.Unicode)]
private static extern IntPtr LoadBlackIceDEVMODE(string szPrinter);
[DllImport("BlackIceDEVMODE.dll", EntryPoint = "ReleaseBlackIceDEVMODE", CharSet = CharSet.Unicode)]
private static extern bool ReleaseBlackIceDEVMODE(IntPtr lDevmode);
[DllImport("BlackIceDEVMODE.dll", EntryPoint = "GetSessionID", CharSet = CharSet.Unicode)]
private static extern int GetSessionID(IntPtr lDevmode, ref int iSessionID);
[DllImport("BlackIceDEVMODE.dll", EntryPoint = "GetInterfaceName", CharSet = CharSet.Unicode)]
private static extern IntPtr GetInterfaceName(IntPtr lDevmode);
//Get session ID from Printer name
public int GetPrinterSessionID(string szPrinterName)
{
int iRet = 0;
// Load the devmode
IntPtr lDevmode = LoadBlackIceDEVMODE(szPrinterName);
if ((Int32)lDevmode > 0)
{
// Get interface ID of the printer driver
GetSessionID(lDevmode, ref iRet);
// Release the DEVMODE
ReleaseBlackIceDEVMODE(lDevmode);
}
// Return printer Session ID
return iRet;
}
//Get interface name from Printer name
public string GetPrinterInterfaceName(string szPrinterName)
{
string sInterfaceName = string.Empty;
// Load the devmode
IntPtr lDevmode = LoadBlackIceDEVMODE(szPrinterName);
if ((Int32)lDevmode > 0)
{
// Get interface ID of the printer driver
IntPtr ipInterfaceName = GetInterfaceName(lDevmode);
sInterfaceName = Marshal.PtrToStringUni(ipInterfaceName);
// Release the DEVMODE
ReleaseBlackIceDEVMODE(lDevmode);
}
// Return printer Interface Name
return sInterfaceName;
}
}
Once imported, one can use the WaitForPrnPipeWithPriority function in the C# code as in the following example
//Printer driver name
string sPrinterName = "Printer Name";
//Create an object of type BiHelper
BiHelper helper = new BiHelper();
//Interface name of Printer driver
string sInterfaceName = helper.GetPrinterInterfaceName(sPrinterName);
//Session ID of Printer driver
int iSessionID = helper.GetPrinterSessionID(sPrinterName);
//Pipe name
szPipeName = @"\\.\pipe\" + sInterfaceName + iSessionID.ToString();
//Start listening for messages. The pipe messages will be forwarded to the WndProc function as WM_USER + 1000 messages
WaitForPrnPipeWithPriority(szPipeName, this.Handle, WM_USER + 1000, THREAD_PRIORITY_TIME_CRITICAL);
//WndProc method to handle operating system messages
protected override void WndProc(ref Message message)
{
if (message.Msg == WM_USER + 1000) // WM_USER + 1000 is the same value that is passed to the WaitForPrnPipeWithPriority function
{
//Read the Printer Driver Messaging Interface structure from the WParam parameter
IntPtr pParams = GlobalLock(message.WParam);
TSPrnMessage sParams;
// The larger message capture structure is available since Printer Driver Version 14.98.
// For compatibility with older drivers, check the size of the structure to see if we recieved the
// new structure or the old one.
bool bNewDriver = ((int)GlobalSize(message.WParam) >= Marshal.SizeOf(typeof(TSPrnMessage)));
if (bNewDriver)
{
// Driver Version is 14.98 or newer, use the new structure
sParams = (TSPrnMessage)Marshal.PtrToStructure(pParams, typeof(TSPrnMessage));
}
else
{
// Driver Version is 14.97 or earlier, copy what we can from the old structure
TSPrnMessageV1 sParamsV1;
sParamsV1 = (TSPrnMessageV1)Marshal.PtrToStructure(pParams, typeof(TSPrnMessageV1));
sParams = new TSPrnMessage(sParamsV1);
}
switch (sParams.dwMessage)
{
case BLACKICE_MESSAGE_STARTDOC:
DisplayAndLog("Start Doc");
DisplayAndLog(" Printer Name: " + sParams.szPrinterName);
DisplayAndLog(" Document Name: " + sParams.szDocName);
DisplayAndLog(" Group File Name: " + sParams.szGroupFileName);
if (bNewDriver)
{
DisplayAndLog(" Job ID: " + sParams.dwJobID);
}
break;
case BLACKICE_MESSAGE_STARTPAGE:
DisplayAndLog("Start Page");
DisplayAndLog(" Printer Name: " + sParams.szPrinterName);
DisplayAndLog(" Document Name: " + sParams.szDocName);
DisplayAndLog(" Page Number: " + sParams.nPageNumber.ToString());
if (bNewDriver)
{
DisplayAndLog(" Job ID: " + sParams.dwJobID);
DisplayAndLog(" Output File Name: " + sParams.szOutputFileName);
DisplayAndLog(" Group File Name: " + sParams.szGroupFileName);
}
else
{
DisplayAndLog(" Output File Name: " + sParams.szFileName);
}
break;
case BLACKICE_MESSAGE_ENDDOC:
DisplayAndLog("End Doc");
DisplayAndLog(" Printer Name: " + sParams.szPrinterName);
DisplayAndLog(" Document Name: " + sParams.szDocName);
if (bNewDriver)
{
DisplayAndLog(" Job ID: " + sParams.dwJobID);
DisplayAndLog(" Output File Name: " + sParams.szOutputFileName);
DisplayAndLog(" Group File Name: " + sParams.szGroupFileName);
}
else
{
DisplayAndLog(" Group File Name: " + sParams.szFileName);
}
break;
case BLACKICE_MESSAGE_ENDPAGE:
DisplayAndLog("End Page");
DisplayAndLog(" Printer Name: " + sParams.szPrinterName);
DisplayAndLog(" Document Name: " + sParams.szDocName);
DisplayAndLog(" Page Number: " + sParams.nPageNumber.ToString());
if (bNewDriver)
{
DisplayAndLog(" Job ID: " + sParams.dwJobID);
DisplayAndLog(" Output File Name: " + sParams.szOutputFileName);
DisplayAndLog(" Group File Name: " + sParams.szGroupFileName);
}
else
{
DisplayAndLog(" Output File Name: " + sParams.szFileName);
}
break;
case BLACKICE_MESSAGE_ABORT:
DisplayAndLog("Abort: Print job has been aborted");
if (bNewDriver)
{
DisplayAndLog(" Printer Name: " + sParams.szPrinterName);
DisplayAndLog(" Document Name: " + sParams.szDocName);
DisplayAndLog(" Job ID: " + sParams.dwJobID);
}
break;
case BLACKICE_MESSAGE_DEVMODE:
DisplayAndLog("ChangeDevmode");
if (bNewDriver)
{
DisplayAndLog(" Printer Name: " + sParams.szPrinterName);
DisplayAndLog(" Document Name: " + sParams.szDocName);
DisplayAndLog(" Job ID: " + sParams.dwJobID);
}
// ChangeDevmode message received, read the DEVMODE structure from the LParam parameter and configure it
IntPtr ipDevmode = message.LParam;
if ((int)ipDevmode > 0)
{
// modify the BlackIceDEVMODE structure as needed
// do not modify the standard DEVMDOE structure, (pDevMode->DM)
// only modify the extended part of the BlackIceDEVMODE structure.
// DO NOT MAKE TIME CONSUMING OPEARTIONS HERE
// The printer drive will wait a maximum of 2 seconds for an updated
// BlackIceDEVMODE structure.
}
break;
case BLACKICE_MESSAGE_ERROR:
DisplayAndLog("Error message was received.");
DisplayAndLog(" Error Code: " + message.LParam.ToString());
break;
case BLACKICE_MESSAGE_MEMIMAGE:
ipDevmode = message.LParam;
if ((int)ipDevmode > 0 && (int)pParams > 0)
{
//Printer driver name
string sPrinterName = CurrentPrinter.Text;
//Create an object of type BiHelper
BiHelper helper = new BiHelper();
//File extension of Printer driver
string sFileExt = helper.GetFileExtension(sPrinterName);
string saveFileName = string.Empty;
saveFileName = GetCustomTempFile("BLI", sFileExt);
//Get pointer to the image data
IntPtr pImage = GlobalLock(message.LParam);
//Get the size of the image data
int dwSize = (int)GlobalSize(message.LParam);
//Copy the image data from the unmanaged memory to a byte array
byte[] buffer = new byte[dwSize];
Marshal.Copy(pImage, buffer, 0, dwSize);
//Write image data to a file
File.WriteAllBytes(saveFileName, buffer);
if (bNewDriver)
{
DisplayAndLog("MemoryImageEx message was received.");
DisplayAndLog(" Printer Name: " + sParams.szPrinterName);
DisplayAndLog(" Document Name: " + sParams.szDocName);
DisplayAndLog(" Job ID: " + sParams.dwJobID);
DisplayAndLog(" The file has been saved to: " + saveFileName);
}
else
{
DisplayAndLog("Print to Memory message received and the file has been saved to: " + saveFileName);
}
//Free unmanaged memory
GlobalUnlock(message.LParam);
GlobalFree(message.LParam);
}
break;
case BLACKICE_MESSAGE_OCR:
ipDevmode = message.LParam;
if (ipDevmode.ToInt32() > 0)
{
if (bNewDriver)
{
//Printer driver name
string sPrinterName = CurrentPrinter.Text;
//Get pointer to the OCR data
IntPtr pOCR = GlobalLock(message.LParam);
string OCRData = Marshal.PtrToStringUni(pOCR);
DisplayAndLog("OCR message was received.");
DisplayAndLog(" Printer Name: " + sParams.szPrinterName);
DisplayAndLog(" Job ID: " + sParams.dwJobID.ToString());
DisplayAndLog(" Document Name: " + sParams.szDocName);
switch (sParams.dwOCRDataType)
{
case BI_OCR_MEM_FORMAT_TEXT:
try
{
DisplayAndLog(" The OCR Data Type is TEXT (1))");
DisplayAndLog(" The OCR Data is: " + OCRData);
string saveFileName = string.Empty;
saveFileName = GetCustomTempFile("BLI", "txt");
//Write OCR data to a file
File.WriteAllText(saveFileName, OCRData);
}
catch (Exception Ex)
{
DisplayAndLog(" " + Ex.ToString());
}
break;
case BI_OCR_MEM_FORMAT_HOCR_HEADER:
try
{
DisplayAndLog(" The OCR Data Type is hOCR header (2)");
DisplayAndLog(" The OCR Data is: " + OCRData);
sHOCRFileName = GetCustomTempFile("BLI", "html");
//Write OCR header to a file
File.WriteAllText(sHOCRFileName, OCRData);
DisplayAndLog(" The file has been saved to: " + sHOCRFileName);
}
catch (Exception Ex)
{
DisplayAndLog(" " + Ex.ToString());
}
break;
case BI_OCR_MEM_FORMAT_HOCR_PAGE:
try
{
DisplayAndLog(" The OCR Data Type is hOCR data (3)");
DisplayAndLog(" The OCR Data is: " + OCRData);
//Append OCR data to a file
File.AppendAllText(sHOCRFileName, OCRData);
DisplayAndLog(" The file has been saved to: " + sHOCRFileName);
}
catch (Exception Ex)
{
DisplayAndLog(" " + Ex.ToString());
}
break;
case BI_OCR_MEM_FORMAT_HOCR_FOOTER:
try
{
DisplayAndLog(" The OCR Data Type is hOCR footer (4)");
DisplayAndLog(" The OCR Data is: " + OCRData);
//Append OCR footer to a file
File.AppendAllText(sHOCRFileName, OCRData);
DisplayAndLog(" The file has been saved to: " + sHOCRFileName);
}
catch (Exception Ex)
{
DisplayAndLog(" " + Ex.ToString());
}
break;
}
}
}
break;
case BLACKICE_MESSAGE_TEXT:
ipDevmode = message.LParam;
if (ipDevmode.ToInt32() > 0)
{
if (bNewDriver)
{
//Get pointer to the TEXT data
IntPtr pTEXT = GlobalLock(message.LParam);
string TEXTData = Marshal.PtrToStringUni(pTEXT);
DisplayAndLog("TEXT message was received.");
DisplayAndLog(" Printer Name: " + sParams.szPrinterName);
DisplayAndLog(" Job ID: " + sParams.dwJobID.ToString());
DisplayAndLog(" Document Name: " + sParams.szDocName);
DisplayAndLog(" Page Number: " + sParams.nPageNumber.ToString());
try
{
//DisplayAndLog(" The TEXT Data is: " + TEXTData);
string saveFileName = string.Empty;
saveFileName = GetCustomTempFile("BLI", "txt");
//Write OCR data to a file
File.WriteAllText(saveFileName, TEXTData);
DisplayAndLog(" The file has been saved to: " + saveFileName);
}
catch (Exception Ex)
{
DisplayAndLog(" " + Ex.ToString());
}
}
}
break;
}
GlobalUnlock(message.WParam);
GlobalFree(message.WParam);
}
base.WndProc(ref message);
}
VB.NET example
Please see following example for IMPORTING the blicectr.dll functions in VB.NET code:
'Black Ice Message Capture functions from blicectr.dll
'Messages reserved for use by the system.
Public Const WM_USER As Integer = &H400
'Base priority of 15 for NORMAL_PRIORITY_CLASS processes.
Public Const THREAD_PRIORITY_TIME_CRITICAL As Integer = 15
Private Declare Unicode Function WaitForPrnPipeWithPriority Lib "blicectr.dll" (pszPipeName As String, hMsgWnd As IntPtr, dwMessageNum As Integer, nPri As Integer) As Integer
Private Declare Unicode Function EndWaitPrnPipe Lib "blicectr.dll" (pszPipeName As String) As Integer
'Locks a global memory object and returns a pointer to the first byte of the object's memory block.
Private Declare Unicode Function GlobalLock Lib "kernel32.dll" (hMem As IntPtr) As IntPtr
'Decrements the lock count associated with a memory object that was allocated with GMEM_MOVEABLE. This function has no effect on memory objects allocated with GMEM_FIXED.
Private Declare Unicode Function GlobalUnlock Lib "kernel32.dll" (hMem As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
'Frees the specified global memory object and invalidates its handle.
Private Declare Unicode Function GlobalFree Lib "kernel32.dll" (hMem As IntPtr) As IntPtr
'Retrieves the current size of the specified global memory object, in bytes.
Private Declare Unicode Function GlobalSize Lib "kernel32.dll" (hMem As IntPtr) As IntPtr
'Printer Driver Messaging Interface structure for Printer Drivers version 14.98 and newer
<StructLayoutAttribute(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
Structure TSPrnMessageV1
Public dwMessage As UInteger
<MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst:=260)> _
Public szDocName As String
<MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst:=260)> _
Public szFileName As String
<MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst:=260)> _
Public szPrinterName As String
Public nPageNumber As Integer
<MarshalAsAttribute(UnmanagedType.Bool)> _
Public fAppendPage As Boolean
<MarshalAsAttribute(UnmanagedType.Bool)> _
Public fPortrait As Boolean
End Structure
'Printer Driver Messaging Interface structure for Printer Drivers version 14.98 and newer
<StructLayoutAttribute(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
Structure TSPrnMessage
Public Sub New(v1 As TSPrnMessageV1)
dwMessage = v1.dwMessage
szDocName = v1.szDocName
szFileName = v1.szFileName
szPrinterName = v1.szPrinterName
nPageNumber = v1.nPageNumber
fAppendPage = v1.fAppendPage
fPortrait = v1.fPortrait
dwJobID = 0
If dwMessage = BLACKICE_MESSAGE_STARTDOC OrElse dwMessage = BLACKICE_MESSAGE_ENDDOC Then
szOutputFileName = ""
szGroupFileName = v1.szFileName
ElseIf dwMessage = BLACKICE_MESSAGE_STARTPAGE OrElse dwMessage = BLACKICE_MESSAGE_ENDPAGE Then
szOutputFileName = v1.szFileName
szGroupFileName = ""
Else
szOutputFileName = ""
szGroupFileName = ""
End If
dwOCRDataType = 0
End Sub
Public dwMessage As UInteger
<MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst:=260)> _
Public szDocName As String
<MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst:=260)> _
Public szFileName As String
<MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst:=260)> _
Public szPrinterName As String
Public nPageNumber As Integer
<MarshalAsAttribute(UnmanagedType.Bool)> _
Public fAppendPage As Boolean
<MarshalAsAttribute(UnmanagedType.Bool)> _
Public fPortrait As Boolean
Public dwJobID As UInteger
<MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst:=260)> _
Public szOutputFileName As String
<MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst:=260)> _
Public szGroupFileName As String
Public dwOCRDataType As UInteger
End Structure
'Printer Message identifiers
Public Const BLACKICE_MESSAGE_STARTDOC As Integer = &H1
Public Const BLACKICE_MESSAGE_STARTPAGE As Integer = &H2
Public Const BLACKICE_MESSAGE_ENDPAGE As Integer = &H3
Public Const BLACKICE_MESSAGE_ENDDOC As Integer = &H4
Public Const BLACKICE_MESSAGE_ABORT As Integer = &H5
Public Const BLACKICE_MESSAGE_ERROR As Integer = &H6
Public Const BLACKICE_MESSAGE_DEVMODE As Integer = &H7
Public Const BLACKICE_MESSAGE_MEMIMAGE As Integer = &H8
Public Const BLACKICE_MESSAGE_OCR As Integer = &H9
Public Const BLACKICE_MESSAGE_TEXT As Integer = &HA
Public Const BI_OCR_MEM_FORMAT_TEXT As Integer = &H1
Public Const BI_OCR_MEM_FORMAT_HOCR_HEADER As Integer = &H2
Public Const BI_OCR_MEM_FORMAT_HOCR_PAGE As Integer = &H3
Public Const BI_OCR_MEM_FORMAT_HOCR_FOOTER As Integer = &H4
BiHelper class with GetPrinterSessionID and GetPrinterInterfaceName functions for WaitForPrnPipeWithPriority function
Imports System.Runtime.InteropServices
Public Class BiHelper
'Black Ice Devmode functions from BlackIceDEVMODE.dll
Private Declare Unicode Function LoadBlackIceDEVMODE Lib "BlackIceDEVMODE.dll" (ByVal sPrinter As String) As IntPtr
Private Declare Unicode Function ReleaseBlackIceDEVMODE Lib "BlackIceDEVMODE.dll" (ByVal lDevmode As IntPtr) As Boolean
Private Declare Unicode Function GetSessionID Lib "BlackIceDEVMODE.dll" (lDevmode As IntPtr, ByRef iSessionID As Integer) As Integer
Private Declare Unicode Function GetInterfaceName Lib "BlackIceDEVMODE.dll" (lDevmode As IntPtr) As IntPtr
'Get session ID from Printer name
Public Function GetPrinterSessionID(szPrinterName As String) As Integer
Dim iRet As Integer = 0
' Load the devmode
Dim lDevmode As IntPtr = LoadBlackIceDEVMODE(szPrinterName)
If lDevmode.ToInt32() > 0 Then
' Get interface ID of the printer driver
GetSessionID(lDevmode, iRet)
' Release the DEVMODE
ReleaseBlackIceDEVMODE(lDevmode)
End If
Return iRet
End Function
'Get interface name from Printer name
Public Function GetPrinterInterfaceName(szPrinterName As String) As String
Dim sInterfaceName As String = String.Empty
' Load the devmode
Dim lDevmode As IntPtr = LoadBlackIceDEVMODE(szPrinterName)
If lDevmode.ToInt32() > 0 Then
' Get interface ID of the printer driver
Dim ipInterfaceName As IntPtr = GetInterfaceName(lDevmode)
sInterfaceName = Marshal.PtrToStringUni(ipInterfaceName)
' Release the DEVMODE
ReleaseBlackIceDEVMODE(lDevmode)
End If
' Return printer interface name
Return sInterfaceName
End Function
End Class
Once imported, one can use the WaitForPrnPipeWithPriority function in the VB.NET code as in the following example
'Printer driver name
Dim sPrinterName As String = "Printer Name"
'Create an object of type BiHelper
Dim helper As New BiHelper()
'Interface name of Printer driver
Dim sInterfaceName As String = helper.GetPrinterInterfaceName(sPrinterName)
'Session ID of Printer driver
Dim iSessionID As Integer = helper.GetPrinterSessionID(sPrinterName)
'Pipe name
szPipeName = (Convert.ToString("\\.\pipe\") & sInterfaceName) + iSessionID.ToString()
'Start listening for messages. The pipe messages will be forwarded to the WndProc function as WM_USER + 1000 messages
WaitForPrnPipeWithPriority(szPipeName, Me.Handle, WM_USER + 1000, THREAD_PRIORITY_TIME_CRITICAL)
Protected Overrides Sub WndProc(ByRef message As Message)
If message.Msg = WM_USER + 1000 Then
' WM_USER + 1000 is the same value that is passed to the WaitForPrnPipeWithPriority function
'Read the Printer Driver Messaging Interface structure from the WParam parameter
Dim pParams As IntPtr = GlobalLock(message.WParam)
Dim sParams As TSPrnMessage = DirectCast(Marshal.PtrToStructure(pParams, GetType(TSPrnMessage)), TSPrnMessage)
' The larger message capture structure is available since Printer Driver Version 14.98.
' For compatibility with older drivers, check the size of the structure to see if we recieved the
' new structure or the old one.
Dim bNewDriver As Boolean = (CInt(GlobalSize(message.WParam)) >= Marshal.SizeOf(GetType(TSPrnMessage)))
If bNewDriver Then
' Driver Version is 14.98 or newer, use the new structure
sParams = DirectCast(Marshal.PtrToStructure(pParams, GetType(TSPrnMessage)), TSPrnMessage)
Else
' Driver Version is 14.97 or earlier, copy what we can from the old structure
Dim sParamsV1 As TSPrnMessageV1
sParamsV1 = DirectCast(Marshal.PtrToStructure(pParams, GetType(TSPrnMessageV1)), TSPrnMessageV1)
sParams = New TSPrnMessage(sParamsV1)
End If
Select Case sParams.dwMessage
Case BLACKICE_MESSAGE_STARTDOC
DisplayAndLog("Start Doc")
DisplayAndLog(" Printer Name: " + sParams.szPrinterName)
DisplayAndLog(" Document Name: " + sParams.szDocName)
DisplayAndLog(" Group File Name: " + sParams.szGroupFileName)
If (bNewDriver) Then
DisplayAndLog(" Job ID: " + sParams.dwJobID.ToString())
End If
Exit Select
Case BLACKICE_MESSAGE_STARTPAGE
DisplayAndLog("Start Page")
DisplayAndLog(" Printer Name: " + sParams.szPrinterName)
DisplayAndLog(" Document Name: " + sParams.szDocName)
DisplayAndLog(" Page Number: " + sParams.nPageNumber.ToString())
If (bNewDriver) Then
DisplayAndLog(" Job ID: " + sParams.dwJobID.ToString())
DisplayAndLog(" Output File Name: " + sParams.szOutputFileName)
DisplayAndLog(" Group File Name: " + sParams.szGroupFileName)
Else
DisplayAndLog(" Output File Name: " + sParams.szFileName)
End If
Exit Select
Case BLACKICE_MESSAGE_ENDDOC
DisplayAndLog("End Doc")
DisplayAndLog(" Printer Name: " + sParams.szPrinterName)
DisplayAndLog(" Document Name: " + sParams.szDocName)
If (bNewDriver) Then
DisplayAndLog(" Job ID: " + sParams.dwJobID.ToString())
DisplayAndLog(" Output File Name: " + sParams.szOutputFileName)
DisplayAndLog(" Group File Name: " + sParams.szGroupFileName)
Else
DisplayAndLog(" Group File Name: " + sParams.szFileName)
End If
Exit Select
Case BLACKICE_MESSAGE_ENDPAGE
DisplayAndLog("End Page")
DisplayAndLog(" Printer Name: " + sParams.szPrinterName)
DisplayAndLog(" Document Name: " + sParams.szDocName)
DisplayAndLog(" Page Number: " + sParams.nPageNumber.ToString())
If (bNewDriver) Then
DisplayAndLog(" Job ID: " + sParams.dwJobID.ToString())
DisplayAndLog(" Output File Name: " + sParams.szOutputFileName)
DisplayAndLog(" Group File Name: " + sParams.szGroupFileName)
Else
DisplayAndLog(" Output File Name: " + sParams.szFileName)
End If
Exit Select
Case BLACKICE_MESSAGE_ABORT
DisplayAndLog("Abort: Print job has been aborted")
If (bNewDriver) Then
DisplayAndLog(" Printer Name: " + sParams.szPrinterName)
DisplayAndLog(" Document Name: " + sParams.szDocName)
DisplayAndLog(" Job ID: " + sParams.dwJobID.ToString())
End If
Exit Select
Case BLACKICE_MESSAGE_DEVMODE
DisplayAndLog("ChangeDevmode")
If (bNewDriver) Then
DisplayAndLog(" Printer Name: " + sParams.szPrinterName)
DisplayAndLog(" Document Name: " + sParams.szDocName)
DisplayAndLog(" Job ID: " + sParams.dwJobID.ToString())
End If
' ChangeDevmode message received, read the DEVMODE structure from the LParam parameter and configure it
Dim ipDevmode As IntPtr = message.LParam
If ipDevmode.ToInt32() > 0 Then
' modify the BlackIceDEVMODE structure as needed
' do not modify the standard DEVMDOE structure, (pDevMode->DM)
' only modify the extended part of the BlackIceDEVMODE structure.
' DO NOT MAKE TIME CONSUMING OPEARTIONS HERE
' The printer drive will wait a maximum of 2 seconds for an updated
' BlackIceDEVMODE structure.
End If
Exit Select
Case BLACKICE_MESSAGE_MEMIMAGE
ipDevmode = message.LParam
If ipDevmode.ToInt32() > 0 Then
'Printer driver name
Dim sPrinterName As String = CurrentPrinter.Text
'Create an object of type BiHelper
Dim helper As New BiHelper()
'File extension of Printer driver
Dim sFileExt As String = helper.GetFileExtension_(sPrinterName)
Dim saveFileName As String = String.Empty
saveFileName = GetCustomTempFile("BLI", sFileExt)
'Get pointer to the image data
Dim pImage As IntPtr = GlobalLock(message.LParam)
'Get the size of the image data
Dim dwSize As Integer = CInt(GlobalSize(message.LParam))
'Copy the image data from the unmanaged memory to a byte array
Dim buffer As Byte() = New Byte(dwSize - 1) {}
Marshal.Copy(pImage, buffer, 0, dwSize)
'Write image data to a file
File.WriteAllBytes(saveFileName, buffer)
If (bNewDriver) Then
DisplayAndLog("MemoryImageEx message was received.")
DisplayAndLog(" Printer Name: " + sParams.szPrinterName)
DisplayAndLog(" Document Name: " + sParams.szDocName)
DisplayAndLog(" Job ID: " + sParams.dwJobID.ToString())
DisplayAndLog(" The file has been saved to: " + saveFileName)
Else
DisplayAndLog("Print to Memory message received and the file has been saved to: " + saveFileName)
End If
'Free unmanaged memory
GlobalUnlock(message.LParam)
GlobalFree(message.LParam)
End If
Exit Select
Case BLACKICE_MESSAGE_ERROR
DisplayAndLog("Error message was received.")
DisplayAndLog(" Error Code: " + message.LParam.ToString())
Exit Select
Case BLACKICE_MESSAGE_OCR
ipDevmode = message.LParam
If ipDevmode.ToInt32() > 0 Then
If (bNewDriver) Then
'Printer driver name
Dim sPrinterName As String = CurrentPrinter.Text
'Get pointer to the OCR data
Dim pOCR As IntPtr = GlobalLock(message.LParam)
Dim OCRData As String = Marshal.PtrToStringUni(pOCR)
DisplayAndLog("OCR message was received.")
DisplayAndLog(" Printer Name: " + sParams.szPrinterName)
DisplayAndLog(" Job ID: " + sParams.dwJobID.ToString())
DisplayAndLog(" Document Name: " + sParams.szDocName)
Select Case sParams.dwOCRDataType
Case BI_OCR_MEM_FORMAT_TEXT
Try
DisplayAndLog(" The OCR Data Type is TEXT (1))")
DisplayAndLog(" The OCR Data is: " + OCRData)
Dim saveFileName As String = String.Empty
saveFileName = GetCustomTempFile("BLI", "txt")
'Write OCR data to a file
File.WriteAllText(saveFileName, OCRData)
Catch Ex As Exception
DisplayAndLog(" " + Ex.ToString())
End Try
Case BI_OCR_MEM_FORMAT_HOCR_HEADER
Try
DisplayAndLog(" The OCR Data Type is hOCR header (2)")
DisplayAndLog(" The OCR Data is: " + OCRData)
sHOCRFileName = GetCustomTempFile("BLI", "html")
'Write OCR header to a file
File.WriteAllText(sHOCRFileName, OCRData)
DisplayAndLog(" The file has been saved to: " & sHOCRFileName)
Catch Ex As Exception
DisplayAndLog(" " + Ex.ToString())
End Try
Case BI_OCR_MEM_FORMAT_HOCR_PAGE
Try
DisplayAndLog(" The OCR Data Type is hOCR data (3)")
DisplayAndLog(" The OCR Data is: " + OCRData)
'Append OCR data to a file
File.AppendAllText(sHOCRFileName, OCRData)
DisplayAndLog(" The file has been saved to: " & sHOCRFileName)
Catch Ex As Exception
DisplayAndLog(" " + Ex.ToString())
End Try
Case BI_OCR_MEM_FORMAT_HOCR_FOOTER
Try
DisplayAndLog(" The OCR Data Type is hOCR footer (4)")
DisplayAndLog(" The OCR Data is: " + OCRData)
'Append OCR footer to a file
File.AppendAllText(sHOCRFileName, OCRData)
DisplayAndLog(" The file has been saved to: " & sHOCRFileName)
Catch Ex As Exception
DisplayAndLog(" " + Ex.ToString())
End Try
End Select
End If
'Free unmanaged memory
GlobalUnlock(message.LParam)
GlobalFree(message.LParam)
End If
Exit Select
End Select
CaseBLACKICE_MESSAGE_TEXT
ipDevmode = message.LParam
If ipDevmode.ToInt32() > 0 Then
If (bNewDriver) Then
'Get pointer to the TEXT data
Dim pTEXT As IntPtr = GlobalLock(message.LParam)
Dim TEXTData As String = Marshal.PtrToStringUni(pTEXT)
DisplayAndLog("TEXT message was received.")
DisplayAndLog(" Printer Name: " + sParams.szPrinterName)
DisplayAndLog(" Job ID: " + sParams.dwJobID.ToString())
DisplayAndLog(" Document Name: " + sParams.szDocName)
DisplayAndLog(" Page Number: " + sParams.nPageNumber.ToString())
Try
'DisplayAndLog(" The TEXT Data is: " + TEXTData);
Dim saveFileName As String = String.Empty
saveFileName = GetCustomTempFile("BLI", "txt")
'Write TEXT data to a file
File.WriteAllText(saveFileName, TEXTData)
DisplayAndLog(" The file has been saved to: " + saveFileName)
Catch Ex As Exception
DisplayAndLog(" " + Ex.ToString())
End Try
End If
'Free unmanaged memory
GlobalUnlock(message.LParam)
GlobalFree(message.LParam)
Exit Select
End If
End Select
GlobalUnlock(message.WParam)
GlobalFree(message.WParam)
End If
MyBase.WndProc(message)
End Sub