Monday, July 29, 2013

Welcome Nimitz



My  Rat Terrier puppy named Nimitz.





Wednesday, July 17, 2013

Using Microsoft.Office.Interop.PowerPoint to convert PPT to PDF

Microsoft PowerPoint can create some pretty good PDF using it's built in Save As functionality. The Interop library allows to code this functionality for large batch jobs.

One notable issues is that trying to open a password protected file, where the password wasn't known and would have preferred a graceful fail as with the Interop.Word library, would pop open a password dialog box and block the batch processing until a user could manually click on cancel.

After a few days of trial and error, I got the following advice from friends at StackOverflow.com - just append a bogus password to the file name when opening the PPT in the form of "c:\temp\filename.ppt::BOGUS_PASSWORD::" - if the PPT file required a password it is ignored, if it's the wrong password it throws an exception, but no password prompt is open on the screen.

Very nice


using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
using Microsoft.Office;
using Microsoft.Office.Interop.PowerPoint;

using MT = Microsoft.Office.Core.MsoTriState;

namespace PowerPointConverter
{
 public class PowerPointConverter : IDisposable
 {
  Application app;
  public PowerPointConverter()
  {
   app = new Microsoft.Office.Interop.PowerPoint.Application();
   app.DisplayAlerts = PpAlertLevel.ppAlertsNone;
   app.ShowWindowsInTaskbar = MT.msoFalse;
   app.WindowState = PpWindowState.ppWindowMinimized;
  }

  public bool ConvertToPDF(FileInfo sourceFile, DirectoryInfo destDir)
  {
   bool success = true;
   

   FileInfo destFile = new FileInfo(destDir.Name + "\\" +
    Path.GetFileNameWithoutExtension(sourceFile.Name) + ".pdf");

   Thread pptThread = new Thread(delegate()
   {
    try
    {
     string openString = sourceFile.FullName + "::BOGUS_PASSWORD::";
     
     Presentation ppt = null;
     ppt = app.Presentations.Open(openString, MT.msoTrue, MT.msoTrue, MT.msoFalse);
     ppt.SaveAs(destFile.FullName, PpSaveAsFileType.ppSaveAsPDF, MT.msoFalse);
     ppt.Close();
     System.Runtime.InteropServices.Marshal.FinalReleaseComObject(ppt);
    }
    catch (System.Runtime.InteropServices.COMException comEx)
    {
     success = false;
    }
   });

   pptThread.Start();
   if (!pptThread.Join(20000))
   {
    pptThread.Abort();
    success = false;
   }

   return success;
  }

    
  public void Dispose()
  {
   Thread appThread = new Thread(delegate()
   {
    try
    {
     if (null != app)
     {
      app.Quit();
      System.Runtime.InteropServices.Marshal.FinalReleaseComObject(app);
     }
    }
    catch (System.Runtime.InteropServices.COMException) { }
   });

   appThread.Start();
   if (!appThread.Join(10000))
   {
    appThread.Abort();
   }
  }
 }
}

Thursday, June 13, 2013

Convert Word documents using Interop API

Have a requirement to convert millions of documents to html, preserving the formatting and style, so trying out Microsoft.Office.Interop.Word's SaveAs API.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Word = Microsoft.Office.Interop.Word;
using Microsoft.Office.Interop.Word;

public class WordTool: IDisposable
  {
    Word._Application oWord;
    object oMissing = System.Reflection.Missing.Value;
    object isVisible = true;
    object readOnly = true;
    object oSaveChanges = false;

    public WordTool()
    {
      // Create an instance of Word.exe
      oWord = new Word.Application();
      oWord.Visible = false;
      oWord.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
    }

    public void Convert(string input, string output)
    {
      WdSaveFormat format;
      switch (Path.GetExtension(output.ToLower()))
      {
        case ".doc":
          format = WdSaveFormat.wdFormatDocument;
          break;
        case ".docx":
          format = WdSaveFormat.wdFormatDocumentDefault;
          break;
        case ".htm":
          format = WdSaveFormat.wdFormatHTML;
          break;
        case ".html":
          format = WdSaveFormat.wdFormatFilteredHTML;
          break;
        case ".pdf":
          format = WdSaveFormat.wdFormatPDF;
          break;
        case ".rtf":
          format = WdSaveFormat.wdFormatRTF;
          break;
        case ".mht":
          format = WdSaveFormat.wdFormatWebArchive;
          break;
        case ".xps":
          format = WdSaveFormat.wdFormatXPS;
          break;
        case ".txt":
          format = WdSaveFormat.wdFormatTextLineBreaks;
          break;
        case ".xml":
          format = WdSaveFormat.wdFormatFlatXML;
          break;
        default:
          format = WdSaveFormat.wdFormatText;
          break;
      }

      object oFormat = format;
      object oInput = input;
      object oOutput = output;

      // Load a document into our instance of word.exe
      Word._Document oDoc = oWord.Documents.Open(ref oInput,
        ref oMissing, ref readOnly, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref isVisible, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing);

      // Make this document the active document.
      oDoc.Activate();

      // Save this document in Word 2003 format.
      oDoc.SaveAs(ref oOutput, ref oFormat,
        ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing);

      // found temp instance of doc if not closed
      oDoc.Close(ref oSaveChanges, ref oMissing, ref oMissing);
    }

    public void Dispose()
    {
      if (null != oWord)
        oWord.Quit(ref oSaveChanges, ref oMissing, ref oMissing);
    }
  }

This solution based on code originally found on Stack Overflow

Thursday, April 18, 2013

C# in memory XSLT processing

Needed to create an in memory (stream) based XSLT, was frustrated all the ready examples were file based, so documenting my solution for future reference and to share the love.

