NiXPS
Wednesday, October 17, 2007
  Using NiXPS Library from VB.NET
We have chosen to develop our NiXPS Library in C++ and one of the nice advantages of this unmanaged language, is that it allows porting to virtually every OS and development platform.

We distribute our NiXPS library on Windows as a DLL with a strict C interface - on top of that we supply the C headers, but also a documented C++ object model which facilitates working with the library if you develop in C++.

If you're working in a productive managed language such as VB.NET, you can also take advantage of the DLL, and this article gives a demonstration to get you going.

As an example we are going to develop an VB.NET app that uses our DLL to merge two XPS files into one single XPS file.

What you need:

Here goes:

As said, our NiXPS Library has a strict C interface. You can find this C api at the beginning of every header file, fi. this is the beginning of NOPackage.h - the header that contains all calls related to working with XPS packages:

extern "C"
{
DLLIMPORTEXPORT NOPackageHandler NOPackage_create(NCommon::UInt32 pCreateEmptyDoc, NCommon::UTF8Char *pName);
DLLIMPORTEXPORT void NOPackage_destroyPackage(NOPackageHandler* pPackage);
DLLIMPORTEXPORT NOPackageHandler NOPackage_readPackageFromFile(NCommon::UTF8Char *pFilename);
DLLIMPORTEXPORT void NOPackage_writePackageToFile(NOPackageHandler* pPackage, NCommon::UTF8Char *pFilename);
DLLIMPORTEXPORT void NOPackage_save(NOPackageHandler* pPackage);
DLLIMPORTEXPORT void NOPackage_getFilename(NOPackageHandler* pPackage, NOStringHandler* pString);
DLLIMPORTEXPORT void NOPackage_setFilename(NOPackageHandler* pPackage, NCommon::UTF8Char* pString);
DLLIMPORTEXPORT NCommon::UInt32 NOPackage_hasFilename(NOPackageHandler* pPackage);
DLLIMPORTEXPORT NCommon::UInt32 NOPackage_getDirty(NOPackageHandler* pPackage);
DLLIMPORTEXPORT NCommon::UInt32 NOPackage_hasCoreProperties(NOPackageHandler* pPackage);
DLLIMPORTEXPORT NOCorePropertiesHandler NOPackage_getCoreProperties(NOPackageHandler* pPackage);
DLLIMPORTEXPORT NOCorePropertiesHandler NOPackage_createCoreProperties(NOPackageHandler* pPackage);
DLLIMPORTEXPORT NCommon::UInt32 NOPackage_getNumberOfDocuments(NOPackageHandler* pPackage);
DLLIMPORTEXPORT NODocumentHandler NOPackage_getDocument(NOPackageHandler* pPackage, NCommon::UInt32 pNum);
DLLIMPORTEXPORT void NOPackage_addDocument(NOPackageHandler* pPackage, NODocumentHandler pDoc, NOProgressReporterHandler pReporter);
DLLIMPORTEXPORT NCommon::UInt32 NOPackage_getDocumentNumberOf(NOPackageHandler* pPackage, NODocumentHandler pDoc);
DLLIMPORTEXPORT NCommon::UInt32 NOPackage_hasThumbnail(NOPackageHandler* pPackage);
DLLIMPORTEXPORT NOThumbnailHandler NOPackage_getThumbnail(NOPackageHandler* pPackage);
DLLIMPORTEXPORT NCommon::UInt32 NOPackage_getNumberOfPages(NOPackageHandler* pPackage);
}

A lot of functions, but for this example we only need the following:

DLLIMPORTEXPORT NOPackageHandler NOPackage_create(NCommon::UInt32 pCreateEmptyDoc, NCommon::UTF8Char *pName);
DLLIMPORTEXPORT void NOPackage_destroyPackage(NOPackageHandler* pPackage);
DLLIMPORTEXPORT NOPackageHandler NOPackage_readPackageFromFile(NCommon::UTF8Char *pFilename);
DLLIMPORTEXPORT void NOPackage_writePackageToFile(NOPackageHandler* pPackage, NCommon::UTF8Char *pFilename);
DLLIMPORTEXPORT NODocumentHandler NOPackage_getDocument(NOPackageHandler* pPackage, NCommon::UInt32 pNum);
DLLIMPORTEXPORT void NOPackage_addDocument(NOPackageHandler* pPackage, NODocumentHandler pDoc, NOProgressReporterHandler pReporter);

Key here is getting access to these calls from our VB.NET program, we do this by 'Declare'-ing these calls. Also to be able to pass handlers back and forth between the VB.NET code and our DLL, we need to redefine the NOHandler and NOProgressReporterHandler in our VB.NET program. So let's start writing our VB.NET program:

