I was asked to turn a old Inventor printing macro into a .NET add-in. This was a fairly simple task and only translating the SendKeys and Shell commands to code required some thinking.
To print using a Océ 9600 large format printer the macro called the following shell command to send the custom settings along with the plot data (generated using Inventors PrintManager.PrintToFile function) to the printer:
"cmd /c copy settings.txt /a + drawing.plt /b "
This told me I needed to first read the custom settings from a file and turn it into ASCII, then combine that with the data in the binary plot file and finally send it to the printer.
I did not know how to send the data to the printer, so I just tried opening a file stream using the printer’s address (without expecting it to work). This gave me the following exceptionally informative error message:
"FileStream was asked to open a device that was not a file. For support for devices like 'com1:' or 'lpt1:', call CreateFile, then use the FileStream constructors that take an OS handle as an IntPtr."
The message told me exactly what I needed to do. I needed to use the CreateFile Windows API call to get a handle I could pass the the FileStream class. As this was the final piece of the puzzle I quite quickly produced the following code:
public void WriteToPrinter(string pltFile, string settings, string printer)
{
IntPtr handle = IntPtr.Zero;
try
{
handle = CreateFile(printer,
(uint)EFileAccess.GenericWrite,
(uint)(EFileShare.Read | EFileShare.Write),
(uint)0,
(uint)(ECreationDisposition.OpenExisting),
(uint)(EFileAttributes.NoBuffering),
(int)IntPtr.Zero);
if (handle.ToInt32() == -1)
{
int hresult = Marshal.GetHRForLastWin32Error();
Marshal.ThrowExceptionForHR(hresult);
}
using (FileStream stream = new FileStream(handle, FileAccess.Write))
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
byte[] asciiArray = Encoding.Convert(Encoding.UTF8,
Encoding.ASCII, File.ReadAllBytes(settings));
writer.Write(asciiArray);
byte[] binaryArray = File.ReadAllBytes(pltFile);
writer.Write(binaryArray);
writer.Close();
}
}
}
finally
{
if (handle != IntPtr.Zero && handle.ToInt32() != -1)
CloseHandle(handle);
}
}
#region Windows API calls
[DllImport("kernel32", SetLastError = true)]
static extern unsafe IntPtr CreateFile(
string FileName,
uint DesiredAccess,
uint ShareMode,
uint SecurityAttributes,
uint CreationDisposition,
uint FlagsAndAttributes,
int hTemplateFile);
[DllImport("kernel32", SetLastError = true)]
static extern unsafe bool CloseHandle(
IntPtr hObject);
[Flags]
public enum EFileAccess : uint
{
GenericWrite = 0x40000000
}
[Flags]
public enum EFileShare : uint
{
Read = 0x00000001,
Write = 0x00000002
}
public enum ECreationDisposition : uint
{
OpenExisting = 3
}
[Flags]
public enum EFileAttributes : uint
{
NoBuffering = 0x20000000
}
#endregion