According to the datasheet, the PCD8544 allows column and row based addressing; row addresses range from 0 to 5 corresponding to the 6 byte-sized columns and column addresses range from 0-83 corresponding to the 84 columns.  
Here is the full c# code for those of you who couldn't access the attachment on the link. Don't forget to download and put the InpOut32.dll in the same folder with the code.
Code:
using System;
using System.Threading;
using System.Runtime.InteropServices;
enum Mode
{
    Data,
    Command
}
class Pin
{
    private int _mask;
    
    public int Mask
    {
       get { return _mask; }
       set { _mask = value; }
    }
    
    public Pin(int mask)
    {
       _mask = mask;
    }
}
class LCD
{
    [DllImport("inpout32.dll")]
    public static extern void Out32(int address, int data);
    
    
    private static int port_address = 0x378;      
    private static int port_data = 0x00;
    private static int reset_delay = 5;
    private static int data_delay = 0;
    private static int MSB = 0x80;         // Most Significant Bit (left-most bit) mask
    private static bool invert = false;         // Inverts parallel port output (useful) if using an inverter HCMOS logic to 
                         // translate TTL (5v output) to 3.3V 
    
    
    // Mapping of parallel port data register bits to LCD inputs
    private static Pin sclk  = new Pin(0x01);      // sclk => 00000001
    private static Pin sdin  = new Pin(0x02);      // sdin => 00000010
    private static Pin dc    = new Pin(0x04);      // d/c  => 00000100
    private static Pin power = new Pin(0x08);      // vdd  => 00001000
    private static Pin reset = new Pin(0x10);       // res  => 00010000
    
    // Encapsulate Out32 function to implement port-wide invert
    public static void Out(int data)
    {
       if (invert)
            Out32(port_address, ~data);
       else
          Out32(port_address, data);
    }
    
    public static void Main()
    {
       {
           Power();
                                   
            Thread.Sleep(reset_delay);
            Reset();
                          
           Init();
                      
           Clear();
           
           GoToXY(15, 1);
           
           WriteString("It works !!");
          
           for (int i = 0; i < 6; i++)
           {
              GoToXY(0, i);
      WriteString(i.ToString());
           }
        }
    }
    
        
    public static void Reset()
    {
       port_data &= ~reset.Mask;         // RES = 0
       Out(port_data);
       
       Thread.Sleep(reset_delay);
       
       port_data |= reset.Mask;         // RES = 1
       Out(port_data);
    }
    public static void Power()
    {
      port_data |= reset.Mask;         // RES = 1
       port_data |= power.Mask;         // VDD = 1
       Out(port_data);
    }
    
    public static void Init()
    {
       Write(0x21, Mode.Command);      // Function Set (Extended) : Horizonta Addressing
       //Write(0x23, Mode.Command);      // Function Set (Extended) : Vertical Addressing
       Write(0x13, Mode.Command);      // Bias System   (BS2=0, BS1=1, BS0=1)
       Write(0xD0, Mode.Command);      // Vop (Operating Voltage) = 8.5v 
                  
       Write(0x20, Mode.Command);      // Function Set (Basic)
       Write(0x0C, Mode.Command);      // Display Control (Normal)
       //Write(0x0D, Mode.Command);      // Display Control (Inverse)
    }
    
    public static void Write(int data, Mode mode)
    {
   for (int i = 0; i < 8; i++)
   {
       if (mode == Mode.Data)
          port_data |= dc.Mask;         // D/C = 1
       else
          port_data &= ~dc.Mask;         // D/C = 0
       port_data &= (~sdin.Mask & ~sclk.Mask);   // SCLK = 0, SDIN = 0
       port_data |= ((data & MSB) >> 6);      // SDIN = Bit(data, 7-i) : MSB first
       
       Out(port_data);
       Thread.Sleep(data_delay);
       port_data |= sclk.Mask;         // SCLK = 1 (latch data)
       Out(port_data);
       Thread.Sleep(data_delay);
       data = (data << 1);            // shift data right by 1 bit
   }
    }
    
    public static void Clear()
    {
       int buffer = data_delay;
       
       // Clear delay
       data_delay = 0;
       
       for (int y = 0; y < 6; y++)
           for (int x = 0; x < 84; x++)
               Write(0x00, Mode.Data);
       
       // Restore delay
       data_delay = buffer;
    }
    
    public static void GoToXY(int x, int y)
    {
       Write(0x40 | y, Mode.Command);       // Set y
       Write(0x80 | x, Mode.Command);       // Set x
    }
    
    public static void WriteString(string s)
    {
       int index;
       
        foreach (char _ch in s)
        {
            index = (int)_ch;
            for (int i = 0; i < 5; i++)
                Write(charmap[index - 32][i], Mode.Data);
        }
    }
    
