Tony Edgecombe

Raw printing in Windows 8

10 Sep 2012

With the introduction of V4 drivers in Windows 8 and Server 2012 Microsoft has taken another step down the road of making everything print related based on XPS. One of the issues this created in several of my programs is raw printing stopped working for printers using V4 drivers.

It appears (although I haven't tested this thoroughly) that if you try and send a document directly to the printer using the established methods Windows treats it as an XPS document. If it is then everything is fine, if not then it drops into a black hole.

Fortunately there is a new data type you can specify "XPS_PASS" which will bypass the driver and send your output directly to the printer, more details on this on MSDN.

To be able to print to both V4 and earlier printers you will need to test for the driver version, this code will flag whether you have a version 4 driver or not.

bool IsV4Driver(wchar_t* printerName)
{
    HANDLE handle;
    PRINTER_DEFAULTS defaults;

    defaults.DesiredAccess = PRINTER_ACCESS_USE;
    defaults.pDatatype = L"RAW";
    defaults.pDevMode = NULL;

    if (::OpenPrinter(printerName, &handle, &defaults) == 0)
    {
        return false;
    }

    DWORD version = GetVersion(handle);

    ::ClosePrinter(handle);

    return version == 4;
}

DWORD GetVersion(HANDLE handle)
{
    DWORD needed;

    ::GetPrinterDriver(handle, NULL, 2, NULL, 0, &needed);
    if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
    {
        return -1;
    }

    std::vector<char> buffer(needed);
    if (::GetPrinterDriver(handle, NULL, 2, (LPBYTE) &buffer[0], needed, &needed) == 0)
    {
        return -1;
    }

    return ((DRIVER_INFO_2*) &buffer[0])->cVersion;
}

Folder Agent

11 May 2012

This week I released my latest project, Folder Agent. It is a Windows application that monitors a folder or directory for new and modified files. It then lets you run actions against that modified file such as copying, moving, emailing or deleting the file. You can also run an external program or script against the file.

There is a template system that lets you build paths and properties dynamically, so you could move files to a folder structure based on the date for instance.

I've been thinking about writing something along these lines for a long time, in fact I first registered the domain in 2005 but was never really satisified with my first few attempts. This time I started by focussing on the core functionality rather than the user interface and the whole thing has come together quickly, in fact from start to finish was only three months.

Deinterleave XPS files

28 Jan 2012

XPS files have a nice feature called interleaving.

When a printer receives an XPS file it needs to receive any resources such as fonts or images before those resources are used on a page. The way this is handled is items are split into parts, so the first part of the page is spooled then it may be followed by a font then more of the page followed by an image and so on.

This is effective for the creator and consumer software but it does make the files difficult to navigate manually.

To work around this I wrote a small utility to deinterleave an XPS file.

Xcode Linking

24 Dec 2010

I've just started a cross platform project in Xcode and one of the problems I came across is it doesn't seem possible to link to different libraries depending on whether you are building the Debug or Release configuration.

I did find an old message on the Apple developer forums that indicates you can do this with dependent projects, the trouble with this is when you clean your target all the dependent projects will clean as well.

In the end I did find a method that works for my project. The trick is to add a "Library Search Path" with the BUILD_STYLE environment variable:

/path/to/mylibrary/build/$(BUILDSTYLE)/x8664

The $(BUILD_STYLE) macro gets expanded to Debug or Release depending on which configuration I am using, I just need to make sure the libraries are created in the appropriate folders.

I can then add the libraries using the setting "Other linker flags" with the -l option:

-l mylibraryname

Not as nice as the Visual Studio solution but it does seem to work.

Implementing the Light Box effect

26 Oct 2010

I'm sure you have seen the effect by now, clicking on an image thumbnail dims the page you are looking at and opens the full size version of the image in the middle of the browser window. The original implementation of this was Lightbox, now we seem to be overrun with clones doing very similar things.

The trouble with including one of these clones in your site is you don't really know what the quality of code is like and most seem to be groaning under the weight of all their features. All I needed was a short script to dim the page and display an image, the rest is overkill for me.

So rather than writing another clone and getting dragged down the same path I thought I'd show you the steps to adding the lightbox effect to your own site.

Most of the work is handled in JavaScript, there isn't anything too demanding but if you haven't used JavaScript before you are probably better off elsewhere. I will also use JQuery simply because scripting the browser is unbearable without it, if you haven't used JQuery before read the introduction before you continue.

So the first stage is to dim the whole page, we do this by adding a <div> element to the end of the body. The div is styled with absolute positioning, fixed to the top left corner and with the width and height set to 100% so it fills the whole browser window. The opacity is set to 0.5, the background colour to black and it is hidden for now.

#bl-curtain {
    position:absolute;
    top:0;
    left:0;
    bottom: 0;
    right: 0;
    width: 100%;
    height:100%;
    background:black;
    opacity: .5;
    display:none;
}