The convenience wrapper that references string names:


public static string DoXslTransform(string xslPath, string xmlBase, string relativeUri)
{

    XslCompiledTransform transform = 
      GetXslCompiledTransform(xslPath);

    Uri baseUri = new Uri(xmlBase);

    XmlReader xmlReader = GetXmlReader(baseUri, relativeUri);

    string data = GetXslToString(transform, xmlReader);

    xmlReader.Close();

    return data;
}

Method to create a stream based XmlReader:


public static XmlReader GetXmlReader(Uri baseUri, string relativeUri)
{
    XmlUrlResolver xmlUrlResolver = new XmlUrlResolver();

    xmlUrlResolver.Credentials = 
      System.Net.CredentialCache.DefaultCredentials;

    Uri fulluri = 
      xmlUrlResolver.ResolveUri(baseUri, relativeUri);

    Stream stream = (Stream)
      xmlUrlResolver.GetEntity(fulluri, null, typeof(Stream));
    return XmlReader.Create(stream);
}

Method to create a compiled transformer:


public static XslCompiledTransform GetXslCompiledTransform(string xslPath)
{
    XslCompiledTransform transform = new XslCompiledTransform();

    XmlReaderSettings xmlReaderSettings = 
      new XmlReaderSettings();
    xmlReaderSettings.DtdProcessing = DtdProcessing.Prohibit;
    xmlReaderSettings.CloseInput = true;

    XsltSettings xsltSettings = new XsltSettings(true, true);

    XmlResolver secureResolver = 
      new XmlSecureResolver(new XmlUrlResolver(), xslPath);

    transform.Load(XmlReader.Create(xslPath, xmlReaderSettings), 
      xsltSettings, secureResolver);

    return transform;
}

Method to do the transformation to string:


public static string GetXslToString(XslCompiledTransform transform, XmlReader xmlReader)
{
    MemoryStream memoryStream = 
      new MemoryStream();
    StreamWriter outStreamWriter = 
      new StreamWriter(memoryStream);

    transform.Transform(xmlReader, null, outStreamWriter);

    outStreamWriter.Flush();
    memoryStream.Position = 0;

    StreamReader reader = new StreamReader(memoryStream);
    
    return reader.ReadToEnd();
}


Tuesday, March 19, 2013

Set the HTML form with data from in the page's address


Use JQuery to fill in a Web form when post-back to the page using method="get".

Assume the a Web page has the following address http://localhost:/Example01.htm and contains the following simple HTML form:


The source code of that form may appear as following:

<form action="Example01.htm" method="get">

  <input id="QueryString" type="text" name="QueryString" />

  <select id="Method" name="Method">
    <option value="And">All Words</option>
    <option value="Or">Any Word</option>
  </select>

  <input type="submit" value="Submit" />

</form> 


Upon submit of the form, which references the current page in the forms action parameter, the page's address is updated with the values from the QueryString and Method input fields:

http://localhost:/Example01.htm?QueryString=my+query+terms&Method=And

The following JavaScript parses the address parameters to re-set the form with the data provided by the user:



<script src="jquery-1.9.1.min.js" type="text/javascript"></script>

<script language="javascript" type="text/javascript">


$(document).ready(function () {

    var vQueryString = getURLParam("QueryString");
    $("#QueryString").val(vQueryString);

    var vMethod = getURLParam("Method");
   $("select#Method option").each(function () {
 if ($(this).val() == vMethod) {
     $(this).prop('selected', true);
 }
    });

});

function getURLParam(name){
 return decodeURIComponent((new RegExp('[?|&]' +
    name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || 
    [, ""])[1].replace(/\+/g, '%20')) || null;
}
</script>

Friday, March 1, 2013

REST calls in CSharp

I needed to code set of REST calls in C# with a some specific requirements that prevented use of simpler WebClient API:


  • Setting the ContentType for "text/xml"
  • Support for GET, DELETE, and POST methods
  • The POST method had to submit data (an XML fragment) and also returned data (XML fragment)

Following is what I hacked out and documenting here so I don't have to look it up again.


XmlDocument RestGet(string uri)
{
    XmlDocument doc = new XmlDocument();

    HttpWebRequest request = 
     (HttpWebRequest)WebRequest.Create(uri);
    request.Method = "GET";
    request.ContentType = "text/xml";

    HttpWebResponse response = 
     (HttpWebResponse)request.GetResponse();
    doc = new XmlDocument();
    doc.Load(response.GetResponseStream());
    response.Close();

    return doc;
}



static XmlDocument RestDelete(string uri)
{
    XmlDocument doc = new XmlDocument();

    HttpWebRequest request = 
     (HttpWebRequest)WebRequest.Create(uri);
    request.Method = "DELETE";
    request.ContentType = "text/xml";

    HttpWebResponse response = 
     (HttpWebResponse)request.GetResponse();
    doc = new XmlDocument();
    doc.Load(response.GetResponseStream());
    response.Close();

    return doc;
}


static XmlDocument RestPost(string uri, string data)
{
    XmlDocument doc = new XmlDocument();

    HttpWebRequest request = 
     (HttpWebRequest)WebRequest.Create(uri);
    request.Method = "POST";
    request.ContentType = "text/xml";

    System.Text.UTF8Encoding encoding = 
     new System.Text.UTF8Encoding();
    byte[] byte1 = encoding.GetBytes(data);
    request.ContentLength = byte1.Length;

    Stream requestStream = request.GetRequestStream();
    requestStream.Write(byte1, 0, byte1.Length);
    requestStream.Close();

    HttpWebResponse response = 
     (HttpWebResponse)request.GetResponse();
    doc = new XmlDocument();
    doc.Load(response.GetResponseStream());
    response.Close();

    return doc;
}