Context is Hindi when printing line numbers in Word 2007

[This post accompanies a question posted here: http://superuser.com/questions/90665/context-is-hindi-when-printing-line-numbers-in-word-2007]

I’m trying to print a Word 2007 document with Line Numbering turned on, and in Word the document looks fine but when I print the document, the line numbers appear in Hindi script.

On screen:
Printed:

I tried deleting my Normal template and allowing Word to create a new one, and testing using that, with no change. I also tried different printers.

The problem goes away if I choose Arabic instead of Context under Word Options -> Advanced -> Show Document Content / Numeral:

However, I would like to keep the setting as Context. The question is, why is the default context of my document Hindi script?

Posted in Technology | Tagged , , | 2 Responses

Registry settings to add Uninstall as a shell option for VSTO manifest files

vsto logo

Visual Studio Tools for the Microsoft Office System (VSTO)

I have been working on some VSTO add-ins and on deploying them, and have something to share that I didn’t find anywhere else.

First of all, let me just say that despite certain hurdles, deploying using ClickOnce has been a very pleasant experience. After following some tutorials on making an MSI, we eventually ended up simply deploying the few needed registry entries to all users, which take care of installing and trusting each add-in. Then, once the add-in is installed, it takes care of updating itself every so often.

Unfortunately, during the period of figuring this out a few users got an older version then a newer version with a new signing certificate, which is I suspect the reason why they get the following error message:

Specified argument was out of the range of valid values.
Parameter name: entryValue

Exception Text
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: entryValue
  at Microsoft.VisualStudio.Tools.Applications.Deployment.RegistryStore.Retrieve(String entryName, Object entryValue, CompareDelegate compareMethod)
  at Microsoft.VisualStudio.Tools.Applications.Deployment.MetadataStore.UpdateLastCheckedTime(String subscriptionID, DateTime newLastCheckedTime)
  at Microsoft.VisualStudio.Tools.Applications.Deployment.ClickOnceAddInDeploymentManager.InstallAddIn()

There is some discussion of this error here.

Anyway, I tried removing the folder: C:\Documents and Settings\%username%\Local Settings\Apps\2.0 which causes the add-ins to re-install themselves, but that didn’t fix the problem.

The second solution I tried worked, which was to uninstall the add-in and then re-install it again. One way to uninstall is to do so via Add/Remove programs (still using XP lingo), but I came across another way from this blog post at ChristophDotNet: simply run this command:

C:\Program Files\Common Files\Microsoft Shared\VSTO\9.0\VSTOinstaller.exe
     /uninstall <name-of-manifest-file.vsto>

I find this way much easier than waiting for the Add/Remove dialog to populate (takes a while on my bloated box). You can read more about the VSTOInstaller on MSDN.

After using this technique for a while, I realized one thing – to install an MSI file, you right-click on it and choose Install, and you can also right-click to Uninstall. However, with .vsto files, you can only install. Why not add the uninstall capability right there using a shell command? And now that I knew what the command was, it was trivial. First, to find out where in the registry the open command is defined, I came across this post on Nikhil’s blog. Then, I simply added an uninstall component to it:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\bootstrap.vsto.1\shell\uninstall]
@="Uninstall"

[HKEY_CLASSES_ROOT\bootstrap.vsto.1\shell\uninstall\command]
@="\"C:\\Program Files\\Common Files\\microsoft shared\\VSTO\\9.0\\VSTOInstaller.exe\" /uninstall \"%1\""

Put that in a .reg file and run it, and you’ll be able to uninstall VSTO add-ins with ease!

This post applies to VSTO version 3.0.

Posted in Technology | Tagged , , , , | 6 Responses

Recursive Active Directory group membership using System.DirectoryServices in .NET 3.5

When coding for an organization that uses Active Directory, you will eventually come across the business case for using groups within groups, i.e. a  user is part of say, the HR-Administration group, and that group is itself a member of the HR-Department group. You may then need to secure your application to only allow members of HR-Department to access certain functionality within it,  and so you need an IsUserInGroup function, but one that looks recursively at groups that are members of the requested group.

Over the years I’ve had to come up with such a function in various technologies: VB6 using ADSI, PHP using the php_ldap extension, and System.DirectoryServices in .NET 2.0 with a custom function for recursing.

A few weeks ago I was using .NET 3.5 and decided to look around again to see if there was an easy alternative. It seems the 3.5 release comes with a revamped System.DirectoryServices which makes things much easier for common use cases. And although there is no function to achieve what we need, there is one that helps us do it: group.GetMembers(true).  The parameter when set to true triggers a recursive search of all groups that are members of the current group, and grabs their members too. So it becomes trivial to achieve an IsUserInGroup function:

using System.DirectoryServices.AccountManagement;

...

