| 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
 | 
|---|