Have you ever tried to get the edit time from the IManDocument or NRTDocument objects within Autonomy WorkSite?

There’s the AccessTime property which returns the date plus time, but the EditDate property is just the date, and the time part is missing (set to 12:00am). So how do you get the date and time?

Turns out you need to use the GetAttributeValueByID method instead, which exposes both the EditDate and EditTime values, so you can just add them together to get the full DateTime value.

wsDocument.GetAttributeValueByID(imProfileAttributeID.imProfileEditTime) + wsDocument.GetAttributeValueByID(imProfileAttributeID.imProfileEditDate)

It’s easy when you know how. Just annoying that they can’t make it easier by exposing a single property directly on the object. Maybe in WorkSite 9.0 perhaps? ;-)

Usually the cause of documents being slow to open in Word is when the attached template is missing – especially when the template is located on a network. Turns out with Word 2010 there can be another reason.

We had a client where some documents were taking between 25 and 30 seconds to open, but only for some users. Word displayed Validating. Press Esc to Cancel in the status bar, but pressing Escape didn’t help.

A bit of research about what the validation process does led me to this article http://blogs.technet.com/b/office2010/archive/2009/12/16/office-2010-file-validation.aspx.

I then found that disabling the validation process by setting the following registry value made the documents open instantly.

[HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Word\Security\FileValidation]
“EnableOnLoad”=dword:00000000

Interestingly the offending documents appear in the list contained in the HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Word\Security\FileValidation\FailedFiles key, so there is something up with them, but we won’t go into that.

Now the other point the article made was that the process only runs on untrusted documents. This turned out to be the key. I re-enabled validation, and added the path to where the attached template was located as a trusted location, and voila, the document opened quickly.

In the end the problem turned out to be a group of users who weren’t getting their Workgroup Template path set correctly, so therefore the network templates were not being trusted.

I’m spending a lot of time in issues lists at the moment, and so many issues are very poorly logged, with no details or steps on how to replicate the problem. Well that’s where the Problem Steps Recorder in Windows 7 comes in very handy.

Get the users to type in PSR into the search box in the Start Menu and hit enter – this will run the Problem Steps Recorder.

Now all they need to do is hit the record button, go through the steps to replicate the problem, hit stop, save the zip file and then email it to you. Simple. And you get a detailed log of what they did, including screenshots so you can see exactly what happened. Much easier to debug your issues now!

Occasionally we come across issues when moving databases from one SQL server to another.  One of the most tricky situations is when you cannot get access to the applications configuration settings for the database you are required to move.

This can be for various reasons, like forgotten passwords, poor application design or where the configuration settings are hard coded into the application itself.

For situations like these you need to think outside the box, especially if there are time constraints involved.

There is a little known tool that comes with Windows called the SQL Server Client Network Utility.  One of the handy things this tool allows you to do is register SQL server instances as aliases.

Therefore you can force all SQL traffic for a particular SQL server instance to another SQL server instance for the server hosting the application.

Please note, I think this tool should only be used only as a last resort when you cannot configure the application through the normal method.

To configure a SQL server instance as an alias, please follow the steps below:

    1. Log onto the server hosting the application as an administrator
    2. Stop any relevant services
    3. Start > Run > cliconfg
    4. Click on the Alias Tab > Click Add

    1. Under Server alias enter the old SQL server instance
    2. Under Server name enter the new SQL server instance
    3. Uncheck Dynamically determine port and enter port 1433 (or an appropriate SQL port if changed from standard)
    4. Click OK

The alias screen should then look similar to the following.  

  1. Click Apply>Click OK
  2. Start any appropriate services
  3. Test the application that it is using the new SQL server via the activity monitor

I experienced an interesting (or should that be frustrating) problem recently during an Office 2010 migration.

We have some code in Word that saves the current document into Autonomy WorkSite. The code works by doing a Save As of the current document to a temporary file, and then saving the document again to free up the first file, which is then imported or checked-in into WorkSite, all pretty standard stuff.

The code has been working fine in 2010 until we changed the default document format for Word from DOCX to DOC. As soon as we changed the document format, Word continues to hold both documents open, and therefore the import/check-in process for WorkSite fails with a “The process cannot access the file because it is being used by another process” error (the error number is -2147221472)

