Just this morning I was trying out a (very old GraphViz) package that required (on Windows) running the Win32Shell to run the package, and got an error '2'.

That annoyed me, so I added support for actually describing what the errors are - that is this package.

I'd appreciate feedback and someone with powers to eventually move if to the FFI repository.

Thanks,
cbc

On Wed, Oct 25, 2017 at 8:27 AM, <commits@source.squeak.org> wrote:
Chris Cunningham uploaded a new version of FFI-Win32 to project The Inbox:
http://source.squeak.org/inbox/FFI-Win32-cbc.13.mcz

==================== Summary ====================

Name: FFI-Win32-cbc.13
Author: cbc
Time: 25 October 2017, 8:25:54.022628 am
UUID: 66fa70bb-22f1-5748-b805-2a201a834489
Ancestors: FFI-Win32-cbc.12

Add descriptive errors for return codes from Wind32Shell.

=============== Diff against FFI-Win32-cbc.12 ===============

Item was added:
+ ----- Method: Win32Shell>>error: (in category 'operations') -----
+ error: code
+       Win32ShellErrors signal: code!

Item was changed:
  ----- Method: Win32Shell>>shellExecute: (in category 'operations') -----
  shellExecute: aFileString
        "Opens (without opening a window) the file specified by aFileString. The file can be an executable file, a document file,
         or a folder."
        | result fileUrlString |
        "@@@@ CHECKME - jrd - Hackity, hack, hack, hack.  Apparently the Win32 url parser doesn't handle %-encoded colons in file paths properly. So we do the conversion ourselves. I'm not sure if the real problem is that we shouldnt be encoding the colons in the first place."
        fileUrlString := (aFileString asLowercase beginsWith: 'file:')
                ifTrue: [(aFileString copyReplaceAll: '%3A' with: ':') copyReplaceAll: '%3a' with: ':' ]
                ifFalse: [aFileString].

        result := self shellExecute: nil
                lpOperation: 'open'
                lpFile: fileUrlString
                lpParameters: nil
                lpDirectory: nil
                nShowCmd: 0.
+       (result <= 32 and: [result >= 0])  ifTrue: [self error: result]!
-       result <= 32 ifTrue: [self error: 'system error, code:', result printString]!

Item was changed:
  ----- Method: Win32Shell>>shellExplore: (in category 'operations') -----
  shellExplore: aPathString
        "Explores the folder specified by aPathString"

        | result |
        result := self shellExecute: nil
                lpOperation: 'explore'
                lpFile: aPathString
                lpParameters: nil
                lpDirectory: nil
                nShowCmd: 1.
+       (result <= 32 and: [result >= 0])  ifTrue: [self error: result]!
-       result <= 32 ifTrue: [self error: 'system error, code:', result printString]!

Item was changed:
  ----- Method: Win32Shell>>shellFind: (in category 'operations') -----
  shellFind: aPathString
        "Initiates a search starting from the specified directory."

        | result |
        result := self shellExecute: nil
                lpOperation: 'find'
                lpFile: nil
                lpParameters: nil
                lpDirectory: aPathString
                nShowCmd: 1.
+       (result <= 32 and: [result >= 0])  ifTrue: [self error: result]!
-       result <= 32 ifTrue: [self error: 'system error, code:', result printString]!

Item was changed:
  ----- Method: Win32Shell>>shellOpen: (in category 'operations') -----
  shellOpen: aFileString
        "Opens the file specified by aFileString. The file can be an executable file, a document file,
         or a folder."
        | result fileUrlString |
        "@@@@ CHECKME - jrd - Hackity, hack, hack, hack.  Apparently the Win32 url parser doesn't handle %-encoded colons in file paths properly. So we do the conversion ourselves. I'm not sure if the real problem is that we shouldnt be encoding the colons in the first place."
        fileUrlString := (aFileString asLowercase beginsWith: 'file:')
                ifTrue: [(aFileString copyReplaceAll: '%3A' with: ':') copyReplaceAll: '%3a' with: ':' ]
                ifFalse: [aFileString].

        result := self shellExecute: nil
                lpOperation: 'open'
                lpFile: fileUrlString
                lpParameters: nil
                lpDirectory: nil
                nShowCmd: 1.