    private static int[][] charmap = new int[][] 
    {
        new int[] { 0x00, 0x00, 0x00, 0x00, 0x00 },   // sp
        new int[] { 0x00, 0x00, 0x2f, 0x00, 0x00 },   // !
        new int[] { 0x00, 0x07, 0x00, 0x07, 0x00 },   // "
        new int[] { 0x14, 0x7f, 0x14, 0x7f, 0x14 },   // #
        new int[] { 0x24, 0x2a, 0x7f, 0x2a, 0x12 },   // $
        new int[] { 0x32, 0x34, 0x08, 0x16, 0x26 },   // %
        new int[] { 0x36, 0x49, 0x55, 0x22, 0x50 },   // &
        new int[] { 0x00, 0x05, 0x03, 0x00, 0x00 },   // '
        new int[] { 0x00, 0x1c, 0x22, 0x41, 0x00 },   // (
        new int[] { 0x00, 0x41, 0x22, 0x1c, 0x00 },   // )
        new int[] { 0x14, 0x08, 0x3E, 0x08, 0x14 },   // *
        new int[] { 0x08, 0x08, 0x3E, 0x08, 0x08 },   // +
        new int[] { 0x00, 0x00, 0x50, 0x30, 0x00 },   // ,
        new int[] { 0x10, 0x10, 0x10, 0x10, 0x10 },   // -
        new int[] { 0x00, 0x60, 0x60, 0x00, 0x00 },   // .
        new int[] { 0x20, 0x10, 0x08, 0x04, 0x02 },   // /
        new int[] { 0x3E, 0x51, 0x49, 0x45, 0x3E },   // 0
        new int[] { 0x00, 0x42, 0x7F, 0x40, 0x00 },   // 1
        new int[] { 0x42, 0x61, 0x51, 0x49, 0x46 },   // 2
        new int[] { 0x21, 0x41, 0x45, 0x4B, 0x31 },   // 3
        new int[] { 0x18, 0x14, 0x12, 0x7F, 0x10 },   // 4
        new int[] { 0x27, 0x45, 0x45, 0x45, 0x39 },   // 5
        new int[] { 0x3C, 0x4A, 0x49, 0x49, 0x30 },   // 6
        new int[] { 0x01, 0x71, 0x09, 0x05, 0x03 },   // 7
        new int[] { 0x36, 0x49, 0x49, 0x49, 0x36 },   // 8
        new int[] { 0x06, 0x49, 0x49, 0x29, 0x1E },   // 9
        new int[] { 0x00, 0x36, 0x36, 0x00, 0x00 },   // :
        new int[] { 0x00, 0x56, 0x36, 0x00, 0x00 },   // ;
        new int[] { 0x08, 0x14, 0x22, 0x41, 0x00 },   // <
        new int[] { 0x14, 0x14, 0x14, 0x14, 0x14 },   // =
        new int[] { 0x00, 0x41, 0x22, 0x14, 0x08 },   // >
        new int[] { 0x02, 0x01, 0x51, 0x09, 0x06 },   // ?
        new int[] { 0x32, 0x49, 0x59, 0x51, 0x3E },   // @
        new int[] { 0x7E, 0x11, 0x11, 0x11, 0x7E },   // A
        new int[] { 0x7F, 0x49, 0x49, 0x49, 0x36 },   // B
        new int[] { 0x3E, 0x41, 0x41, 0x41, 0x22 },   // C
        new int[] { 0x7F, 0x41, 0x41, 0x22, 0x1C },   // D
        new int[] { 0x7F, 0x49, 0x49, 0x49, 0x41 },   // E
        new int[] { 0x7F, 0x09, 0x09, 0x09, 0x01 },   // F
        new int[] { 0x3E, 0x41, 0x49, 0x49, 0x7A },   // G
        new int[] { 0x7F, 0x08, 0x08, 0x08, 0x7F },   // H
        new int[] { 0x00, 0x41, 0x7F, 0x41, 0x00 },   // I
        new int[] { 0x20, 0x40, 0x41, 0x3F, 0x01 },   // J
        new int[] { 0x7F, 0x08, 0x14, 0x22, 0x41 },   // K
        new int[] { 0x7F, 0x40, 0x40, 0x40, 0x40 },   // L
        new int[] { 0x7F, 0x02, 0x0C, 0x02, 0x7F },   // M
        new int[] { 0x7F, 0x04, 0x08, 0x10, 0x7F },   // N
        new int[] { 0x3E, 0x41, 0x41, 0x41, 0x3E },   // O
        new int[] { 0x7F, 0x09, 0x09, 0x09, 0x06 },   // P
        new int[] { 0x3E, 0x41, 0x51, 0x21, 0x5E },   // Q
        new int[] { 0x7F, 0x09, 0x19, 0x29, 0x46 },   // R
        new int[] { 0x46, 0x49, 0x49, 0x49, 0x31 },   // S
        new int[] { 0x01, 0x01, 0x7F, 0x01, 0x01 },   // T
        new int[] { 0x3F, 0x40, 0x40, 0x40, 0x3F },   // U
        new int[] { 0x1F, 0x20, 0x40, 0x20, 0x1F },   // V
        new int[] { 0x3F, 0x40, 0x38, 0x40, 0x3F },   // W
        new int[] { 0x63, 0x14, 0x08, 0x14, 0x63 },   // X
        new int[] { 0x07, 0x08, 0x70, 0x08, 0x07 },   // Y
        new int[] { 0x61, 0x51, 0x49, 0x45, 0x43 },   // Z
        new int[] { 0x00, 0x7F, 0x41, 0x41, 0x00 },   // [
        new int[] { 0x55, 0x2A, 0x55, 0x2A, 0x55 },   // 55
        new int[] { 0x00, 0x41, 0x41, 0x7F, 0x00 },   // ]
        new int[] { 0x04, 0x02, 0x01, 0x02, 0x04 },   // ^
        new int[] { 0x40, 0x40, 0x40, 0x40, 0x40 },   // _
        new int[] { 0x00, 0x01, 0x02, 0x04, 0x00 },   // '
        new int[] { 0x20, 0x54, 0x54, 0x54, 0x78 },   // a
        new int[] { 0x7F, 0x48, 0x44, 0x44, 0x38 },   // b
        new int[] { 0x38, 0x44, 0x44, 0x44, 0x20 },   // c
        new int[] { 0x38, 0x44, 0x44, 0x48, 0x7F },   // d
        new int[] { 0x38, 0x54, 0x54, 0x54, 0x18 },   // e  
        new int[] { 0x08, 0x7E, 0x09, 0x01, 0x02 },   // f
        new int[] { 0x0C, 0x52, 0x52, 0x52, 0x3E },   // g
        new int[] { 0x7F, 0x08, 0x04, 0x04, 0x78 },   // h
        new int[] { 0x00, 0x44, 0x7D, 0x40, 0x00 },   // i
        new int[] { 0x20, 0x40, 0x44, 0x3D, 0x00 },   // j
        new int[] { 0x7F, 0x10, 0x28, 0x44, 0x00 },   // k
        new int[] { 0x00, 0x41, 0x7F, 0x40, 0x00 },   // l
        new int[] { 0x7C, 0x04, 0x18, 0x04, 0x78 },   // m
        new int[] { 0x7C, 0x08, 0x04, 0x04, 0x78 },   // n
        new int[] { 0x38, 0x44, 0x44, 0x44, 0x38 },   // o
        new int[] { 0x7C, 0x14, 0x14, 0x14, 0x08 },   // p
        new int[] { 0x08, 0x14, 0x14, 0x18, 0x7C },   // q
        new int[] { 0x7C, 0x08, 0x04, 0x04, 0x08 },   // r
        new int[] { 0x48, 0x54, 0x54, 0x54, 0x20 },   // s
        new int[] { 0x04, 0x3F, 0x44, 0x40, 0x20 },   // t
        new int[] { 0x3C, 0x40, 0x40, 0x20, 0x7C },   // u
        new int[] { 0x1C, 0x20, 0x40, 0x20, 0x1C },   // v
        new int[] { 0x3C, 0x40, 0x30, 0x40, 0x3C },   // w
        new int[] { 0x44, 0x28, 0x10, 0x28, 0x44 },   // x
        new int[] { 0x0C, 0x50, 0x50, 0x50, 0x3C },   // y
        new int[] { 0x44, 0x64, 0x54, 0x4C, 0x44 },   // z
        new int[] { 0x00, 0x7F, 0x3E, 0x1C, 0x08 },   // > Filled
        new int[] { 0x08, 0x1C, 0x3E, 0x7F, 0x00 },      // < Filled
        new int[] { 0x08, 0x7C, 0x7E, 0x7C, 0x08 },   // Arrow up
        new int[] { 0x10, 0x3E, 0x7E, 0x3E, 0x10 },   // Arrow down    
        new int[] { 0x3E, 0x3E, 0x3E, 0x3E, 0x3E },   // Stop
        new int[] { 0x00, 0x7F, 0x3E, 0x1C, 0x08 }    // Play
    };
}
[/code]