views:

217

answers:

3

The purpose is to generate proposal documents that can manually be edited in Word after the fact, but before sending them out to the customers.

Much proposal content would be drawn from existing HTML website content (backing CMS) and also some custom (non-HTML) injection for certain scenarios. Of course the conditional logic could go into server-side ASP.NET to vary the content appropriately.

I'm open to 3rd-party tools if raw manipulation of the Word API is arduous. In fact a good 3rd party tool might be the answer.

+3  A: 

Use the Aspose Words component for .Net.

Aspose Words Component Link

The component natively understands the Microsoft Word file format without having to install any Microsoft Office products on your application environment. You can then start from an existing word template or programatically build up an entire Microsoft Word document from scratch. The Word object model then allows you to export to doc / docx etc and save as a native Word file to wherever you required.

They have plenty of demos set up on their website.

Brian Scott
+1 Thanks for the link and also for reminding me that Word would have to be installed on the server if its API were used directly.
John K
The Adpose component looks quite interesting. Their site points to an interesting page on the Microsoft site, which talks about the problems with server-side Office automation: http://support.microsoft.com/default.aspx?scid=kb;EN-US;q257757#kb2
Mike
@Mike, thanks for the link, it's very telling.
John K
+1  A: 

I've not used any third-party tools before, as I've only ever written Office automation applications for PCs which already have Office installed.

Creating documents from scratch, or basing them on a template, is quite straightforward. With templates, you can define bookmarks and mail-merge fields to make finding and replacing document elements easier.

Here's a few things that you may find useful:

Named and Optional Arguments
The Word object model is reasonably easy to work with. VB.NET used to be easier to work with than C#: as the Office automation APIs were originally written with VB in mind, you could take advantage of optional parameters. In earlier versions of C#, you had to specify every argument in API calls, which was quite tedious. I understand that this has changed in Visual C# 2010:

How to: Use Named and Optional Arguments in Office Programming (C# Programming Guide) http://msdn.microsoft.com/en-us/library/dd264738.aspx

Tutorials
I found these tutorials quite handy:

Automating Office Programs with VB.NET
http://www.xtremevbtalk.com/showthread.php?t=160433

VB.NET Office Automation FAQ
http://www.xtremevbtalk.com/showthread.php?t=160459

Understanding the Word Object Model from a .NET Developer's Perspective
http://msdn.microsoft.com/en-us/library/aa192495%28office.11%29.aspx

Early and Late binding
One point worth mentioning: late-binding is normally recommended against, but it can be very useful if you don't know what version of Office will be deployed on the application's host. Early-binding tends to operate faster, and has the advantage of intellisense in your IDE:

Using early binding and late binding in Automation
http://support.microsoft.com/kb/245115

Early vs. Late Binding
http://word.mvps.org/faqs/interdev/earlyvslatebinding.htm

Search and Replace
One thing to be aware of is that the find and replacement objects may not work as you would expect. Rather than searching the whole document, it searches just the main text. If you have text frames in the document, these will be ignored. Instead, you have to loop through all the StoryRanges, and search the content of each. Here's what I do in VB.NET to search the main text story and text frames:

Private Sub FindReplaceAll(ByVal objDoc As Object, ByVal strFind As String, ByVal strReplacement As String)
    Dim rngStory As Object

    For Each rngStory In objDoc.StoryRanges
        Do
            If rngStory.StoryType = wdMainTextStory Or rngStory.StoryType = wdTextFrameStory Then
                With rngStory.Find
                    .Text = strFind
                    .Replacement.Text = strReplacement
                    .Wrap = wdFindContinue
                    .Execute(Replace:=wdReplaceAll)
                End With
            End If
            rngStory = rngStory.NextStoryRange
        Loop Until rngStory Is Nothing
    Next rngStory
End Sub

StoryRanges Collection Object
http://msdn.microsoft.com/en-us/library/bb178940%28office.12%29.aspx

Mike
+1 very thorough. Thanks.
John K
+1  A: 

You can look into using XSL to generate some WordML.

This technique is definitely convoluted but gives you a lot power in your layout.

nokturnal
+1 Now this is interesting stuff allow human-readable source to create a Word doc without needing MS Word installed on the server. I'm going to add this link http://msdn.microsoft.com/en-us/library/aa537167(office.11).aspx#officewordwordmltoxsl-fo_introductiontowordprocessingmlxslfoformatting
John K