Monday, 29 March 2004

Microsoft Word Automate WordCount frustration

It's amazing how difficult it can be to find information about MS Word when writing VBA (or automation using C#) - I needed to find the wordcount and charactercount programmatically, but the "document properties" m_Word.ActiveDocument.Words.Count and m_Word.ActiveDocument.Characters.Count don't seem to relate to ANYTHING!?!?!.

Thankfully this page myITforum.com : Document Word Counter gave me a push in the right direction:

object missing = System.Reflection.Missing.Value;
m_Word.ActiveDocument.ComputeStatistics(Microsoft.Office.Interop.Word.WdStatistic.wdStatisticWords, ref missing);

Why have Words and Characters properties if they don't DO anything???

P.S. Originally thought DSOFile would be able to do this job - but the Word and Char Count stored in the document properties in the filesystem isn't always up-to-date or meaningful either - it seems like ComputeStatistics is the only reliable way...

Wednesday, 24 March 2004

Parsing html markup text using MSHTML

Came across this article today; wondering whether this is a good solution for improving Searcharoo.net - both it's ability to "spider" the web by finding links in Html, and also parsing the Html into words for indexing (eg. pulling out the META tags, etc)... Parsing html markup text using MSHTML By Hendrik Swanepoel

I really want something lightweight that will help parse Html (a) links for spidering and (b) words for indexing... Other than some complex Regex, MSHTML is the only other option I've come across...

Sunday, 21 March 2004

WorldPay with C#/.NET [2]

Maybe useful info for those using C# with WorldPay...

WorldPay.COMcallbackClass callback = new WorldPay.COMcallbackClass(); 
callback.processCallback(); 
if (callback.hadError() ) { 
Trace.Write("WorldPay Error", callback.getRawAuthMessage() ) 
} 
if (callback.didTransSuc() ) { 

// #### WORLDPAY demo page #### 
string traceInfo = ""; 
traceInfo +="culture:" + Thread.CurrentThread.CurrentCulture.EnglishName + "\n"; 
traceInfo +="uiculture:" + Thread.CurrentThread.CurrentUICulture.EnglishName + "\n"; 

traceInfo +="getTransId:" + callback.getTransId() + "\n"; 
traceInfo +="getRawAuthMessage:" + callback.getRawAuthMessage() + "\n"; 
traceInfo +="getRawAuthCode:" + callback.getRawAuthCode() + "\n"; 
traceInfo +="getTransTime:" + callback.getTransTime() + "\n"; 
traceInfo +="shopperId:" + callback.shopperId + "\n"; 

traceInfo +="getInstallationId:" + callback.getInstallationId() + "\n"; 
traceInfo +="getCompanyName:" + callback.getCompanyName() + "\n"; 
traceInfo +="getAuthMode:" + callback.getAuthMode() + "\n"; 
traceInfo +="getAmount:" + callback.getAmount() + "\n"; 
traceInfo +="getCurrencyISOCode:" + callback.getCurrencyISOCode() + "\n"; 
traceInfo +="getAmountString:" + callback.getAmountString() + "\n"; 

traceInfo +="getDescription:" + callback.getDescription() + "\n"; 
traceInfo +="Customer getName:" + callback.getName() + "\n"; 
traceInfo +="Customer getAddress:" + callback.getAddress() + "\n"; 
traceInfo +="Customer getPostalCode:" + callback.getPostalCode() + "\n"; 
traceInfo +="Customer getCountryISOCode:" + callback.getCountryISOCode() + "\n"; 
traceInfo +="Customer getTelephone:" + callback.getTelephone() + "\n"; 
traceInfo +="Customer getFax:" + callback.getFax() + "\n"; 
traceInfo +="Customer getEmail:" + callback.getEmail() + "\n"; 

traceInfo +="\nTRANS_ID:" + callback.getParameterString("MC_DataID") + "\n";  // CUSTOM PARAM prefix with MC_ 
traceInfo +="MEMBER_ID:" + callback.getParameterString("MC_MemberID") + "\n"; // CUSTOM PARAM 

Trace.Write("WorldPay", traceInfo);

And if you're programming in Japanese... trying to get Japanese characters to display on the WorldPay pages was a real pain-- encoding issues (i'm using UTF-8 for my site - they use Shift_JIS). To set the job description, name and address info i'm currently using this hack

