In this five part series we’ll show the reader how to programmatically manipulate InfoPath form templates.
Part 1 of 5: The story
There are many scenarios where you might need to modify an InfoPath form template (.XSN) after it’s already in use. Let’s say the URL of your Web Service changes.
With InfoPath 2003 you need to change the URL manually:
With InfoPath 2003 with Service Pack 1 (SP1), just open the form in Design mode, go to Tools menu, select Change Data Source, and in the wizard locate the new URL.
But this isn’t (just) a sneaky way to convince you to download the SP1 Preview.
What if you are responsible for maintaining hundreds of InfoPath forms which rely on the Web service? Even with SP1 this would be a lot of work. It would be nice to do it programmatically.
The good news is that this is possible, even without SP1. The InfoPath XSN format is really a CAB file, and the files that make up the template are XML files which can easily be modified programmatically. You can pack/unpack a CAB file with help of extract.exe and makecab.exe utilities that are accessible for Windows users. Now the only things you need is to implement a small utility using script or managed code that will do the described above sequence automatically. Inside of the utility you should do the following:
If you write a wrapper around this process to enumerate all the form templates, your hundreds of forms will be updated just in a few minutes.
Using this approach you can change not only URLs but SQL connection strings, files names, etc. If you want to learn more about the XSN format and the files that make it up, check out the InfoPath 2003 SDK. As always, be careful – save backup copies, test your code, test the templates before and after, etc.
At the end of this discussion, the patient reader expects a good sample that supports the idea explained above. And we will definitely do it in the following parts 2-5 of the series.
To be continued.
In the InfoPath 2003 Service Pack 1 Preview you can create a fully trusted form template by signing the XSN with a code signing certificate. Here’s what you do:
At this point, you need to choose a certificate that can be used for code signing.
If you do not have a certificate, you can choose the Create Certificate button. This will create a test certificate – not a certificate that has been authenticated by a certificate authority.
While you are developing your form template, you will not be able to preview with full trust permissions unless you register the form template.
The first time your users fill out the form that you have signed with a certain certificate, they will see a Security Warning dialog that notifies them that the form template is digitally signed and asks if they trust the publisher. Once they have checked the box to trust the publisher, they will be able to open any form template that asks for full trust and is signed with that same certificate.
You can view the list of trusted publishers in the SP1 version of InfoPath by selecting Tools | Options and clicking on the Trusted Publishers button.
If users find that the option to trust the publisher is disabled, that means that the root of the certificate used is not trusted on the user’s machine.
When you received your code-signing certificate, you asked the CA (Certificate Authority) for it. What the CA delivered to you is a certificate that is now in your personal folder that is trusted by you and by anybody who trusts the CA that issued it. So, for example, if you get a code signing certificate from Verisign, any user will have the option to trust you as a publisher as long as they also have Verisign in the list of Trusted Root Certification Authorities on their machine. Once a user has trusted the root of a certificate, the option to trust the publisher will be enabled in the Security Warning dialog that is displayed when they fill out a fully-trusted, signed form.
Users can trust the root of a certificate through the Security Warning dialog that comes up when they open a form template. When the Security Warning dialog is open:
One of the first things that experienced form designers will notice when using InfoPath is that layout of controls is not on a 2D design surface – it’s what we call “flow-based”. Controls function like images – or even character glyphs – in an application like Word. You can drag them around and insert them between words and use blank lines or spaces for positioning. To those designers who are used to precise layout using pixel grids or absolute coordinates, this can be disconcerting.
To experienced web designers, however, this model is very familiar. Web pages have to be designed to layout dynamically based on the target device. When you’re designing a web page you simply don’t know how wide the browser window which will eventually display the page is, how large the fonts are for the user viewing the page, or even what color settings are applicable. And, of course, different browsers display the same content differently even if all other variables are the same.
InfoPath templates face a similar set of challenges – but in this case, it’s the data and the form that is dynamic. A variable number of records can appear, parts of the form can show and hide, and users can type different amounts of text into controls which grow. A fixed 2D layout for controls simply wouldn’t work.
Couple that with a desire to have our views be compatible with web standards (XSLT outputting XHTML), and you can see why we built InfoPath with a flow-based layout mechanism.
A lot of the coolest features in the various Office System applications are likely to fall into two buckets: either you’ve never heard of them, or you couldn’t live without them. Here are a few: Format Painter, Styles & Formatting, Fill Down, and Pivot Tables. Once you’ve used any of those, it’s hard to imagine not having them.
Tables for layout are like that.
Web designers know that the trick for good dynamic layout is to use tables. Rather than absolute positions, tables allow for 2D layout of controls by expressing constraints and relative positioning. Even tools like the WinForms designer in Visual Studio .NET are moving in this direction, encouraging the use of docking and panels instead of Top/Left/Width/Height. This makes layout tweaks easier and can even make things like localization much more straightforward.
A few tips for creating layout using tables:
In the InfoPath 2003 SP-1 Preview we’ve added a few more table features:
If you’ve never used the Draw Table tool, you should try it. Select Table | Draw Table. This will show the Table toolbar, and enter a mode where you can drag out a rectangle using the mouse to create the first cell, and then draw lines across it to split the cell into two. Keep drawing lines to keep splitting cells. You can change the Border Style on the toolbar to change the style of the borders you create, or use the Eraser tool to erase borders – merging cells.
Here’s a cool trick from the team. In the SP-1 Preview, there exists the availability to include a background image. Here’s a sample grid image:
Copy the above image and save it to your system as a bmp (no loss in fidelity). Now go into the View properties dialog, click on ‘Use a background picture’. In the ‘Files of type’ dropdown, select ‘All Files (*.*)’ and finally select the grid image you just saved. Back in the View Properties dialog, check “Tile horizontally” and “Tile vertically”. Click OK.
Now you have yourself a grid by which to align your controls and text by – this is especially useful when aligning controls between layout tables, aligning tables themselves, or in cases where tables just aren’t appropriate. When you are ready to publish the form, just go back to the properties dialog and take out the background image.
Background on URNs
InfoPath SP1 included changes to the mail deployment model to allow for easier ways to distribute form templates to a group. One of the tools for making this deployment model work is the URN (Uniform Resource Name). These URNs are generated automatically by InfoPath and should be unique for each new form template you build.
Note: It’s possible to get a URN that’s identical to an existing one, but not very likely. This will be explained more later on.
To see the URN for your form template, you can select ‘File | Properties’ when in the Designer. The URN is listed there as the ‘Form ID’. It is called a Form ID because it is used in the deployment model to identify a form template that may be opened from different locations. The URN is generated by combining three sections separated by semicolons based in part on the form template’s properties. Here’s a sample URN:
It consists of three parts:
Note: The Namespace Timestamp is used whenever a user starts out building the schema within InfoPath. If a form template is built from an XML or XSD file which has its own Namespace, then that Namespace will be used.
The Conflict Dialog
This dialog will appear any time that you open a form template on your machine that has a URN that matches an existing URN that you’ve previously opened and cached, but references a different Access Path (or publish location, URL). As you can see in the example above, I have a file called ‘blogsample.xsn’ that I’ve opened from My Documents, but the conflict dialog is saying that I’ve previously opened a file with the same URN from my Desktop. I got myself into this situation by publishing the same form template to two separate locations with the same filename and then opening each of them. Because the Form Name and Namespace timestamp are identical for both XSNs, so is the URN.
There are two options at this point. I can either open the newer template (Version 188.8.131.52) by clicking ‘Replace Form on Your Computer’ or the older one (Version 184.108.40.206) by clicking ‘Keep Form on Your Computer’. It is important to note that this dialog does not affect the original copies of these files in any way. It will only update your local cache and it will update the file that is shown with this Form Name in your Fill Out a Form dialog.
For anyone who has developed an InfoPath form template against a schema, database, or Web service that has changed since the form template was initially created, the following should be some good news. The SP1 Preview Release of InfoPath contains the ability to provide InfoPath with an updated version of your schema or data source and InfoPath will update your solution accordingly. That’s right, gone are the days of hand modifying the XSF, template file, XSL, etc. in order to change the schema. You can change your main data source via the ToolsàConvert Main Data Source menu entry or a data connection via the modify button for that source in the ToolsàData Connection dialog.
When you provide InfoPath the updated data source, InfoPath will update the schema files stored in the form template and look for and apply changes between the old and new data source. In particular InfoPath will look for type changes, cardinality changes, namespace changes, adds, deletes, renames, and move operations. For any recognized operation, all existing bindings in the view, XSF, and event handler hookup will be fixed accordingly (note, it is still your responsibility to fix business logic code.) Unfortunately InfoPath is not omnipotent, so it might not be the best idea to wait until you have renamed, moved, and extremely modified the children of an element before providing the updated schema to InfoPath ;-)
(And if a menu option to update your data source isn't convenient enough, tomorrow we'll start a five part series on the InfoPath Team Blog showing you how you can automate this sort of operation by taking advantage of InfoPath's XML-based form template file format.)
Part 3 of 5: Modifying the XSF
Because manifest.xsf file is just a plain xml file, the easiest way to modify it is to open it in an XML DOM, find the corresponding attributes with XPath, and replace their existing values with new data.
We will divide the process in two functions. The first one will be responsible for opening and saving the xml file. The second one will find and modify the attribute value.
The serviceURL and wsdlURL parameters are strings with values like “http://mywebservice” and “http://mywebservice?WSDL” accordingly.
var XsfNamespace =
var XpathToServiceUrl =
var XpathToWsdlUrl =
function FixupXSF(xsfInputPath, xsfOutputPath, serviceURL, wsdlURL)
var Fso = new ActiveXObject ("Scripting.FileSystemObject");
var Dom = new ActiveXObject("msxml2.domdocument.5.0");
Dom.validateOnParse=false; // for ignoring xsi:nil errors..
"xmlns:xsf='" + XsfNamespace + "'");
if(serviceURL != null)
ModifyAttribute(Dom, XpathToServiceUrl, serviceURL);
if(wsdlURL != null)
ModifyAttribute(Dom, XpathToWsdlUrl, wsdlURL);
function ModifyAttribute(dom, xpath, value)
var AttributeList = dom.selectNodes(xpath);
var Attribute = AttributeList.nextNode();
if(Attribute == null)
Attribute.nodeValue = value;
The XSF file was modified. Now we should restore our XSN and we will do it in the next part of the series.
Part 2 of 5: Unpacking the XSN
To unpack XSN one should use extract.exe utility. It can be found in the %SystemRoot%\system32 directory or in the Microsoft Cabinet Software Development Kit. For the command usage details just run “extract /?”.
In this part we will also introduce several auxiliary functions that will be extensively used throughout the entire discussion topic.
var ExtractExeLocation = "%SystemRoot%\\SYSTEM32";
var ExtractExe = Combine(ExtractExeLocation, "extract.exe");
function Combine(dir, file)
return dir + "\\" + file ;
return ("\"" + string + "\"");
function Exec(string, flagWait)
if (flagWait == null)
flagWait = true;
var WScriptShell = WScript.CreateObject("WScript.Shell");
return WScriptShell.Run(string, 0, flagWait);
function ExtractFilesFromXSN(xsnInputPath, outputDirectory)
// add the location to place extracted files,
// a flag "/Y" that prevents prompting before overwriting
// an existing file, and a flag "/E" that orders to
// extract all files
if (outputDirectory != null)
Parameters = " /Y /E /L " + QuoteStr(outputDirectory);
+ " " + QuoteStr(xsnInputPath), true);
Now we have a tool to unpack XSN. All of the InfoPath form template files are accessible for changing. In the next part of the series we will be modifying the manifest itself.
Part 5 of 5: The final function
And the final function is
var XsnInputPath = Combine(inputDirectory, xsnInputName);
var XsfInputPath = Combine(inputDirectory, "manifest.xsf");
var XsfOutputPath = Combine(outputDirectory, "manifest.xsf");
FixupXSF(XsfInputPath, XsfOutputPath, serviceURL, wsdlURL);
MakeXSNFromFiles(inputDirectory, "manifest.xsf", outputDirectory, xsnOutputName);
Now the gentle reader has free reins to drive the code above to the helpful utility.
Converting the script to managed code would be a good exercise as well.
The Microsoft Knowledge Base is an amazing source of content and "How To" type articles, not just a place to go when you think you're seeing a bug.
Here's one such "How To" article - how to put an image on a Button control:
And check out the InfoPath 2003 Support Center:
Also, just a reminder - if you have a question about InfoPath (using it, developing with it, etc) a good to get support is to use the newsgroup microsoft.public.infopath (or try the web interface). The InfoPath team will try and respond to questions posted to the blog comments, but you're more likely to get a quick answer from someone on the product or support team, or another member of the community - like our awesome MVPs - by using the newsgroup.
Part 4 of 5: Repacking the XSN
For packing algorithm we will use another useful utility from the Cabinet SDK which called “makecab.exe”. It can be found in the same place where extract.exe lives.
This utility needs some data description file that we will build automatically from the XSF file.
var MakecabExeLocation = "%SystemRoot%\\SYSTEM32";
var MakecabExe = Combine(MakecabExeLocation, "makecab.exe");
function SaveToFile(data, filePath)
var TextStream = Fso.OpenTextFile (filePath, 2);
var DDF = "";
DDF += ".Set DiskDirectoryTemplate=\r\n";
DDF += ".Set CabinetNameTemplate='"
+ Combine(outDir, xsnName) + "'\r\n";
DDF += QuoteStr(Combine(inputDirectory, xsfName)) + "\r\n";
var Filelist = Dom.selectNodes("//xsf:files/xsf:file/@name");
for (var i=0; i<Filelist.length; i++)
DDF += QuoteStr(Combine(inputDirectory, Filelist(i).text))
var DDFPath = Combine(outputDirectory, "makecab.ddf");
+ " /v1 /f " + QuoteStr(DDFPath)
+ " /L " + QuoteStr(outputDirectory), true);
In the last fifth part of the discussion we will come up with the final function.
A few customers have run into an unspecified error when attempting to add service pack features to an RTM form template when using the InfoPath SP1 Preview Release design mode. For anyone who has created a form template outside of InfoPath or added/changed the schemas for a form template by hand this might be an interesting read.
There is a section in the XSF called the documentSchemas section that is used to define all the namespaces and their corresponding XSD schema for the form template. Here is the documentSchemas element InfoPath creates for a form template that uses two namespaces “http://root” and “http://imported”, each with its own schema:
<xsf:documentSchemas> <xsf:documentSchema rootSchema="yes" location="http://root root.xsd"></xsf:documentSchema> <xsf:documentSchema location="http://imported imported.xsd"></xsf:documentSchema></xsf:documentSchemas>
Note that in this case, the root element of the form template comes from root.xsd and its documentSchema entry has an attribute “rootSchema” with a value of “yes”. The documentSchemas section should contain an entry for every namespace that is used in the main data source for the form template; herein lays the problem. The InfoPath team has seen a number of form templates where schemas were added outside of InfoPath but the documentSchemas section was not updated accordingly. Depending on whether you are the glass half empty or half full type of person, the RTM version of InfoPath didn’t mind this but the SP1 Preview Release does.
That should suffice to explain the issue; where does that leave you?
With all that said there is some pretty good news – with the SP1 Preview Release you can now provide an updated schema to InfoPath and we will update the form template accordingly. This will be the topic of another blog entry soon!