A halfhearted blog about one guys experiences and thoughts with a few code snips thrown in. Includes topics such as travel, motorcycles, programming, New York City, and anything that interests me enough to document.
Monday, July 29, 2013
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
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
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:
<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>
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
- 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; }