You can easily replicate the issue with the following VBA code which saves the current active document to two different temp files, and then tries to delete the first file:

Sub SaveAsDemo()
ActiveDocument.SaveAs2(Environ(“TEMP”) & “\TestDoc1.doc”)
ActiveDocument.SaveAs2(Environ(“TEMP”) & “\TestDoc2.doc”)
Kill(Environ(“TEMP”) & “\TestDoc1.doc”)
End Sub

If you have the “Save files in this format” setting set to Word Document (*.docx), the code will run fine. Now change the setting to Word 97 – 2003 Document (*.doc) and run the code, and you’ll get a Run-time Error (70), Permission denied. If you look in the temp directory, you’ll see both files are still open (they have corresponding Word temp files)

So how do you get around this “undocumented feature”?

I found a couple of blog posts that mentioned that it’s just a matter of timing, and a pause would fix this issue. In my testing, this didn’t work (since it didn’t work when I just step through the code)

What I did find that worked was just doing it all twice! So the following code works a treat:

Sub SaveAsDemo()
ActiveDocument.SaveAs2(Environ(“TEMP”) & “\TestDoc1.doc”)
ActiveDocument.SaveAs2(Environ(“TEMP”) & “\TestDoc2.doc”)
ActiveDocument.SaveAs2(Environ(“TEMP”) & “\TestDoc1.doc”)
ActiveDocument.SaveAs2(Environ(“TEMP”) & “\TestDoc2.doc”)
Kill(Environ(“TEMP”) & “\TestDoc1.doc”)
End Sub

No idea why this works – it just does!

So in the production code I added a check to see what the default save format was, and did an extra lot of saves if it was set to Doc.

Sub SaveAsDemo()
ActiveDocument.SaveAs2(Environ(“TEMP”) & “\TestDoc1.doc”)
ActiveDocument.SaveAs2(Environ(“TEMP”) & “\TestDoc2.doc”)
If Application.DefaultSaveFormat = “Doc” Then
            ActiveDocument.SaveAs2(Environ(“TEMP”) & “\TestDoc1.doc”)
ActiveDocument.SaveAs2(Environ(“TEMP”) & “\TestDoc2.doc”)
End If
        Kill(Environ(“TEMP”) & “\TestDoc1.doc”)
End Sub

And there you have it, a dodgy workaround around for a very dodgy problem. Hopefully it’ll get fixed one day soon (but where would the fun in that be!)

Autonomy recently released WorkSite 8.5 SP3 Update 1, which includes updated integration for Office 2007 and 2010. The integration, so far, is much better than the old version.

The only problem is that it kills all your code that used the old iManOXP.dll (iManO2K.iManageExtensibility) but don’t worry, it’s easy to update your code to get it running.

I’ll walk through updating a Word template (VBA), but the same general principles apply to VB6 or VB.Net.

  • Firstly, open your custom Word template, go to the VBA editor and remove the reference to “WorkSite Office2000 Integration”. Add a new reference to “WorkSite Integration Interfaces Library”.
  • Now change all your objects that use the old iManO2K.iManageExtensibilty object and point instead to WorkSiteAddinInterfaces.iManageExtensibility (you could just do a search through the entire project for iManO2K.iMan and replace with WorkSiteAddinInterfaces.iMan to save hunting around)

For example:

Private WithEvents objWorkSite As iManO2K.iManageExtensibility

becomes

Private WithEvents objWorkSite As WorkSiteAddinInterfaces.iManageExtensibility

  • Then change the name used for the WorkSite COMAddin from either “iManO2K.AddinForWord2000” if you’re coming from Word 2003, or “oUTR02K.Connect” for Word 2007/2010 to “WorkSiteOffice2007Addins.Connect”.

For example:

Set objWorkSite = Application.COMAddIns(“iManO2K.AddinForWord2000”).Object

or

Set objWorkSite = Application.COMAddIns(“oUTR02K.Connect”).Object

becomes

Set objWorkSite = Application.COMAddIns(“WorkSiteOffice2007Addins.Connect”).Object

  • Next you need to update the parameters of any of the events that use the type Object, and change them to use the type Variant instead.