public static bool IsUserInGroup(string username, string groupname)
{
    var foundUser = false;
    using (var context = new PrincipalContext(ContextType.Domain, "microsoft.com"))
    using (var group = GroupPrincipal.FindByIdentity(context, groupname))
    {
        if (group == null)
        {
            throw new ArgumentException("Group could not be found: " + groupname);
        }

        // GetMembers(true) is recursive (groups-within-groups)
        foreach (var member in group.GetMembers(true))
        {
            if (member.SamAccountName.Equals(username))
            {
                foundUser = true;
                break;
            }
        }
    }
    return foundUser;
}
Posted in Technology | Comments closed

Now using Windows 7 Release Candidate

I recently installed Windows 7 – which is currently being developed and will be released in the next few months – on my home computer. I had heard good things about it, and was keen to test out this latest preview version. It replaced my 6-month old XP installation. Here are some screenshots of things that stood out to me in the new Windows.

windows7

The installation went very smoothly, took somewhere around 30 minutes (had to go away from the computer and come back so couldn’t tell exactly how long it took). The first thing I noticed, it installed drivers for my video card, then detected the monitors connected and figured out their maximum resolutions, and set Windows to those resolutions as well as the side-by-side layout of the monitors. Everything worked perfectly! Quite impressed. To change these settings further, the interface looks like this:

display

Another change was with themes. They now seem more well integrated, with sound schemes and lists of wallpapers to go along with each theme. When you click on the theme it changes to it there and then, and very quickly. You also hear a preview sound from that theme, which makes for a great choosing experience:

themes

The quick launch area next to the Start menu has gotten a revamp – mouse over also shows a preview of all the windows of that type that are open:

quick-launch

One of the new features is Libraries, which are special folders that show files from different sources. You get to define which paths these files come from, but they all show together in one convenient view:

librariesOf course, the icons themselves are new, and rendered very beautifully – I just noticed the Control Panel icon which looks very nice:

iconsStarting to test out other features – the desktop Gadgets are there just like Vista, but worked really well and fast for me:

gadgets

There is a new item in the Control Panel called Devices and Printers. This seems to provide a much more convenient location to see your installed hardware and configure them. Each icon represents a type of device, and they all have their own context menus of actions:

devices

Thats about it for what I noticed in the first few minutes. Microsoft Paint also got an interface lift:

paint

So far the experience has been quite pleasant – very responsive and fast, sleek polished UI, high availability of drivers and installation seems very well automated, and stable – haven’t had any crashes yet.

If you would like to try it out for yourself, here’s the link:

win7_subhero_downloadrc
Posted in Technology | Tagged , | Leave a comment

Prezi for stunning presentations

Prezi logoSome days ago I was introduced to this website: prezi.com, for creating presentations online. The editor uses Flash and is entirely online, and you can upload pictures, videos and other flash animations to it.

Anyway, I had signed up for their closed beta and earlier today I received a login. The timing was quite fortuitous as I had a presentation scheduled for later in the day and decided to re-do the PowerPoint slides on Prezi. It was quite quick to do, and I exported some of the elements from the PowerPoint presentation and uploaded them to Prezi – took maybe two or three hours in total.

Here’s the resulting creation:

Prezi screenshot - Windows Workflow Foundation

Click through to open and view it. When viewing, use the arrows in the bottom right corner to navigate:

Prezi - Navigation

Or you can simply click on an object to zoom in on it.

 

The editor is also quite neat – there is a round menu system:

Prezi menu

And when you click on a shape you can move/scale/rotate it with this round control:

Prezi - Round menu

Very innovative interface! This promises to be a popular online resource. Visit their site and sign up, and you can play around with the demos.

Posted in Technology | Tagged , , , , , | 2 Responses

Changing Printer settings using the Windows API

I have been working on a program that prints any document you provide to it, as long as there is an application installed on your computer that can handle that document. One issue that we have with it is Duplex printing, i.e. getting the documents to print double-sided. This is a story of how we solved this issue.

The way this problem used to be handled is to install two printers, one set to always print single-sided and another to always print double-sided. Actually a third would be needed to allow the user to keep custom settings for their own preferences. The application would then switch the default printer in Windows to the appropriate printer, depending on the user choice and duplex requirement. We needed to keep the same user interface, but would have liked to have been able to use just the one printer and programmatically set duplex on or off. In this case I was using Visual Basic 6 although it could just as well have been in C#. Neither VB6 nor the .NET framework seem to provide an in-built way to change the Windows printer settings, they let you change the settings for the current session but not persisted.

I found some examples for how to do change a printer’s settings using calls to the Windows API:

How to set duplex printing for Microsoft Word Automation clients
http://support.microsoft.com/kb/828638

Controlling the Printer from Word VBA
http://pubs.logicalexpressions.com/Pub0009/LPMArticle.asp?ID=116

The examples call WINSPOOL.DRV to set the printer properties. When making these calls, one needs to specify the security level required, and in all the examples I found they would use PRINTER_NORMAL_ACCESS:

Const STANDARD_RIGHTS_REQUIRED = 0xF0000
Const PRINTER_ACCESS_USE = 0x00008
Const PRINTER_NORMAL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_USE)