+       (result <= 32 and: [result >= 0])  ifTrue: [self error: result]!
-       result <= 32 ifTrue: [self error: 'system error, code:', result printString]!

Item was added:
+ SharedPool subclass: #Win32ShellErrors
+       instanceVariableNames: 'errorNumber description'
+       classVariableNames: 'ERROR_BAD_FORMAT ERROR_FILE_NOT_FOUND ERROR_PATH_NOT_FOUND OUT_OF_MEMORY_OR_RESOURCES SE_ERR_ACCESSDENIED SE_ERR_ACCOSINCOMPLETE SE_ERR_DDEBUSY SE_ERR_DDEFAIL SE_ERR_DDETIMEOUT SE_ERR_DDLNOTFOUND SE_ERR_FNF SE_ERR_NOASSOC SE_ERR_OOM SE_ERR_PNF SE_ERR_SHARE'
+       poolDictionaries: ''
+       category: 'FFI-Win32-Examples'!
+ Win32ShellErrors class
+       instanceVariableNames: 'errors'!
+ Win32ShellErrors class
+       instanceVariableNames: 'errors'!

Item was added:
+ ----- Method: Win32ShellErrors class>>initialize (in category 'as yet unclassified') -----
+ initialize
+       self initializeWindowConstants!

Item was added:
+ ----- Method: Win32ShellErrors class>>initializeWindowConstants (in category 'as yet unclassified') -----
+ initializeWindowConstants
+       OUT_OF_MEMORY_OR_RESOURCES := self new errorNumber: 0; description: 'The operating system is out of memory or resources'.
+       SE_ERR_FNF := self new errorNumber: 2; description: 'The specified file was not found'.
+       SE_ERR_PNF := self new errorNumber: 3; description: 'The specified path was not found'.
+       SE_ERR_ACCESSDENIED := self new errorNumber: 5; description: 'The operating system denied access to the specified file'.
+       SE_ERR_OOM := self new errorNumber: 8; description: 'There was not enough memory to complete the operation'.
+       ERROR_BAD_FORMAT := self new errorNumber: 11; description: 'The .EXE file is invalid (non-Win32 .EXE or error in .EXE image)'.
+       SE_ERR_SHARE := self new errorNumber: 26; description: 'A sharing violation occurred'.
+       SE_ERR_ACCOSINCOMPLETE := self new errorNumber: 27; description: 'The filename association is incomplete or invalid'.
+       SE_ERR_DDETIMEOUT := self new errorNumber: 28; description: 'The DDE transaction could not be completed because the request timed out'.
+       SE_ERR_DDEFAIL := self new errorNumber: 29; description: 'The DDE transaction failed'.
+       SE_ERR_DDEBUSY := self new errorNumber: 30; description: 'The DDE transaction could not be completed because other DDE transactions were being processed'.
+       SE_ERR_NOASSOC := self new errorNumber: 31; description: 'There is no application associated with the given filename extension'.
+       SE_ERR_DDLNOTFOUND := self new errorNumber: 32; description: 'The specified dynamic-link library was not found'.
+       errors := Dictionary new: (self allInstances size).
+       self allInstances do: [:err|
+               errors at: err errorNumber put: err
+               ].!

Item was added:
+ ----- Method: Win32ShellErrors class>>signal: (in category 'as yet unclassified') -----
+ signal: code
+       | err |
+       err := errors at: code ifAbsent: [Error signal: 'system error, code:', code].
+       Error signal: err errorString!

Item was added:
+ ----- Method: Win32ShellErrors>>description (in category 'accessing') -----
+ description
+
+       ^ description
+ !

Item was added:
+ ----- Method: Win32ShellErrors>>description: (in category 'accessing') -----
+ description: anObject
+
+       description := anObject.
+ !

Item was added:
+ ----- Method: Win32ShellErrors>>errorNumber (in category 'accessing') -----
+ errorNumber
+
+       ^ errorNumber
+ !

Item was added:
+ ----- Method: Win32ShellErrors>>errorNumber: (in category 'accessing') -----
+ errorNumber: anObject
+
+       errorNumber := anObject.
+ !

Item was added:
+ ----- Method: Win32ShellErrors>>errorString (in category 'accessing') -----
+ errorString
+       ^'system error, code: ', errorNumber, ' "', description, '"'!