For example:

Private Sub objWorkSite_DocumentBeforePrint(ByVal Doc As Object, IgnoreIManagePrint As Boolean, Cancel As Boolean)

becomes

Private Sub objWorkSite_DocumentBeforePrint(ByVal Doc As Variant, IgnoreIManagePrint As Boolean, Cancel As Boolean)

You shouldn’t need to change the code within any of those subs.

And that should be it – with any luck your addins and templates will start working again. I guess I better get cracking updating all our other apps, addins and code. Keep you posted on what else I discover.

 

Update on Monday, July 4, 2011 at 10:16PM

Turns out that the members of the ConnectionMode enumerated type have changed slightly – they’ve been prefixed with ConnectionMode_.

So if you’re checking the connection mode of WorkSite, then you’d change the code from

If objWorkSite.CurrentMode = nrindeterminatemode Then objWorkSite.Connect

to

If objWorkSite.CurrentMode = ConnectionMode_nrindeterminatemode Then objWorkSite.Connect

 

Update on Wednesday, June 27, 2012 at 4:18PM

As of WorkSite 8.5 SP3 Update 5, the Office Integration is backwards compatible, so there’s no need to do any of this updating, your code should now just work. So forget about the other versions and go straight to Update 5 and newer.

Often we have clients who want Word to open without an initial document being displayed. This is usually because they don’t want the initial document based on the normal template. Doing a winword /a is no good, as it kills off all the other add-ins – so your DMS is usually killed off in the process, let alone all your other add-ins.

Life was simple in the days of Word 2003 – to get rid of the initial you could just do an ActiveDocument.Close in an AutoExec sub and you’re away. But that doesn’t work in 2010 as there no active document yet during the AutoExec.

So how did we get around it? Well it turns out we had to use the Document_Change event instead.

Within one of your startup templates, add a new Class object, call it AppEvents and insert the following code:

Option Explicit

Private WithEvents objApplication As Word.Application

Private Sub Class_Initialize()
objApplication = Word.Application
End Sub

Private Sub objApplication_DocumentChange()
On Error Resume Next
        If StartingUp Then
            If Documents.Count > 0 Then
                ‘ Close any new document created using normal.dot/normal.dotm
                If ActiveDocument.Name = ActiveDocument.Fullname And _
InStr(1, ActiveDocument.AttachedTemplate, “Normal.dot”, vbTextCompare) Then
                    ActiveDocument.Close(wdDoNotSaveChanges)
StartingUp = False
                    Exit Sub
                End If
            End If
        End If
    End Sub

Now create a new module, call it AutoMacros (or anything else you like) and add the following code:

Option Explicit

Dim oAppEvents As AppEvents
Dim StartingUp As Boolean

Sub AutoExec()
StartingUp = True
        oAppEvents = New AppEvents
End Sub

So why add the StartingUp variable? Well if we don’t have it, then any new document you try to create based on Normal will automatically close. Whilst that doesn’t sound too bad in a lot of cases, it has one bad side effect – you can’t do a compare into a new document, as the new document that gets created is always based on Normal. There are probably a few other possible bad side effects too – but we didn’t bother looking any further after that one!

Have you had a play with watermarks in Word 2007 or 2010? It looks great – a nice little graphical drop down so you can see what you’re inserting, the ability to create custom watermarks, what’s not to like?

For simple documents, this works really well. The problem is once you come to a document with multiple sections, or with different page headers. For example, set up a document with a few sections, and make sure the “Link To Previous” setting is off. Now go to any section, and insert a new watermark. See – it looks good. But now look at the other sections – they don’t have the watermark. That’s not too big a deal – so you then go to the other sections and add the watermark again. That looks good too, but now go look at the first section you put the watermark on, and it’s gone! The process removes all watermarks from all other sections, and only inserts the watermark on the new section. Now this is getting dangerous when it comes to legal documents. You get the same issues when you use different first page footers within a section.