In my testing, this worked fine on a local printer but when trying to change the settings on a network printer I was getting “access denied” errors. After some investigation, I got an explanation for what was happening. The following two articles provided the needed insight:

If you ask for STANDARD_RIGHTS_REQUIRED, you may as well ask for the moon
http://blogs.msdn.com/oldnewthing/archive/2008/02/27/7912126.aspx

Changing printer settings using C# (also see one of the first comments in the thread)
http://www.codeproject.com/KB/dotnet/NET_Printer_Library.aspx?display=PrintAll

In short, the problem was I didn’t have full administrative access to the network printers in question; I could only change local print preferences. To accomodate this, a lower access level needs to be passed to the function call. Here’s the full range of available levels:

'Access levels for interacting with a device
Const DELETE = &H10000
Const READ_CONTROL = &H20000          ' Read device information
Const WRITE_DAC = &H40000             ' Write Device Access Control info
Const WRITE_OWNER = &H80000           ' Change the object owner
' Combining these for full access to the device
Const STANDARD_RIGHTS_REQUIRED = &HF0000

'Access rights to print servers
Const SERVER_ACCESS_ADMINISTER = &H1
Const SERVER_ACCESS_ENUMERATE = &H2
'Access rights for printers
Const PRINTER_ACCESS_ADMINISTER = &H4
Const PRINTER_ACCESS_USE = &H8

For me the following seemed to work:

' Access which allows you to set duplex on or off
Const PRINTER_NORMAL_ACCESS = (READ_CONTROL Or PRINTER_ACCESS_USE)

This would be useful to know when making calls to other API functions where the security levels need to be taken into account, in a network environment.

Here’s the full code, based on the example provided in the article above. I only tested the SetDuplex function.

Option Explicit

Private Type PRINTER_DEFAULTS
   pDatatype As Long
   pDevmode As Long
   DesiredAccess As Long
End Type

Private Type PRINTER_INFO_2
   pServerName As Long
   pPrinterName As Long
   pShareName As Long
   pPortName As Long
   pDriverName As Long
   pComment As Long
   pLocation As Long
   pDevmode As Long               ' Pointer to DEVMODE
   pSepFile As Long
   pPrintProcessor As Long
   pDatatype As Long
   pParameters As Long
   pSecurityDescriptor As Long    ' Pointer to SECURITY_DESCRIPTOR
   Attributes As Long
   Priority As Long
   DefaultPriority As Long
   StartTime As Long
   UntilTime As Long
   Status As Long
   cJobs As Long
   AveragePPM As Long
End Type

Private Type DEVMODE
   dmDeviceName As String * 32
   dmSpecVersion As Integer
   dmDriverVersion As Integer
   dmSize As Integer
   dmDriverExtra As Integer
   dmFields As Long
   dmOrientation As Integer
   dmPaperSize As Integer
   dmPaperLength As Integer
   dmPaperWidth As Integer
   dmScale As Integer
   dmCopies As Integer
   dmDefaultSource As Integer
   dmPrintQuality As Integer
   dmColor As Integer
   dmDuplex As Integer
   dmYResolution As Integer
   dmTTOption As Integer
   dmCollate As Integer
   dmFormName As String * 32
   dmUnusedPadding As Integer
   dmBitsPerPel As Integer
   dmPelsWidth As Long
   dmPelsHeight As Long
   dmDisplayFlags As Long
   dmDisplayFrequency As Long
   dmICMMethod As Long
   dmICMIntent As Long
   dmMediaType As Long
   dmDitherType As Long
   dmReserved1 As Long
   dmReserved2 As Long
End Type

Private Const DM_ORIENTATION = &H1
Private Const DM_PAPERSIZE = &H2
Private Const DM_PAPERLENGTH = &H4
Private Const DM_PAPERWIDTH = &H8
Private Const DM_DEFAULTSOURCE = &H200
Private Const DM_PRINTQUALITY = &H400
Private Const DM_COLOR = &H800
Private Const DM_DUPLEX = &H1000

Private Const DM_IN_BUFFER = 8
Private Const DM_OUT_BUFFER = 2

Private Const DELETE = &H10000
Private Const READ_CONTROL = &H20000          ' Allowed to read device information
Private Const WRITE_DAC = &H40000             ' Allowed to write device access control info
Private Const WRITE_OWNER = &H80000           ' Allowed to change the object owner
' Combining these for full access to a device  (DELETE + READ_CONTROL + WRITE_DAC + WRITE_OWNER):
Private Const STANDARD_RIGHTS_REQUIRED = &HF0000

Private Const SERVER_ACCESS_ADMINISTER = &H1  ' Access rights to administer print servers.
Private Const SERVER_ACCESS_ENUMERATE = &H2   ' Access rights to enumerate print servers.
Private Const PRINTER_ACCESS_ADMINISTER = &H4 ' Access rights for printers to perform administrative tasks.
Private Const PRINTER_ACCESS_USE = &H8        ' Access rights for printers for general use (printing, querying).