In our HTML we need an image thumbnail enclosed in an anchor tag, with the class set to boxlight:

    <a href="image.png">
        <img class="boxlight" src="thumb.png"
            alt="Screenshot thumbnail" border="0">
    </a>

JQuery lets us capture a click on any images marked with the boxlight class:

$(document).ready(function() {
    $('.boxlight').click(function() {

We will drop out for IE6 or earlier, I think you can probably get this to work with IE6 but I just don't care:

if ($.browser.msie && parseInt($.browser.version) &lt;= 6) {
    return true;
}

It's probably a good idea to fetch the url from the parent anchor early on and drop out if we can't find it:

url = $(this).parents('a').attr('href');
if (!url) return true;

Now we add our new <div> to the end of the current body:

$('body').append('&lt;div id="bl-curtain">&lt;/div>');

This will pick up the style from the earlier style sheet but for IE we need to add the opacity filter after the element is in the page:

if ($.browser.msie) {
    $('#bl-curtain').css('filter', 'alpha(opacity=50)');
}

If the user clicks on the background we need to clear the image and curtain:

$('#bl-curtain').click(function() {
    fadeOut();
});

Finally we can get around to producing an effect, start by fading in the curtain to cover the existing page:

$('#bl-curtain').fadeIn();

With the background in place we need to start loading the main image:

var img = new Image();
$(img)
    .attr('src', url)
    .attr('id', 'bl-image')
    .click(fadeOut)
    .one('load', function() {
        onImageLoad(this);
    });

If the image is in the browsers cache then IE doesn't fire the event so we need to do this manually, this might be the same for Opera, I haven't checked:

if ($.browser.msie && !$(img).complete) {
    $(img).trigger('load');
}

We return false so the browser doesn't try and follow the link in the anchor tag as we have done everything here:

    return false;
    });
});

The onLoad function has a fair amount of work to do, mostly checking if the image is too big for the browser window and if it is resizing it accordingly:

function onImageLoad(image) {
    // Once the image has loaded we can add it to the document
    $('body').append(image);

    imageWidth = $(image).width();
    imageHeight = $(image).height();

    // Resize the image if it is too big for the browser window
    viewPortWidth = $(window).width();
    viewPortHeight = $(window).height();

    if (viewPortWidth &lt; imageWidth || viewPortHeight &lt; imageHeight) {
        horizontalScalingFactor = imageWidth / viewPortWidth;
        verticalScalingFactor = imageHeight / viewPortHeight;

        scaling = Math.max(horizontalScalingFactor, verticalScalingFactor);

        imageHeight = imageHeight / scaling;
        imageWidth = imageWidth / scaling;

        $(image).css('height', imageHeight);
        $(image).css('width', imageWidth);

    }

    // Centre the image in the page
    $(image).css('margin-top', -imageHeight / 2);
    $(image).css('margin-left', -imageWidth / 2);

    // Finally we can fade it in
    $(image).fadeIn();
}

You might have noticed the negative margins applied to the image in the last piece of code, that is because the styling for the image places the top left corner in the centre of the page:

#bl-image {
    position:absolute;
    top:50%;
    left:50%;
    display:none;
}

The last piece of code fades out the image and background then removes them from the page:

function fadeOut() {
    $('#bl-curtain,#bl-image').fadeOut(function() {
        $(this).remove();
    });
}