It’s very easy to create your own custom code for inserting and deleting bookmarks, and even use the existing built-in bookmarks in 2007/2010. Turns out the bookmarks you see are just auto-text entries, and it’s the name of the entries you see in the list. For example the Draft watermarks are auto-text entries “DRAFT 1” and “DRAFT 2”. So you just need some code to insert the appropriate auto-text into the document, so look no further…

Sub InsertWatermark(ByVal WatermarkAutoTextName As String)
  If Documents.Count > 0 Then
  Application.ScreenUpdating = False
‘ Store the current location in document
ActiveDocument.Bookmarks.Add(Range:=Selection.Range, Name:=“WatermarkTempBookmark”)
‘ Load all building block templates
Templates.LoadBuildingBlocks()
‘ Find autotext entry first
Dim oTemplate As Template
Dim oAutoTextEntry As AutoTextEntry
Dim EntryFound As Boolean
Dim oSection As Section
Dim oRange As Range
EntryFound = False
For Each oTemplate In Templates
For Each oAutoTextEntry In oTemplate.AutoTextEntries
If LCase(oAutoTextEntry.Name) = LCase(WatermarkAutoTextName) Then
‘ Insert autotext in all headers in all sections of document
        For Each oSection In ActiveDocument.Sections
oRange = oSection.Headers(wdHeaderFooterPrimary).Range
oRange.Collapse(wdCollapseStart)
oAutoTextEntry.Insert(rngRange, True)
oRange = oSection.Headers(wdHeaderFooterFirstPage).Range
oRange.Collapse(wdCollapseStart)
oAutoTextEntry.Insert(rngRange, True)
oRange = oSection.Headers(wdHeaderFooterEvenPages).Range
oRange.Collapse(wdCollapseStart)
oAutoTextEntry.Insert(rngRange, True)
Next oSection
EntryFound = True
Exit For
End If
Next oAutoTextEntry
If EntryFound Then Exit For
Next oTemplate
‘ Return to original place in document
If ActiveDocument.Bookmarks.Exists(“WatermarkTempBookmark”) Then
Selection.GoTo(What:=wdGoToBookmark, Name:=“WatermarkTempBookmark”)
ActiveDocument.Bookmarks(“WatermarkTempBookmark”).Delete()
End If
Application.ScreenUpdating = True
End If
End Sub

Now just setup a sub to call the above with the appropriate autotext name, and add a button and callback to call this sub. As an example, the following sub will insert the first DRAFT watermark – “DRAFT 1”.

Sub InsertDraftWatermark()
InsertWatermark(“DRAFT 1”)
End Sub

Now all you need is a routine to remove the watermarks. That’s the easy part. All the watermarks inserted by the default autotexts contain “PowerPlusWaterMarkObject” in the name – so we just need to check the name of the shape objects throughout the document and delete them.

Sub RemoveWatermarks()
‘ Removes all Word 2010 watermarks
On Error Resume Next

  If Documents.Count > 0 Then
Dim WatermarkShape As Shape
‘ Remove from body of document – the normal 2010 option inserts into the body
For Each WatermarkShape In ActiveDocument.Shapes
If InStr(1, WatermarkShape.Name, “PowerPlusWaterMarkObject”, vbTextCompare) = 1 Then
WatermarkShape.Delete()
End If
Next
‘ Remove from headers
Dim oSection As Section
For Each oSection In ActiveDocument.Sections
For Each WatermarkShape In oSection.Headers(wdHeaderFooterPrimary).Shapes
If InStr(1, WatermarkShape.Name, “PowerPlusWaterMarkObject”, vbTextCompare) = 1 Then
WatermarkShape.Delete()
End If
Next
For Each WatermarkShape In oSection.Headers(wdHeaderFooterFirstPage).Shapes
If InStr(1, WatermarkShape.Name, “PowerPlusWaterMarkObject”, vbTextCompare) = 1 Then
WatermarkShape.Delete()
End If
Next
For Each WatermarkShape In oSection.Headers(wdHeaderFooterEvenPages).Shapes
If InStr(1, WatermarkShape.Name, “PowerPlusWaterMarkObject”, vbTextCompare) = 1 Then
WatermarkShape.Delete()
End If
Next
Next oSection
End If
End Sub