' Access which allows you to set duplex on or off
Private Const PRINTER_NORMAL_ACCESS = (READ_CONTROL Or PRINTER_ACCESS_USE)

Private Const PRINTER_ENUM_CONNECTIONS = &H4
Private Const PRINTER_ENUM_LOCAL = &H2

Private Declare Function ClosePrinter Lib "winspool.drv" _
      (ByVal hPrinter As Long) As Long
Private Declare Function DocumentProperties Lib "winspool.drv" _
      Alias "DocumentPropertiesA" (ByVal hwnd As Long, _
      ByVal hPrinter As Long, ByVal pDeviceName As String, _
      ByVal pDevModeOutput As Long, ByVal pDevModeInput As Long, _
      ByVal fMode As Long) As Long
Private Declare Function GetPrinter Lib "winspool.drv" Alias _
      "GetPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, _
      pPrinter As Byte, ByVal cbBuf As Long, pcbNeeded As Long) As Long
Private Declare Function OpenPrinter Lib "winspool.drv" Alias _
      "OpenPrinterA" (ByVal pPrinterName As String, phPrinter As Long, _
      pDefault As PRINTER_DEFAULTS) As Long
Private Declare Function SetPrinter Lib "winspool.drv" Alias _
      "SetPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, _
      pPrinter As Byte, ByVal Command As Long) As Long
Private Declare Function EnumPrinters Lib "winspool.drv" _
      Alias "EnumPrintersA" _
      (ByVal flags As Long, ByVal name As String, ByVal Level As Long, _
      pPrinterEnum As Long, ByVal cdBuf As Long, pcbNeeded As Long, _
      pcReturned As Long) As Long

Private Declare Function PtrToStr Lib "kernel32" Alias "lstrcpyA" _
      (ByVal RetVal As String, ByVal Ptr As Long) As Long