Imports System.Runtime.InteropServices
Imports System.Text

Module Module1
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure Handler
Public mPackage As Integer
Public mID As Short
Public mType As Integer
Public mError As Integer
End Structure

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure ProgressReporterHandler
Public mFunction As Integer
Public mHandler As Integer
End Structure

' Package functions we need
Declare Function NOPackage_readPackageFromFile Lib "NiXPSAccess_D.dll" (ByVal pFilename As String) As Handler
Declare Sub NOPackage_destroyPackage Lib "NiXPSAccess_D.dll" (ByRef pPackage As Handler)
Declare Sub NOPackage_writePackageToFile Lib "NiXPSAccess_D.dll" (ByRef pPackage As Handler, ByVal pFilename As String)
Declare Function NOPackage_create Lib "NiXPSAccess_D.dll" (ByVal pCreateEmptyDoc As Integer, ByVal pFilename As String) As Handler
Declare Sub NOPackage_addDocument Lib "NiXPSAccess_D.dll" (ByRef pPackage As Handler, ByVal pDocument As Handler, ByVal pReporter As ProgressReporterHandler)
Declare Function NOPackage_getDocument Lib "NiXPSAccess_D.dll" (ByRef pPackage As Handler, ByVal pNum As Integer) As Handler

Ok - that's maybe much in one go, let me go over this;

We use the 'StructLayout' magic to ensure that our structure has the same layout as what we expect in the DLL.

The 'Declare' (for functions that return something) and 'Sub' (for void functions) lines are really just the 6 functions described earlier, we declare these as being part from the 'NiXPSAccess_D.dll', and made sure the parameter list is in accordance with the DLL api.
Please note that I use the Debug build of the library (NiXPSAccess_D.dll), you should use the Release build (NiXPSAccess.dll) in production software.


Next, we write the routine that performs the merge:

Sub Main()
Dim lFileHandler, lFileOutHandler As Handler
Dim lDoc As Handler
Dim lProgress As ProgressReporterHandler
Dim lFile1 As String = "interface.xps"
Dim lFile2 As String = "Office2007.xps"
Dim lFileOut As String = "out.xps"

lProgress.mFunction = 0
lProgress.mHandler = 0

' create a new XPS file (package) which contains all the documents
lFileOutHandler = NOPackage_create(0, lFileOut)

' Open lFile1, get the first document, and insert it in the output document, close again
lFileHandler = NOPackage_readPackageFromFile(lFile1)
lDoc = NOPackage_getDocument(lFileHandler, 0)
NOPackage_addDocument(lFileOutHandler, lDoc, lProgress)
NOPackage_destroyPackage(lFileHandler)

' Same procedure for lFile2
lFileHandler = NOPackage_readPackageFromFile(lFile2)
lDoc = NOPackage_getDocument(lFileHandler, 0)
NOPackage_addDocument(lFileOutHandler, lDoc, lProgress)
NOPackage_destroyPackage(lFileHandler)

' write out the resulting XPS doc, and clean-up
NOPackage_writePackageToFile(lFileOutHandler, lFileOut)
NOPackage_destroyPackage(lFileOutHandler)
End Sub

We get handlers to the input files (File1 & File2), get a handler to the first document in those XPS files, and add that to our output file (FileOut). And of course clean everything up with destroy calls.

Please note that this code assumes all testfiles are located in the working directory, and also that NiXPSAccess_D.dll is copied to the working dir.

When you run this VB.NET app, you'll get a resulting XPS file that contains the two input files. Using the NiXPS Library from VB.NET!
 
Comments: Post a Comment

Subscribe to Post Comments [Atom]





<< Home

Archives
September 2006 / October 2006 / November 2006 / December 2006 / January 2007 / February 2007 / March 2007 / April 2007 / May 2007 / June 2007 / July 2007 / August 2007 / September 2007 / October 2007 / November 2007 / December 2007 / January 2008 / February 2008 / March 2008 / April 2008 / May 2008 / June 2008 / July 2008 / August 2008 / September 2008 / October 2008 / November 2008 / December 2008 / January 2009 / February 2009 / March 2009 / April 2009 / May 2009 / June 2009 / July 2009 / August 2009 / September 2009 / October 2009 / November 2009 / December 2009 / January 2010 / February 2010 / March 2010 / April 2010 / May 2010 / June 2010 / July 2010 / September 2010 / October 2010 / November 2010 / January 2011 /

NiXPS home
XPS info from the creators
    follow me on Twitter
    Add to Technorati Favorites

    Subscribe to
    Posts [Atom]