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 , , , , , | 16 Comments

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 , , , , | 288 Comments

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 Comment

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 Comments

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 Comments

StackOverflow answers your programming questions

StackOverflow logo

Today I discovered a nice service for getting quick answers to programming questions. I had come across StackOverflow.com before, but I actually had a question to ask now so I signed up and asked it. Within an hour, I had some responses, and in two hours I had many possible answers that would all work for me.

The way this site works, from what I gathered from their FAQ, is that anyone can ask a question as long as it is related to programming. Then, as people answer they get awarded reputation, and with certain levels of reputation you can vote up or down answers, then with more rep you can edit answers and so on. It is all community-run, so to speak. 

Anyway, results speak for themselves, and as you can see from the question I asked there were a number of attempts at answering it:
http://stackoverflow.com/questions/486896/adding-a-parameter-to-the-url-with-javascript

 

Testing the answers

I got carried away looking at the answers and trying to figure out which one was better, so I could “accept” one as the right answer. I therefore came up with a page to test the different methods of answering the same question:

Click here to run the test with your own browser

You can look a the code to see the methods, I changed them slightly so they could be plugged in to the project I was working on.

Here are my results, using the browsers I had on my computer (Windows XP SP3 Core2 2.13Ghz):

Test results on Chrome
Chrome
 
Test results on Firefox 3.0
Firefox 3.0
 
Test results on Internet Explorer 7
IE7 (on another machine WinXP Pentium D 2.8ghz)
 
Test results on Internet Explorer 8 RC1
IE8 RC1
 
Test results on Opera 9.63
Opera 9.63
 
Test results on Safari 3.1.1
Safari 3.1.1

Posted in Technology | Tagged , , , | Leave a comment

The ability to classify things

FUNDAEC logoI just completed the first two chapters of the unit “Classification”. This forms part of the entry-level text Basic Arithmetic, part of the educational program Preparation for Social Action (PSA) from FUNDAEC. According to the instructions for the tutor, this unit provides students with the opportunity to develop further the fundamental capability of classifying things.

ARITMÉTICA,

Why Arithmetic? I’m not sure, but I was invited to a study group for PSA, and that’s the book they are currently working on. Once I figure out more about the whole sequence of things I’ll post that here. I’m just catching up on the first two chapters, and tomorrow we’ll be doing the third in our study group. Looking forward to it!

The first two chapters were on Sets and Subsets. They seek to develop further the basic capability of classification, which we acquire from early childhood, by providing examples and exercises designed to help the student think about the theory then apply it to real world objects and situations. Some of the exercises, for example, get you to make a set of the crops, or towns, or animals in your surroundings. The style of the exercises is similar to another program that is related to FUNDAEC – the Ruhi Institute’s sequence of courses, and anyone familiar with the exercises in those books will be quite comfortable with these. 

After introducing the basic concepts, such as how to define a set (by rule or roster), identical sets, the empty set ∅, set-builder notation, the “belongs to” symbol ∈ and the “is part of” symbol ⊂, there were some questions designed to make the students reflect on one of the applications of these concepts in daily life – to the human race. The premise here is that we can take the set of all humans, divide it into certain subsets and talk about the relationships between those subsets. For example, parents and children – how should they behave towards each other? Is it with love and respect, or through control and violence?

I can already see how useful and exciting this material is – how it combines many levels of education together – while teaching concepts of arithmetic, it makes students actively aware of the world around them and how to apply those concepts to that world; it provides an introduction to other disciplines such as botany, food sciences and geography; and right there at the beginning is the most important part – teaching morals and ethical values, the spiritual aspect of education. All of this in a few pages of text and exercises, which would probably only take a few hours to go through in a group setting. Brilliant!

Coming up next in this series: Species then Genus.

Posted in Education, Spirituality | Tagged , , , , | 3 Comments