Private Declare Function StrLen Lib "kernel32" Alias "lstrlenA" _
      (ByVal Ptr As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
      (pDest As Any, pSource As Any, ByVal cbLength As Long)
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Private Declare Function DeviceCapabilities Lib "winspool.drv" _
      Alias "DeviceCapabilitiesA" (ByVal lpDeviceName As String, _
      ByVal lpPort As String, ByVal iIndex As Long, lpOutput As Any, _
      ByVal dev As Long) As Long

Public Sub SetColorMode(ByVal sPrinterName As String, iColorMode As Long)
   SetPrinterProperty sPrinterName, DM_COLOR, iColorMode
End Sub

Public Function GetColorMode(ByVal sPrinterName As String) As Long
  GetColorMode = GetPrinterProperty(sPrinterName, DM_COLOR)
End Function

Public Sub SetDuplex(ByVal sPrinterName As String, iDuplex As Long)
   SetPrinterProperty sPrinterName, DM_DUPLEX, iDuplex
End Sub

Public Function GetDuplex(ByVal sPrinterName As String) As Long
   GetDuplex = GetPrinterProperty(sPrinterName, DM_DUPLEX)
End Function

Public Sub SetPrintQuality(ByVal sPrinterName As String, iQuality As Long)
   SetPrinterProperty sPrinterName, DM_PRINTQUALITY, iQuality
End Sub

Public Function GetPrintQuality(ByVal sPrinterName As String) As Long
   GetPrintQuality = GetPrinterProperty(sPrinterName, DM_PRINTQUALITY)
End Function

Private Function SetPrinterProperty(ByVal sPrinterName As String, ByVal iPropertyType As Long, _
      ByVal iPropertyValue As Long) As Boolean

   'Code adapted from Microsoft KB article Q230743

    Dim hPrinter As Long          'handle for the current printer
    Dim pd As PRINTER_DEFAULTS
    Dim pinfo As PRINTER_INFO_2
    Dim dm As DEVMODE

    Dim yDevModeData() As Byte        'Byte array to hold contents
                                      'of DEVMODE structure
    Dim yPInfoMemory() As Byte        'Byte array to hold contents
                                      'of PRINTER_INFO_2 structure
    Dim iBytesNeeded As Long
    Dim iRet As Long
    Dim iJunk As Long
    Dim iCount As Long
      
    On Error GoTo cleanup

    pd.DesiredAccess = PRINTER_NORMAL_ACCESS
    iRet = OpenPrinter(sPrinterName, hPrinter, pd)
    If (iRet = 0) Or (hPrinter = 0) Then
       'Can't access current printer. Bail out doing nothing
       Exit Function
    End If

    'Get the size of the DEVMODE structure to be loaded
    iRet = DocumentProperties(0, hPrinter, sPrinterName, 0, 0, 0)
    If (iRet < 0) Then
       'Can't access printer properties.
       GoTo cleanup
    End If

    'Make sure the byte array is large enough
    'Some printer drivers lie about the size of the DEVMODE structure they
    'return, so an extra 100 bytes is provided just in case!
    ReDim yDevModeData(0 To iRet + 100) As Byte
      
    'Load the byte array
    iRet = DocumentProperties(0, hPrinter, sPrinterName, _
                VarPtr(yDevModeData(0)), 0, DM_OUT_BUFFER)
    If (iRet < 0) Then
       GoTo cleanup
    End If

    'Copy the byte array into a structure so it can be manipulated
    Call CopyMemory(dm, yDevModeData(0), Len(dm))

    If dm.dmFields And iPropertyType = 0 Then
       'Wanted property not available. Bail out.
       GoTo cleanup
    End If

    'Set the property to the appropriate value
    Select Case iPropertyType
    Case DM_ORIENTATION
       dm.dmOrientation = iPropertyValue
    Case DM_PAPERSIZE
       dm.dmPaperSize = iPropertyValue
    Case DM_PAPERLENGTH
       dm.dmPaperLength = iPropertyValue
    Case DM_PAPERWIDTH
       dm.dmPaperWidth = iPropertyValue
    Case DM_DEFAULTSOURCE
       dm.dmDefaultSource = iPropertyValue
    Case DM_PRINTQUALITY
       dm.dmPrintQuality = iPropertyValue
    Case DM_COLOR
       dm.dmColor = iPropertyValue
    Case DM_DUPLEX
       dm.dmDuplex = iPropertyValue
    End Select
      
    'Load the structure back into the byte array
    Call CopyMemory(yDevModeData(0), dm, Len(dm))

    'Tell the printer about the new property
    iRet = DocumentProperties(0, hPrinter, sPrinterName, _
          VarPtr(yDevModeData(0)), VarPtr(yDevModeData(0)), _
          DM_IN_BUFFER Or DM_OUT_BUFFER)

    If (iRet < 0) Then
       GoTo cleanup
    End If

    'The code above *ought* to be sufficient to set the property
    'correctly. Unfortunately some brands of Postscript printer don't
    'seem to respond correctly. The following code is used to make
    'sure they also respond correctly.
    Call GetPrinter(hPrinter, 2, 0, 0, iBytesNeeded)
    If (iBytesNeeded = 0) Then
       'Couldn't access shared printer settings
       GoTo cleanup
    End If
      
    'Set byte array large enough for PRINTER_INFO_2 structure
    ReDim yPInfoMemory(0 To iBytesNeeded + 100) As Byte

    'Load the PRINTER_INFO_2 structure into byte array
    iRet = GetPrinter(hPrinter, 2, yPInfoMemory(0), iBytesNeeded, iJunk)
    If (iRet = 0) Then
       'Couldn't access shared printer settings
       GoTo cleanup
    End If

    'Copy byte array into the structured type
    Call CopyMemory(pinfo, yPInfoMemory(0), Len(pinfo))

    'Load the DEVMODE structure with byte array containing
    'the new property value
    pinfo.pDevmode = VarPtr(yDevModeData(0))
      
    'Set security descriptor to null
    pinfo.pSecurityDescriptor = 0
     
    'Copy the PRINTER_INFO_2 structure back into byte array
    Call CopyMemory(yPInfoMemory(0), pinfo, Len(pinfo))

    'Send the new details to the printer
    iRet = SetPrinter(hPrinter, 2, yPInfoMemory(0), 0)

    'Indicate whether it all worked or not!
    SetPrinterProperty = CBool(iRet)

cleanup:
   'Release the printer handle
   If (hPrinter <> 0) Then Call ClosePrinter(hPrinter)
      
   'Flush the message queue. If you don't do this,
   'you can get page fault errors when you try to
   'print a document immediately after setting a printer property.
   For iCount = 1 To 20
      DoEvents
   Next iCount
   End Function

Private Function GetPrinterProperty(ByVal sPrinterName As String, ByVal iPropertyType As Long) As Long

  'Code adapted from Microsoft KB article Q230743

  Dim hPrinter As Long
  Dim pd As PRINTER_DEFAULTS
  Dim dm As DEVMODE

  Dim yDevModeData() As Byte
  Dim iRet As Long
      
  On Error GoTo cleanup
      
  pd.DesiredAccess = PRINTER_NORMAL_ACCESS
      
  'Get the printer handle
  iRet = OpenPrinter(sPrinterName, hPrinter, pd)
  If (iRet = 0) Or (hPrinter = 0) Then
     'Couldn't access the printer
      Exit Function
  End If

  'Find out how many bytes needed for the printer properties
  iRet = DocumentProperties(0, hPrinter, sPrinterName, 0, 0, 0)
  If (iRet < 0) Then
     'Couldn't access printer properties
      GoTo cleanup
  End If

  'Make sure the byte array is large enough, including the
  '100 bytes extra in case the printer driver is lying.
  ReDim yDevModeData(0 To iRet + 100) As Byte
      
  'Load the printer properties into the byte array
  iRet = DocumentProperties(0, hPrinter, sPrinterName, _
              VarPtr(yDevModeData(0)), 0, DM_OUT_BUFFER)
  If (iRet < 0) Then
     'Couldn't access printer properties
     GoTo cleanup
  End If



  'Copy the byte array to the DEVMODE structure
  Call CopyMemory(dm, yDevModeData(0), Len(dm))

  If Not dm.dmFields And iPropertyType = 0 Then
     'Requested property not available on this printer.
     GoTo cleanup
  End If

  'Get the value of the requested property
  Select Case iPropertyType
  Case DM_ORIENTATION
     GetPrinterProperty = dm.dmOrientation
  Case DM_PAPERSIZE
     GetPrinterProperty = dm.dmPaperSize
  Case DM_PAPERLENGTH
     GetPrinterProperty = dm.dmPaperLength
  Case DM_PAPERWIDTH
     GetPrinterProperty = dm.dmPaperWidth
  Case DM_DEFAULTSOURCE
     GetPrinterProperty = dm.dmDefaultSource
  Case DM_PRINTQUALITY
     GetPrinterProperty = dm.dmPrintQuality
  Case DM_COLOR
     GetPrinterProperty = dm.dmColor
  Case DM_DUPLEX
     GetPrinterProperty = dm.dmDuplex
  End Select
      
cleanup:
   'Release the printer handle
   If (hPrinter <> 0) Then Call ClosePrinter(hPrinter)

End Function
Posted in Technology | Tagged , , , , , | 13 Responses

Delete EXD files to fix “Object library invalid” error

We have a Microsoft Word template that contains macros, which was working fine but all of a sudden in the last few days, whenever you invoke the template you get the following error:

Word has encountered a problem.

Word has encountered a problem.

If you open the template file instead of invoking a New document from it, you get a more detailed error:

Object library invalid or contains references to object definitions that could not be found

Object library invalid or contains references to object definitions that could not be found

 

This was obviously due to a change in our systems. After googling awhile, I found this article which explains that the error can happen after installing a certain Windows update: http://support.microsoft.com/default.aspx?scid=kb;en-us;932349. The update installs new versions of certain Visual Basic 6.0 Runtime files. The article provides a link to a cumulative update rollup which I tried, to no avail.

Upon further investigation, I found that the files had been updated fine. However, there is a corresponding EXD file that is created for each of the runtime files, when you use the controls provided by the runtime files in the Visual Basic designer. When the runtime files are updated, these EXD files are now invalid and hence this error occurs. To fix the error, you need to delete the EXD files and they will be re-created as needed.

These files should be located in the folder: %APPDATA%\Microsoft\Forms\

On Windows XP, it is usually located in:
C:\Documents and Settings\%USERNAME%\Application Data\Microsoft\Forms\

And on Windows Vista/7:
C:\Users\%USERNAME%\AppData\Roaming\Microsoft\Forms\

EXD files

It was easy enough to fix for myself, but others were having this problem – so I made a script that given the username deletes the files. I had users run the script (you can post it as a link on a webpage and as long as you use Internet Explorer and low security settings it can be invoked from there):

// Function to delete EXD files from user Application Data folder
//     This is to resolve an issue with Word VBA macros that use VB runtimes, which the EXDs point to
function deleteEXDs(){
    var strToPath = "%appdata%\\Microsoft\\Forms\\";
    try {
		var fso = new ActiveXObject("Scripting.FileSystemObject");
		var shell = new ActiveXObject("WScript.Shell");
	}
    catch (err) {
        alert("Could not create ActiveXObject.\nThis script should be run from Internet Explorer, \n" + 
		      "with low security settings (e.g. Intranet or Trusted Sites).");
		return;
    }
    
    try {
		var appdata = shell.SpecialFolders("AppData");
		var strToPath = appdata + "\\Microsoft\\Forms\\";
		var fldr = fso.GetFolder(strToPath);
		var noEXDs = true;

		for (var e = new Enumerator(fldr.Files);  !e.atEnd();  e.moveNext())
		{
			if (fso.GetExtensionName(e.item()).toLowerCase() == 'exd')
			{
				noEXDs = false;
				try {
					var filename = new String(e.item());
					e.item().Delete();
					alert('DELETED ' + filename);
				}
				catch (err)
				{
			        alert("Error - could not delete " + e.item() + ".\nDescription: " + err.description);
				}
			}
		}
		
		if (noEXDs) alert('No EXD files found.');
    } 
    catch (err) {
        alert("Error - could not clean up EXD files.\nDescription: " + err.description);
    }
}

Edit 26 Oct 2010:
Thanks for all the positive comments!

I noticed that this solution of deleting the EXD files is now also being mentioned in the Microsoft KB article: http://support.microsoft.com/kb/957924/en-us

Edit 1 July 2011:
Thanks to the comment below by Paul M Edwards, I updated the script to use the AppData environment variable, so it should now work with Windows newer than XP.

Posted in Technology | Tagged , , , , | Comments closed

Family and Order

FUNDAEC logoTonight I learned more about classification, specifically Family and Order. This is in continuation of the book Basic Arithmetic which I started last week, part of the FUNDAEC course on Preparation for Social Action.

150px-biological_classification_l_pengosvgFamily is a higher level classification than genus, i.e. it is a superset of genara. The idea is that some genara are very similar, such as Canis (dog, coyote, wolf) and Vulpes (red fox, swift fox), as they share many common characteristics and probably only differ in a few. These can be grouped into a family called Canidae.

The text continues in the manner which I am getting used to by now; interspersed in the lesson text are questions which are based on your current comprehension of the subject. They cause you to reflect on what you don’t yet know, and then answer the question in the next paragraph. This reflection and consequent group discussion, if your group pauses to answer the questions, really helps put the answers in perspective once you do get to them. It causes the process of learning to be an active one which involves the learners, rather than just listening to a set of facts. One has to be careful though to make sure the group discussions don’t get out of hand, as everyone may have an opinion on the answer, usually based on random incomplete prior knowledge of the subject matter, while the answer will be provided shortly.

Back to the chapter, we did some more set exercises grouping genera into families, and then were provided with a table of a few families with the instruction to examine and retain as much as possible of the information provided. This is interesting because the mode of instruction here is not one of forcing the student to memorize facts, but of providing the facts in context and allowing the student to retain as much as they naturally can, but also having them realize that they can always look back at this chapter or look up the information from other sources.

The questions continued as usual, talking about genara and families and their set/subset relationships, and then came a question about whether all human beings belong to the same family. This was an interesting diversion from the other questions about animals, because it suddenly brings into focus that in terms of species and animal-level classification constructs, we are really the same. We can all produce offspring therefore we are the same species, the most basic level of the hierarchy. But the question also evokes sentiments of belonging to the same family, with the traditional meaning of the word family (husband, wife and children).

Then came some more questions describing sets of animals and getting you to identify subset relationships, but this time the description was vague enough to encompass both dogs and cats, and bears and maybe even crocodiles. So we start to see that even family is not broad enough, and anticipate a higher level construct.

anophelesThis chapter then diverted attention in the reflection section to talk about another form of interaction between species, in addition to mutualism and commensalism – that of parasitism. This is where one organism benefits at the expense of the other. An example is given of the genus Plasmodium and of the four species within it that cause malaria. A detailed discussion then ensues on how malaria is transmitted through a certain genus of mosquito Anopheles, of the history of the fight against this disease, some tips on how to control its spread on a local level and a suggestion of how it could be done on a larger scale. This gets the participants to think about a particular problem (and an application of the concept of sets and of parasites) and how the problem could be solved. Our group talked about malaria a little, and I shared my story of having been sick with malaria many times a year while growing up in Cameroon, and of one occasion where I was hospitalized for a few days while they tried different series of malaria medication until they brought one from another town that finally worked.

Next, a shorter chapter on order. As a concept used for animal classification, an order consists of one or more families grouped together into a larger set which share common characteristics. An example would be the order Carnivora which includes the families Canidae and Felidae, which in turn include the genera Canis and Vulpes, and Panthera, Felis and Lynx. These in turn break down into the dog and wolf, red fox and swift fox, tiger and lion, domestic cat and wildcat, lynx and bobcat respectively.

One of the questions was a little confusing – it asked if there are orders with thousands of species. We thought, we don’t know, but it seems probably. Then it asked if there are orders with millions of species, then billions. Unsure of the biological facts, what does one answer? I guess knowing the infinite diversity of the universe one could assume that it is possible for there to be such a large range of species, but it seems unlikely that people would have spent that much time classifying so many species and grouping them all under orders. I guess we can always find out by doing some research on the internet, but the intent of the question seems to have been, as usual, to get you to think beyond the boundaries of your knowledge. And then another question about the human being, wether the order in which the human belongs contains only one family. Some people in the group were proposing that humans are entirely apart from animals in terms of classification because we belong to the human kindgom which is as distinct from the animal kingdom as the animal is from the vegetable. But on the other hand, scientific classification of animals could have grouped humans together with apes and other creatures with similar characteristics to us, at least in terms of our animalistic bodies.

Galapagos, Santiago, Highlands 011The reflection question was on the concept of endangered species, triggering thought on what factors contribute to a species being considered as endangered, and then describing some of the solutions that people and governments have come up with to the problem of endangered species. A positive example was given of the curbing of whaling by some nations, and how some whale species have made an amazing come-back. A further example was given of Charles Darwin visiting the Galapagos Islands and the subsequent history of the giant Galapagos tortoises over the years.

I never imagined I would learn so much about biology, which was one of my least favorite subjects in high school, but this is such a pleasant process that the information is somehow sinking in. I even dare to think it will be useful one day.

Next week: class, then phylum and kingdom.

Posted in Education | Tagged , , , , , , , , | 1 Response

Collation in Oracle using NLS_SORT

Yesterday I attended a technical presentation on Character Sets. As I told the presenter afterwards, to me attending this meeting was like reading the Kitab-i-Iqan (book of certitude) and then looking at religious history – it was the key that suddenly made everything else clear. I had come across the terms Character Set, Character Encoding, collation, UTF8, ASCII, ANSI, etc many times and had some idea what they referred to, but was really confused about how they all relate to each other. Now, it was all much more clear. We’ll have a second part of the presentation later, and I may post a summary of the concepts after that.

Sorting ShellsBut already puting theory to practice – this morning I had a request to remove diacritics from a listing of countries, so they sort properly. I thought “Aha!” This is a collation issue. Collation refers to setting items in order, and in the case of databases the collation sequence is the set of rules by which characters are ordered – for example a, b, c, ä or a, ä, b, c. So instead of simply removing the diacritics I googled “oracle collation” and ended up finding a better solution:

 

Oracle uses a setting called NLS_LANG to determine a number of things – language, territory and character set. This is an important setting, as any Oracle DBA would tell you. The default collation sequence is derived from the language portion of that setting, as there is a corresponding NLS_SORT setting for each NLS_LANGUAGE, but then there are also more custom values that you can use. Once you set a value for NLS_SORT, that collating sequence will then be used for sorting when running a query with the ORDER BY clause. 

First let’s check what our current collation sequence is set to:

SELECT SYS_CONTEXT ('USERENV', 'NLS_SORT')
  FROM DUAL;

Then, get a list of the possible values you can set NLS_SORT to:

SELECT *
  FROM v$nls_valid_values
 WHERE parameter = 'SORT';

Choose the collation sequence you want to use from this list. In my case, I wasn’t quite sure which one I wanted, so I searched some more and found one called BINARY_AI which did what I was looking for. Turns out each value in the above table of possible values can have a hybrid definition, by adding a suffix of _CI (case insensitivity) or _AI (accent-insensitive and case-insensitive).

Finally, to set the collation sequence for the current session:

ALTER SESSION SET nls_sort='BINARY_AI';

 

Example:

My query for a list of countries originally gave these results (NLS_SORT was set to BINARY):

 Romania
 Russian Federation
 Rwanda
 Réunion

After the NLS_SORT was set to BINARY_AI:

 Réunion
 Romania
 Russian Federation
 Rwanda
Posted in Spirituality, Technology | Tagged , , , , | 10 Responses

Species and Genus

FUNDAEC logoTonight we went through the next two chapters of Basic Arithmetic (see Ability to Classify for the previous two). 

We were confronted with the question, how do we group animals together? The style of the exercises forces one to such a conclusion, as they first try to get us to group animals together without knowledge of the concept of species, and see how hard a time we have of it. Our group, of university-educated adults, spent a fair bit of time on those questions, although partly because we didn’t have intricate knowledge of the difference between dogs and other similar species. We’ll have to do our research next time, before the class!

Belinha has more than good looksSo after struggling with which characteristics are shared by dogs and which aren’t, the concept of species was explained in more detail, and some more set related exercises. Species was defined as animals that can cross and produce offspring with the same characteristics as themselves. Then, reflection on interactions between species. I can already see that the reflection sections of this book try to connect the study of the basic science in question to social and spiritual concepts. In this case, talk of mutualism between species, with the heart-warming example of the symbiosis between the clown fish and the sea anemone – where the bright clown fish attracts predators to the anemone, which with its poisonous tentacles paralyses, traps and eats the predator, with the clown fish feasting on the scraps. The rub here is that the clown fish is immune to the anemone’s poison. Anyway, talk of mutualism echoed to me the spiritual principle of unity in diversity, how diverse species can come together for a common purpose.

Next, Genus. I keep thinking “add an I to make genius” – but that’s off-topic. As we talk about species, we are asked to compare species and decide which ones are similar. This, larger set of species, can be called a genus. Frankly, I had never heard of this concept, or maybe forgotten a one-off mention in some class in high school. For genus and species names we use latin words, because it is a dead language. So Canis would be the genus of dogs, wolves, jackals, etc. I guess that’s where canine comes from.

A zonky

Some more set-related exercises involving species and genus as sets and subsets of each other, the concept of a hybrid was introduced (animals of different species can sometimes cross producing one with different characteristics, who can’t reproduce) – and there was some joking among our group trying to come up with names for hybrids such as a wog (wolf-dog), jion (lion-jaguar) etc. Then, my favorite the reflection questions. This time the concept of commensalism where one species benefits from a second, while the second is neither benefited nor harmed by the first. Examples for both this and mutualism were hard to come by as we weren’t really experts in animals and their habits, but we could tell that a random sampling of National Geographic TV would supply us with ample examples. What struck out to me was how this concept of commensalism could be related to tolerance, while mutualism could be cooperation or love – the parallels between patterns of nature and the names and attributes of God.

I’ll be preparing for the next class by reading through the next two chapters, Family and Order, and doing any necessary research to be able to better answer the questions in the group setting. The genius (not genus) of this text unfolds as we progress through it, and you can see how the different spheres of knowledge are woven together so as the student goes through this text, they get a wholistic education and see the inter-relations between the branches of knowledge, as well as see their applications to real-life phenomena.

Posted in Education, Spirituality | Tagged , , , , , , | 2 Responses