_PROGRAMMING FOR THE OS/2 2.0 WORKPLACE SHELL_ by Joel Barnum [LISTING ONE] // spread.c -- a sample WPS application #define INCL_WIN #define INCL_GPI #include #include #include #include "spread.h" #define WM_INIT WM_USER // Internal function prototypes int main ( int argc, char *argv[] ); BOOL savefile ( PSZ szFname, LONG alValues[] ); BOOL openfile ( PSZ szFname, LONG alValues[] ); BOOL settype ( HFILE hf, PSZ pszType ); MRESULT EXPENTRY ValueDlgProc ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ); MRESULT EXPENTRY ClientWinProc ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); // global variables HAB hab; // Anchor block handle int main ( int argc, char *argv[] ) { HMQ hmq; // Message queue handle HWND hwndFrame; // Frame window handle HWND hwndClient; // Client window handle QMSG qmsg; // Message from queue ULONG flCreate; // Window creation flags BOOL fSuccess; // return from API hab = WinInitialize ( 0 ); hmq = WinCreateMsgQueue ( hab, 0 ); fSuccess = WinRegisterClass (hab,"spread",ClientWinProc,CS_SIZEREDRAW,0); flCreate = FCF_SYSMENU | FCF_SIZEBORDER | FCF_TITLEBAR | FCF_MINMAX | FCF_SHELLPOSITION | FCF_TASKLIST | FCF_ICON; hwndFrame = WinCreateStdWindow ( HWND_DESKTOP, WS_VISIBLE , &flCreate, "spread", NULL, 0L, 0 , ID_WINDOW, &hwndClient ); if ( hwndFrame == NULLHANDLE ) DosExit ( 1, 1 ); // send the client a message passing arg count and arguments WinSendMsg ( hwndClient, WM_INIT, MPFROMSHORT ( argc ) ,MPFROMP ( argv )); while ( WinGetMsg ( hab, &qmsg, NULLHANDLE, 0, 0 ) != FALSE ) WinDispatchMsg ( hab, &qmsg ); fSuccess = WinDestroyWindow ( hwndFrame ); fSuccess = WinDestroyMsgQueue ( hmq ); fSuccess = WinTerminate ( hab ); return 0; } //************************************************************ MRESULT EXPENTRY ClientWinProc ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) { BOOL fSuccess; // return from API static LONG alValues[2]; // spreadsheet values static HWND hwndMenu; // popup menu handle static CHAR szFname[255]; // file name switch( msg ) { case WM_BUTTON2DOWN: { POINTL ptl; // display a popup menu at the coordinates the user clicked ptl.x = SHORT1FROMMP ( mp1 ); ptl.y = SHORT2FROMMP ( mp1 ); WinMapWindowPoints ( hwnd, HWND_DESKTOP, &ptl, 1 ); fSuccess = WinPopupMenu ( HWND_DESKTOP , hwnd , hwndMenu , ptl.x , ptl.y , 0 , PU_KEYBOARD | PU_NONE | PU_MOUSEBUTTON1 ); } return (MRESULT)FALSE; case WM_CLOSE: savefile ( szFname, alValues ); WinPostMsg( hwnd, WM_QUIT, 0L, 0L ); return (MRESULT) NULL; case WM_COMMAND: switch ( SHORT1FROMMP ( mp1 ) ) { case IDM_CHANGE: { ULONG result; // display a modal dialog to let user enter in new values result = WinDlgBox ( HWND_DESKTOP , WinQueryWindow ( hwnd, QW_PARENT ), ValueDlgProc , NULLHANDLE , DLG_VALUES , alValues ); if ( result == DID_OK ) WinInvalidateRect ( hwnd, NULL, TRUE ); } break; } return (MRESULT)NULL; case WM_CREATE: //load our popup menu hwndMenu = WinLoadMenu ( HWND_DESKTOP , NULLHANDLE, ID_MENU ); return (MRESULT)FALSE; case WM_INIT: // user-defined message { int argc; // argument count CHAR **argv; // input arguments CHAR szTitle[255]; // titlebar text // extract argument count and strings argc = SHORT1FROMMP ( mp1 ); argv = PVOIDFROMMP ( mp2 ); // if there were no input arguments, exit if ( argc < 2 ) { WinMessageBox ( HWND_DESKTOP , WinQueryWindow ( hwnd, QW_PARENT ) , "You must specify an input file" , "Error", 0 , MB_OK | MB_ERROR ); DosExit ( 1, 1 ); } // attempt to open input file strcpy ( szFname, argv[1] ); if ( openfile ( argv[1], alValues ) == FALSE ) { WinMessageBox ( HWND_DESKTOP , WinQueryWindow ( hwnd, QW_PARENT ) , argv[1] , "Unable to open file", 0 , MB_OK | MB_ERROR ); DosExit ( 1, 1 ); } // update the titlebar text strcpy ( szTitle, "Spreadsheet - " ); strcat ( szTitle, szFname ); WinSetWindowText ( WinQueryWindow ( hwnd, QW_PARENT ),szTitle); } return (MRESULT)NULL; case WM_PAINT: { LONG lSuccess; // return from API HPS hps; // cached PS POINTL ptl; // coordinates for draw CHAR sz[50]; // temp string hps = WinBeginPaint ( hwnd , NULLHANDLE, NULL ); fSuccess = GpiErase ( hps ); // draw the values and their sum ptl.x = 100; ptl.y = 125; _itoa ( alValues[0], sz, 10 ); lSuccess = GpiCharStringAt ( hps, &ptl, strlen ( sz ) , sz ); ptl.y = 100; _itoa ( alValues[1], sz, 10 ); lSuccess = GpiCharStringAt ( hps, &ptl, strlen ( sz ) , sz ); ptl.y = 75; lSuccess = GpiMove ( hps, &ptl ); ptl.x = 200; lSuccess = GpiLine ( hps, &ptl ); ptl.x = 100; ptl.y = 50; _itoa ( alValues[0] + alValues[1], sz, 10 ); lSuccess = GpiCharStringAt ( hps, &ptl, strlen ( sz ) , sz ); ptl.x = 50; ptl.y = 25; strcpy ( sz, "Press the right mouse button to change values" ); lSuccess = GpiCharStringAt ( hps, &ptl, strlen ( sz ) , sz ); fSuccess = WinEndPaint ( hps ); } return (MRESULT) NULL; default: return WinDefWindowProc( hwnd, msg, mp1, mp2 ); } return WinDefWindowProc( hwnd, msg, mp1, mp2 ); } // savefile: saves the current values to a file // RETURNS: TRUE if successful, FALSE if not BOOL savefile ( PSZ szFname, LONG alValues[] ) { HFILE h; // file handle ULONG ulAction; // action taken by OPEN ULONG ulActualWritten; // count written to file APIRET rc; // return code // open the current file rc = DosOpen ( szFname, &h, &ulAction, 0L , 0, OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW , OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, NULL ); if ( rc != 0 ) return FALSE; // write the two values rc = DosWrite ( h, alValues, 8, &ulActualWritten ); if ( ( rc != 0 ) || ( ulActualWritten != 8 ) ) { DosClose ( h ); return FALSE; } // write our .TYPE EA on the file settype ( h, "XX Company Spreadsheet" ); // close the file DosClose ( h ); return TRUE; } // openfile: reads spreadsheet values from the specified file // RETURNS: TRUE if successful, FALSE if not BOOL openfile ( PSZ szFname, LONG alValues[] ) { HFILE h; // file handle ULONG ulAction; // action taken by OPEN ULONG ulActualRead; // count read from file APIRET rc; // return code // open the file rc = DosOpen ( szFname, &h, &ulAction, 0L , 0 , OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW , OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE , NULL ); if ( rc != 0 ) return FALSE; // read the values rc = DosRead ( h, alValues, 8, &ulActualRead ); if ( rc != 0 ) { DosClose ( h ); return FALSE; } // zero length files are OK, but otherwise less than 8 bytes means bad file if ( ulActualRead < 8 ) if ( ulActualRead != 0 ) { DosClose ( h ); return FALSE; } // close the file DosClose ( h ); return TRUE; } // settype: sets the .TYPE ea for a data file BOOL settype ( HFILE hf, PSZ pszType ) { // define a .TYPE EA structure typedef struct _TYPEEALIST { ULONG cbList; // length of all EAs in list ULONG ulNextEa; // offset of next EA BYTE bFlags; // EA flags BYTE cbName; // length of name USHORT cbEA; // sizeof EA CHAR szName[6]; // ".TYPE" USHORT usType; // EA data type USHORT cbValue; // sizeof value CHAR achValue[1]; // placeholder for EA value } TEALIST, *PTEALIST; EAOP2 eaop; // extended attributes structure PTEALIST ptea; // points to TYPE EA list PSZ psz1, psz2; // temp pointers USHORT cb; // structure length APIRET rc; // return from API // allocate memory for the TYPE EA list // -1 because the structure itself defines 1 char cb = strlen ( pszType ) - 1 + sizeof ( TEALIST ); ptea = (PTEALIST)malloc ( cb ); // initialize the EA structures // fill in the EA value itself: for .TYPE it's the file type // can't use strcpy!! (needs to add '\0') psz1 = pszType; psz2 = ptea->achValue; while ( *psz1 != '\0' ) *psz2++ = *psz1++; // fill in length of the EA value ptea->cbValue = strlen ( pszType ); // fill type of EA value ptea->usType = 0xfffd; // length-preceded ASCII // length of EA (includes value + type and length fields) ptea->cbEA = ptea->cbValue + sizeof(ptea->usType) + sizeof (ptea->cbValue); // fill in the EA name (it's a null terminated string so strcpy is OK) strcpy ( ptea->szName, ".TYPE" ); // fill in EA name length ptea->cbName = (BYTE)strlen ( ".TYPE" ); // point to the TYPE EA list structure eaop.fpFEA2List = (PFEA2LIST)ptea; eaop.fpGEA2List = NULL; ptea->cbList = cb; // structure length ptea->ulNextEa = 0; // no more EAs ptea->bFlags = 0; // noncritical // attach the .TYPE extended attribute to the file rc = DosSetFileInfo ( hf, 2, (PBYTE)&eaop , sizeof (EAOP2) ); free ( ptea ); return (BOOL)rc; } MRESULT EXPENTRY ValueDlgProc ( HWND hwnd, ULONG msg , MPARAM mp1, MPARAM mp2 ) { static PLONG alValues; switch ( msg ) { case WM_INITDLG: // retrieve a pointer to values array alValues = PVOIDFROMMP ( mp2 ); // write current values into entry fields WinSetDlgItemShort ( hwnd, DLG_VALUE1, (SHORT)alValues[0], TRUE ); WinSetDlgItemShort ( hwnd, DLG_VALUE2, (SHORT)alValues[1], TRUE ); // set the focus to the first entryfield WinSetFocus ( HWND_DESKTOP, WinWindowFromID ( hwnd, DLG_VALUE1 ) ); return (MRESULT)TRUE; case WM_COMMAND: switch ( SHORT1FROMMP ( mp1 ) ) { case DID_CANCEL: WinDismissDlg ( hwnd, DID_CANCEL ); break; case DID_OK: // retrieve values from entry fields WinQueryDlgItemShort ( hwnd, DLG_VALUE1 , (PSHORT)&alValues[0], TRUE ); WinQueryDlgItemShort ( hwnd, DLG_VALUE2 , (PSHORT)&alValues[1], TRUE ); WinDismissDlg ( hwnd, DID_OK ); } return (MRESULT)NULL; default: return WinDefDlgProc( hwnd, msg, mp1, mp2 ); } return WinDefDlgProc( hwnd, msg, mp1, mp2 ); } [LISTING TWO] #include #include "spread.h" rcinclude spread.dlg ICON ID_WINDOW spread.ico MENU ID_MENU BEGIN MENUITEM "~Change values", IDM_CHANGE END ASSOCTABLE 1 { "XX Company Spreadsheet", "*.SPR", spread.ico } [LISTING THREE] # Subclass of WPDataFile for Spreadsheet sample WPS application #include class: WPSpread, external stem = wpspread, local, external prefix = wpspread_, classprefix = wpspreadM_, major version = 1, minor version = 2; parent: WPDataFile; passthru: C.ih; #define INCL_WIN #define INCL_DOS #define INCL_DEV #define INCL_GPI #define INCL_WPCLASS #define INCL_WPFOLDER #include #include #include endpassthru; /* .ih */ data: HPOINTER hicon, class; // class icon methods: override wpclsQueryTitle, class; override wpclsInitData, class; override wpclsQueryIcon, class; override wpclsQueryInstanceFilter, class; override wpclsQueryInstanceType, class; override wpPrintObject; [LISTING FOUR] /* This file was generated by the SOM Compiler. FileName: wpspread.c. * Generated using: SOM Precompiler spc: 1.22 SOM Emitter emitc: 1.24 */ #define WPSpread_Class_Source #include "wpspread.ih" BOOL openfile ( PSZ szFname, LONG alValues[] ); BOOL printspread ( WPSpread *somSelf, PPRINTDEST pPrintDest );; #undef SOM_CurrentClass #define SOM_CurrentClass SOMMeta SOM_Scope PSZ SOMLINK wpspreadM_wpclsQueryTitle(M_WPSpread *somSelf) { M_WPSpreadData *somThis = M_WPSpreadGetData(somSelf); M_WPSpreadMethodDebug("M_WPSpread","wpspreadM_wpclsQueryTitle"); return _wpclsQueryInstanceType( somSelf ); } SOM_Scope void SOMLINK wpspreadM_wpclsInitData(M_WPSpread *somSelf) { HMODULE hmod; // module handle PSZ psz; // module file name APIRET rc; // return from API M_WPSpreadData *somThis = M_WPSpreadGetData(somSelf); M_WPSpreadMethodDebug("M_WPSpread","wpspreadM_wpclsInitData"); // initialize the parent classes first parent_wpclsInitData ( somSelf ); // query our module name psz = _somLocateClassFile( SOMClassMgrObject, SOM_IdFromString( "WPChart" ) , WPSpread_MajorVersion , WPSpread_MinorVersion ); // query our module handle if ( psz != NULL ) rc = DosQueryModuleHandle ( psz, &hmod ); // load the icon (same as pointer) and store in class data _hicon = WinLoadPointer ( HWND_DESKTOP, hmod, 1 ); } SOM_Scope HPOINTER SOMLINK wpspreadM_wpclsQueryIcon(M_WPSpread *somSelf) { M_WPSpreadData *somThis = M_WPSpreadGetData(somSelf); M_WPSpreadMethodDebug("M_WPSpread","wpspreadM_wpclsQueryIcon"); return _hicon; } SOM_Scope PSZ SOMLINK wpspreadM_wpclsQueryInstanceFilter(M_WPSpread *somSelf) { M_WPSpreadData *somThis = M_WPSpreadGetData(somSelf); M_WPSpreadMethodDebug("M_WPSpread","wpspreadM_wpclsQueryInstanceFilter"); return ".SPR"; } SOM_Scope PSZ SOMLINK wpspreadM_wpclsQueryInstanceType(M_WPSpread *somSelf) { M_WPSpreadData *somThis = M_WPSpreadGetData(somSelf); M_WPSpreadMethodDebug("M_WPSpread","wpspreadM_wpclsQueryInstanceType"); return "XX Company Spreadsheet"; } #undef SOM_CurrentClass #define SOM_CurrentClass SOMInstance SOM_Scope BOOL SOMLINK wpspread_wpPrintObject(WPSpread *somSelf, PPRINTDEST pPrintDest, ULONG ulReserved) { /* WPSpreadData *somThis = WPSpreadGetData(somSelf); */ WPSpreadMethodDebug("WPSpread","wpspread_wpPrintObject"); return printspread ( somSelf, pPrintDest ); } //************* Following code NOT generated by SOM compiler // printspread: prints the file this object represents // RETURNS: TRUE if successful, FALSE if not BOOL printspread ( WPSpread *somSelf, PPRINTDEST pPrintDest ) { HDC hdcPrinter; // printer DC HAB hab; // anchor block handle HPS hps; // micro PS SIZEL sizel; // presentation page size LONG alValues[2]; // spreadsheet values BOOL fSuccess; // return from API BOOL lSuccess; // return from API CHAR szFname[255]; // file name ULONG cb; // filename length POINTL ptl; // drawing coordinates CHAR sz[50]; // temporary string // create a printer device context hab = WinQueryAnchorBlock ( HWND_DESKTOP ); hdcPrinter = DevOpenDC ( hab , pPrintDest->lType , pPrintDest->pszToken , pPrintDest->lCount , pPrintDest->pdopData , NULLHANDLE ); // create a micro PS associated with the printer DC sizel.cx = sizel.cy = 0; hps = GpiCreatePS ( hab, hdcPrinter, &sizel , GPIT_MICRO | PU_LOENGLISH | GPIA_ASSOC ); // open the file associated with this object cb = 255; _wpQueryRealName ( somSelf, szFname, &cb, TRUE ); fSuccess = openfile ( szFname , alValues ); // start a printer job lSuccess = DevEscape ( hdcPrinter, DEVESC_STARTDOC , strlen ( _wpQueryTitle ( somSelf ) ) , _wpQueryTitle ( somSelf ) , NULL, NULL ); // print the values ptl.x = 100; ptl.y = 125; _itoa ( alValues[0], sz, 10 ); lSuccess = GpiCharStringAt ( hps, &ptl, strlen ( sz ) , sz ); ptl.y = 100; _itoa ( alValues[1], sz, 10 ); lSuccess = GpiCharStringAt ( hps, &ptl, strlen ( sz ) , sz ); ptl.y = 75; lSuccess = GpiMove ( hps, &ptl ); ptl.x = 200; lSuccess = GpiLine ( hps, &ptl ); ptl.x = 100; ptl.y = 50; _itoa ( alValues[0] + alValues[1], sz, 10 ); lSuccess = GpiCharStringAt ( hps, &ptl, strlen ( sz ) , sz ); // end a printer job lSuccess = DevEscape ( hdcPrinter, DEVESC_ENDDOC , 0 , NULL, NULL, NULL ); // clean up DevCloseDC ( hdcPrinter ); GpiDestroyPS ( hps ); return TRUE; } // openfile: reads spreadsheet values from the specified file // RETURNS: TRUE if successful, FALSE if not BOOL openfile ( PSZ szFname, LONG alValues[] ) { HFILE h; // file handle ULONG ulAction; // action taken by OPEN ULONG ulActualRead; // count read from file APIRET rc; // return code // open the file rc = DosOpen ( szFname, &h, &ulAction, 0L , 0, OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW , OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, NULL ); if ( rc != 0 ) return FALSE; // read the values rc = DosRead ( h, alValues, 8, &ulActualRead ); if ( ( rc != 0 ) || ( ulActualRead != 8 ) ) { DosClose ( h ); return FALSE; } // close the file DosClose ( h ); return TRUE; } [LISTING FIVE] // install.c -- installation program for spreadsheet app // compile and link with: icc /Ss /Ti install.c #define INCL_WINWORKPLACE #include int main ( int argc, char *argv[] ) { HAB hab; // anchor block HOBJECT hobjFolder; // folder object HOBJECT hobjProg; // program object BOOL fSuccess; // return from API // create an anchor block so we can retrieve errors hab = WinInitialize ( 0 ); // create a folder on the desktop for our program object hobjFolder = WinCreateObject ( "WPFolder", "My Folder" , "OBJECTID=" , "" , CO_REPLACEIFEXISTS ); if ( hobjFolder == NULLHANDLE ) { ULONG ul; // error code ul = WinGetLastError ( hab ); printf ("Unable to create folder, error = %x\n", ERRORIDERROR ( ul ) ); } // register our object class for our data files fSuccess = WinRegisterObjectClass ( "WPSpread" , "c:\\book\\wpsart\\wpspread.dll" ); if ( fSuccess == FALSE ) { ULONG ul; // error code ul = WinGetLastError ( hab ); printf ("Unable to register class, error = %x\n", ERRORIDERROR ( ul ) ); } // create a program object for our EXE file hobjProg = WinCreateObject ( "WPProgram", "Spreadsheet App" , "EXENAME=c:\\book\\wpsart\\spread.exe;" "ASSOCTYPE=XX Company Spreadsheet,,;" "ASSOCFILTER=*.SPR,," , "" , CO_REPLACEIFEXISTS ); if ( hobjProg == NULLHANDLE ) { ULONG ul; // error code ul = WinGetLastError ( hab ); printf ("Unable to create program object, error = %x\n", ERRORIDERROR ( ul ) ); } WinTerminate ( hab ); }