| 1 | /****************************************************************************** | 
|---|
| 2 | * REXX OS/2 Printer Utility API (RXPRTUTL.DLL)                               * | 
|---|
| 3 | * (C) 2011,2016 Alex Taylor                                                  * | 
|---|
| 4 | *                                                                            * | 
|---|
| 5 | * LICENSE:                                                                   * | 
|---|
| 6 | *                                                                            * | 
|---|
| 7 | *   Redistribution and use in source and binary forms, with or without       * | 
|---|
| 8 | *   modification, are permitted provided that the following conditions are   * | 
|---|
| 9 | *   met:                                                                     * | 
|---|
| 10 | *                                                                            * | 
|---|
| 11 | *   1. Redistributions of source code must retain the above copyright        * | 
|---|
| 12 | *      notice, this list of conditions and the following disclaimer.         * | 
|---|
| 13 | *                                                                            * | 
|---|
| 14 | *   2. Redistributions in binary form must reproduce the above copyright     * | 
|---|
| 15 | *      notice, this list of conditions and the following disclaimer in the   * | 
|---|
| 16 | *      documentation and/or other materials provided with the distribution.  * | 
|---|
| 17 | *                                                                            * | 
|---|
| 18 | *   3. The name of the author may not be used to endorse or promote products * | 
|---|
| 19 | *      derived from this software without specific prior written permission. * | 
|---|
| 20 | *                                                                            * | 
|---|
| 21 | *   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR     * | 
|---|
| 22 | *   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED           * | 
|---|
| 23 | *   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE   * | 
|---|
| 24 | *   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,       * | 
|---|
| 25 | *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES       * | 
|---|
| 26 | *   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR       * | 
|---|
| 27 | *   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)       * | 
|---|
| 28 | *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,      * | 
|---|
| 29 | *   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * | 
|---|
| 30 | *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          * | 
|---|
| 31 | *   POSSIBILITY OF SUCH DAMAGE.                                              * | 
|---|
| 32 | *                                                                            * | 
|---|
| 33 | ******************************************************************************/ | 
|---|
| 34 |  | 
|---|
| 35 | #define INCL_DEV | 
|---|
| 36 | #define INCL_DOSERRORS | 
|---|
| 37 | #define INCL_DOSMISC | 
|---|
| 38 | #define INCL_DOSMODULEMGR | 
|---|
| 39 | #define INCL_DOSPROFILE | 
|---|
| 40 | #define INCL_SPL | 
|---|
| 41 | #define INCL_SPLDOSPRINT | 
|---|
| 42 | #define INCL_SPLERRORS | 
|---|
| 43 | #define INCL_PM | 
|---|
| 44 | #define INCL_WIN | 
|---|
| 45 | #define INCL_WINWORKPLACE | 
|---|
| 46 | #ifndef OS2_INCLUDED | 
|---|
| 47 | #include <os2.h> | 
|---|
| 48 | #endif | 
|---|
| 49 | #include <ctype.h> | 
|---|
| 50 | #include <stdio.h> | 
|---|
| 51 | #include <stdlib.h> | 
|---|
| 52 | #include <string.h> | 
|---|
| 53 | #define INCL_RXSHV | 
|---|
| 54 | #define INCL_RXFUNC | 
|---|
| 55 | #include <rexxsaa.h> | 
|---|
| 56 |  | 
|---|
| 57 | #include "shfuncs.h" | 
|---|
| 58 |  | 
|---|
| 59 |  | 
|---|
| 60 | // CONSTANTS | 
|---|
| 61 |  | 
|---|
| 62 | #define SZ_LIBRARY_NAME         "RXPRTUTL"  // Name of this library | 
|---|
| 63 | #define SZ_VERSION              "0.3"       // Current version of this library | 
|---|
| 64 |  | 
|---|
| 65 | //This is now defined by the Makefile: | 
|---|
| 66 | //#define SZ_ERROR_NAME           "RPUERROR"  // REXX variable used to store error codes | 
|---|
| 67 |  | 
|---|
| 68 | #define APPNAME_LEAD_STR        "PM_" | 
|---|
| 69 | #define APPNAME_PM_PORT_DRIVER  "PM_PORT_DRIVER" | 
|---|
| 70 | #define APPNAME_PM_SPOOLER_PORT "PM_SPOOLER_PORT" | 
|---|
| 71 | #define APPNAME_PM_PRINT_OBJECT "PM_PrintObject" | 
|---|
| 72 | #define APPNAME_PM_ABS_OBJECTS  "PM_Abstract:Objects" | 
|---|
| 73 | #define APPNAME_PM_WPS_LOCATION "PM_Workplace:Location" | 
|---|
| 74 |  | 
|---|
| 75 | #define ID_OBJINFO_QUEUENAME    3 | 
|---|
| 76 | #define ID_OBJINFO_RPQUEUENAME  13 | 
|---|
| 77 |  | 
|---|
| 78 | // Values that should be defined in pmsplb.h if it actually existed | 
|---|
| 79 | #define TYPE_SHORT_WAIT         1 | 
|---|
| 80 | #define TYPE_LONG_WAIT          2 | 
|---|
| 81 | #define BIDI_SET_PORTDRV        0x19 | 
|---|
| 82 | #define BIDI_Q_PORTDRV          0x8019 | 
|---|
| 83 |  | 
|---|
| 84 | // Values used by WinOpenObject | 
|---|
| 85 | #define OPEN_DEFAULT       0 | 
|---|
| 86 | #define OPEN_CONTENTS      1 | 
|---|
| 87 | #define OPEN_SETTINGS      2 | 
|---|
| 88 | #define OPEN_HELP          3 | 
|---|
| 89 | #define OPEN_TREE          101 | 
|---|
| 90 | #define OPEN_DETAILS       102 | 
|---|
| 91 |  | 
|---|
| 92 | // Maximum string lengths... | 
|---|
| 93 | #ifdef NO_SHARED_SOURCE | 
|---|
| 94 | #define US_COMPOUND_MAXZ    250                                  // ...of a compound variable | 
|---|
| 95 | #define US_ERRSTR_MAXZ      250                                  // ...of an error string | 
|---|
| 96 | #endif | 
|---|
| 97 |  | 
|---|
| 98 | #define US_INTEGER_MAXZ         12                                   // ...of an integer string | 
|---|
| 99 | #define US_STEM_MAXZ          ( US_COMPOUND_MAXZ - US_INTEGER_MAXZ ) // ...of a stem | 
|---|
| 100 | #define US_DRVINFO_MAXZ       ( CCHMAXPATH + 8 + 32 )                // ...of an driver/port info string | 
|---|
| 101 | #define US_PRTINFO_MAXZ         180                                  // ...of a printer info string | 
|---|
| 102 | #define US_PORT_MAXZ            64                                   // ...of a port name | 
|---|
| 103 | #define US_PRTDEV_MAXZ          9                                    // ...of a print device name | 
|---|
| 104 |  | 
|---|
| 105 |  | 
|---|
| 106 | // DATA TYPES | 
|---|
| 107 |  | 
|---|
| 108 | /* Structures needed used to parse PM_Abstract:Object data | 
|---|
| 109 | */ | 
|---|
| 110 | #pragma pack(1) | 
|---|
| 111 | typedef struct _Object_Info | 
|---|
| 112 | { | 
|---|
| 113 | USHORT cbName;       // Size of szName, including terminator | 
|---|
| 114 | USHORT cbData;       // Number of additional data bytes following szName | 
|---|
| 115 | CHAR   szName[1];    // Name of object type | 
|---|
| 116 | } OBJINFO, *POBJINFO; | 
|---|
| 117 |  | 
|---|
| 118 | typedef struct _Object_Tag_Info | 
|---|
| 119 | { | 
|---|
| 120 | USHORT usTagFormat;  // Tag data format | 
|---|
| 121 | USHORT usTag;        // Tag ID | 
|---|
| 122 | USHORT cbTag;        // Size of tag data | 
|---|
| 123 | } OITAG, *POITAG; | 
|---|
| 124 | #pragma pack() | 
|---|
| 125 |  | 
|---|
| 126 |  | 
|---|
| 127 | // GLOBALS | 
|---|
| 128 |  | 
|---|
| 129 | // List of functions to be registered by RPULoadFuncs | 
|---|
| 130 | static PSZ RxFunctionTbl[] = { | 
|---|
| 131 | "RPULoadFuncs",         // drop only | 
|---|
| 132 | "RPUDropFuncs", | 
|---|
| 133 | "RPUDeviceDelete", | 
|---|
| 134 | "RPUEnumModels", | 
|---|
| 135 | "RPUEnumDrivers", | 
|---|
| 136 | "RPUEnumPorts", | 
|---|
| 137 | "RPUEnumPrinters", | 
|---|
| 138 | "RPUQueueDefault", | 
|---|
| 139 | "RPUQueueHold", | 
|---|
| 140 | "RPUOpenView", | 
|---|
| 141 | "RPUPortDelete", | 
|---|
| 142 | "RPUPortDialog", | 
|---|
| 143 | "RPUPortInfo", | 
|---|
| 144 | "RPUPortInstall", | 
|---|
| 145 | "RPUPortQuery", | 
|---|
| 146 | "RPUPortSet", | 
|---|
| 147 | "RPUPrinterCreate", | 
|---|
| 148 | "RPUPrinterDelete", | 
|---|
| 149 | "RPUPrinterQuery", | 
|---|
| 150 | "RPUVersion" | 
|---|
| 151 | }; | 
|---|
| 152 |  | 
|---|
| 153 |  | 
|---|
| 154 | // FUNCTION DECLARATIONS | 
|---|
| 155 |  | 
|---|
| 156 | // Exported REXX functions | 
|---|
| 157 | RexxFunctionHandler RPULoadFuncs; | 
|---|
| 158 | RexxFunctionHandler RPUDropFuncs; | 
|---|
| 159 | RexxFunctionHandler RPUVersion; | 
|---|
| 160 | RexxFunctionHandler RPUDeviceDelete; | 
|---|
| 161 | RexxFunctionHandler RPUEnumModels; | 
|---|
| 162 | RexxFunctionHandler RPUEnumDrivers; | 
|---|
| 163 | RexxFunctionHandler RPUEnumPorts; | 
|---|
| 164 | RexxFunctionHandler RPUEnumPrinters; | 
|---|
| 165 | RexxFunctionHandler RPUOpenView; | 
|---|
| 166 | RexxFunctionHandler RPUPortDelete; | 
|---|
| 167 | RexxFunctionHandler RPUPortDialog; | 
|---|
| 168 | RexxFunctionHandler RPUPortInfo; | 
|---|
| 169 | RexxFunctionHandler RPUPortInstall; | 
|---|
| 170 | RexxFunctionHandler RPUPortQuery; | 
|---|
| 171 | RexxFunctionHandler RPUPortSet; | 
|---|
| 172 | RexxFunctionHandler RPUPrinterCreate; | 
|---|
| 173 | RexxFunctionHandler RPUPrinterDelete; | 
|---|
| 174 | RexxFunctionHandler RPUPrinterQuery; | 
|---|
| 175 | RexxFunctionHandler RPUQueueDefault; | 
|---|
| 176 | RexxFunctionHandler RPUQueueHold; | 
|---|
| 177 |  | 
|---|
| 178 | // TODO | 
|---|
| 179 |  | 
|---|
| 180 | // Internal functions | 
|---|
| 181 | PSZ     GetObjectID( PSZ pszHandle ); | 
|---|
| 182 | HOBJECT PrinterObjectHandle( PSZ pszQueueName ); | 
|---|
| 183 | ULONG   UniqueDeviceName( PSZ pszName ); | 
|---|
| 184 | #ifdef NO_SHARED_SOURCE | 
|---|
| 185 | BOOL    SaveResultString( PRXSTRING prsResult, PCH pchBytes, ULONG ulBytes ); | 
|---|
| 186 | BOOL    WriteCompoundVariable( PSZ pszStem, PSZ pszTail, PSZ pszValue ); | 
|---|
| 187 | //    BOOL    WriteSimpleVariable( PSZ pszName, PSZ pszValue ); | 
|---|
| 188 | BOOL    WriteStemElement( PSZ pszStem, ULONG ulIndex, PSZ pszValue ); | 
|---|
| 189 | void    WriteErrorCode( ULONG ulError, PSZ pszContext ); | 
|---|
| 190 | #endif | 
|---|
| 191 |  | 
|---|
| 192 |  | 
|---|
| 193 | /* ************************************************************************* * | 
|---|
| 194 | * EXPORTED REXX FUNCTIONS                                                   * | 
|---|
| 195 | * ************************************************************************* */ | 
|---|
| 196 |  | 
|---|
| 197 | /* ------------------------------------------------------------------------- * | 
|---|
| 198 | * RPULoadFuncs                                                              * | 
|---|
| 199 | *                                                                           * | 
|---|
| 200 | * Register all RPU* REXX functions except this one.                         * | 
|---|
| 201 | *                                                                           * | 
|---|
| 202 | * REXX ARGUMENTS:    None                                                   * | 
|---|
| 203 | * REXX RETURN VALUE: ""                                                     * | 
|---|
| 204 | * ------------------------------------------------------------------------- */ | 
|---|
| 205 | ULONG APIENTRY RPULoadFuncs( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 206 | { | 
|---|
| 207 | int entries, | 
|---|
| 208 | i; | 
|---|
| 209 |  | 
|---|
| 210 | // Reset the error indicator | 
|---|
| 211 | WriteErrorCode( 0, NULL ); | 
|---|
| 212 |  | 
|---|
| 213 | if ( argc > 0 ) return ( 40 ); | 
|---|
| 214 | entries = sizeof(RxFunctionTbl) / sizeof(PSZ); | 
|---|
| 215 |  | 
|---|
| 216 | // Start from 1 to skip RPULoadFuncs (we don't want to re-register ourselves) | 
|---|
| 217 | for ( i = 1; i < entries; i++ ) | 
|---|
| 218 | RexxRegisterFunctionDll( RxFunctionTbl[i], SZ_LIBRARY_NAME, RxFunctionTbl[i] ); | 
|---|
| 219 |  | 
|---|
| 220 | SaveResultString( prsResult, NULL, 0 ); | 
|---|
| 221 | return ( 0 ); | 
|---|
| 222 | } | 
|---|
| 223 |  | 
|---|
| 224 |  | 
|---|
| 225 | /* ------------------------------------------------------------------------- * | 
|---|
| 226 | * RPUDropFuncs                                                              * | 
|---|
| 227 | *                                                                           * | 
|---|
| 228 | * Deregister all RPU* REXX functions, including this one.                   * | 
|---|
| 229 | *                                                                           * | 
|---|
| 230 | * REXX ARGUMENTS:    None                                                   * | 
|---|
| 231 | * REXX RETURN VALUE: ""                                                     * | 
|---|
| 232 | * ------------------------------------------------------------------------- */ | 
|---|
| 233 | ULONG APIENTRY RPUDropFuncs( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 234 | { | 
|---|
| 235 | int entries, | 
|---|
| 236 | i; | 
|---|
| 237 |  | 
|---|
| 238 | // Reset the error indicator | 
|---|
| 239 | WriteErrorCode( 0, NULL ); | 
|---|
| 240 |  | 
|---|
| 241 | if ( argc > 0 ) return ( 40 ); | 
|---|
| 242 | entries = sizeof(RxFunctionTbl) / sizeof(PSZ); | 
|---|
| 243 | for ( i = 0; i < entries; i++ ) | 
|---|
| 244 | RexxDeregisterFunction( RxFunctionTbl[i] ); | 
|---|
| 245 |  | 
|---|
| 246 | SaveResultString( prsResult, NULL, 0 ); | 
|---|
| 247 | return ( 0 ); | 
|---|
| 248 | } | 
|---|
| 249 |  | 
|---|
| 250 |  | 
|---|
| 251 | /* ------------------------------------------------------------------------- * | 
|---|
| 252 | * RPUVersion                                                               * | 
|---|
| 253 | *                                                                           * | 
|---|
| 254 | * Returns the current library version.                                      * | 
|---|
| 255 | *                                                                           * | 
|---|
| 256 | * REXX ARGUMENTS:    None                                                   * | 
|---|
| 257 | * REXX RETURN VALUE: Current version in the form "major.minor.refresh"      * | 
|---|
| 258 | * ------------------------------------------------------------------------- */ | 
|---|
| 259 | ULONG APIENTRY RPUVersion( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 260 | { | 
|---|
| 261 | CHAR szVersion[ 12 ]; | 
|---|
| 262 |  | 
|---|
| 263 | // Reset the error indicator | 
|---|
| 264 | WriteErrorCode( 0, NULL ); | 
|---|
| 265 |  | 
|---|
| 266 | if ( argc > 0 ) return ( 40 ); | 
|---|
| 267 | sprintf( szVersion, "%s", SZ_VERSION ); | 
|---|
| 268 |  | 
|---|
| 269 | SaveResultString( prsResult, szVersion, strlen(szVersion) ); | 
|---|
| 270 | return ( 0 ); | 
|---|
| 271 | } | 
|---|
| 272 |  | 
|---|
| 273 |  | 
|---|
| 274 | /* ------------------------------------------------------------------------- * | 
|---|
| 275 | * RPUDeviceDelete                                                           * | 
|---|
| 276 | *                                                                           * | 
|---|
| 277 | * Deletes a local print device which lacks a printer queue.  Can be useful  * | 
|---|
| 278 | * for cleaning up bad or corrupted printer definitions.                     * | 
|---|
| 279 | *                                                                           * | 
|---|
| 280 | * REXX ARGUMENTS:                                                           * | 
|---|
| 281 | *   1. The name of the print device to be deleted.               (REQUIRED) * | 
|---|
| 282 | *                                                                           * | 
|---|
| 283 | * REXX RETURN VALUE:                                                        * | 
|---|
| 284 | *   1 on success, or 0 if an error occurred.                                * | 
|---|
| 285 | * ------------------------------------------------------------------------- */ | 
|---|
| 286 | ULONG APIENTRY RPUDeviceDelete( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 287 | { | 
|---|
| 288 | PSZ    pszDeviceName = NULL; | 
|---|
| 289 | SPLERR rc; | 
|---|
| 290 |  | 
|---|
| 291 |  | 
|---|
| 292 | // Reset the error indicator | 
|---|
| 293 | WriteErrorCode( 0, NULL ); | 
|---|
| 294 |  | 
|---|
| 295 | // Validate the REXX arguments | 
|---|
| 296 | if (( argc != 1 ) || ( ! RXVALIDSTRING( argv[0] ))) | 
|---|
| 297 | return ( 40 ); | 
|---|
| 298 |  | 
|---|
| 299 | pszDeviceName = argv[0].strptr; | 
|---|
| 300 |  | 
|---|
| 301 | rc = SplDeleteDevice( NULL, pszDeviceName ); | 
|---|
| 302 | if ( rc != NO_ERROR ) { | 
|---|
| 303 | WriteErrorCode( rc, "SplDeleteDevice"); | 
|---|
| 304 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 305 | return 0; | 
|---|
| 306 | } | 
|---|
| 307 |  | 
|---|
| 308 | SaveResultString( prsResult, PSZ_ONE, 1 ); | 
|---|
| 309 | return ( 0 ); | 
|---|
| 310 | } | 
|---|
| 311 |  | 
|---|
| 312 |  | 
|---|
| 313 | /* ------------------------------------------------------------------------- * | 
|---|
| 314 | * RPUEnumModels                                                             * | 
|---|
| 315 | *                                                                           * | 
|---|
| 316 | * Gets a list of the printer models supported by the specified print        * | 
|---|
| 317 | * driver.                                                                   * | 
|---|
| 318 | *                                                                           * | 
|---|
| 319 | * REXX ARGUMENTS:                                                           * | 
|---|
| 320 | *   1. Filespec of the printer driver to query.                  (REQUIRED) * | 
|---|
| 321 | *   2. The name of the stem in which to return the results.      (REQUIRED) * | 
|---|
| 322 | *                                                                           * | 
|---|
| 323 | * REXX RETURN VALUE:                                                        * | 
|---|
| 324 | *   1 on success, or 0 if an error occurred.                                * | 
|---|
| 325 | * ------------------------------------------------------------------------- */ | 
|---|
| 326 | ULONG APIENTRY RPUEnumModels( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 327 | { | 
|---|
| 328 | HAB    hab;                         // desktop anchor-block handle | 
|---|
| 329 | PSZ    pszDriver;                   // print driver filespec | 
|---|
| 330 | CHAR   szStem[ US_STEM_MAXZ ],      // buffers used for building stem | 
|---|
| 331 | szNumber[ US_INTEGER_MAXZ ]; // ... | 
|---|
| 332 | BOOL   fSuccess;                    // success indicator | 
|---|
| 333 | PSTR32 aDeviceName;                 // array of device names | 
|---|
| 334 | PSTR64 aDeviceDesc;                 // array of device descriptions | 
|---|
| 335 | PSTR16 aDataType;                   // array of data types | 
|---|
| 336 | LONG   pldn = 0L,                   // number of device names/descriptions | 
|---|
| 337 | pldt = 0L,                   // number of data types | 
|---|
| 338 | i; | 
|---|
| 339 | APIRET rc = 0; | 
|---|
| 340 |  | 
|---|
| 341 | // Reset the error indicator | 
|---|
| 342 | WriteErrorCode( 0, NULL ); | 
|---|
| 343 |  | 
|---|
| 344 | // Make sure we have exactly two valid arguments | 
|---|
| 345 | if (( argc != 2 ) || | 
|---|
| 346 | ( ! RXVALIDSTRING( argv[0] )) || | 
|---|
| 347 | ( ! RXVALIDSTRING( argv[1] )) || | 
|---|
| 348 | ( RXSTRLEN( argv[1] ) > US_STEM_MAXZ )) | 
|---|
| 349 | return ( 40 ); | 
|---|
| 350 | pszDriver = argv[0].strptr; | 
|---|
| 351 |  | 
|---|
| 352 | if ( argv[1].strptr[ argv[1].strlength-1 ] == '.') argv[1].strlength--; | 
|---|
| 353 | strncpy( szStem, argv[1].strptr, RXSTRLEN( argv[1] )); | 
|---|
| 354 | szStem[ RXSTRLEN( argv[1] ) ] = '\0'; | 
|---|
| 355 |  | 
|---|
| 356 | hab = WinInitialize( 0 ); | 
|---|
| 357 | if ( !hab ) { | 
|---|
| 358 | WriteErrorCode( 0, "WinInitialize"); | 
|---|
| 359 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 360 | return ( 0 ); | 
|---|
| 361 | } | 
|---|
| 362 |  | 
|---|
| 363 | // Query the size of the available data | 
|---|
| 364 | fSuccess = DevQueryDeviceNames( hab, pszDriver, &pldn, NULL, NULL, &pldt, NULL ); | 
|---|
| 365 | if ( !fSuccess ) { | 
|---|
| 366 | WriteErrorCode( ERRORIDERROR( WinGetLastError( hab )), "DevQueryDeviceNames"); | 
|---|
| 367 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 368 | goto cleanup; | 
|---|
| 369 | } | 
|---|
| 370 |  | 
|---|
| 371 | // Now get the actual data | 
|---|
| 372 | /* (This originally used malloc() - switched to DosAllocMem() while in the | 
|---|
| 373 | * process of trying to hunt down an intermittent trap.  In fact, the trap | 
|---|
| 374 | * was probably caused by a flaw in WriteStemElement() which has since been | 
|---|
| 375 | * fixed.) | 
|---|
| 376 | */ | 
|---|
| 377 | #if 1 | 
|---|
| 378 | rc = DosAllocMem( (PVOID) &aDeviceName, (ULONG) pldn * sizeof( STR32 ), PAG_WRITE | PAG_COMMIT ); | 
|---|
| 379 | if ( rc != NO_ERROR ) { | 
|---|
| 380 | WriteErrorCode( rc, "DosAllocMem"); | 
|---|
| 381 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 382 | goto cleanup; | 
|---|
| 383 | } | 
|---|
| 384 | rc = DosAllocMem( (PVOID) &aDeviceDesc, (ULONG) pldn * sizeof( STR64 ), PAG_WRITE | PAG_COMMIT ); | 
|---|
| 385 | if ( rc != NO_ERROR ) { | 
|---|
| 386 | WriteErrorCode( rc, "DosAllocMem"); | 
|---|
| 387 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 388 | DosFreeMem( aDeviceName ); | 
|---|
| 389 | goto cleanup; | 
|---|
| 390 | } | 
|---|
| 391 | rc = DosAllocMem( (PVOID) &aDataType, (ULONG) pldt * sizeof( STR16 ), PAG_WRITE | PAG_COMMIT ); | 
|---|
| 392 | if ( rc != NO_ERROR ) { | 
|---|
| 393 | WriteErrorCode( rc, "DosAllocMem"); | 
|---|
| 394 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 395 | DosFreeMem( aDeviceName ); | 
|---|
| 396 | DosFreeMem( aDeviceDesc ); | 
|---|
| 397 | goto cleanup; | 
|---|
| 398 | } | 
|---|
| 399 | #else | 
|---|
| 400 | aDeviceName = malloc( pldn * sizeof( STR32 )); | 
|---|
| 401 | if ( !aDeviceName ) { | 
|---|
| 402 | WriteErrorCode( ERROR_NOT_ENOUGH_MEMORY, "malloc"); | 
|---|
| 403 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 404 | goto cleanup; | 
|---|
| 405 | } | 
|---|
| 406 | aDeviceDesc = malloc( pldn * sizeof( STR64 )); | 
|---|
| 407 | if ( !aDeviceDesc ) { | 
|---|
| 408 | WriteErrorCode( ERROR_NOT_ENOUGH_MEMORY, "malloc"); | 
|---|
| 409 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 410 | free( aDeviceName ); | 
|---|
| 411 | goto cleanup; | 
|---|
| 412 | } | 
|---|
| 413 | aDataType = malloc( pldt * sizeof( STR16 )); | 
|---|
| 414 | if ( !aDataType ) { | 
|---|
| 415 | WriteErrorCode( ERROR_NOT_ENOUGH_MEMORY, "malloc"); | 
|---|
| 416 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 417 | free( aDeviceName ); | 
|---|
| 418 | free( aDeviceDesc ); | 
|---|
| 419 | goto cleanup; | 
|---|
| 420 | } | 
|---|
| 421 | #endif | 
|---|
| 422 | fSuccess = DevQueryDeviceNames( hab, pszDriver, &pldn, aDeviceName, | 
|---|
| 423 | aDeviceDesc, &pldt, aDataType ); | 
|---|
| 424 | for ( i = 0; i < pldn; i++ ) { | 
|---|
| 425 | WriteStemElement( szStem, i+1, (PSZ)aDeviceName[i] ); | 
|---|
| 426 | } | 
|---|
| 427 | sprintf( szNumber, "%u", pldn ); | 
|---|
| 428 | WriteStemElement( szStem, 0, szNumber ); | 
|---|
| 429 |  | 
|---|
| 430 | // Return 1 on success | 
|---|
| 431 | SaveResultString( prsResult, PSZ_ONE, 1 ); | 
|---|
| 432 |  | 
|---|
| 433 | #if 1 | 
|---|
| 434 | DosFreeMem( aDeviceName ); | 
|---|
| 435 | DosFreeMem( aDeviceDesc ); | 
|---|
| 436 | DosFreeMem( aDataType ); | 
|---|
| 437 | #else | 
|---|
| 438 | free( aDeviceName ); | 
|---|
| 439 | free( aDeviceDesc ); | 
|---|
| 440 | free( aDataType ); | 
|---|
| 441 | #endif | 
|---|
| 442 |  | 
|---|
| 443 | cleanup: | 
|---|
| 444 | WinTerminate( hab ); | 
|---|
| 445 | return ( 0 ); | 
|---|
| 446 | } | 
|---|
| 447 |  | 
|---|
| 448 |  | 
|---|
| 449 | /* ------------------------------------------------------------------------- * | 
|---|
| 450 | * RPUEnumPorts                                                              * | 
|---|
| 451 | *                                                                           * | 
|---|
| 452 | * Gets a list of the printer ports currently defined on the system. Returns * | 
|---|
| 453 | * a REXX array (stem) consisting of one string per port, of the form:       * | 
|---|
| 454 | *   <port> <driver> <driver path>                                           * | 
|---|
| 455 | *                                                                           * | 
|---|
| 456 | * REXX ARGUMENTS:                                                           * | 
|---|
| 457 | *   1. The name of the stem in which to return the results.      (REQUIRED) * | 
|---|
| 458 | *                                                                           * | 
|---|
| 459 | * REXX RETURN VALUE:                                                        * | 
|---|
| 460 | *   1 on success, or 0 if an error occurred.                                * | 
|---|
| 461 | * ------------------------------------------------------------------------- */ | 
|---|
| 462 | ULONG APIENTRY RPUEnumPorts( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 463 | { | 
|---|
| 464 | PPRPORTINFO1 pInfo; | 
|---|
| 465 | PVOID        pbuf; | 
|---|
| 466 | ULONG        cbBuf, | 
|---|
| 467 | cTotal, | 
|---|
| 468 | cReturned, | 
|---|
| 469 | cbNeeded, | 
|---|
| 470 | i; | 
|---|
| 471 | CHAR         szStem[ US_STEM_MAXZ ],      // buffers used for building stem | 
|---|
| 472 | szNumber[ US_INTEGER_MAXZ ], // ... | 
|---|
| 473 | szInfo[ US_DRVINFO_MAXZ ]; | 
|---|
| 474 | SPLERR       rc; | 
|---|
| 475 |  | 
|---|
| 476 | // Reset the error indicator | 
|---|
| 477 | WriteErrorCode( 0, NULL ); | 
|---|
| 478 |  | 
|---|
| 479 | // Make sure we have exactly one valid argument (the stem name) | 
|---|
| 480 | if (( argc != 1 ) || ( ! RXVALIDSTRING( argv[0] ))) | 
|---|
| 481 | return ( 40 ); | 
|---|
| 482 | if ( argv[0].strptr[ argv[0].strlength-1 ] == '.') argv[0].strlength--; | 
|---|
| 483 | strncpy( szStem, argv[0].strptr, RXSTRLEN( argv[0] )); | 
|---|
| 484 | szStem[ RXSTRLEN( argv[0] ) ] = '\0'; | 
|---|
| 485 |  | 
|---|
| 486 | // Query the amount of available data | 
|---|
| 487 | rc = SplEnumPort( NULL, 1, NULL, 0L, &cReturned, &cTotal, &cbNeeded, NULL ); | 
|---|
| 488 | if (( rc != ERROR_MORE_DATA ) && ( rc != NERR_BufTooSmall )) { | 
|---|
| 489 | WriteErrorCode( rc, "SplEnumPort"); | 
|---|
| 490 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 491 | return ( 0 ); | 
|---|
| 492 | } | 
|---|
| 493 |  | 
|---|
| 494 | // Now get the actual data | 
|---|
| 495 | pbuf = malloc( cbNeeded ); | 
|---|
| 496 | if ( !pbuf ) { | 
|---|
| 497 | WriteErrorCode( ERROR_NOT_ENOUGH_MEMORY, "malloc"); | 
|---|
| 498 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 499 | return ( 0 ); | 
|---|
| 500 | } | 
|---|
| 501 | cbBuf = cbNeeded; | 
|---|
| 502 | rc = SplEnumPort( NULL, 1, pbuf, cbBuf, | 
|---|
| 503 | &cReturned, &cTotal, &cbNeeded, NULL ); | 
|---|
| 504 | if ( rc == NO_ERROR ) { | 
|---|
| 505 | pInfo = (PPRPORTINFO1) pbuf; | 
|---|
| 506 | for ( i = 0; i < cReturned; i++ ) { | 
|---|
| 507 | sprintf( szInfo, "%.32s %.8s %s", | 
|---|
| 508 | pInfo->pszPortName, | 
|---|
| 509 | pInfo->pszPortDriverName? pInfo->pszPortDriverName: "", | 
|---|
| 510 | pInfo->pszPortDriverPathName? pInfo->pszPortDriverPathName: ""); | 
|---|
| 511 | WriteStemElement( szStem, i+1, szInfo ); | 
|---|
| 512 | pInfo++; | 
|---|
| 513 | } | 
|---|
| 514 | sprintf( szNumber, "%u", cReturned ); | 
|---|
| 515 | WriteStemElement( szStem, 0, szNumber ); | 
|---|
| 516 | SaveResultString( prsResult, PSZ_ONE, 1 ); | 
|---|
| 517 | } | 
|---|
| 518 | else { | 
|---|
| 519 | WriteErrorCode( rc, "SplEnumPort"); | 
|---|
| 520 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 521 | } | 
|---|
| 522 | free( pbuf ); | 
|---|
| 523 |  | 
|---|
| 524 | return ( 0 ); | 
|---|
| 525 | } | 
|---|
| 526 |  | 
|---|
| 527 |  | 
|---|
| 528 | /* ------------------------------------------------------------------------- * | 
|---|
| 529 | * RPUEnumDrivers                                                            * | 
|---|
| 530 | *                                                                           * | 
|---|
| 531 | * Gets a list of the printer drivers currently installed on the system.     * | 
|---|
| 532 | * Returns a REXX array (stem) with each item being a driver name string.    * | 
|---|
| 533 | *                                                                           * | 
|---|
| 534 | * REXX ARGUMENTS:                                                           * | 
|---|
| 535 | *   1. The name of the stem in which to return the results.      (REQUIRED) * | 
|---|
| 536 | *                                                                           * | 
|---|
| 537 | * REXX RETURN VALUE:                                                        * | 
|---|
| 538 | *   1 on success, or 0 if an error occurred.                                * | 
|---|
| 539 | * ------------------------------------------------------------------------- */ | 
|---|
| 540 | ULONG APIENTRY RPUEnumDrivers( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 541 | { | 
|---|
| 542 | PSZ    pszDriverName; | 
|---|
| 543 | PBYTE  pbuf; | 
|---|
| 544 | ULONG  cbBuf, | 
|---|
| 545 | cTotal, | 
|---|
| 546 | cReturned, | 
|---|
| 547 | cbNeeded, | 
|---|
| 548 | i; | 
|---|
| 549 | CHAR   szStem[ US_STEM_MAXZ ],      // buffers used for building stem | 
|---|
| 550 | szNumber[ US_INTEGER_MAXZ ]; // ... | 
|---|
| 551 | SPLERR rc; | 
|---|
| 552 |  | 
|---|
| 553 |  | 
|---|
| 554 | // Reset the error indicator | 
|---|
| 555 | WriteErrorCode( 0, NULL ); | 
|---|
| 556 |  | 
|---|
| 557 | // Make sure we have exactly one valid argument (the stem name) | 
|---|
| 558 | if (( argc != 1 ) || ( ! RXVALIDSTRING( argv[0] ))) | 
|---|
| 559 | return ( 40 ); | 
|---|
| 560 | if ( argv[0].strptr[ argv[0].strlength-1 ] == '.') argv[0].strlength--; | 
|---|
| 561 | strncpy( szStem, argv[0].strptr, RXSTRLEN( argv[0] )); | 
|---|
| 562 | szStem[ RXSTRLEN( argv[0] ) ] = '\0'; | 
|---|
| 563 |  | 
|---|
| 564 | // Query the amount of available data | 
|---|
| 565 | rc = SplEnumDriver( NULL, 0L, NULL, 0L, &cReturned, &cTotal, &cbNeeded, NULL ); | 
|---|
| 566 | if (( rc != ERROR_MORE_DATA ) && ( rc != NERR_BufTooSmall )) { | 
|---|
| 567 | WriteErrorCode( rc, "SplEnumDriver"); | 
|---|
| 568 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 569 | return ( 0 ); | 
|---|
| 570 | } | 
|---|
| 571 |  | 
|---|
| 572 | // Now get the actual data | 
|---|
| 573 | pbuf  = (PBYTE) malloc( cbNeeded ); | 
|---|
| 574 | if ( !pbuf ) { | 
|---|
| 575 | WriteErrorCode( ERROR_NOT_ENOUGH_MEMORY, "malloc"); | 
|---|
| 576 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 577 | return ( 0 ); | 
|---|
| 578 | } | 
|---|
| 579 | cbBuf = cbNeeded; | 
|---|
| 580 | rc = SplEnumDriver( NULL, 0L, pbuf, cbBuf, &cReturned ,&cTotal, &cbNeeded, NULL ) ; | 
|---|
| 581 | if ( rc == NO_ERROR ) { | 
|---|
| 582 | pszDriverName = (PSZ) pbuf; | 
|---|
| 583 | for ( i = 0; i < cReturned ; i++ ) { | 
|---|
| 584 | WriteStemElement( szStem, i+1, pszDriverName ); | 
|---|
| 585 | pszDriverName += DRIV_NAME_SIZE + DRIV_DEVICENAME_SIZE + 2; | 
|---|
| 586 | } | 
|---|
| 587 | sprintf( szNumber, "%u", cReturned ); | 
|---|
| 588 | WriteStemElement( szStem, 0, szNumber ); | 
|---|
| 589 | SaveResultString( prsResult, PSZ_ONE, 1 ); | 
|---|
| 590 | } | 
|---|
| 591 | else { | 
|---|
| 592 | WriteErrorCode( rc, "SplEnumDriver"); | 
|---|
| 593 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 594 | } | 
|---|
| 595 | free( pbuf ); | 
|---|
| 596 |  | 
|---|
| 597 | return ( 0 ); | 
|---|
| 598 | } | 
|---|
| 599 |  | 
|---|
| 600 |  | 
|---|
| 601 | /* ------------------------------------------------------------------------- * | 
|---|
| 602 | * RPUEnumPrinters                                                           * | 
|---|
| 603 | *                                                                           * | 
|---|
| 604 | * Gets a list of the printers currently defined on the system.  Returns a   * | 
|---|
| 605 | * compound (stem) variable with the following format:                       * | 
|---|
| 606 | *                                                                           * | 
|---|
| 607 | *   (stem).0               Number of printers                               * | 
|---|
| 608 | *   (stem).i.!name         Printer device (a.k.a. physical) name            * | 
|---|
| 609 | *   (stem).i.!queue        Printer queue name ('' for direct printers)      * | 
|---|
| 610 | *   (stem).i.!host         Name of LAN host where printer queue is located  * | 
|---|
| 611 | *                          ('' for non-LAN printers)                        * | 
|---|
| 612 | *   (stem).i.!description  Printer description (name of WPS object)         * | 
|---|
| 613 | *   (stem).i.!handle       Printer's object handle ('' for direct printers) * | 
|---|
| 614 | *   (stem).i.!flags        Zero or more of the following flags (any order): * | 
|---|
| 615 | *                            D  This is the default printer queue           * | 
|---|
| 616 | *                            P  Printer queue is paused (held)              * | 
|---|
| 617 | *                                                                           * | 
|---|
| 618 | * REXX ARGUMENTS:                                                           * | 
|---|
| 619 | *   1. The name of the stem in which to return the results.      (REQUIRED) * | 
|---|
| 620 | *                                                                           * | 
|---|
| 621 | * REXX RETURN VALUE:                                                        * | 
|---|
| 622 | *   1 on success, or 0 if an error occurred.                                * | 
|---|
| 623 | * ------------------------------------------------------------------------- */ | 
|---|
| 624 | ULONG APIENTRY RPUEnumPrinters( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 625 | { | 
|---|
| 626 | PPRINTERINFO pPInfo     = NULL;     // pointer to enumerated printer information | 
|---|
| 627 | PPRQINFO6    pQInfo     = NULL;     // queue information (level 6) | 
|---|
| 628 | PVOID        pbEnum     = NULL,     // buffer for SplEnumPrinter | 
|---|
| 629 | pbQueue    = NULL;     // buffer for SplQueryQueue | 
|---|
| 630 | PSZ          pszToken; | 
|---|
| 631 | HOBJECT      hObj;                  // printer WPS object handle | 
|---|
| 632 |  | 
|---|
| 633 | /* Note: SPL_PR_LOCAL_ONLY apparently doesn't prevent SplEnumPrinter from | 
|---|
| 634 | *       including remote printers, it only stops it from probing them | 
|---|
| 635 | *       to query the remote queue information in addition to the local | 
|---|
| 636 | *       queue.  Specifying it here prevents a 'stall' when the remote | 
|---|
| 637 | *       host is offline or unavailable. | 
|---|
| 638 | */ | 
|---|
| 639 | ULONG        flType     = SPL_PR_QUEUE | SPL_PR_DIRECT_DEVICE | SPL_PR_LOCAL_ONLY, | 
|---|
| 640 | cbBuf      = 0, | 
|---|
| 641 | cTotal     = 0, | 
|---|
| 642 | cReturned  = 0, | 
|---|
| 643 | cbNeeded   = 0, | 
|---|
| 644 | ulCount    = 0,        // number of printers found | 
|---|
| 645 | i; | 
|---|
| 646 | CHAR         szFlags[ 3 ],          // string of flag characters | 
|---|
| 647 | szHandle[ 9 ],         // string for hex object handle | 
|---|
| 648 | // buffers used for building compound variables: | 
|---|
| 649 | szStem[ US_STEM_MAXZ - US_INTEGER_MAXZ - 1 ], | 
|---|
| 650 | szNumber[ US_INTEGER_MAXZ ], | 
|---|
| 651 | szStemNode[ US_STEM_MAXZ ]; | 
|---|
| 652 | SPLERR       rc; | 
|---|
| 653 |  | 
|---|
| 654 |  | 
|---|
| 655 | // Reset the error indicator | 
|---|
| 656 | WriteErrorCode( 0, NULL ); | 
|---|
| 657 |  | 
|---|
| 658 | // Make sure we have exactly one valid argument (the stem name) | 
|---|
| 659 | if (( argc != 1 ) || ( ! RXVALIDSTRING( argv[0] ))) | 
|---|
| 660 | return ( 40 ); | 
|---|
| 661 | if ( argv[0].strptr[ argv[0].strlength-1 ] == '.') argv[0].strlength--; | 
|---|
| 662 | strncpy( szStem, argv[0].strptr, RXSTRLEN( argv[0] )); | 
|---|
| 663 | szStem[ RXSTRLEN( argv[0] ) ] = '\0'; | 
|---|
| 664 |  | 
|---|
| 665 |  | 
|---|
| 666 | /* Our enumeration query asks for two types of devices: direct (non-queued) | 
|---|
| 667 | * printers, and printer queues. | 
|---|
| 668 | * | 
|---|
| 669 | * In the latter case, it's important to note that we ask for the queues | 
|---|
| 670 | * themselves rather than queued printers.  Why?  Because we'll need to | 
|---|
| 671 | * gather information about both printers and their underlying queues (some | 
|---|
| 672 | * things associated with printer objects actually belong to the queue | 
|---|
| 673 | * rather than the printer device). | 
|---|
| 674 | * | 
|---|
| 675 | * The thing is, given a printer name, there doesn't seem to be an easy way | 
|---|
| 676 | * to find out the queue associated with it.  So we need to do it the other | 
|---|
| 677 | * way around: get the queue names, then we can identify the printers | 
|---|
| 678 | * connected to them. | 
|---|
| 679 | */ | 
|---|
| 680 |  | 
|---|
| 681 | // Query the amount of available data | 
|---|
| 682 | rc = SplEnumPrinter( NULL, 0L, flType, NULL, 0L, | 
|---|
| 683 | &cReturned, &cTotal, &cbNeeded, NULL ); | 
|---|
| 684 | if (( rc != ERROR_MORE_DATA ) && ( rc != NERR_BufTooSmall )) | 
|---|
| 685 | //   && ( rc != ERROR_INVALID_PARAMETER )) | 
|---|
| 686 | { | 
|---|
| 687 | WriteErrorCode( rc, "SplEnumPrinter"); | 
|---|
| 688 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 689 | return ( 0 ); | 
|---|
| 690 | } | 
|---|
| 691 |  | 
|---|
| 692 | // Now get the actual data | 
|---|
| 693 | pbEnum = malloc( cbNeeded ); | 
|---|
| 694 | if ( !pbEnum ) { | 
|---|
| 695 | WriteErrorCode( ERROR_NOT_ENOUGH_MEMORY, "malloc"); | 
|---|
| 696 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 697 | return ( 0 ); | 
|---|
| 698 | } | 
|---|
| 699 | cbBuf = cbNeeded; | 
|---|
| 700 | rc = SplEnumPrinter( NULL, 0L, flType, pbEnum, cbBuf, | 
|---|
| 701 | &cReturned, &cTotal, &cbNeeded, NULL ); | 
|---|
| 702 | if ( rc != NO_ERROR ) { | 
|---|
| 703 | WriteErrorCode( rc, "SplEnumPrinter"); | 
|---|
| 704 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 705 | goto cleanup; | 
|---|
| 706 | } | 
|---|
| 707 |  | 
|---|
| 708 | pPInfo = (PPRINTERINFO) pbEnum; | 
|---|
| 709 | for ( i = 0; i < cReturned; i++ ) { | 
|---|
| 710 |  | 
|---|
| 711 | if ( pPInfo->flType == SPL_PR_DIRECT_DEVICE ) { | 
|---|
| 712 |  | 
|---|
| 713 | /* Direct print device.  No queue, no handle; flags do not apply. | 
|---|
| 714 | * The destination name and description are those of the printer | 
|---|
| 715 | * device itself, so we don't need any additional queries. | 
|---|
| 716 | */ | 
|---|
| 717 | sprintf( szStemNode, "%s.%u", szStem, ++ulCount ); | 
|---|
| 718 |  | 
|---|
| 719 | WriteCompoundVariable( szStemNode, "!name", | 
|---|
| 720 | pPInfo->pszPrintDestinationName ); | 
|---|
| 721 | WriteCompoundVariable( szStemNode, "!description", | 
|---|
| 722 | pPInfo->pszDescription ); | 
|---|
| 723 | WriteCompoundVariable( szStemNode, "!queue", ""); | 
|---|
| 724 | WriteCompoundVariable( szStemNode, "!flags", ""); | 
|---|
| 725 | WriteCompoundVariable( szStemNode, "!handle", ""); | 
|---|
| 726 |  | 
|---|
| 727 | WriteCompoundVariable( szStemNode, "!host", | 
|---|
| 728 | pPInfo->pszComputerName? | 
|---|
| 729 | pPInfo->pszComputerName: ""); | 
|---|
| 730 | } | 
|---|
| 731 | else if ( pPInfo->flType == SPL_PR_QUEUE ) { | 
|---|
| 732 |  | 
|---|
| 733 | /* Print queue.  We need to query the queue to find out the details | 
|---|
| 734 | * of the print device(s) connected to it. | 
|---|
| 735 | */ | 
|---|
| 736 | rc = SplQueryQueue( pPInfo->pszComputerName, | 
|---|
| 737 | pPInfo->pszPrintDestinationName, | 
|---|
| 738 | 6L, NULL, 0L, &cbNeeded ); | 
|---|
| 739 | if (( rc != NO_ERROR ) && ( rc != NERR_BufTooSmall )) { | 
|---|
| 740 | WriteErrorCode( rc, "SplQueryQueue"); | 
|---|
| 741 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 742 | //goto cleanup; | 
|---|
| 743 | continue; | 
|---|
| 744 | } | 
|---|
| 745 | pbQueue = malloc( cbNeeded ); | 
|---|
| 746 | if ( !pbQueue ) { | 
|---|
| 747 | WriteErrorCode( ERROR_NOT_ENOUGH_MEMORY, "malloc"); | 
|---|
| 748 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 749 | //goto cleanup; | 
|---|
| 750 | continue; | 
|---|
| 751 | } | 
|---|
| 752 | cbBuf = cbNeeded; | 
|---|
| 753 | rc = SplQueryQueue( pPInfo->pszComputerName, pPInfo->pszPrintDestinationName, | 
|---|
| 754 | 6L, pbQueue, cbBuf, &cbNeeded ); | 
|---|
| 755 | if ( rc != NO_ERROR ) { | 
|---|
| 756 | WriteErrorCode( rc, "SplQueryQueue"); | 
|---|
| 757 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 758 | free( pbQueue ); | 
|---|
| 759 | //goto cleanup; | 
|---|
| 760 | continue; | 
|---|
| 761 | } | 
|---|
| 762 | pQInfo = (PPRQINFO6) pbQueue; | 
|---|
| 763 |  | 
|---|
| 764 | // Now go through the list of printers connected to this queue... | 
|---|
| 765 | pszToken = strtok( pQInfo->pszPrinters, ","); | 
|---|
| 766 | while ( pszToken ) { | 
|---|
| 767 | sprintf( szStemNode, "%s.%u", szStem, ++ulCount ); | 
|---|
| 768 | WriteCompoundVariable( szStemNode, "!name", pszToken ); | 
|---|
| 769 | WriteCompoundVariable( szStemNode, "!description", pQInfo->pszComment ); | 
|---|
| 770 | WriteCompoundVariable( szStemNode, "!queue", pQInfo->pszName ); | 
|---|
| 771 | WriteCompoundVariable( szStemNode, "!driver", pQInfo->pszDriverName ); | 
|---|
| 772 | WriteCompoundVariable( szStemNode, "!host", | 
|---|
| 773 | pQInfo->pszRemoteComputerName ? | 
|---|
| 774 | pQInfo->pszRemoteComputerName: ""); | 
|---|
| 775 |  | 
|---|
| 776 | hObj = PrinterObjectHandle( pQInfo->pszName ); | 
|---|
| 777 | if ( hObj ) | 
|---|
| 778 | sprintf( szHandle, "%X", hObj ); | 
|---|
| 779 | else | 
|---|
| 780 | sprintf( szHandle, ""); | 
|---|
| 781 | WriteCompoundVariable( szStemNode, "!handle", szHandle ); | 
|---|
| 782 |  | 
|---|
| 783 | memset( szFlags, 0, sizeof( szFlags )); | 
|---|
| 784 | if ( pQInfo->fsType & PRQ3_TYPE_APPDEFAULT ) | 
|---|
| 785 | strcat( szFlags, "D"); | 
|---|
| 786 | if ( pQInfo->fsStatus & PRQ3_PAUSED ) | 
|---|
| 787 | strcat( szFlags, "P"); | 
|---|
| 788 | WriteCompoundVariable( szStemNode, "!flags", szFlags ); | 
|---|
| 789 |  | 
|---|
| 790 | pszToken = strtok( NULL, ","); | 
|---|
| 791 | } // while | 
|---|
| 792 |  | 
|---|
| 793 | free( pbQueue ); | 
|---|
| 794 | } | 
|---|
| 795 |  | 
|---|
| 796 | pPInfo++; | 
|---|
| 797 | } | 
|---|
| 798 | sprintf( szNumber, "%u", ulCount ); | 
|---|
| 799 | WriteStemElement( szStem, 0, szNumber ); | 
|---|
| 800 | SaveResultString( prsResult, PSZ_ONE, 1 ); | 
|---|
| 801 |  | 
|---|
| 802 | cleanup: | 
|---|
| 803 | free( pbEnum ); | 
|---|
| 804 | return ( 0 ); | 
|---|
| 805 | } | 
|---|
| 806 |  | 
|---|
| 807 |  | 
|---|
| 808 | /* ------------------------------------------------------------------------- * | 
|---|
| 809 | * RPUOpenView                                                               * | 
|---|
| 810 | *                                                                           * | 
|---|
| 811 | * Opens the requested view of the WPS object corresponding to the specified * | 
|---|
| 812 | * print queue.  (Note that WPS printer objects are associated with a queue  * | 
|---|
| 813 | * rather than a printer device, so it is the queue name that must be passed * | 
|---|
| 814 | * to this function.)                                                        * | 
|---|
| 815 | *                                                                           * | 
|---|
| 816 | * REXX ARGUMENTS:                                                           * | 
|---|
| 817 | *   1. The name of the printer queue for the object to open.  (REQUIRED)    * | 
|---|
| 818 | *   2. Optional view flag, one of:                                          * | 
|---|
| 819 | *        O  Object's default view  (DEFAULT)                                * | 
|---|
| 820 | *        D  Details view                                                    * | 
|---|
| 821 | *        I  Icon view                                                       * | 
|---|
| 822 | *        S  Settings                                                        * | 
|---|
| 823 | *                                                                           * | 
|---|
| 824 | * REXX RETURN VALUE:                                                        * | 
|---|
| 825 | *   1 on success, or 0 if an error occurred.                                * | 
|---|
| 826 | * ------------------------------------------------------------------------- */ | 
|---|
| 827 | ULONG APIENTRY RPUOpenView( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 828 | { | 
|---|
| 829 | HOBJECT hObj; | 
|---|
| 830 | ULONG   ulView = OPEN_DEFAULT; | 
|---|
| 831 | BOOL    fRC; | 
|---|
| 832 |  | 
|---|
| 833 |  | 
|---|
| 834 | // Reset the error indicator | 
|---|
| 835 | WriteErrorCode( 0, NULL ); | 
|---|
| 836 |  | 
|---|
| 837 | // Make sure we have at least one valid argument (the queue name) | 
|---|
| 838 | if ( argc < 1  || ( !RXVALIDSTRING(argv[0]) )) return ( 40 ); | 
|---|
| 839 | pszName = argv[0].strptr; | 
|---|
| 840 |  | 
|---|
| 841 | // Second argument: view (optional, but must be correct if specified) | 
|---|
| 842 | if ( argc == 2 ) { | 
|---|
| 843 | if ( RXVALIDSTRING(argv[1]) ) { | 
|---|
| 844 | switch ( argv[1].strptr[0] ) { | 
|---|
| 845 | case 'o': | 
|---|
| 846 | case 'O': ulView = OPEN_DEFAULT;  break; | 
|---|
| 847 | case 'd': | 
|---|
| 848 | case 'D': ulView = OPEN_DETAILS;  break; | 
|---|
| 849 | case 'i': | 
|---|
| 850 | case 'I': ulView = OPEN_CONTENTS; break; | 
|---|
| 851 | case 's': | 
|---|
| 852 | case 'S': ulView = OPEN_SETTINGS; break; | 
|---|
| 853 | default : return ( 40 ); | 
|---|
| 854 | } | 
|---|
| 855 | } | 
|---|
| 856 | else return ( 40 ); | 
|---|
| 857 | } | 
|---|
| 858 | if ( argc > 2 ) return ( 40 ); | 
|---|
| 859 |  | 
|---|
| 860 | hObj = PrinterObjectHandle( pszName ); | 
|---|
| 861 | if ( !hObj ) { | 
|---|
| 862 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 863 | return ( 0 ); | 
|---|
| 864 | } | 
|---|
| 865 |  | 
|---|
| 866 | fRC = WinOpenObject( hObj, ulView, TRUE ); | 
|---|
| 867 |  | 
|---|
| 868 | SaveResultString( prsResult, fRC? PSZ_ONE: PSZ_ZERO, 1 ); | 
|---|
| 869 | return ( 0 ); | 
|---|
| 870 | } | 
|---|
| 871 |  | 
|---|
| 872 |  | 
|---|
| 873 | /* ------------------------------------------------------------------------- * | 
|---|
| 874 | * RPUPortInfo                                                               * | 
|---|
| 875 | *                                                                           * | 
|---|
| 876 | * Queries basic information about a local port.  This is different from     * | 
|---|
| 877 | * RPUPortQuery() in that the latter returns port configuration information  * | 
|---|
| 878 | * from the port driver itself, whereas this function only returns what the  * | 
|---|
| 879 | * spooler itself knows about the port.                                      * | 
|---|
| 880 | *                                                                           * | 
|---|
| 881 | * REXX ARGUMENTS:                                                           * | 
|---|
| 882 | *   1. The name of the port.                                     (REQUIRED) * | 
|---|
| 883 | *   2. The name of the stem in which to return the results:      (REQUIRED) * | 
|---|
| 884 | *      (stem).!name       The name of the port                              * | 
|---|
| 885 | *      (stem).!driver     The name of the port driver                       * | 
|---|
| 886 | *      (stem).!converter  The name of the protocol converter used           * | 
|---|
| 887 | *   TODO                                                                    * | 
|---|
| 888 | *      (stem).!printer    The device name of the printer(s) using this      * | 
|---|
| 889 | *                         port, if any ('' if not in use)                   * | 
|---|
| 890 | *                                                                           * | 
|---|
| 891 | * REXX RETURN VALUE:                                                        * | 
|---|
| 892 | *   1 on success, or 0 if an error occurred.                                * | 
|---|
| 893 | * ------------------------------------------------------------------------- */ | 
|---|
| 894 | ULONG APIENTRY RPUPortInfo( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 895 | { | 
|---|
| 896 | PPRPORTINFO2 pInfo      = NULL; | 
|---|
| 897 | PVOID        pbuf       = NULL; | 
|---|
| 898 | ULONG        cbBuf      = 0, | 
|---|
| 899 | cbNeeded   = 0; | 
|---|
| 900 | CHAR         szStem[ US_STEM_MAXZ ];   // compound variable stem name | 
|---|
| 901 | PSZ          pszPortName; | 
|---|
| 902 | SPLERR       rc; | 
|---|
| 903 |  | 
|---|
| 904 |  | 
|---|
| 905 | // Reset the error indicator | 
|---|
| 906 | WriteErrorCode( 0, NULL ); | 
|---|
| 907 |  | 
|---|
| 908 | // Validate the REXX arguments | 
|---|
| 909 | if (( argc != 2 ) || | 
|---|
| 910 | ( ! RXVALIDSTRING( argv[0] )) || ( ! RXVALIDSTRING( argv[1] ))) | 
|---|
| 911 | return ( 40 ); | 
|---|
| 912 |  | 
|---|
| 913 | pszPortName = argv[0].strptr; | 
|---|
| 914 |  | 
|---|
| 915 | // Initialize the result stem name | 
|---|
| 916 | if ( RXSTRLEN(argv[1]) > US_STEM_MAXZ ) return ( 40 ); | 
|---|
| 917 | if ( argv[1].strptr[ argv[1].strlength-1 ] == '.') argv[1].strlength--; | 
|---|
| 918 | strncpy( szStem, argv[1].strptr, RXSTRLEN( argv[1] )); | 
|---|
| 919 | szStem[ RXSTRLEN( argv[1] ) ] = '\0'; | 
|---|
| 920 |  | 
|---|
| 921 |  | 
|---|
| 922 | // Query the amount of available data | 
|---|
| 923 | rc = SplQueryPort( NULL, pszPortName, 2L, NULL, 0L, &cbNeeded ); | 
|---|
| 924 | if (( rc != ERROR_MORE_DATA ) && ( rc != NERR_BufTooSmall )) | 
|---|
| 925 | { | 
|---|
| 926 | WriteErrorCode( rc, "SplQueryPort"); | 
|---|
| 927 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 928 | return ( 0 ); | 
|---|
| 929 | } | 
|---|
| 930 |  | 
|---|
| 931 | // Now get the actual data | 
|---|
| 932 | pbuf = malloc( cbNeeded ); | 
|---|
| 933 | if ( !pbuf ) { | 
|---|
| 934 | WriteErrorCode( ERROR_NOT_ENOUGH_MEMORY, "malloc"); | 
|---|
| 935 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 936 | return ( 0 ); | 
|---|
| 937 | } | 
|---|
| 938 | cbBuf = cbNeeded; | 
|---|
| 939 | rc = SplQueryPort( NULL, pszPortName, 2L, pbuf, cbBuf, &cbNeeded ); | 
|---|
| 940 | if ( rc == NO_ERROR ) { | 
|---|
| 941 | pInfo = (PPRPORTINFO2) pbuf; | 
|---|
| 942 | WriteCompoundVariable( szStem, "!name",      pInfo->pszPortName ); | 
|---|
| 943 | WriteCompoundVariable( szStem, "!driver",    pInfo->pszPortDriver ); | 
|---|
| 944 | WriteCompoundVariable( szStem, "!converter", pInfo->pszProtocolConverter ); | 
|---|
| 945 | SaveResultString( prsResult, PSZ_ONE, 1 ); | 
|---|
| 946 | } | 
|---|
| 947 | else { | 
|---|
| 948 | WriteErrorCode( rc, "SplQueryPort"); | 
|---|
| 949 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 950 | } | 
|---|
| 951 |  | 
|---|
| 952 | free( pbuf ); | 
|---|
| 953 | return ( 0 ); | 
|---|
| 954 | } | 
|---|
| 955 |  | 
|---|
| 956 |  | 
|---|
| 957 | /* ------------------------------------------------------------------------- * | 
|---|
| 958 | * RPUPortInstall                                                            * | 
|---|
| 959 | *                                                                           * | 
|---|
| 960 | * Creates a new printer port.                                               * | 
|---|
| 961 | *                                                                           * | 
|---|
| 962 | * REXX ARGUMENTS:                                                           * | 
|---|
| 963 | *   1. The name of the port driver without any extension.  This must be     * | 
|---|
| 964 | *      installed and registered in OS2.INI already.         (REQUIRED)      * | 
|---|
| 965 | *   2. The name of the new port to be created.  If not specified, the port  * | 
|---|
| 966 | *      driver will be responsible for using a default name.  This should    * | 
|---|
| 967 | *      generally be specified, as the driver is not guaranteed to support   * | 
|---|
| 968 | *      omitting it.                                         (DEFAULT: none) * | 
|---|
| 969 | *                                                                           * | 
|---|
| 970 | * REXX RETURN VALUE:                                                        * | 
|---|
| 971 | *   1 on success, or 0 if an error occurred.                                * | 
|---|
| 972 | * ------------------------------------------------------------------------- */ | 
|---|
| 973 | ULONG APIENTRY RPUPortInstall( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 974 | { | 
|---|
| 975 | HAB     hab;                        // desktop anchor-block handle | 
|---|
| 976 | HMODULE hPdr = NULLHANDLE;          // handle to port driver module | 
|---|
| 977 | PFN     pfnInstallPort;             // pointer to driver's SplPdInstallPort entrypoint | 
|---|
| 978 | ULONG   ulCB;                       // return value from PrfQueryProfileString() | 
|---|
| 979 | PSZ     pszPdrName     = NULL,      // name of the specified port driver | 
|---|
| 980 | pszPortName    = NULL;      // name of the new port to create | 
|---|
| 981 | CHAR    szPathName[ CCHMAXPATH+1 ]; // FQN of the port driver module | 
|---|
| 982 | APIRET  rc = 0;                     // return code from Dos...() functions | 
|---|
| 983 |  | 
|---|
| 984 |  | 
|---|
| 985 | // Reset the error indicator | 
|---|
| 986 | WriteErrorCode( 0, NULL ); | 
|---|
| 987 |  | 
|---|
| 988 | // Make sure we have at least one valid argument (the port driver name) | 
|---|
| 989 | if ( argc < 1  || ( !RXVALIDSTRING(argv[0]) )) return ( 40 ); | 
|---|
| 990 | pszPdrName = argv[0].strptr; | 
|---|
| 991 |  | 
|---|
| 992 | // Second argument: new port name (optional, but must be correct if specified) | 
|---|
| 993 | if ( argc >= 2 ) { | 
|---|
| 994 | if ( RXVALIDSTRING(argv[1]) ) | 
|---|
| 995 | pszPortName = strupr( argv[1].strptr ); | 
|---|
| 996 | else return ( 40 ); | 
|---|
| 997 | } | 
|---|
| 998 |  | 
|---|
| 999 | // Get the path to the installed port driver | 
|---|
| 1000 | hab = WinInitialize( 0 ); | 
|---|
| 1001 | if ( !hab ) { | 
|---|
| 1002 | WriteErrorCode( 0, "WinInitialize"); | 
|---|
| 1003 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1004 | return ( 0 ); | 
|---|
| 1005 | } | 
|---|
| 1006 |  | 
|---|
| 1007 | ulCB = PrfQueryProfileString( HINI_SYSTEMPROFILE, APPNAME_PM_PORT_DRIVER, | 
|---|
| 1008 | pszPdrName, NULL, (PVOID) szPathName, CCHMAXPATH ); | 
|---|
| 1009 | if ( !ulCB ) { | 
|---|
| 1010 | WriteErrorCode( ERRORIDERROR( WinGetLastError( hab )), "PrfQueryProfileString"); | 
|---|
| 1011 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1012 | goto cleanup; | 
|---|
| 1013 | } | 
|---|
| 1014 |  | 
|---|
| 1015 | // Load the port driver DLL and register its port install routine | 
|---|
| 1016 | rc = DosLoadModule( NULL, 0, szPathName, &hPdr ); | 
|---|
| 1017 | if ( rc != NO_ERROR || !hPdr ) { | 
|---|
| 1018 | WriteErrorCode( rc, "DosLoadModule"); | 
|---|
| 1019 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1020 | goto cleanup; | 
|---|
| 1021 | } | 
|---|
| 1022 | rc = DosQueryProcAddr( hPdr, 0, "SPLPDINSTALLPORT", &pfnInstallPort ); | 
|---|
| 1023 | if ( rc != NO_ERROR ) { | 
|---|
| 1024 | WriteErrorCode( rc, "DosQueryProcAddr"); | 
|---|
| 1025 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1026 | goto finish; | 
|---|
| 1027 | } | 
|---|
| 1028 |  | 
|---|
| 1029 | // Now create the new port (the driver will assign it default settings) | 
|---|
| 1030 | rc = pfnInstallPort( hab, pszPortName ); | 
|---|
| 1031 | if ( rc == NO_ERROR ) { | 
|---|
| 1032 | // Return 1 on success | 
|---|
| 1033 | SaveResultString( prsResult, PSZ_ONE, 1 ); | 
|---|
| 1034 | } | 
|---|
| 1035 | else { | 
|---|
| 1036 | WriteErrorCode( rc, "SplPdInstallPort"); | 
|---|
| 1037 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1038 | } | 
|---|
| 1039 |  | 
|---|
| 1040 | finish: | 
|---|
| 1041 | DosFreeModule( hPdr ); | 
|---|
| 1042 | cleanup: | 
|---|
| 1043 | WinTerminate( hab ); | 
|---|
| 1044 | return ( 0 ); | 
|---|
| 1045 | } | 
|---|
| 1046 |  | 
|---|
| 1047 |  | 
|---|
| 1048 | /* ------------------------------------------------------------------------- * | 
|---|
| 1049 | * RPUPortQuery                                                              * | 
|---|
| 1050 | *                                                                           * | 
|---|
| 1051 | * Queries the specified port's configuration settings.  IMPORTANT: not all  * | 
|---|
| 1052 | * port drivers support this; the standard OS/2 serial and parallel port     * | 
|---|
| 1053 | * drivers do NOT.  When this API is not supported, the return value should  * | 
|---|
| 1054 | * be ''.  Otherwise, the format of the returned configuration data is a     * | 
|---|
| 1055 | * string of binary data in port driver-specific format (the caller assumes  * | 
|---|
| 1056 | * responsibility for knowing how to interpret it).                          * | 
|---|
| 1057 | *                                                                           * | 
|---|
| 1058 | * REXX ARGUMENTS:                                                           * | 
|---|
| 1059 | *   1. The name of the port driver without any extension.  This must be     * | 
|---|
| 1060 | *      installed and registered in OS2.INI already.              (REQUIRED) * | 
|---|
| 1061 | *   2. The name of the port to be queried.                       (REQUIRED) * | 
|---|
| 1062 | *                                                                           * | 
|---|
| 1063 | * REXX RETURN VALUE:                                                        * | 
|---|
| 1064 | *   Binary data representing the port configuration, in whatever format is  * | 
|---|
| 1065 | *   returned by the driver's SplPdQuery->BIDI_Q_PORTDRV routine.  This      * | 
|---|
| 1066 | *   depends on the particular port driver; consult its API documentation.   * | 
|---|
| 1067 | *   '' will be returned if an error occurred.                               * | 
|---|
| 1068 | * ------------------------------------------------------------------------- */ | 
|---|
| 1069 | ULONG APIENTRY RPUPortQuery( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 1070 | { | 
|---|
| 1071 | HAB     hab;                        // desktop anchor-block handle | 
|---|
| 1072 | HMODULE hPdr = NULLHANDLE;          // handle to port driver module | 
|---|
| 1073 | PFN     pfnQueryPort;               // pointer to driver's SplPdSet entrypoint | 
|---|
| 1074 | ULONG   ulCB,                       // return value from PrfQueryProfileString() | 
|---|
| 1075 | cBuf;                       // size of configuration buffer | 
|---|
| 1076 | PSZ     pszPdrName  = NULL,         // name of the specified port driver | 
|---|
| 1077 | pszPortName = NULL;         // name of the new port to create | 
|---|
| 1078 | CHAR    szPathName[ CCHMAXPATH+1 ]; // FQN of the port driver module | 
|---|
| 1079 | PBYTE   pBuf;                       // Pointer to configuration buffer | 
|---|
| 1080 | APIRET  rc = 0;                     // return code from Dos...() functions | 
|---|
| 1081 |  | 
|---|
| 1082 |  | 
|---|
| 1083 | // Reset the error indicator | 
|---|
| 1084 | WriteErrorCode( 0, NULL ); | 
|---|
| 1085 |  | 
|---|
| 1086 | // Make sure we have exactly two valid arguments | 
|---|
| 1087 | if ( argc != 2 || | 
|---|
| 1088 | !RXVALIDSTRING( argv[0] ) || | 
|---|
| 1089 | !RXVALIDSTRING( argv[1] )) | 
|---|
| 1090 | return ( 40 ); | 
|---|
| 1091 | pszPdrName  = strupr( argv[0].strptr ); | 
|---|
| 1092 | pszPortName = strupr( argv[1].strptr ); | 
|---|
| 1093 |  | 
|---|
| 1094 | // Get the path to the installed port driver | 
|---|
| 1095 | hab = WinInitialize( 0 ); | 
|---|
| 1096 | if ( !hab ) { | 
|---|
| 1097 | WriteErrorCode( 0, "WinInitialize"); | 
|---|
| 1098 | SaveResultString( prsResult, NULL, 0 ); | 
|---|
| 1099 | return ( 0 ); | 
|---|
| 1100 | } | 
|---|
| 1101 |  | 
|---|
| 1102 | ulCB = PrfQueryProfileString( HINI_SYSTEMPROFILE, APPNAME_PM_PORT_DRIVER, | 
|---|
| 1103 | pszPdrName, NULL, (PVOID) szPathName, CCHMAXPATH ); | 
|---|
| 1104 | if ( !ulCB ) { | 
|---|
| 1105 | WriteErrorCode( ERRORIDERROR( WinGetLastError( hab )), "PrfQueryProfileString"); | 
|---|
| 1106 | SaveResultString( prsResult, NULL, 0 ); | 
|---|
| 1107 | goto cleanup; | 
|---|
| 1108 | } | 
|---|
| 1109 |  | 
|---|
| 1110 | // Load the port driver DLL and register its query routine | 
|---|
| 1111 | rc = DosLoadModule( NULL, 0, szPathName, &hPdr ); | 
|---|
| 1112 | if ( rc != NO_ERROR || !hPdr ) { | 
|---|
| 1113 | WriteErrorCode( rc, "DosLoadModule"); | 
|---|
| 1114 | SaveResultString( prsResult, NULL, 0 ); | 
|---|
| 1115 | goto cleanup; | 
|---|
| 1116 | } | 
|---|
| 1117 | rc = DosQueryProcAddr( hPdr, 0, "SPLPDQUERY", &pfnQueryPort ); | 
|---|
| 1118 | if ( rc != NO_ERROR ) { | 
|---|
| 1119 | WriteErrorCode( rc, "DosQueryProcAddr"); | 
|---|
| 1120 | SaveResultString( prsResult, NULL, 0 ); | 
|---|
| 1121 | goto finish; | 
|---|
| 1122 | } | 
|---|
| 1123 |  | 
|---|
| 1124 | // Now get the port configuration | 
|---|
| 1125 | rc = pfnQueryPort( pszPortName, TYPE_SHORT_WAIT, BIDI_Q_PORTDRV, NULL, 0, NULL, &cBuf ); | 
|---|
| 1126 | if ( cBuf && ( rc == NO_ERROR ) || | 
|---|
| 1127 | ( rc == ERROR_MORE_DATA ) || ( rc == NERR_BufTooSmall )) | 
|---|
| 1128 | { | 
|---|
| 1129 | pBuf = (PBYTE) malloc( cBuf ); | 
|---|
| 1130 | if ( pBuf ) { | 
|---|
| 1131 | rc = pfnQueryPort( pszPortName, TYPE_SHORT_WAIT, BIDI_Q_PORTDRV, NULL, 0, pBuf, &cBuf ); | 
|---|
| 1132 | if ( rc == NO_ERROR ) { | 
|---|
| 1133 | // Write the data contents to our return RXSTRING | 
|---|
| 1134 | if ( !SaveResultString( prsResult, pBuf, cBuf )) | 
|---|
| 1135 | SaveResultString( prsResult, NULL, 0 ); | 
|---|
| 1136 | } | 
|---|
| 1137 | else { | 
|---|
| 1138 | WriteErrorCode( rc, "SplPdQuery 2"); | 
|---|
| 1139 | SaveResultString( prsResult, NULL, 0 ); | 
|---|
| 1140 | } | 
|---|
| 1141 | free( pBuf ); | 
|---|
| 1142 | } | 
|---|
| 1143 | else { | 
|---|
| 1144 | WriteErrorCode( ERROR_NOT_ENOUGH_MEMORY, "malloc"); | 
|---|
| 1145 | SaveResultString( prsResult, NULL, 0 ); | 
|---|
| 1146 | } | 
|---|
| 1147 | } | 
|---|
| 1148 | else { | 
|---|
| 1149 | WriteErrorCode( rc, "SplPdQuery 1"); | 
|---|
| 1150 | SaveResultString( prsResult, NULL, 0 ); | 
|---|
| 1151 | } | 
|---|
| 1152 |  | 
|---|
| 1153 | finish: | 
|---|
| 1154 | DosFreeModule( hPdr ); | 
|---|
| 1155 | cleanup: | 
|---|
| 1156 | WinTerminate( hab ); | 
|---|
| 1157 | return ( 0 ); | 
|---|
| 1158 | } | 
|---|
| 1159 |  | 
|---|
| 1160 |  | 
|---|
| 1161 | /* ------------------------------------------------------------------------- * | 
|---|
| 1162 | * RPUPortSet                                                                * | 
|---|
| 1163 | *                                                                           * | 
|---|
| 1164 | * Sets the specified port's configuration settings.  IMPORTANT: not all     * | 
|---|
| 1165 | * port drivers support this; the standard OS/2 serial and parallel port     * | 
|---|
| 1166 | * drivers do NOT.  Depending on the port driver, there are two possible     * | 
|---|
| 1167 | * outcomes when this API is not supported:                                  * | 
|---|
| 1168 | *   A. Port driver does not have an entrypoint for SplPdSet. This is the    * | 
|---|
| 1169 | *      case for any port driver using pre-Warp conventions. RPUPortSet will * | 
|---|
| 1170 | *      return 0 and RPUERROR will be "1: DosQueryProcAddr".                 * | 
|---|
| 1171 | *   B. Port driver supports SplPdSet but does not (correctly) implement the * | 
|---|
| 1172 | *      BIDI_SET_PORTDRV command. This is the case for some third-party port * | 
|---|
| 1173 | *      drivers. In this case, whether or not RPUPortSet returns a success   * | 
|---|
| 1174 | *      code entirely depends on how conscientiously the port driver itself  * | 
|---|
| 1175 | *      is written, but the "INITIALIZATION" key (and possibly others) in    * | 
|---|
| 1176 | *      the port's entry in OS2SYS.INI will not be updated. The application  * | 
|---|
| 1177 | *      should always check for this after calling RPUPortSet!               * | 
|---|
| 1178 | * If the application determines that either of these failure conditions has * | 
|---|
| 1179 | * occurred, it is advisable to call RPUPortDialog as a fallback measure.    * | 
|---|
| 1180 | *                                                                           * | 
|---|
| 1181 | * Because of the above, use of this function is not generally encouraged    * | 
|---|
| 1182 | * except when absolutely necessary.                                         * | 
|---|
| 1183 | *                                                                           * | 
|---|
| 1184 | * REXX ARGUMENTS:                                                           * | 
|---|
| 1185 | *   1. The name of the port driver without any extension.  This must be     * | 
|---|
| 1186 | *      installed and registered in OS2.INI already.              (REQUIRED) * | 
|---|
| 1187 | *   2. The name of the port to be configured.                    (REQUIRED) * | 
|---|
| 1188 | *   3. Byte sequence representing the new port configuration.  The format   * | 
|---|
| 1189 | *      depends on the port driver (and it is up to the caller to know what  * | 
|---|
| 1190 | *      it is).                                                   (REQUIRED) * | 
|---|
| 1191 | *                                                                           * | 
|---|
| 1192 | * REXX RETURN VALUE:                                                        * | 
|---|
| 1193 | *   1 on success, or 0 if an error occurred.                                * | 
|---|
| 1194 | * ------------------------------------------------------------------------- */ | 
|---|
| 1195 | ULONG APIENTRY RPUPortSet( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 1196 | { | 
|---|
| 1197 | HAB     hab;                        // desktop anchor-block handle | 
|---|
| 1198 | HMODULE hPdr = NULLHANDLE;          // handle to port driver module | 
|---|
| 1199 | PFN     pfnSetPort;                 // pointer to driver's SplPdSet entrypoint | 
|---|
| 1200 | ULONG   ulCB,                       // return value from PrfQueryProfileString() | 
|---|
| 1201 | cBuf;                       // size of configuration buffer | 
|---|
| 1202 | PSZ     pszPdrName  = NULL,         // name of the specified port driver | 
|---|
| 1203 | pszPortName = NULL;         // name of the new port to create | 
|---|
| 1204 | CHAR    szPathName[ CCHMAXPATH+1 ]; // FQN of the port driver module | 
|---|
| 1205 | PBYTE   pBuf;                       // Pointer to configuration buffer | 
|---|
| 1206 | APIRET  rc = 0;                     // return code from Dos...() functions | 
|---|
| 1207 |  | 
|---|
| 1208 |  | 
|---|
| 1209 | // Reset the error indicator | 
|---|
| 1210 | WriteErrorCode( 0, NULL ); | 
|---|
| 1211 |  | 
|---|
| 1212 | // Make sure we have exactly three valid arguments | 
|---|
| 1213 | if ( argc != 3 || | 
|---|
| 1214 | !RXVALIDSTRING( argv[0] ) || | 
|---|
| 1215 | !RXVALIDSTRING( argv[1] ) || | 
|---|
| 1216 | !RXVALIDSTRING( argv[2] )  ) | 
|---|
| 1217 | return ( 40 ); | 
|---|
| 1218 | pszPdrName  = strupr( argv[0].strptr ); | 
|---|
| 1219 | pszPortName = strupr( argv[1].strptr ); | 
|---|
| 1220 | pBuf        = argv[2].strptr; | 
|---|
| 1221 | cBuf        = argv[2].strlength; | 
|---|
| 1222 |  | 
|---|
| 1223 | // Get the path to the installed port driver | 
|---|
| 1224 | hab = WinInitialize( 0 ); | 
|---|
| 1225 | if ( !hab ) { | 
|---|
| 1226 | WriteErrorCode( 0, "WinInitialize"); | 
|---|
| 1227 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1228 | return ( 0 ); | 
|---|
| 1229 | } | 
|---|
| 1230 |  | 
|---|
| 1231 | ulCB = PrfQueryProfileString( HINI_SYSTEMPROFILE, APPNAME_PM_PORT_DRIVER, | 
|---|
| 1232 | pszPdrName, NULL, (PVOID) szPathName, CCHMAXPATH ); | 
|---|
| 1233 | if ( !ulCB ) { | 
|---|
| 1234 | WriteErrorCode( ERRORIDERROR( WinGetLastError( hab )), "PrfQueryProfileString"); | 
|---|
| 1235 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1236 | goto cleanup; | 
|---|
| 1237 | } | 
|---|
| 1238 |  | 
|---|
| 1239 | // Load the port driver DLL and register its configuration routine | 
|---|
| 1240 | rc = DosLoadModule( NULL, 0, szPathName, &hPdr ); | 
|---|
| 1241 | if ( rc != NO_ERROR || !hPdr ) { | 
|---|
| 1242 | WriteErrorCode( rc, "DosLoadModule"); | 
|---|
| 1243 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1244 | goto cleanup; | 
|---|
| 1245 | } | 
|---|
| 1246 | rc = DosQueryProcAddr( hPdr, 0, "SPLPDSET", &pfnSetPort ); | 
|---|
| 1247 | if ( rc != NO_ERROR ) { | 
|---|
| 1248 | WriteErrorCode( rc, "DosQueryProcAddr"); | 
|---|
| 1249 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1250 | goto finish; | 
|---|
| 1251 | } | 
|---|
| 1252 |  | 
|---|
| 1253 | // Now set the new port configuration | 
|---|
| 1254 | rc = pfnSetPort( pszPortName, TYPE_LONG_WAIT, BIDI_SET_PORTDRV, pBuf, cBuf ); | 
|---|
| 1255 | if ( rc == NO_ERROR ) { | 
|---|
| 1256 | // Return 1 on success | 
|---|
| 1257 | SaveResultString( prsResult, PSZ_ONE, 1 ); | 
|---|
| 1258 | } | 
|---|
| 1259 | else { | 
|---|
| 1260 | WriteErrorCode( rc, "SplPdSet"); | 
|---|
| 1261 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1262 | } | 
|---|
| 1263 |  | 
|---|
| 1264 | finish: | 
|---|
| 1265 | DosFreeModule( hPdr ); | 
|---|
| 1266 | cleanup: | 
|---|
| 1267 | WinTerminate( hab ); | 
|---|
| 1268 | return ( 0 ); | 
|---|
| 1269 | } | 
|---|
| 1270 |  | 
|---|
| 1271 |  | 
|---|
| 1272 | /* ------------------------------------------------------------------------- * | 
|---|
| 1273 | * RPUPortDialog                                                             * | 
|---|
| 1274 | *                                                                           * | 
|---|
| 1275 | * Brings up the specified port's configuration dialog.  This function can   * | 
|---|
| 1276 | * only be used from a PM process.                                           * | 
|---|
| 1277 | *                                                                           * | 
|---|
| 1278 | * REXX ARGUMENTS:                                                           * | 
|---|
| 1279 | *   1. The name of the port driver without any extension.  This must be     * | 
|---|
| 1280 | *      installed and registered in OS2.INI already.              (REQUIRED) * | 
|---|
| 1281 | *   2. The name of the port to be configured.                    (REQUIRED) * | 
|---|
| 1282 | *                                                                           * | 
|---|
| 1283 | * REXX RETURN VALUE:                                                        * | 
|---|
| 1284 | *   1 if the user modified the port configuration.                          * | 
|---|
| 1285 | *   0 if no changes were made, or if an error occurred.                     * | 
|---|
| 1286 | * ------------------------------------------------------------------------- */ | 
|---|
| 1287 | ULONG APIENTRY RPUPortDialog( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 1288 | { | 
|---|
| 1289 | HAB     hab;                        // desktop anchor-block handle | 
|---|
| 1290 | HMODULE hPdr = NULLHANDLE;          // handle to port driver module | 
|---|
| 1291 | PFN     pfnSetPort;                 // pointer to driver's SplPdSet entrypoint | 
|---|
| 1292 | ULONG   ulCB,                       // return value from PrfQueryProfileString() | 
|---|
| 1293 | flModified  = 0;            // flag indicating settings were changed | 
|---|
| 1294 | PSZ     pszPdrName  = NULL,         // name of the specified port driver | 
|---|
| 1295 | pszPortName = NULL;         // name of the new port to create | 
|---|
| 1296 | CHAR    szPathName[ CCHMAXPATH+1 ]; // FQN of the port driver module | 
|---|
| 1297 | APIRET  rc = 0;                     // return code from Dos...() functions | 
|---|
| 1298 |  | 
|---|
| 1299 |  | 
|---|
| 1300 | // Reset the error indicator | 
|---|
| 1301 | WriteErrorCode( 0, NULL ); | 
|---|
| 1302 |  | 
|---|
| 1303 | // Make sure we have exactly two valid arguments | 
|---|
| 1304 | if ( argc != 2 || | 
|---|
| 1305 | !RXVALIDSTRING( argv[0] ) || | 
|---|
| 1306 | !RXVALIDSTRING( argv[1] )  ) | 
|---|
| 1307 | return ( 40 ); | 
|---|
| 1308 | pszPdrName  = strupr( argv[0].strptr ); | 
|---|
| 1309 | pszPortName = strupr( argv[1].strptr ); | 
|---|
| 1310 |  | 
|---|
| 1311 | // Get the path to the installed port driver | 
|---|
| 1312 | hab = WinInitialize( 0 ); | 
|---|
| 1313 | if ( !hab ) { | 
|---|
| 1314 | WriteErrorCode( 0, "WinInitialize"); | 
|---|
| 1315 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1316 | return ( 0 ); | 
|---|
| 1317 | } | 
|---|
| 1318 |  | 
|---|
| 1319 | ulCB = PrfQueryProfileString( HINI_SYSTEMPROFILE, APPNAME_PM_PORT_DRIVER, | 
|---|
| 1320 | pszPdrName, NULL, (PVOID) szPathName, CCHMAXPATH ); | 
|---|
| 1321 | if ( !ulCB ) { | 
|---|
| 1322 | WriteErrorCode( ERRORIDERROR( WinGetLastError( hab )), "PrfQueryProfileString"); | 
|---|
| 1323 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1324 | goto cleanup; | 
|---|
| 1325 | } | 
|---|
| 1326 |  | 
|---|
| 1327 | // Load the port driver DLL and register its dialog routine | 
|---|
| 1328 | rc = DosLoadModule( NULL, 0, szPathName, &hPdr ); | 
|---|
| 1329 | if ( rc != NO_ERROR || !hPdr ) { | 
|---|
| 1330 | WriteErrorCode( rc, "DosLoadModule"); | 
|---|
| 1331 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1332 | goto cleanup; | 
|---|
| 1333 | } | 
|---|
| 1334 | rc = DosQueryProcAddr( hPdr, 0, "SPLPDSETPORT", &pfnSetPort ); | 
|---|
| 1335 | if ( rc != NO_ERROR ) { | 
|---|
| 1336 | WriteErrorCode( rc, "DosQueryProcAddr"); | 
|---|
| 1337 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1338 | goto finish; | 
|---|
| 1339 | } | 
|---|
| 1340 |  | 
|---|
| 1341 | // Now show the port configuration dialog | 
|---|
| 1342 | rc = pfnSetPort( hab, pszPortName, &flModified ); | 
|---|
| 1343 | if ( rc == NO_ERROR ) { | 
|---|
| 1344 | // Return 1 if settings were modified | 
|---|
| 1345 | SaveResultString( prsResult, flModified? PSZ_ONE: PSZ_ZERO, 1 ); | 
|---|
| 1346 | } | 
|---|
| 1347 | else { | 
|---|
| 1348 | WriteErrorCode( rc, "SplPdSetPort"); | 
|---|
| 1349 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1350 | } | 
|---|
| 1351 |  | 
|---|
| 1352 | finish: | 
|---|
| 1353 | DosFreeModule( hPdr ); | 
|---|
| 1354 | cleanup: | 
|---|
| 1355 | WinTerminate( hab ); | 
|---|
| 1356 | return ( 0 ); | 
|---|
| 1357 | } | 
|---|
| 1358 |  | 
|---|
| 1359 |  | 
|---|
| 1360 | /* ------------------------------------------------------------------------- * | 
|---|
| 1361 | * RPUPortDelete                                                             * | 
|---|
| 1362 | *                                                                           * | 
|---|
| 1363 | * Deletes a printer port.                                                   * | 
|---|
| 1364 | *                                                                           * | 
|---|
| 1365 | * REXX ARGUMENTS:                                                           * | 
|---|
| 1366 | *   1. The name of the port to be deleted.                       (REQUIRED) * | 
|---|
| 1367 | *                                                                           * | 
|---|
| 1368 | * REXX RETURN VALUE:                                                        * | 
|---|
| 1369 | *   1 on success, or 0 if an error occurred.                                * | 
|---|
| 1370 | * ------------------------------------------------------------------------- */ | 
|---|
| 1371 | ULONG APIENTRY RPUPortDelete( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 1372 | { | 
|---|
| 1373 | PSZ    pszPortName; | 
|---|
| 1374 | SPLERR rc = 0; | 
|---|
| 1375 |  | 
|---|
| 1376 |  | 
|---|
| 1377 | // Reset the error indicator | 
|---|
| 1378 | WriteErrorCode( 0, NULL ); | 
|---|
| 1379 |  | 
|---|
| 1380 | // Make sure we have at least one valid argument (the port name) | 
|---|
| 1381 | if ( argc < 1  || ( !RXVALIDSTRING(argv[0]) )) return ( 40 ); | 
|---|
| 1382 | pszPortName = strupr( argv[0].strptr ); | 
|---|
| 1383 |  | 
|---|
| 1384 | rc = SplDeletePort( NULL, pszPortName ); | 
|---|
| 1385 | if ( rc == NO_ERROR ) { | 
|---|
| 1386 | // Return 1 on success | 
|---|
| 1387 | SaveResultString( prsResult, PSZ_ONE, 1 ); | 
|---|
| 1388 | } | 
|---|
| 1389 | else { | 
|---|
| 1390 | WriteErrorCode( rc, "SplDeletePort"); | 
|---|
| 1391 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1392 | } | 
|---|
| 1393 |  | 
|---|
| 1394 | return ( 0 ); | 
|---|
| 1395 | } | 
|---|
| 1396 |  | 
|---|
| 1397 |  | 
|---|
| 1398 | /* ------------------------------------------------------------------------- * | 
|---|
| 1399 | * RPUPrinterCreate                                                          * | 
|---|
| 1400 | *                                                                           * | 
|---|
| 1401 | * Creates a new local printer object.  The associated print queue and       * | 
|---|
| 1402 | * device are created automatically.  However, the specified output port     * | 
|---|
| 1403 | * must exist, and the specified printer driver/model must have been         * | 
|---|
| 1404 | * installed already.                                                        * | 
|---|
| 1405 | *                                                                           * | 
|---|
| 1406 | * The WPS object is created with default settings, and will be assigned an  * | 
|---|
| 1407 | * object-ID automatically by the WPS.                                       * | 
|---|
| 1408 | *                                                                           * | 
|---|
| 1409 | * NOTE: This function will NOT create a remote (LAN) printer object.        * | 
|---|
| 1410 | *                                                                           * | 
|---|
| 1411 | * REXX ARGUMENTS:                                                           * | 
|---|
| 1412 | *   1. The printer description, used as the WPS object title.    (REQUIRED) * | 
|---|
| 1413 | *   2. The name of the underlying print queue. Must be a legal              * | 
|---|
| 1414 | *      queue name according to OS/2 (but what is that...?)       (REQUIRED) * | 
|---|
| 1415 | *   3. The name of the printer port, which must exist already.   (REQUIRED) * | 
|---|
| 1416 | *   4. The default printer driver.model to be associated with               * | 
|---|
| 1417 | *      the device. If specified, this must be installed in the              * | 
|---|
| 1418 | *      system already. If not specified, IBMNULL is assumed.    (OPTIONAL)  * | 
|---|
| 1419 | *                                                                           * | 
|---|
| 1420 | * REXX RETURN VALUE:                                                        * | 
|---|
| 1421 | *   1 on success, or 0 if an error occurred.                                * | 
|---|
| 1422 | * ------------------------------------------------------------------------- */ | 
|---|
| 1423 | ULONG APIENTRY RPUPrinterCreate( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 1424 | { | 
|---|
| 1425 | PRDINFO3  devinfo       = {0}; | 
|---|
| 1426 | PRQINFO3  qinfo         = {0}; | 
|---|
| 1427 | PSZ       pszQueueName  = NULL, | 
|---|
| 1428 | pszPortName   = NULL, | 
|---|
| 1429 | pszModel      = NULL, | 
|---|
| 1430 | pszTitle      = NULL; | 
|---|
| 1431 | CHAR      szDevice[ US_PRTDEV_MAXZ ] = {0}; | 
|---|
| 1432 | SPLERR    rc; | 
|---|
| 1433 |  | 
|---|
| 1434 |  | 
|---|
| 1435 | // Reset the error indicator | 
|---|
| 1436 | WriteErrorCode( 0, NULL ); | 
|---|
| 1437 |  | 
|---|
| 1438 | // Validate the REXX arguments | 
|---|
| 1439 | if (( argc < 3 ) || ( argc > 4 )  || ( ! RXVALIDSTRING( argv[0] )) || | 
|---|
| 1440 | ( ! RXVALIDSTRING( argv[1] )) || ( ! RXVALIDSTRING( argv[2] ))) | 
|---|
| 1441 | return ( 40 ); | 
|---|
| 1442 | if (( argc > 3 ) && ( ! RXVALIDSTRING( argv[3] ))) | 
|---|
| 1443 | return ( 40 ); | 
|---|
| 1444 |  | 
|---|
| 1445 | pszTitle      = argv[0].strptr; | 
|---|
| 1446 | pszQueueName  = argv[1].strptr; | 
|---|
| 1447 | pszPortName   = argv[2].strptr; | 
|---|
| 1448 | if ( argc > 3 ) pszModel = argv[3].strptr; | 
|---|
| 1449 |  | 
|---|
| 1450 | // Generate a suitable (unique) device name, based on the queue name | 
|---|
| 1451 | strncpy( szDevice, pszQueueName, US_PRTDEV_MAXZ-1 ); | 
|---|
| 1452 | if (( rc = UniqueDeviceName( szDevice )) != NO_ERROR ) { | 
|---|
| 1453 | if ( rc == 1 )      // shouldn't really happen | 
|---|
| 1454 | WriteErrorCode( rc, "UniqueDeviceName"); | 
|---|
| 1455 | else | 
|---|
| 1456 | WriteErrorCode( rc, "SplEnumDevice"); | 
|---|
| 1457 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1458 | return ( 0 ); | 
|---|
| 1459 | } | 
|---|
| 1460 |  | 
|---|
| 1461 | // Create the device | 
|---|
| 1462 | devinfo.pszPrinterName = szDevice; | 
|---|
| 1463 | devinfo.pszUserName    = NULL; | 
|---|
| 1464 | devinfo.pszLogAddr     = pszPortName; | 
|---|
| 1465 | devinfo.pszComment     = pszTitle; | 
|---|
| 1466 | devinfo.pszDrivers     = pszModel ? pszModel : "IBMNULL"; | 
|---|
| 1467 | devinfo.usTimeOut      = 45; | 
|---|
| 1468 | rc = SplCreateDevice( NULL, 3, &devinfo, sizeof( devinfo )); | 
|---|
| 1469 | if ( rc != NO_ERROR ) { | 
|---|
| 1470 | WriteErrorCode( rc, "SplCreateDevice"); | 
|---|
| 1471 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1472 | return ( 0 ); | 
|---|
| 1473 | } | 
|---|
| 1474 |  | 
|---|
| 1475 | // Create the queue (automatically creates printer object) | 
|---|
| 1476 | qinfo.pszName       = pszQueueName; | 
|---|
| 1477 | qinfo.uPriority     = PRQ_DEF_PRIORITY; | 
|---|
| 1478 | qinfo.fsType        = PRQ3_TYPE_RAW; | 
|---|
| 1479 | qinfo.pszPrProc     = "PMPRINT"; | 
|---|
| 1480 | qinfo.pszComment    = pszTitle; | 
|---|
| 1481 | qinfo.pszPrinters   = szDevice; | 
|---|
| 1482 | qinfo.pszDriverName = pszModel ? pszModel : "IBMNULL"; | 
|---|
| 1483 | rc = SplCreateQueue( NULL, 3, &qinfo, sizeof( qinfo )); | 
|---|
| 1484 | if ( rc != NO_ERROR ) { | 
|---|
| 1485 | WriteErrorCode( rc, "SplCreateQueue"); | 
|---|
| 1486 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1487 | SplDeleteDevice( NULL, szDevice ); | 
|---|
| 1488 | return ( 0 ); | 
|---|
| 1489 | } | 
|---|
| 1490 |  | 
|---|
| 1491 | SaveResultString( prsResult, PSZ_ONE, 1 ); | 
|---|
| 1492 | return ( 0 ); | 
|---|
| 1493 | } | 
|---|
| 1494 |  | 
|---|
| 1495 |  | 
|---|
| 1496 | /* ------------------------------------------------------------------------- * | 
|---|
| 1497 | * RPUPrinterDelete                                                          * | 
|---|
| 1498 | *                                                                           * | 
|---|
| 1499 | * Deletes a local printer queue and its associated print device definition. * | 
|---|
| 1500 | *                                                                           * | 
|---|
| 1501 | * REXX ARGUMENTS:                                                           * | 
|---|
| 1502 | *   1. The name of the printer queue to be deleted.              (REQUIRED) * | 
|---|
| 1503 | *                                                                           * | 
|---|
| 1504 | * REXX RETURN VALUE:                                                        * | 
|---|
| 1505 | *   1 on success, or 0 if an error occurred.  (1 will be returned even if   * | 
|---|
| 1506 | *   the WPS printer object could not be deleted, so long as the queue and   * | 
|---|
| 1507 | *   device were destroyed successfully.)                                    * | 
|---|
| 1508 | * ------------------------------------------------------------------------- */ | 
|---|
| 1509 | ULONG APIENTRY RPUPrinterDelete( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 1510 | { | 
|---|
| 1511 | PPRQINFO3 pInfo         = NULL; | 
|---|
| 1512 | ULONG     cbBuf         = 0; | 
|---|
| 1513 | PSZ       pszQueueName  = NULL, | 
|---|
| 1514 | pszDeviceName = NULL; | 
|---|
| 1515 | HOBJECT   hObj; | 
|---|
| 1516 | SPLERR    rc; | 
|---|
| 1517 |  | 
|---|
| 1518 |  | 
|---|
| 1519 | // Reset the error indicator | 
|---|
| 1520 | WriteErrorCode( 0, NULL ); | 
|---|
| 1521 |  | 
|---|
| 1522 | // Validate the REXX arguments | 
|---|
| 1523 | if (( argc != 1 ) || ( ! RXVALIDSTRING( argv[0] ))) | 
|---|
| 1524 | return ( 40 ); | 
|---|
| 1525 |  | 
|---|
| 1526 | pszQueueName = argv[0].strptr; | 
|---|
| 1527 | hObj = PrinterObjectHandle( pszQueueName ); | 
|---|
| 1528 |  | 
|---|
| 1529 | rc = SplQueryQueue( NULL, pszQueueName, 3, NULL, 0, &cbBuf ); | 
|---|
| 1530 | if (( rc != NO_ERROR ) && ( rc != NERR_BufTooSmall )) { | 
|---|
| 1531 | WriteErrorCode( rc, "SplQueryQueue"); | 
|---|
| 1532 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1533 | return ( 0 ); | 
|---|
| 1534 | } | 
|---|
| 1535 | pInfo = (PPRQINFO3) malloc( cbBuf ); | 
|---|
| 1536 | if ( !pInfo ) { | 
|---|
| 1537 | WriteErrorCode( ERROR_NOT_ENOUGH_MEMORY, "malloc"); | 
|---|
| 1538 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1539 | return ( 0 ); | 
|---|
| 1540 | } | 
|---|
| 1541 | rc = SplQueryQueue( NULL, pszQueueName, 3, pInfo, cbBuf, &cbBuf ); | 
|---|
| 1542 | if ( rc != NO_ERROR ) { | 
|---|
| 1543 | WriteErrorCode( rc, "SplQueryQueue"); | 
|---|
| 1544 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1545 | goto cleanup; | 
|---|
| 1546 | } | 
|---|
| 1547 | pszDeviceName = strtok( pInfo->pszPrinters, ","); | 
|---|
| 1548 | rc = SplDeleteDevice( NULL, pszDeviceName ); | 
|---|
| 1549 | if ( rc != NO_ERROR ) { | 
|---|
| 1550 | WriteErrorCode( rc, "SplDeleteDevice"); | 
|---|
| 1551 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1552 | goto cleanup; | 
|---|
| 1553 | } | 
|---|
| 1554 |  | 
|---|
| 1555 | // Try and destroy the WPS object | 
|---|
| 1556 | //  - NB This causes a long delay when deleting an offline LAN printer | 
|---|
| 1557 | if ( hObj != NULLHANDLE ) WinDestroyObject( hObj ); | 
|---|
| 1558 |  | 
|---|
| 1559 | SaveResultString( prsResult, PSZ_ONE, 1 ); | 
|---|
| 1560 | cleanup: | 
|---|
| 1561 | free( pInfo ); | 
|---|
| 1562 | return ( 0 ); | 
|---|
| 1563 | } | 
|---|
| 1564 |  | 
|---|
| 1565 |  | 
|---|
| 1566 | /* ------------------------------------------------------------------------- * | 
|---|
| 1567 | * RPUPrinterQuery                                                           * | 
|---|
| 1568 | *                                                                           * | 
|---|
| 1569 | * Gets information about the specified printer device.                      * | 
|---|
| 1570 | *                                                                           * | 
|---|
| 1571 | *   (stem).!description  Printer description (name of WPS object)           * | 
|---|
| 1572 | *   (stem).!port         Name of the port the printer is using              * | 
|---|
| 1573 | *   (stem).!driver2      List of the drivers used by this printer           * | 
|---|
| 1574 | *   (stem).!jobflags     Zero or more of the following flags (any order):   * | 
|---|
| 1575 | *                            E  A printer error has occurred                * | 
|---|
| 1576 | *                            H  Printer destination is paused (held)        * | 
|---|
| 1577 | *                            I  Intervention required                       * | 
|---|
| 1578 | *                            N  Printer has raised a notification alert     * | 
|---|
| 1579 | *                            O  Printer is offline                          * | 
|---|
| 1580 | *                            P  Printer is out of paper                     * | 
|---|
| 1581 | *                                                                           * | 
|---|
| 1582 | * REXX ARGUMENTS:                                                           * | 
|---|
| 1583 | *   1. The name of the printer device being queried.             (REQUIRED) * | 
|---|
| 1584 | *   2. The name of the stem in which to return the results.      (REQUIRED) * | 
|---|
| 1585 | *                                                                           * | 
|---|
| 1586 | * REXX RETURN VALUE:                                                        * | 
|---|
| 1587 | *   1 on success, or 0 if an error occurred.                                * | 
|---|
| 1588 | * ------------------------------------------------------------------------- */ | 
|---|
| 1589 | ULONG APIENTRY RPUPrinterQuery( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 1590 | { | 
|---|
| 1591 | PPRDINFO3 pInfo      = NULL; | 
|---|
| 1592 | PVOID     pbuf       = NULL; | 
|---|
| 1593 | ULONG     cbBuf      = 0, | 
|---|
| 1594 | cbNeeded   = 0; | 
|---|
| 1595 | PSZ       pszDeviceName; | 
|---|
| 1596 | CHAR      szFlags[ 8 ] = {0}, | 
|---|
| 1597 | szStem[ US_STEM_MAXZ ];   // compound variable stem name | 
|---|
| 1598 | SPLERR    rc; | 
|---|
| 1599 |  | 
|---|
| 1600 |  | 
|---|
| 1601 | // Reset the error indicator | 
|---|
| 1602 | WriteErrorCode( 0, NULL ); | 
|---|
| 1603 |  | 
|---|
| 1604 | // Validate the REXX arguments | 
|---|
| 1605 | if (( argc != 2 ) || | 
|---|
| 1606 | ( ! RXVALIDSTRING( argv[0] )) || ( ! RXVALIDSTRING( argv[1] ))) | 
|---|
| 1607 | return ( 40 ); | 
|---|
| 1608 |  | 
|---|
| 1609 | pszDeviceName = argv[0].strptr; | 
|---|
| 1610 |  | 
|---|
| 1611 | // Initialize the result stem name | 
|---|
| 1612 | if ( RXSTRLEN(argv[1]) > US_STEM_MAXZ ) return ( 40 ); | 
|---|
| 1613 | if ( argv[1].strptr[ argv[1].strlength-1 ] == '.') argv[1].strlength--; | 
|---|
| 1614 | strncpy( szStem, argv[1].strptr, RXSTRLEN( argv[1] )); | 
|---|
| 1615 | szStem[ RXSTRLEN( argv[1] ) ] = '\0'; | 
|---|
| 1616 |  | 
|---|
| 1617 |  | 
|---|
| 1618 | // Query the amount of available data | 
|---|
| 1619 | rc = SplQueryDevice( NULL, pszDeviceName, 3L, NULL, 0L, &cbNeeded ); | 
|---|
| 1620 | if (( rc != ERROR_MORE_DATA ) && ( rc != NERR_BufTooSmall )) | 
|---|
| 1621 | { | 
|---|
| 1622 | WriteErrorCode( rc, "SplQueryDevice"); | 
|---|
| 1623 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1624 | return ( 0 ); | 
|---|
| 1625 | } | 
|---|
| 1626 |  | 
|---|
| 1627 | // Now get the actual data | 
|---|
| 1628 | pbuf = malloc( cbNeeded ); | 
|---|
| 1629 | if ( !pbuf ) { | 
|---|
| 1630 | WriteErrorCode( ERROR_NOT_ENOUGH_MEMORY, "malloc"); | 
|---|
| 1631 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1632 | return ( 0 ); | 
|---|
| 1633 | } | 
|---|
| 1634 | cbBuf = cbNeeded; | 
|---|
| 1635 | rc = SplQueryDevice( NULL, pszDeviceName, 3L, pbuf, cbBuf, &cbNeeded ); | 
|---|
| 1636 | if ( rc == NO_ERROR ) { | 
|---|
| 1637 | pInfo = (PPRDINFO3) pbuf; | 
|---|
| 1638 | WriteCompoundVariable( szStem, "!name", pInfo->pszPrinterName ); | 
|---|
| 1639 | WriteCompoundVariable( szStem, "!port", pInfo->pszLogAddr ); | 
|---|
| 1640 | WriteCompoundVariable( szStem, "!description", pInfo->pszComment ); | 
|---|
| 1641 | WriteCompoundVariable( szStem, "!drivers", pInfo->pszDrivers ); | 
|---|
| 1642 | if ( pInfo->fsStatus & PRJ_ERROR  )      strcat( szFlags, "E"); | 
|---|
| 1643 | if ( pInfo->fsStatus & PRJ_DESTPAUSED )  strcat( szFlags, "H"); | 
|---|
| 1644 | if ( pInfo->fsStatus & PRJ_INTERV )      strcat( szFlags, "I"); | 
|---|
| 1645 | if ( pInfo->fsStatus & PRJ_NOTIFY )      strcat( szFlags, "N"); | 
|---|
| 1646 | if ( pInfo->fsStatus & PRJ_DESTOFFLINE ) strcat( szFlags, "O"); | 
|---|
| 1647 | if ( pInfo->fsStatus & PRJ_DESTNOPAPER ) strcat( szFlags, "P"); | 
|---|
| 1648 | WriteCompoundVariable( szStem, "!jobflags", szFlags ); | 
|---|
| 1649 | SaveResultString( prsResult, PSZ_ONE, 1 ); | 
|---|
| 1650 | } | 
|---|
| 1651 | else { | 
|---|
| 1652 | WriteErrorCode( rc, "SplQueryDevice"); | 
|---|
| 1653 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1654 | } | 
|---|
| 1655 |  | 
|---|
| 1656 | free( pbuf ); | 
|---|
| 1657 | return ( 0 ); | 
|---|
| 1658 | } | 
|---|
| 1659 |  | 
|---|
| 1660 |  | 
|---|
| 1661 | /* ------------------------------------------------------------------------- * | 
|---|
| 1662 | * RPUQueueDefault                                                           * | 
|---|
| 1663 | *                                                                           * | 
|---|
| 1664 | * Sets the requested printer queue as the system default printer.           * | 
|---|
| 1665 | *                                                                           * | 
|---|
| 1666 | * REXX ARGUMENTS:                                                           * | 
|---|
| 1667 | *   1. The name of the printer queue to set as default. (REQUIRED)          * | 
|---|
| 1668 | *                                                                           * | 
|---|
| 1669 | * REXX RETURN VALUE:                                                        * | 
|---|
| 1670 | *   1 on success, or 0 if an error occurred.                                * | 
|---|
| 1671 | * ------------------------------------------------------------------------- */ | 
|---|
| 1672 | ULONG APIENTRY RPUQueueDefault( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 1673 | { | 
|---|
| 1674 | HOBJECT hObj; | 
|---|
| 1675 | BOOL    fRC; | 
|---|
| 1676 |  | 
|---|
| 1677 | // Reset the error indicator | 
|---|
| 1678 | WriteErrorCode( 0, NULL ); | 
|---|
| 1679 |  | 
|---|
| 1680 | // Make sure we have at least one valid argument (the queue name) | 
|---|
| 1681 | if ( argc != 1  || ( !RXVALIDSTRING(argv[0]) )) return ( 40 ); | 
|---|
| 1682 | pszName = argv[0].strptr; | 
|---|
| 1683 |  | 
|---|
| 1684 | hObj = PrinterObjectHandle( pszName ); | 
|---|
| 1685 | if ( !hObj ) return ( 40 ); | 
|---|
| 1686 |  | 
|---|
| 1687 | fRC = WinSetObjectData( hObj, "APPDEFAULT=YES;"); | 
|---|
| 1688 |  | 
|---|
| 1689 | SaveResultString( prsResult, fRC? PSZ_ONE: PSZ_ZERO, 1 ); | 
|---|
| 1690 | return ( 0 ); | 
|---|
| 1691 | } | 
|---|
| 1692 |  | 
|---|
| 1693 |  | 
|---|
| 1694 | /* ------------------------------------------------------------------------- * | 
|---|
| 1695 | * RPUQueueHold                                                              * | 
|---|
| 1696 | *                                                                           * | 
|---|
| 1697 | * Holds or releases the specified print queue.                              * | 
|---|
| 1698 | *                                                                           * | 
|---|
| 1699 | * REXX ARGUMENTS:                                                           * | 
|---|
| 1700 | *   1. The name of the printer queue to hold or release. (REQUIRED)         * | 
|---|
| 1701 | *   2. Action flag, one of:                                                 * | 
|---|
| 1702 | *        Y  Hold printer (DEFAULT)                                          * | 
|---|
| 1703 | *        N  Release printer                                                 * | 
|---|
| 1704 | *                                                                           * | 
|---|
| 1705 | * REXX RETURN VALUE:                                                        * | 
|---|
| 1706 | *   1 on success, or 0 if an error occurred.                                * | 
|---|
| 1707 | * ------------------------------------------------------------------------- */ | 
|---|
| 1708 | ULONG APIENTRY RPUQueueHold( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult ) | 
|---|
| 1709 | { | 
|---|
| 1710 | PSZ    pszQueueName;           // Print queue name | 
|---|
| 1711 | BOOL   fHold = TRUE; | 
|---|
| 1712 | SPLERR rc; | 
|---|
| 1713 |  | 
|---|
| 1714 |  | 
|---|
| 1715 | // Reset the error indicator | 
|---|
| 1716 | WriteErrorCode( 0, NULL ); | 
|---|
| 1717 |  | 
|---|
| 1718 | // Make sure we have at least one valid argument (the queue name) | 
|---|
| 1719 | if ( argc < 1 || argc > 2 || ( !RXVALIDSTRING(argv[0]) )) return ( 40 ); | 
|---|
| 1720 | pszQueueName = argv[0].strptr; | 
|---|
| 1721 |  | 
|---|
| 1722 | // Second argument: view (optional, but must be correct if specified) | 
|---|
| 1723 | if ( argc == 2 ) { | 
|---|
| 1724 | if ( RXVALIDSTRING(argv[1]) ) { | 
|---|
| 1725 | switch ( argv[1].strptr[0] ) { | 
|---|
| 1726 | case 'y': | 
|---|
| 1727 | case 'Y': fHold = TRUE;  break; | 
|---|
| 1728 | case 'n': | 
|---|
| 1729 | case 'N': fHold = FALSE; break; | 
|---|
| 1730 | default : return ( 40 ); | 
|---|
| 1731 | } | 
|---|
| 1732 | } | 
|---|
| 1733 | else return ( 40 ); | 
|---|
| 1734 | } | 
|---|
| 1735 |  | 
|---|
| 1736 | rc = fHold ? SplHoldQueue( NULL, pszQueueName ) : | 
|---|
| 1737 | SplReleaseQueue( NULL, pszQueueName ); | 
|---|
| 1738 | if ( rc != NO_ERROR ) { | 
|---|
| 1739 | WriteErrorCode( rc, fHold ? "SplHoldQueue" : "SplReleaseQueue"); | 
|---|
| 1740 | SaveResultString( prsResult, PSZ_ZERO, 1 ); | 
|---|
| 1741 | } | 
|---|
| 1742 | else | 
|---|
| 1743 | SaveResultString( prsResult, PSZ_ONE, 1 ); | 
|---|
| 1744 |  | 
|---|
| 1745 | return ( 0 ); | 
|---|
| 1746 | } | 
|---|
| 1747 |  | 
|---|
| 1748 |  | 
|---|
| 1749 | /* ************************************************************************* * | 
|---|
| 1750 | * INTERNAL PRINTER-RELATED FUNCTIONS                                        * | 
|---|
| 1751 | * ************************************************************************* */ | 
|---|
| 1752 |  | 
|---|
| 1753 | /* ------------------------------------------------------------------------- * | 
|---|
| 1754 | * PrinterObjectHandle                                                       * | 
|---|
| 1755 | *                                                                           * | 
|---|
| 1756 | * Given a print queue name, obtain the handle to the WPS printer object     * | 
|---|
| 1757 | * associated with that queue.  This is done by querying OS2.INI for the     * | 
|---|
| 1758 | * queues defined in PM_PrintObject and reading the associated handle IDs.   * | 
|---|
| 1759 | *                                                                           * | 
|---|
| 1760 | * ARGUMENTS:                                                                * | 
|---|
| 1761 | *   PSZ pszQueueName: The printer queue name.  This is NOT the same as the  * | 
|---|
| 1762 | *                     printer device name, although in many cases they may  * | 
|---|
| 1763 | *                     have the same value.                                  * | 
|---|
| 1764 | *                                                                           * | 
|---|
| 1765 | * RETURNS: HOBJECT                                                          * | 
|---|
| 1766 | *   WPS object handle of the printer object; NULLHANDLE if no object was    * | 
|---|
| 1767 | *   found or an error occurred.                                             * | 
|---|
| 1768 | * ------------------------------------------------------------------------- */ | 
|---|
| 1769 | HOBJECT PrinterObjectHandle( PSZ pszQueueName ) | 
|---|
| 1770 | { | 
|---|
| 1771 | PVOID   pbuf = NULL, | 
|---|
| 1772 | pdata = NULL; | 
|---|
| 1773 | PBYTE   pb, | 
|---|
| 1774 | pbEnd, | 
|---|
| 1775 | pbGrpEnd; | 
|---|
| 1776 | POBJINFO pInfo = NULL; | 
|---|
| 1777 | POITAG   pTag = NULL; | 
|---|
| 1778 | PSZ     psz, | 
|---|
| 1779 | pszName; | 
|---|
| 1780 | CHAR    szValue[ 256 ], | 
|---|
| 1781 | szObject[ 5 ]; | 
|---|
| 1782 | ULONG   cbTotal  = 0, | 
|---|
| 1783 | cbActual = 0, | 
|---|
| 1784 | ulHandle; | 
|---|
| 1785 | HOBJECT hObj = 0; | 
|---|
| 1786 | BOOL    fFound, | 
|---|
| 1787 | fRC; | 
|---|
| 1788 |  | 
|---|
| 1789 |  | 
|---|
| 1790 | fRC = PrfQueryProfileSize( HINI_USERPROFILE, | 
|---|
| 1791 | APPNAME_PM_PRINT_OBJECT, NULL, &cbTotal ); | 
|---|
| 1792 | if ( !fRC || !cbTotal ) { | 
|---|
| 1793 | //WriteErrorCode( ERRORIDERROR( WinGetLastError( hab )), "PrfQueryProfileSize"); | 
|---|
| 1794 | return NULLHANDLE; | 
|---|
| 1795 | } | 
|---|
| 1796 | pbuf = malloc( cbTotal ); | 
|---|
| 1797 | if ( !pbuf ) { | 
|---|
| 1798 | WriteErrorCode( ERROR_NOT_ENOUGH_MEMORY, "malloc"); | 
|---|
| 1799 | return NULLHANDLE; | 
|---|
| 1800 | } | 
|---|
| 1801 |  | 
|---|
| 1802 | cbActual = PrfQueryProfileString( HINI_USERPROFILE, APPNAME_PM_PRINT_OBJECT, | 
|---|
| 1803 | NULL, NULL, pbuf, cbTotal ); | 
|---|
| 1804 | if ( !cbActual ) { | 
|---|
| 1805 | //WriteErrorCode( ERRORIDERROR( WinGetLastError( hab )), "PrfQueryProfileString"); | 
|---|
| 1806 | return NULLHANDLE; | 
|---|
| 1807 | } | 
|---|
| 1808 |  | 
|---|
| 1809 | fFound = FALSE; | 
|---|
| 1810 | psz = (PSZ) pbuf; | 
|---|
| 1811 | while ( *psz && !fFound ) { | 
|---|
| 1812 | #if 1 | 
|---|
| 1813 |  | 
|---|
| 1814 | /* Just checking the queue names associated with the handle in | 
|---|
| 1815 | * PM_PrintObject is not reliable, because remote (LAN) printers | 
|---|
| 1816 | * will store the name of the _remote_ queue there (which is not | 
|---|
| 1817 | * only impossible to map to a local queue name, it may actually | 
|---|
| 1818 | * be the same AS a local queue name... for a different printer). | 
|---|
| 1819 | * | 
|---|
| 1820 | * So what we do here is parse the queue name out of the object | 
|---|
| 1821 | * settings (from PM_Abstract:Objects).  We also have to handle | 
|---|
| 1822 | * remote printers slightly differently from local ones. | 
|---|
| 1823 | * | 
|---|
| 1824 | * I am indebted to Henk Kelder's WPTOOLS source code for providing | 
|---|
| 1825 | * the basic logic, although the code below is largely original. | 
|---|
| 1826 | */ | 
|---|
| 1827 |  | 
|---|
| 1828 | if ( sscanf( psz, "%u", &ulHandle ) && LOUSHORT( ulHandle )) { | 
|---|
| 1829 | sprintf( szObject, "%X", LOUSHORT( ulHandle )); | 
|---|
| 1830 | fRC = PrfQueryProfileSize( HINI_USERPROFILE, APPNAME_PM_ABS_OBJECTS, | 
|---|
| 1831 | szObject, &cbTotal ); | 
|---|
| 1832 | if ( !fRC || ( cbTotal < 25 ) || ((pdata = malloc( cbTotal )) == NULL )) { | 
|---|
| 1833 | psz += strlen( psz ) + 1; | 
|---|
| 1834 | continue; | 
|---|
| 1835 | } | 
|---|
| 1836 | if ( PrfQueryProfileData( HINI_USERPROFILE, APPNAME_PM_ABS_OBJECTS, | 
|---|
| 1837 | szObject, (PVOID) pdata, &cbTotal )) | 
|---|
| 1838 | { | 
|---|
| 1839 | BOOL fRemote; | 
|---|
| 1840 | pbEnd = (PBYTE) pdata + cbTotal; | 
|---|
| 1841 | pszName = (PSZ) pdata + sizeof( ULONG ); | 
|---|
| 1842 | fRemote = strcmp( pszName, "WPRPrinter") ? FALSE : TRUE; | 
|---|
| 1843 | pb = (PBYTE) pszName + strlen( pszName ) + 17; | 
|---|
| 1844 | while (( pb < pbEnd ) && !fFound ) { | 
|---|
| 1845 | pInfo = (POBJINFO) pb; | 
|---|
| 1846 | pb += sizeof( OBJINFO ) + strlen( pInfo->szName ); | 
|---|
| 1847 | pbGrpEnd = pb + pInfo->cbData; | 
|---|
| 1848 | if ( pbGrpEnd > pbEnd ) pbGrpEnd = pbEnd; | 
|---|
| 1849 | while (( pb < pbGrpEnd ) && !fFound ) { | 
|---|
| 1850 | pTag = (POITAG) pb; | 
|---|
| 1851 | pb += sizeof( OITAG ); | 
|---|
| 1852 | /* For network printers, tag ID 3 indicates the name of | 
|---|
| 1853 | * the queue on the remote server.  We want the local | 
|---|
| 1854 | * queue name, which has tag ID 13. | 
|---|
| 1855 | */ | 
|---|
| 1856 | if ( fRemote && ( pTag->usTag == ID_OBJINFO_RPQUEUENAME )) { | 
|---|
| 1857 | memcpy( szValue, pb, pTag->cbTag ); | 
|---|
| 1858 | if ( !strcmp( szValue, pszQueueName )) { | 
|---|
| 1859 | hObj = (HOBJECT) ulHandle; | 
|---|
| 1860 | fFound = TRUE; | 
|---|
| 1861 | } | 
|---|
| 1862 | } | 
|---|
| 1863 | // For local printers, just look for tag ID 3 | 
|---|
| 1864 | else if ( pTag->usTag == ID_OBJINFO_QUEUENAME ) { | 
|---|
| 1865 | memcpy( szValue, pb, pTag->cbTag ); | 
|---|
| 1866 | if ( !strcmp( szValue, pszQueueName )) { | 
|---|
| 1867 | hObj = (HOBJECT) ulHandle; | 
|---|
| 1868 | fFound = TRUE; | 
|---|
| 1869 | } | 
|---|
| 1870 | } | 
|---|
| 1871 | pb += pTag->cbTag; | 
|---|
| 1872 | } | 
|---|
| 1873 | } | 
|---|
| 1874 | } | 
|---|
| 1875 | free( pdata ); | 
|---|
| 1876 | } | 
|---|
| 1877 | #else | 
|---|
| 1878 | /* Old method, do not use (unreliable for the reasons noted above). | 
|---|
| 1879 | */ | 
|---|
| 1880 | if ( !PrfQueryProfileString( HINI_USERPROFILE, APPNAME_PM_PRINT_OBJECT, | 
|---|
| 1881 | psz, NULL, szValue, 255 )) | 
|---|
| 1882 | { | 
|---|
| 1883 | //WriteErrorCode( ERRORIDERROR( WinGetLastError( hab )), "PrfQueryProfileString"); | 
|---|
| 1884 | break; | 
|---|
| 1885 | } | 
|---|
| 1886 | if (( strcmp( szValue, pszQueueName ) == 0 ) && | 
|---|
| 1887 | ( sscanf( psz, "%u", (PULONG) &hObj ) == 1 )) | 
|---|
| 1888 | { | 
|---|
| 1889 | fFound = TRUE; | 
|---|
| 1890 | break; | 
|---|
| 1891 | } | 
|---|
| 1892 | #endif | 
|---|
| 1893 | psz += strlen( psz ) + 1; | 
|---|
| 1894 | } | 
|---|
| 1895 |  | 
|---|
| 1896 | free ( pbuf ); | 
|---|
| 1897 | return ( hObj ); | 
|---|
| 1898 | } | 
|---|
| 1899 |  | 
|---|
| 1900 |  | 
|---|
| 1901 | /* ------------------------------------------------------------------------- * | 
|---|
| 1902 | * GetObjectID                                                               * | 
|---|
| 1903 | *                                                                           * | 
|---|
| 1904 | * Given a WPS object handle, find out the corresponding object ID if one    * | 
|---|
| 1905 | * exists.                                                                   * | 
|---|
| 1906 | *                                                                           * | 
|---|
| 1907 | * ARGUMENTS:                                                                * | 
|---|
| 1908 | *   PSZ pszHandle: The WPS object handle, as a hexadecimal string.  This    * | 
|---|
| 1909 | *                  should have no prefix, and be all upper-case.            * | 
|---|
| 1910 | *                                                                           * | 
|---|
| 1911 | * RETURNS: PSZ                                                              * | 
|---|
| 1912 | *   The object ID string.  It is up to the caller to free it when done.     * | 
|---|
| 1913 | *   This will be NULL if no object ID was found.                            * | 
|---|
| 1914 | * ------------------------------------------------------------------------- */ | 
|---|
| 1915 | PSZ GetObjectID( PSZ pszHandle ) | 
|---|
| 1916 | { | 
|---|
| 1917 | PVOID   pbuf = NULL; | 
|---|
| 1918 | ULONG   cbTotal  = 0, | 
|---|
| 1919 | cbActual = 0; | 
|---|
| 1920 | CHAR    szValue[ 9 ]; | 
|---|
| 1921 | PSZ     psz, | 
|---|
| 1922 | pszObjID = NULL; | 
|---|
| 1923 | BOOL    fRC; | 
|---|
| 1924 |  | 
|---|
| 1925 |  | 
|---|
| 1926 | fRC = PrfQueryProfileSize( HINI_USERPROFILE, | 
|---|
| 1927 | APPNAME_PM_WPS_LOCATION, NULL, &cbTotal ); | 
|---|
| 1928 | if ( !fRC || !cbTotal ) { | 
|---|
| 1929 | //WriteErrorCode( ERRORIDERROR( WinGetLastError( hab )), "PrfQueryProfileSize"); | 
|---|
| 1930 | return NULL; | 
|---|
| 1931 | } | 
|---|
| 1932 | pbuf = malloc( cbTotal ); | 
|---|
| 1933 | if ( !pbuf ) { | 
|---|
| 1934 | WriteErrorCode( ERROR_NOT_ENOUGH_MEMORY, "malloc"); | 
|---|
| 1935 | return NULL; | 
|---|
| 1936 | } | 
|---|
| 1937 |  | 
|---|
| 1938 | cbActual = PrfQueryProfileString( HINI_USERPROFILE, APPNAME_PM_WPS_LOCATION, | 
|---|
| 1939 | NULL, NULL, pbuf, cbTotal ); | 
|---|
| 1940 | if ( !cbActual ) { | 
|---|
| 1941 | //WriteErrorCode( ERRORIDERROR( WinGetLastError( hab )), "PrfQueryProfileString"); | 
|---|
| 1942 | return NULL; | 
|---|
| 1943 | } | 
|---|
| 1944 |  | 
|---|
| 1945 | psz = (PSZ) pbuf; | 
|---|
| 1946 | while ( *psz ) { | 
|---|
| 1947 | if ( !PrfQueryProfileString( HINI_USERPROFILE, APPNAME_PM_WPS_LOCATION, | 
|---|
| 1948 | psz, NULL, szValue, 8 )) | 
|---|
| 1949 | { | 
|---|
| 1950 | //WriteErrorCode( ERRORIDERROR( WinGetLastError( hab )), "PrfQueryProfileString"); | 
|---|
| 1951 | break; | 
|---|
| 1952 | } | 
|---|
| 1953 | if (( strcmp( szValue, pszHandle ) == 0 ) && | 
|---|
| 1954 | (( pszObjID = strdup( psz )) != NULL )) | 
|---|
| 1955 | { | 
|---|
| 1956 | break; | 
|---|
| 1957 | } | 
|---|
| 1958 | psz += strlen( psz ) + 1; | 
|---|
| 1959 | } | 
|---|
| 1960 |  | 
|---|
| 1961 | free ( pbuf ); | 
|---|
| 1962 | return ( pszObjID ); | 
|---|
| 1963 | } | 
|---|
| 1964 |  | 
|---|
| 1965 |  | 
|---|
| 1966 | /* ------------------------------------------------------------------------- * | 
|---|
| 1967 | * UniqueDeviceName                                                          * | 
|---|
| 1968 | *                                                                           * | 
|---|
| 1969 | * Check (and, if necessary, modify) the specified print device name to make * | 
|---|
| 1970 | * sure it is unique.                                                        * | 
|---|
| 1971 | *                                                                           * | 
|---|
| 1972 | * ARGUMENTS:                                                                * | 
|---|
| 1973 | *   PSZ pszName : Pointer to device name buffer (9-byte CHAR buffer)        * | 
|---|
| 1974 | *                                                                           * | 
|---|
| 1975 | * RETURNS: ULONG                                                            * | 
|---|
| 1976 | *   0 on success, 1 if no unique name could be generated, or the return     * | 
|---|
| 1977 | *   code from SplEnumDevice() if an error occurred.                         * | 
|---|
| 1978 | * ------------------------------------------------------------------------- */ | 
|---|
| 1979 | ULONG UniqueDeviceName( PSZ pszName ) | 
|---|
| 1980 | { | 
|---|
| 1981 | PBYTE     pBuf; | 
|---|
| 1982 | PPRDINFO3 pprd3; | 
|---|
| 1983 | CHAR      szNumber[ US_PRTDEV_MAXZ ] = {0}; | 
|---|
| 1984 | ULONG     i, n, pos, | 
|---|
| 1985 | ulNumber  = 0, | 
|---|
| 1986 | ulAvail   = 0, | 
|---|
| 1987 | cbBuf     = 0; | 
|---|
| 1988 | BOOL      fUnique   = FALSE; | 
|---|
| 1989 | SPLERR    rc; | 
|---|
| 1990 |  | 
|---|
| 1991 |  | 
|---|
| 1992 | rc = SplEnumDevice( NULL, 3, NULL, 0, &ulNumber, &ulAvail, &cbBuf, NULL ); | 
|---|
| 1993 | if ( rc == ERROR_MORE_DATA || rc == NERR_BufTooSmall ) { | 
|---|
| 1994 | pBuf = malloc( cbBuf ); | 
|---|
| 1995 | if ( pBuf ) { | 
|---|
| 1996 | rc = SplEnumDevice( NULL, 3, pBuf, cbBuf, &ulNumber, &ulAvail, &cbBuf, NULL ); | 
|---|
| 1997 | if ( rc == NO_ERROR ) { | 
|---|
| 1998 | n = 1; | 
|---|
| 1999 | while ( !fUnique && ( n < 999 )) {     // max 999 as a sanity check | 
|---|
| 2000 | for ( i = 0; i < ulNumber; i++ )  { | 
|---|
| 2001 | pprd3 = (PPRDINFO3) pBuf + i; | 
|---|
| 2002 | if ( stricmp( pszName, pprd3->pszPrinterName ) == 0 ) break; | 
|---|
| 2003 | } | 
|---|
| 2004 | if ( i >= ulNumber ) fUnique = TRUE; | 
|---|
| 2005 | else { | 
|---|
| 2006 | sprintf( szNumber, "%u", n++ ); | 
|---|
| 2007 | pos = strlen( pszName ) - strlen( szNumber ); | 
|---|
| 2008 | pszName[ pos ] = '\0'; | 
|---|
| 2009 | strncat( pszName, szNumber, US_PRTDEV_MAXZ-1 ); | 
|---|
| 2010 | } | 
|---|
| 2011 | } | 
|---|
| 2012 | } | 
|---|
| 2013 | free( pBuf ); | 
|---|
| 2014 | if ( rc == NO_ERROR && !fUnique ) return 1; | 
|---|
| 2015 | } | 
|---|
| 2016 | } | 
|---|
| 2017 | else if ( rc == NO_ERROR ) fUnique = TRUE; | 
|---|
| 2018 | return rc; | 
|---|
| 2019 | } | 
|---|
| 2020 |  | 
|---|
| 2021 |  | 
|---|
| 2022 | /* ************************************************************************* * | 
|---|
| 2023 | * INTERNAL REXX DLL UTILITY FUNCTIONS                                       * | 
|---|
| 2024 | * ************************************************************************* */ | 
|---|
| 2025 |  | 
|---|
| 2026 | #ifdef NO_SHARED_SOURCE | 
|---|
| 2027 |  | 
|---|
| 2028 | /* ------------------------------------------------------------------------- * | 
|---|
| 2029 | * SaveResultString                                                          * | 
|---|
| 2030 | *                                                                           * | 
|---|
| 2031 | * Writes new string contents to the specified RXSTRING, allocating any      * | 
|---|
| 2032 | * additional memory that may be required.  If the string to be written has  * | 
|---|
| 2033 | * zero length, nothing is done.                                             * | 
|---|
| 2034 | *                                                                           * | 
|---|
| 2035 | * This function should be used in place of MAKERXSTRING to generate all     * | 
|---|
| 2036 | * REXX return values.                                                       * | 
|---|
| 2037 | *                                                                           * | 
|---|
| 2038 | * ARGUMENTS:                                                                * | 
|---|
| 2039 | *   PRXSTRING prsResult: Pointer to an existing RXSTRING for writing.       * | 
|---|
| 2040 | *   PCH       pchBytes : The string contents to write to prsResult.         * | 
|---|
| 2041 | *   ULONG     ulBytes  : The number of bytes in pchBytes to write.          * | 
|---|
| 2042 | *                                                                           * | 
|---|
| 2043 | * RETURNS: BOOL                                                             * | 
|---|
| 2044 | *   TRUE if prsResult was successfully updated.  FALSE otherwise.           * | 
|---|
| 2045 | * ------------------------------------------------------------------------- */ | 
|---|
| 2046 | BOOL SaveResultString( PRXSTRING prsResult, PCH pchBytes, ULONG ulBytes ) | 
|---|
| 2047 | { | 
|---|
| 2048 | ULONG ulRC; | 
|---|
| 2049 | PCH   pchNew; | 
|---|
| 2050 |  | 
|---|
| 2051 | if ( ulBytes == 0 ) return ( FALSE ); | 
|---|
| 2052 | if ( ulBytes > 256 ) { | 
|---|
| 2053 | // REXX provides 256 bytes by default; allocate more if necessary | 
|---|
| 2054 | ulRC = DosAllocMem( (PVOID) &pchNew, ulBytes, PAG_WRITE | PAG_COMMIT ); | 
|---|
| 2055 | if ( ulRC != 0 ) { | 
|---|
| 2056 | WriteErrorCode( ulRC, "DosAllocMem"); | 
|---|
| 2057 | return ( FALSE ); | 
|---|
| 2058 | } | 
|---|
| 2059 | prsResult->strptr = pchNew; | 
|---|
| 2060 | } | 
|---|
| 2061 | memcpy( prsResult->strptr, pchBytes, ulBytes ); | 
|---|
| 2062 | prsResult->strlength = ulBytes; | 
|---|
| 2063 |  | 
|---|
| 2064 | return ( TRUE ); | 
|---|
| 2065 | } | 
|---|
| 2066 |  | 
|---|
| 2067 |  | 
|---|
| 2068 | /* ------------------------------------------------------------------------- * | 
|---|
| 2069 | * WriteStemElement                                                          * | 
|---|
| 2070 | *                                                                           * | 
|---|
| 2071 | * Creates a stem element (compound variable) in the calling REXX program    * | 
|---|
| 2072 | * using the REXX shared variable pool interface.                            * | 
|---|
| 2073 | *                                                                           * | 
|---|
| 2074 | * ARGUMENTS:                                                                * | 
|---|
| 2075 | *   PSZ   pszStem  : The name of the stem (before the '.')                  * | 
|---|
| 2076 | *   ULONG ulIndex  : The number of the stem element (after the '.')         * | 
|---|
| 2077 | *   PSZ   pszValue : The value to write to the compound variable.           * | 
|---|
| 2078 | *                                                                           * | 
|---|
| 2079 | * RETURNS: BOOL                                                             * | 
|---|
| 2080 | *   TRUE on success, FALSE on failure.                                      * | 
|---|
| 2081 | * ------------------------------------------------------------------------- */ | 
|---|
| 2082 | BOOL WriteStemElement( PSZ pszStem, ULONG ulIndex, PSZ pszValue ) | 
|---|
| 2083 | { | 
|---|
| 2084 | SHVBLOCK shvVar;                   // REXX shared variable pool block | 
|---|
| 2085 | ULONG    ulRc, | 
|---|
| 2086 | ulBytes; | 
|---|
| 2087 | CHAR     szCompoundName[ US_COMPOUND_MAXZ ]; | 
|---|
| 2088 |  | 
|---|
| 2089 | sprintf( szCompoundName, "%s.%d", pszStem, ulIndex ); | 
|---|
| 2090 | if ( pszValue == NULL ) { | 
|---|
| 2091 | pszValue = ""; | 
|---|
| 2092 | ulBytes  = 0; | 
|---|
| 2093 | } else { | 
|---|
| 2094 | ulBytes = strlen( pszValue ); | 
|---|
| 2095 | } | 
|---|
| 2096 | MAKERXSTRING( shvVar.shvname, szCompoundName, strlen(szCompoundName) ); | 
|---|
| 2097 | shvVar.shvvalue.strptr    = pszValue; | 
|---|
| 2098 | shvVar.shvvalue.strlength = ulBytes; | 
|---|
| 2099 | shvVar.shvnamelen  = RXSTRLEN( shvVar.shvname ); | 
|---|
| 2100 | shvVar.shvvaluelen = RXSTRLEN( shvVar.shvvalue ); | 
|---|
| 2101 | shvVar.shvcode     = RXSHV_SYSET; | 
|---|
| 2102 | shvVar.shvnext     = NULL; | 
|---|
| 2103 | ulRc = RexxVariablePool( &shvVar ); | 
|---|
| 2104 | if ( ulRc > 1 ) { | 
|---|
| 2105 | WriteErrorCode( shvVar.shvret, "RexxVariablePool (SHVBLOCK.shvret)"); | 
|---|
| 2106 | return FALSE; | 
|---|
| 2107 | } | 
|---|
| 2108 | return TRUE; | 
|---|
| 2109 |  | 
|---|
| 2110 | } | 
|---|
| 2111 |  | 
|---|
| 2112 |  | 
|---|
| 2113 | /* ------------------------------------------------------------------------- * | 
|---|
| 2114 | * WriteCompoundVariable                                                     * | 
|---|
| 2115 | *                                                                           * | 
|---|
| 2116 | * Creates a compound variable in the calling REXX program using the REXX    * | 
|---|
| 2117 | * shared variable pool interface.                                           * | 
|---|
| 2118 | *                                                                           * | 
|---|
| 2119 | * ARGUMENTS:                                                                * | 
|---|
| 2120 | *   PSZ   pszStem  : The name of the stem (before the '.')                  * | 
|---|
| 2121 | *   PSZ   pszTail  : The name of the trailing portion (after the '.')       * | 
|---|
| 2122 | *   PSZ   pszValue : The value to write to the compound variable.           * | 
|---|
| 2123 | *                                                                           * | 
|---|
| 2124 | * RETURNS: BOOL                                                             * | 
|---|
| 2125 | *   TRUE on success, FALSE on failure.                                      * | 
|---|
| 2126 | * ------------------------------------------------------------------------- */ | 
|---|
| 2127 | BOOL WriteCompoundVariable( PSZ pszStem, PSZ pszTail, PSZ pszValue ) | 
|---|
| 2128 | { | 
|---|
| 2129 | SHVBLOCK shvVar;                   // REXX shared variable pool block | 
|---|
| 2130 | ULONG    ulRc, | 
|---|
| 2131 | ulBytes; | 
|---|
| 2132 | CHAR     szCompoundName[ US_COMPOUND_MAXZ ]; | 
|---|
| 2133 |  | 
|---|
| 2134 | sprintf( szCompoundName, "%s.%s", pszStem, pszTail ); | 
|---|
| 2135 | if ( pszValue == NULL ) { | 
|---|
| 2136 | pszValue = ""; | 
|---|
| 2137 | ulBytes  = 0; | 
|---|
| 2138 | } else { | 
|---|
| 2139 | ulBytes = strlen( pszValue ); | 
|---|
| 2140 | } | 
|---|
| 2141 | MAKERXSTRING( shvVar.shvname, szCompoundName, strlen(szCompoundName) ); | 
|---|
| 2142 | shvVar.shvvalue.strptr    = pszValue; | 
|---|
| 2143 | shvVar.shvvalue.strlength = ulBytes; | 
|---|
| 2144 | shvVar.shvnamelen  = RXSTRLEN( shvVar.shvname ); | 
|---|
| 2145 | shvVar.shvvaluelen = RXSTRLEN( shvVar.shvvalue ); | 
|---|
| 2146 | shvVar.shvcode     = RXSHV_SYSET; | 
|---|
| 2147 | shvVar.shvnext     = NULL; | 
|---|
| 2148 | ulRc = RexxVariablePool( &shvVar ); | 
|---|
| 2149 | if ( ulRc > 1 ) { | 
|---|
| 2150 | WriteErrorCode( shvVar.shvret, "RexxVariablePool (SHVBLOCK.shvret)"); | 
|---|
| 2151 | return FALSE; | 
|---|
| 2152 | } | 
|---|
| 2153 | return TRUE; | 
|---|
| 2154 | } | 
|---|
| 2155 |  | 
|---|
| 2156 |  | 
|---|
| 2157 | /* ------------------------------------------------------------------------- * | 
|---|
| 2158 | * WriteSimpleVariable                                                       * | 
|---|
| 2159 | *                                                                           * | 
|---|
| 2160 | * Creates a variable in the calling REXX program using the REXX shared      * | 
|---|
| 2161 | * variable pool interface.                                                  * | 
|---|
| 2162 | *                                                                           * | 
|---|
| 2163 | * ARGUMENTS:                                                                * | 
|---|
| 2164 | *   PSZ pszName  : The name of the variable to write.                       * | 
|---|
| 2165 | *   PSZ pszValue : The value to write to the variable.                      * | 
|---|
| 2166 | *                                                                           * | 
|---|
| 2167 | * RETURNS: BOOL                                                             * | 
|---|
| 2168 | * ------------------------------------------------------------------------- */ | 
|---|
| 2169 | BOOL WriteSimpleVariable( PSZ pszName, PSZ pszValue ) | 
|---|
| 2170 | { | 
|---|
| 2171 | SHVBLOCK shvVar;                   // REXX shared variable pool block | 
|---|
| 2172 | ULONG    ulRc; | 
|---|
| 2173 | CHAR     szText[ US_COMPOUND_MAXZ ]; | 
|---|
| 2174 |  | 
|---|
| 2175 | strncpy( szText, pszValue, US_COMPOUND_MAXZ-1 ); | 
|---|
| 2176 | MAKERXSTRING( shvVar.shvname,  pszName, strlen(pszName) ); | 
|---|
| 2177 | MAKERXSTRING( shvVar.shvvalue, szText,  strlen(szText) ); | 
|---|
| 2178 | shvVar.shvnamelen  = RXSTRLEN( shvVar.shvname ); | 
|---|
| 2179 | shvVar.shvvaluelen = RXSTRLEN( shvVar.shvvalue ); | 
|---|
| 2180 | shvVar.shvcode     = RXSHV_SYSET; | 
|---|
| 2181 | shvVar.shvnext     = NULL; | 
|---|
| 2182 | ulRc = RexxVariablePool( &shvVar ); | 
|---|
| 2183 | if ( ulRc > 1 ) { | 
|---|
| 2184 | WriteErrorCode( shvVar.shvret, "RexxVariablePool (SHVBLOCK.shvret)"); | 
|---|
| 2185 | return FALSE; | 
|---|
| 2186 | } | 
|---|
| 2187 | return TRUE; | 
|---|
| 2188 | } | 
|---|
| 2189 |  | 
|---|
| 2190 |  | 
|---|
| 2191 | /* ------------------------------------------------------------------------- * | 
|---|
| 2192 | * WriteErrorCode                                                            * | 
|---|
| 2193 | *                                                                           * | 
|---|
| 2194 | * Writes an error code to a special variable in the calling REXX program    * | 
|---|
| 2195 | * using the REXX shared variable pool interface.  This is used to return    * | 
|---|
| 2196 | * API error codes to the REXX program, since the REXX functions themselves  * | 
|---|
| 2197 | * normally return string values.                                            * | 
|---|
| 2198 | *                                                                           * | 
|---|
| 2199 | * ARGUMENTS:                                                                * | 
|---|
| 2200 | *   ULONG ulError   : The error code returned by the failing API call.      * | 
|---|
| 2201 | *   PSZ   pszContext: A string describing the API call that failed.         * | 
|---|
| 2202 | *                                                                           * | 
|---|
| 2203 | * RETURNS: N/A                                                              * | 
|---|
| 2204 | * ------------------------------------------------------------------------- */ | 
|---|
| 2205 | void WriteErrorCode( ULONG ulError, PSZ pszContext ) | 
|---|
| 2206 | { | 
|---|
| 2207 | SHVBLOCK shvVar;                   // REXX shared variable pool block | 
|---|
| 2208 | ULONG    ulRc; | 
|---|
| 2209 | CHAR     szErrorText[ US_ERRSTR_MAXZ ]; | 
|---|
| 2210 |  | 
|---|
| 2211 | if ( pszContext == NULL ) | 
|---|
| 2212 | sprintf( szErrorText, "%X", ulError ); | 
|---|
| 2213 | else | 
|---|
| 2214 | sprintf( szErrorText, "%X: %s", ulError, pszContext ); | 
|---|
| 2215 | MAKERXSTRING( shvVar.shvname,  SZ_ERROR_NAME, strlen(SZ_ERROR_NAME) ); | 
|---|
| 2216 | MAKERXSTRING( shvVar.shvvalue, szErrorText,   strlen(szErrorText) ); | 
|---|
| 2217 | shvVar.shvnamelen  = RXSTRLEN( shvVar.shvname ); | 
|---|
| 2218 | shvVar.shvvaluelen = RXSTRLEN( shvVar.shvvalue ); | 
|---|
| 2219 | shvVar.shvcode     = RXSHV_SYSET; | 
|---|
| 2220 | shvVar.shvnext     = NULL; | 
|---|
| 2221 | ulRc = RexxVariablePool( &shvVar ); | 
|---|
| 2222 | if ( ulRc > 1 ) | 
|---|
| 2223 | printf("Unable to set %s: rc = %d\n", shvVar.shvname.strptr, shvVar.shvret ); | 
|---|
| 2224 | } | 
|---|
| 2225 |  | 
|---|
| 2226 | #endif | 
|---|