// so manually converting to HTML Unicode Entities 
// as discussed here http://www.randyrants.com/archives/000348.asp 
int ch1; 
string snail2="";  
foreach (char c in currentTransaction.Desc) { 
ch1 = c; 
if (!((ch1 >= 160) && (ch1 < 256))) {// if in 'ascii' range - *THINK* this works....
snail2 += c; // leave as-is 
} else { // convert to entity format Ӓ 
snail2 += string.Concat("&#", ch1.ToString(System.Globalization.NumberFormatInfo.InvariantInfo), ";"); 
} 
} 
purchase.setDescription (snail2); // HACK: HTML Entity Encoding 
[4-May-04] UPDATED CODE here

i18nguy.com

My job often involves multilingual programming (or at the very least content translation). This site i18nguy.com has an excellent collection of links on Internationalization (I18n), Localization (L10n), Standards etc. I've found it useful on a number of occasions, but sometimes I just go there to browse and learn.

Today's fav page is guidelines and resources.

Thursday, 18 March 2004

WayOffTopic: simple file exchange 'extranet'

Part of our everyday business is moving large files back and forth between offices (and countries). Usually FTP does the trick, but more and more clients are having firewall troubles with FTP (and to be honest, I'd rather not have the FTP service running at all).

What I wanted was a simple extranet application with an HTML File Upload and the ability to easily create client 'users' for one-off upload/downloads.

Google found Forms Authentication Using An XML Users File on MSDN, which has almost enough code to get me started.

First time in ages I've found an MS 'sample' useful (except the source projects on asp.net and winforms.net)!

Monday, 15 March 2004

SQL Server 2005 "Yukon" Full-Text Search

Interesting article about the 'internals' of the full-text-search in SQL Server, including discussion of ranking.

Data Access & Storage Home: SQL Server "Yukon" Full-Text Search: Internals and Enhancements (Microsoft SQL Server 9.0 Technical Articles)

First time I've seen "Yukon" officially named "SQLServer 2005"... maybe some useful ideas in there for Searcharoo

Sunday, 14 March 2004

Simple Site Search in .NET (1)

This article appeared on the MSDN Home Page recently: Part 4: Building a Better Binary Search Tree and it raised my curiousity about using the code provided to build a simple 'search engine' in C#.

I did a quick search to see what else was around (cheap/free products, or sample code) and found a few inspirational articles on WebMonkey, Perlfect and Apache.

A couple more articles on opening a file, removing white space and parsing HTML was all that was needed to get a basic search tool 'up and running' -- look for the code soon at Searcharoo.Net!

After being inspired by it, I didn't implement the Binary Search Tree straight away, that's another story...

WorldPay with C#/.NET

I'm in the process of converting an ecom site from ASP 'Classic' to .NET. The site uses the WorldPay gateway COM.

WorldPay supplies sample ASP files: purchase.asp and callback.asp. Purchase.asp "ported" just fine to C# (after using Reference -> Add Reference -> COM -> WorldPay Select COM to import the DLL).

BUT their callback.asp script failed with the following error

System.Runtime.InteropServices.COMException (0x80004005): aspcomp.AspComponentException: AspComponent: Retreiving MTx object context failed
at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)
at WorldPay.COMcallbackClass.processCallback()
at ASP.callback_aspx.Page_Load(Object sender, EventArgs e) in C:\Inetpub\worldpay\callback.aspx:

on

WorldPay.COMcallbackClass callback = new WorldPay.COMcallbackClass();
callback.processCallback();

I couldn't figure out why one page would work and the other not. Surely it's the same DLL being imported/loaded? Changing the Identity in IIS, removing code, adding try/catch... nothing fixed the problem.

Just as I was about to give up and leave that one page in ASP 'Classic', I remembered long ago reading about a 'compability mode' in ASP.NET. A quick Google revealed this doco on aspcompat=true.

And it works! I could not find a single reference to this Googling for 'WorldPay' 'InterOp' 'Error' or any other likely terms -- surely I'm not the first!?!?

[hmm.. my first blog post...]