So there you have it, code to insert and remove watermarks throughout the entire document, no matter how you setup your sections and headers. The code could probably be done a little better. Also there is the issue of creating custom watermarks. And then there’s the question of getting this functionality into the ribbon. If you need the answers to all those questions (and more) then get in touch with us. You might be surprised what we have hidden up our sleeves (just wish there were some descent cards up there – I still can’t manage a win at poker, or do a card trick that slightly impresses the kids)

 

Update on Monday, February 10, 2014 at 10:32PM

Just to let you all know that this issue has been fixed in Word 2013.

Our hands were tied recently when we had to develop a 32 bit web app due to the reliance on a 3rd party app that was 32 bit only.

We quickly worked out how to get the app running in 32 bit mode in IIS7 just by setting the “Enable 32-Bit Applications” setting within the application pool used for the app.

This worked great until we went to do this on a server running OWA 2010. After setting the application pool to run 32 bit apps, we still got an error:

Service Unavailable

HTTP Error 503. The service is unavailable.

And as an added bonus, the application pool was now stopped. Yippee – I guess that was 5 errors in less than 5 minutes!

A quick look in the Application event log showed the following error:

The Module DLL ‘C:\Program Files\Microsoft\Exchange Server\V14\Bin\kerbauth.dll’ could not be loaded due to a configuration problem. The current configuration only supports loading images built for a x86 processor architecture. The data field contains the error number. To learn more about this issue, including how to troubleshooting this kind of processor architecture mismatch error, see http://go.microsoft.com/fwlink/?LinkId=29349.

The Source was IIS-W3SVC-WP and the Event ID was 2282.

A bit of research pointed us in the direction of setting the kerbauth.dll to be 64 bit only in the applicationHost.config file for IIS (located in C:\Windows\System32\inetsrv\config). So we stopped IIS and edited the file. In the globalModules section, we found the line for kerbauth, and added the precondition=”bitness64” attribute as follows:

<add name=kerbauthimage=C:\Program Files\Microsoft\Exchange Server\V14\Bin\kerbauth.dllpreCondition=bitness64 />

We restarted IIS (and also the app pool!) and now the app showed the following error:

HTTP Error 500.0 – Internal Server Error

Calling LoadLibraryEx on ISAPI filter “C:\Program Files\Microsoft\Exchange Server\V14\ClientAccess\owa\auth\owaauth.dll” failed

So we applied the same theory again, and again for each dll that caused an issue – luckily for us there were only two – owaauth.dll and AirFilter.dll. Both were listed in the <isapiFilters> section of the applicationHost.config file:

<filter name=Exchange OWA Cookie Authentication ISAPI Filterpath=C:\Program Files\Microsoft\Exchange Server\V14\ClientAccess\owa\auth\owaauth.dllenabled=true preCondition=bitness64 />

<filter name=Exchange ActiveSync ISAPI Filterpath=C:\Program Files\Microsoft\Exchange Server\V14\ClientAccess\sync\bin\AirFilter.dllenabled=true preCondition=bitness64/>

We restarted IIS again and voila – a happy application, and OWA still worked to boot. Who says you need to run 32 bit apps on a separate server! Happy days…

Now I’ve just gotta get that song out of my head… “taking care of bitness and working overtime…” ;-)

Recently I was dealing with an interesting issue regarding the SplendidCRM marketing system.

Whenever the client sent emails out via the CRM, it would not de-duplicate the emails.  Therefore, if the recipient was on two target lists in the campaign they would receive the email twice. Not ideal really.

After much searching I could not find any settings in the CRM which offer the de-duplication of emails, so I decided to come up with my own solution.

After downloading the latest SplendidCRM community edition which comes with all the source code including SQL stored procedures, I dug through the code and found that the send email function was using the spCAMPAIGNS_SendEmail stored procedure.

I decided to update this stored procedure so that it marks any duplicate email as deleted when the campaign is sent, and now the recipients only receive the email once. I found this to be the most efficient and cost effective solution for our client.

Please click here to download the updated SQL query for the stored procedure.

Please note: Should you apply this updated stored procedure, please be aware that it supplied as is and applied at your own risk.  You should ensure adequate backups are in place and that you apply any appropriate testing for your environment.

© Copyright - DocAssist 2022