home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / drgwps.zip / drgpmwps.c < prev    next >
C/C++ Source or Header  |  1993-08-08  |  33KB  |  778 lines

  1. /*********************************************************************
  2.  *                                                                   *
  3.  * MODULE NAME :  drgpmwps.c             AUTHOR:  Rick Fishman       *
  4.  * DATE WRITTEN:  08-01-93                                           *
  5.  *                                                                   *
  6.  * HOW TO RUN THIS PROGRAM:                                          *
  7.  *                                                                   *
  8.  *  Just enter DRGPMWPS on the command line.                         *
  9.  *                                                                   *
  10.  * MODULE DESCRIPTION:                                               *
  11.  *                                                                   *
  12.  *  Root module for DRGPMWPS.EXE, a program that demonstrates using  *
  13.  *  Drag/Drop on OS/2 2.x between a normal PM program and a WPS      *
  14.  *  object. This program creates a container window that is used to  *
  15.  *  drag from and drop on.                                           *
  16.  *                                                                   *
  17.  *  The drag window starts out with some icons in it that can be     *
  18.  *  dragged. If you drag from this window, the icon can be dropped   *
  19.  *  on a WPS object. If it is dropped, the WPS object will retain    *
  20.  *  that icon. Be careful - it will really stick, so if you do this  *
  21.  *  you've got to be prepared to change it back.                     *
  22.  *                                                                   *
  23.  *  You can also drop WPS objects on the window. If you do, a        *
  24.  *  messagebox is displayed that gives you a minimal amount of       *
  25.  *  information about the object, just to let you know that the      *
  26.  *  interaction between the PM window and the WPS object was         *
  27.  *  successful.                                                      *
  28.  *                                                                   *
  29.  *  The WPS object class is registered in this dll and an instance   *
  30.  *  is created. That instance is also destroyed and the class        *
  31.  *  deregistered when the PM window is destroyed, so all cleanup     *
  32.  *  is done automatically. This program first tries to load the      *
  33.  *  WPS object's dll from the directory where this program is        *
  34.  *  loaded from. If it doesn't find it there, LIBPATH is used.       *
  35.  *                                                                   *
  36.  *  The WPS object is created visible so you can see that it's there.*
  37.  *  If this were a real application, you would use the               *
  38.  *  NOTVISIBLE=YES string on the WinCreateObject because the user    *
  39.  *  has no idea about the 'agent' object and wouldn't want that icon *
  40.  *  on their desktop.                                                *
  41.  *                                                                   *
  42.  *  The icons in the container are found in the current directory.   *
  43.  *  That means that you can run this program from a directory with   *
  44.  *  a lot of icons and really have some fun. It is actually a        *
  45.  *  convenient way to assign icons to program objects. With a little *
  46.  *  work this program can be a nice little desktop icon manager.     *
  47.  *                                                                   *
  48.  * OTHER MODULES:                                                    *
  49.  *                                                                   *
  50.  *  drag.c     - contains all drag/drop processing code.             *
  51.  *  heap.c     - contains the code to create/maintain a shared memory*
  52.  *               heap.                                               *
  53.  *  commdata.c - contains the code to create/maintain a shared memory*
  54.  *               segment with information common to this program and *
  55.  *               the WPS object class.                               *
  56.  *  drgagent.c - the module that contains the code for the WPS       *
  57.  *               object.                                             *
  58.  *  commwin.c  - contains the code for the WPS object's object       *
  59.  *               window.                                             *
  60.  *                                                                   *
  61.  * NOTES:                                                            *
  62.  *                                                                   *
  63.  *  This sample was coded fairly quickly so there are bound to be    *
  64.  *  some anomalies.                                                  *
  65.  *                                                                   *
  66.  *  I hope this code proves useful for other PM programmers. The     *
  67.  *  more of us the better!                                           *
  68.  *                                                                   *
  69.  * HISTORY:                                                          *
  70.  *                                                                   *
  71.  *  08-01-93 - Program coding started.                               *
  72.  *                                                                   *
  73.  *  Rick Fishman                                                     *
  74.  *  Code Blazers, Inc.                                               *
  75.  *  4113 Apricot                                                     *
  76.  *  Irvine, CA. 92720                                                *
  77.  *  CIS ID: 72251,750                                                *
  78.  *                                                                   *
  79.  *********************************************************************/
  80.  
  81. #pragma strings(readonly)   // used for debug version of memory mgmt routines
  82.  
  83. /*********************************************************************/
  84. /*------- Include relevant sections of the OS/2 header files --------*/
  85. /*********************************************************************/
  86.  
  87. #define  INCL_DOSMODULEMGR
  88. #define  INCL_DOSPROCESS
  89. #define  INCL_SHLERRORS
  90. #define  INCL_WINERRORS
  91. #define  INCL_WINDIALOGS
  92. #define  INCL_WINFRAMEMGR
  93. #define  INCL_WINPOINTERS
  94. #define  INCL_WINSHELLDATA
  95. #define  INCL_WINSTDCNR
  96. #define  INCL_WINSTDDRAG
  97. #define  INCL_WINSYS
  98. #define  INCL_WINTIMER
  99. #define  INCL_WINWINDOWMGR
  100.  
  101. #define  GLOBALS_DEFINED    // extern globals instantiated
  102.  
  103. /**********************************************************************/
  104. /*----------------------------- INCLUDES -----------------------------*/
  105. /**********************************************************************/
  106.  
  107. #include <os2.h>
  108. #include <stdarg.h>
  109. #include <stdio.h>
  110. #include <stdlib.h>
  111. #include <string.h>
  112. #include "drgpmwps.h"
  113. #include "common.h"
  114.  
  115. /*********************************************************************/
  116. /*------------------- APPLICATION DEFINITIONS -----------------------*/
  117. /*********************************************************************/
  118.  
  119. #define PROGRAM_TITLE       "PM/WPS Drag/Drop Sample"
  120.  
  121. #define MESSAGE_SIZE        1024
  122.  
  123. #define FRAME_FLAGS         (FCF_TASKLIST   | FCF_TITLEBAR   | FCF_SYSMENU | \
  124.                              FCF_MINMAX     | FCF_SIZEBORDER | FCF_ICON    | \
  125.                              FCF_ACCELTABLE)
  126.  
  127. #define CONTAINER_STYLES    (CCS_SINGLESEL | CCS_MINIRECORDCORE | \
  128.                              CCS_AUTOPOSITION)
  129.  
  130. #define TIMER_INTERVAL      1000
  131. #define MAX_TIMER_ITERS     10
  132.  
  133. /**********************************************************************/
  134. /*---------------------------- STRUCTURES ----------------------------*/
  135. /**********************************************************************/
  136.  
  137.  
  138. /**********************************************************************/
  139. /*----------------------- FUNCTION PROTOTYPES ------------------------*/
  140. /**********************************************************************/
  141.  
  142. int  main             ( void );
  143. void GetCurrentPath   ( void );
  144. HWND CreateWindow     ( HAB hab );
  145. BOOL InsertRecords    ( HWND hwndCnr );
  146. void SizeAndShowWindow( HWND hwndFrame );
  147. void CreateDrgAgent   ( void );
  148. void DestroyDrgAgent  ( void );
  149.  
  150. FNWP wpFrame;
  151.  
  152. /**********************************************************************/
  153. /*------------------------ GLOBAL VARIABLES --------------------------*/
  154. /**********************************************************************/
  155.  
  156. PFNWP pfnwpFrame;
  157.  
  158. char szCnrTitle[] = "Drag to a WPS object\n"
  159.                     "or drop a WPS object here";
  160.  
  161. HAB  hab;
  162.  
  163. HOBJECT hObjAgent;
  164.  
  165. int cTimerIters;
  166.  
  167. /**********************************************************************/
  168. /*------------------------------ MAIN --------------------------------*/
  169. /*                                                                    */
  170. /*  PROGRAM ENTRYPOINT                                                */
  171. /*                                                                    */
  172. /*  PARMS: nothing                                                    */
  173. /*                                                                    */
  174. /*  NOTES:                                                            */
  175. /*                                                                    */
  176. /*  RETURNS: return code                                              */
  177. /*                                                                    */
  178. /*--------------------------------------------------------------------*/
  179. /**********************************************************************/
  180. int main( void )
  181. {
  182.     HMQ  hmq = NULLHANDLE;
  183.     QMSG qmsg;
  184.     HWND hwndFrame = NULLHANDLE;
  185.  
  186.     // This macro is defined for the debug version of the C Set/2 Memory
  187.     // Management routines. Since the debug version writes to stderr, we
  188.     // send all stderr output to a debuginfo file.
  189.  
  190. #ifdef __DEBUG_ALLOC__
  191.     freopen( DEBUG_FILENAME, "w", stderr );
  192. #endif
  193.  
  194.     hab = WinInitialize( 0 );
  195.  
  196.     if( hab )
  197.         hmq = WinCreateMsgQueue( hab, 0 );
  198.     else
  199.     {
  200.         DosBeep( 1000, 100 );
  201.         fprintf( stderr, "WinInitialize failed!" );
  202.     }
  203.  
  204.     if( hmq )
  205.     {
  206.         GetCurrentPath();
  207.  
  208.         CreateDrgAgent();
  209.  
  210.         hwndFrame = CreateWindow( hab );
  211.  
  212.         if( hwndFrame )
  213.             while( WinGetMsg( hab, &qmsg, NULLHANDLE, 0, 0 ) )
  214.                 WinDispatchMsg( hab, &qmsg );
  215.     }
  216.     else if( hab )
  217.         Msg( "WinCreateMsgQueue RC(%X)", HABERR( hab ) );
  218.  
  219.     if( hwndFrame )
  220.         WinDestroyWindow( hwndFrame );
  221.  
  222.     DestroyDrgAgent();
  223.  
  224.     if( hmq )
  225.         WinDestroyMsgQueue( hmq );
  226.  
  227.     if( hab )
  228.         WinTerminate( hab );
  229.  
  230. #ifdef __DEBUG_ALLOC__
  231.     _dump_allocated( -1 );
  232. #endif
  233.  
  234.     return 0;
  235. }
  236.  
  237. /**********************************************************************/
  238. /*------------------------- GetCurrentPath ---------------------------*/
  239. /*                                                                    */
  240. /*  STORE THE CURRENT DRIVE/DIRECTORY.                                */
  241. /*                                                                    */
  242. /*  PARMS: nothing                                                    */
  243. /*                                                                    */
  244. /*  NOTES: This stores the current drive:\directory\  that is used    */
  245. /*         to create temporary files in.                              */
  246. /*                                                                    */
  247. /*  RETURNS: nothing                                                  */
  248. /*                                                                    */
  249. /*--------------------------------------------------------------------*/
  250. /**********************************************************************/
  251. void GetCurrentPath()
  252. {
  253.     PBYTE  pbCurrent = szCurrentPath;
  254.     INT    cbBuf = sizeof szCurrentPath, cbUsed;
  255.     ULONG  ulDrive, ulCurrDriveNo, ulDriveMap, cbPath;
  256.     APIRET rc;
  257.  
  258.     // Fill in the drive letter, colon, and backslash
  259.  
  260.     rc = DosQueryCurrentDisk( &ulCurrDriveNo, &ulDriveMap );
  261.  
  262.     if( !rc )                                // Use 'current' drive
  263.     {
  264.         *(pbCurrent++) = (BYTE) (ulCurrDriveNo + ('A' - 1));
  265.         *(pbCurrent++) = ':';
  266.         *(pbCurrent++) = '\\';
  267.     }
  268.     else
  269.     {                                        // API failed - use drive C:
  270.         strcpy( pbCurrent, "C:\\" );
  271.         pbCurrent += 3;                      // Incr our place in the buffer
  272.     }
  273.  
  274.     cbUsed = pbCurrent - szCurrentPath;      // How many bytes left?
  275.  
  276.     // Fill in the current directory
  277.  
  278.     ulDrive = *szCurrentPath - 'A' + 1;      // Get drive number from letter
  279.     cbPath = cbBuf - cbUsed;                 // How many bytes left?
  280.  
  281.     rc = DosQueryCurrentDir( ulDrive, pbCurrent, &cbPath );
  282.                                              // Get 'current' directory
  283.     if( szCurrentPath[ strlen( szCurrentPath ) - 1 ] != '\\' )
  284.         strcat( szCurrentPath, "\\" );       // Add trailing backslash
  285. }
  286.  
  287. /**********************************************************************/
  288. /*-------------------------- CreateWindow ----------------------------*/
  289. /*                                                                    */
  290. /*  CREATE THE APPLICATION WINDOW                                     */
  291. /*                                                                    */
  292. /*  PARMS: anchor block handle                                        */
  293. /*                                                                    */
  294. /*  NOTES:                                                            */
  295. /*                                                                    */
  296. /*  RETURNS: frame window handle                                      */
  297. /*                                                                    */
  298. /*--------------------------------------------------------------------*/
  299. /**********************************************************************/
  300. HWND CreateWindow( HAB hab )
  301. {
  302.     FRAMECDATA fcdata;
  303.     HWND       hwndFrame = NULLHANDLE, hwndCnr = NULLHANDLE;
  304.  
  305.     memset( &fcdata, 0, sizeof fcdata );
  306.     fcdata.cb            = sizeof( FRAMECDATA );
  307.     fcdata.idResources   = ID_RESOURCES;
  308.     fcdata.flCreateFlags = FRAME_FLAGS;
  309.  
  310.     // Create the container as the client window of the frame. There is no
  311.     // need for a normal client window. Because of this we must subclass the
  312.     // frame window so we can catch the messages that the container sends to
  313.     // its owner.
  314.  
  315.     hwndFrame = WinCreateWindow( HWND_DESKTOP, WC_FRAME, NULL,
  316.                                  FS_NOBYTEALIGN | WS_CLIPCHILDREN,
  317.                                  0, 0, 0, 0, NULLHANDLE, HWND_TOP,
  318.                                  1, &fcdata, NULL );
  319.     if( hwndFrame )
  320.     {
  321.         pfnwpFrame = WinSubclassWindow( hwndFrame, wpFrame );
  322.  
  323.         if( pfnwpFrame )
  324.         {
  325.             hwndCnr = WinCreateWindow( hwndFrame, WC_CONTAINER, NULL,
  326.                                        WS_VISIBLE | CONTAINER_STYLES,
  327.                                        0, 0, 0, 0, hwndFrame, HWND_TOP,
  328.                                        FID_CLIENT, NULL, NULL );
  329.             if( hwndCnr )
  330.                 WinSetWindowText( hwndFrame, PROGRAM_TITLE );
  331.             else
  332.             {
  333.                 WinDestroyWindow( hwndFrame );
  334.                 hwndFrame = NULLHANDLE;
  335.                 Msg( "WinCreateWindow(hwndCnr) RC(%X)", HABERR( hab ) );
  336.             }
  337.         }
  338.         else
  339.         {
  340.             WinDestroyWindow( hwndFrame );
  341.             hwndFrame = NULLHANDLE;
  342.             Msg( "WinSubclassWindow RC(%X)", HABERR( hab ) );
  343.         }
  344.     }
  345.     else
  346.         Msg( "WinCreateWindow(hwndFrame) RC(%X)", HABERR( hab ) );
  347.  
  348.     if( hwndFrame )
  349.     {
  350.         // Create the shared memory heap
  351.  
  352.         HeapCreate();
  353.  
  354.         // Create the shared memory segment that contains information shared
  355.         // by the PM window and the WPS object.
  356.  
  357.         CommdataCreate();
  358.  
  359.         // Start a time that is used to indicate if there is a problem with the
  360.         // creation of the WPS object's object window. In order to communicate
  361.         // with the WPS object, the WPS object must have created an object
  362.         // window and placed its handle in the shared segment. If we time out
  363.         // this program will be ended after an error message is displayed.
  364.  
  365.         if( hObjAgent )
  366.             WinStartTimer( hab, hwndFrame, 1, TIMER_INTERVAL );
  367.     }
  368.  
  369.     if( hwndFrame )
  370.     {
  371.         CNRINFO cnri;
  372.  
  373.         // Set container into Icon view and give it a read-only title
  374.  
  375.         cnri.cb           = sizeof( CNRINFO );
  376.         cnri.pszCnrTitle  = szCnrTitle;
  377.         cnri.flWindowAttr = CV_ICON | CA_CONTAINERTITLE | CA_TITLESEPARATOR |
  378.                             CA_TITLEREADONLY;
  379.  
  380.         if( !WinSendMsg( hwndCnr, CM_SETCNRINFO, MPFROMP( &cnri ),
  381.                          MPFROMLONG( CMA_FLWINDOWATTR | CMA_CNRTITLE ) ) )
  382.         {
  383.             WinDestroyWindow( hwndFrame );
  384.             hwndFrame = NULLHANDLE;
  385.             Msg( "CM_SETCNRINFO RC(%X)", HABERR( hab ) );
  386.         }
  387.     }
  388.  
  389.     if( hwndFrame )
  390.     {
  391.         SizeAndShowWindow( hwndFrame );
  392.         if( !InsertRecords( hwndCnr ) )
  393.         {
  394.             WinDestroyWindow( hwndFrame );
  395.             hwndFrame = NULLHANDLE;
  396.         }
  397.     }
  398.  
  399.     return hwndFrame;
  400. }
  401.  
  402. /**********************************************************************/
  403. /*-------------------------- InsertRecords ---------------------------*/
  404. /*                                                                    */
  405. /*  INSERT RECORDS INTO A CONTAINER                                   */
  406. /*                                                                    */
  407. /*  PARMS: container window handle                                    */
  408. /*                                                                    */
  409. /*  NOTES: We insert a record for every .ico file we find in the      */
  410. /*         current directory. If we find no .ico files we put up an   */
  411. /*         error message.                                             */
  412. /*                                                                    */
  413. /*  RETURNS: TRUE if successful, FALSE if not                         */
  414. /*                                                                    */
  415. /*--------------------------------------------------------------------*/
  416. /**********************************************************************/
  417. BOOL InsertRecords( HWND hwndCnr )
  418. {
  419.     BOOL         fSuccess = TRUE;
  420.     RECORDINSERT ri;
  421.     PCNRREC      pCnrRec;
  422.     FILEFINDBUF3 ffb;
  423.     HDIR         hdir = HDIR_SYSTEM;
  424.     ULONG        cFiles = 1, cIconsFound = 0;
  425.     APIRET       rc;
  426.  
  427.     memset( &ri, 0, sizeof( RECORDINSERT ) );
  428.     ri.cb                 = sizeof( RECORDINSERT );
  429.     ri.pRecordOrder       = (PRECORDCORE) CMA_END;
  430.     ri.pRecordParent      = (PRECORDCORE) NULL;
  431.     ri.zOrder             = (USHORT) CMA_TOP;
  432.     ri.cRecordsInsert     = 1;
  433.     ri.fInvalidateRecord  = TRUE;
  434.  
  435.     rc = DosFindFirst( "*.ico", &hdir, FILE_NORMAL,
  436.                        &ffb, sizeof ffb, &cFiles, FIL_STANDARD );
  437.     while( !rc )
  438.     {
  439.         cIconsFound++;
  440.  
  441.         pCnrRec = WinSendMsg( hwndCnr, CM_ALLOCRECORD, MPFROMLONG(EXTRA_BYTES),
  442.                               MPFROMLONG( 1 ) );
  443.  
  444.         if( pCnrRec )
  445.         {
  446.             strcpy( pCnrRec->szFileName, ffb.achName );
  447.  
  448.             pCnrRec->mrc.pszIcon  = (PSZ) &pCnrRec->szFileName;
  449.             pCnrRec->mrc.hptrIcon = WinLoadFileIcon( ffb.achName, FALSE );
  450.             if( !pCnrRec->mrc.hptrIcon )
  451.                 pCnrRec->mrc.hptrIcon =
  452.                     WinQuerySysPointer( HWND_DESKTOP, SPTR_QUESICON, FALSE );
  453.  
  454.             if( !WinSendMsg( hwndCnr, CM_INSERTRECORD, MPFROMP( pCnrRec ),
  455.                              MPFROMP( &ri ) ) )
  456.             {
  457.                 fSuccess = FALSE;
  458.                 Msg( "InsertRecords CM_INSERTRECORD RC(%X)", HWNDERR(hwndCnr) );
  459.             }
  460.         }
  461.  
  462.         rc = DosFindNext( hdir, &ffb, sizeof ffb, &cFiles );
  463.     }
  464.  
  465.     if( !cIconsFound )
  466.     {
  467.         Msg( "No icons found in this directory. Please copy at least one "
  468.              "icon into this directory or start this program from a "
  469.              "directory with at least one icon in it" );
  470.  
  471.         fSuccess = FALSE;
  472.     }
  473.  
  474.     return fSuccess;
  475. }
  476.  
  477. /**********************************************************************/
  478. /*------------------------ SizeAndShowWindow -------------------------*/
  479. /*                                                                    */
  480. /*  SIZE AND SHOW THE FRAME WINDOW.                                   */
  481. /*                                                                    */
  482. /*  PARMS: frame window handle                                        */
  483. /*                                                                    */
  484. /*  NOTES:                                                            */
  485. /*                                                                    */
  486. /*  RETURNS: nothing                                                  */
  487. /*                                                                    */
  488. /*--------------------------------------------------------------------*/
  489. /**********************************************************************/
  490. void SizeAndShowWindow( HWND hwndFrame )
  491. {
  492.     LONG cxDesktop = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
  493.     LONG cyDesktop = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
  494.  
  495.     // Place the window in the center of the screen and make it the size
  496.     // of half the width and half the height.
  497.  
  498.     WinSetWindowPos( hwndFrame, HWND_TOP,
  499.                      cxDesktop / 4, cyDesktop / 4,
  500.                      cxDesktop / 2, cyDesktop / 2,
  501.                      SWP_MOVE | SWP_SIZE | SWP_SHOW | SWP_ACTIVATE |
  502.                      SWP_ZORDER );
  503.  
  504.     // The container was set up as the client window of the frame. We
  505.     // need to set focus to it - otherwise it will not accept keystrokes
  506.     // right away.
  507.  
  508.     WinSetFocus( HWND_DESKTOP, WinWindowFromID( hwndFrame, FID_CLIENT ) );
  509. }
  510.  
  511. /**********************************************************************/
  512. /*----------------------------- wpFrame ------------------------------*/
  513. /*                                                                    */
  514. /*  SUBCLASSED FRAME WINDOW PROCEDURE.                                */
  515. /*                                                                    */
  516. /*  PARMS: normal winproc parms                                       */
  517. /*                                                                    */
  518. /*  NOTES:                                                            */
  519. /*                                                                    */
  520. /*  RETURNS: MRESULT value                                            */
  521. /*                                                                    */
  522. /*--------------------------------------------------------------------*/
  523. /**********************************************************************/
  524. MRESULT EXPENTRY wpFrame( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  525. {
  526.     switch( msg )
  527.     {
  528.         case WM_TIMER:
  529.  
  530.             // If we time out, that means something went wrong on the WPS
  531.             // object's end.
  532.  
  533.             if( pCommData && pCommData->hwndComm )
  534.             {
  535.                 WinStopTimer( hab, hwnd, 1 );
  536.                 WinPostMsg( pCommData->hwndComm, UM_SET_HOBJECT,
  537.                             MPFROMLONG( hObjAgent ), NULL );
  538.             }
  539.             else if( ++cTimerIters > MAX_TIMER_ITERS )
  540.             {
  541.                 WinStopTimer( hab, hwnd, 1 );
  542.                 Msg( "Drag Agent not running! We can't do anything" );
  543.             }
  544.  
  545.             return 0;
  546.  
  547.         case UM_DRAGINFO:
  548.         {
  549.             POBJECTDATA pObjData = (POBJECTDATA) mp1;
  550.  
  551.             // The WPS object has passed us information about an object that
  552.             // was dropped on us. Display the information then free the shared
  553.             // memory object.
  554.  
  555.             if( pObjData->fPgmObject )
  556.                 Msg( "*** DROPPED ITEM INFO ***\n"
  557.                      "Object Name: %s\n"
  558.                      "Object Class Name: %s\n"
  559.                      "Exe Name: %s\n"
  560.                      "Program Parameters: %s\n"
  561.                      "Program's Startup Directory: %s\n",
  562.                      pObjData->szTitle,
  563.                      pObjData->szClassName,
  564.                      pObjData->szExeName,
  565.                      pObjData->szParms,
  566.                      pObjData->szStartupDir );
  567.             else
  568.                 Msg( "*** DROPPED ITEM INFO ***\n"
  569.                      "Object Name: %s\n"
  570.                      "Object Class Name: %s\n",
  571.                      pObjData->szTitle,
  572.                      pObjData->szClassName );
  573.             HeapFree( pObjData );
  574.             break;
  575.         }
  576.  
  577.         case UM_DROP:
  578.         {
  579.             char szIconInfo[ CCHMAXPATH ];
  580.  
  581.             // The WPS object has passed us the HOBJECT of a WPS object that
  582.             // one of our icons was dropped on. Set that object's icon to the
  583.             // icon that was dropped on it.
  584.  
  585.             sprintf( szIconInfo, "%s%s%s", "ICONFILE=", szCurrentPath,
  586.                      pCnrRecBeingDragged->szFileName );
  587.  
  588.             if( !WinSetObjectData( (HOBJECT) mp1, szIconInfo ) )
  589.                 Msg( "WinsSetObjectData failed!" );
  590.  
  591.             return 0;
  592.         }
  593.  
  594.         case WM_DESTROY:
  595.  
  596.             // Free all container resources associated with any records that
  597.             // were inserted (note that the container is actually the client
  598.             // window.
  599.  
  600.             WinSendDlgItemMsg( hwnd, FID_CLIENT, CM_REMOVERECORD, NULL,
  601.                                MPFROM2SHORT( 0, CMA_FREE ) );
  602.  
  603.             // Destroy the shared memory that holds the data common to both
  604.             // the PM window and the WPS object.
  605.  
  606.             CommdataDestroy();
  607.  
  608.             // Free the shared memory heap.
  609.  
  610.             HeapDestroy();
  611.             break;
  612.  
  613.         case WM_COMMAND:
  614.  
  615.             // Process the accelerator key
  616.  
  617.             if( SHORT1FROMMP( mp1 ) == IDM_EXIT )
  618.             {
  619.                 WinPostMsg( hwnd, WM_SYSCOMMAND, MPFROMSHORT( SC_CLOSE ),
  620.                             MPFROM2SHORT( CMDSRC_ACCELERATOR, FALSE ) );
  621.                 return 0;
  622.             }
  623.  
  624.             break;
  625.  
  626.         case WM_CONTROL:
  627.             if( SHORT1FROMMP( mp1 ) == FID_CLIENT )
  628.                 switch( SHORT2FROMMP( mp1 ) )
  629.                 {
  630.                     case CN_INITDRAG:
  631.                         dragInit( hwnd, (PCNRDRAGINIT) mp2 );
  632.                         return 0;
  633.  
  634.                     case CN_DRAGOVER:
  635.                         return dragOver( hwnd, (PCNRDRAGINFO) mp2 );
  636.  
  637.                     case CN_DROP:
  638.                         dragDrop( hwnd, (PCNRDRAGINFO) mp2 );
  639.                         return 0;
  640.                 }
  641.  
  642.             break;
  643.     }
  644.  
  645.     return pfnwpFrame( hwnd, msg, mp1, mp2 );
  646. }
  647.  
  648. /**********************************************************************/
  649. /*-------------------------- CreateDrgAgent --------------------------*/
  650. /*                                                                    */
  651. /*  CREATE THE WPS AGENT OBJECT                                       */
  652. /*                                                                    */
  653. /*  PARMS: nothing                                                    */
  654. /*                                                                    */
  655. /*  NOTES:                                                            */
  656. /*                                                                    */
  657. /*  RETURNS: nothing                                                  */
  658. /*                                                                    */
  659. /*--------------------------------------------------------------------*/
  660. /**********************************************************************/
  661. void CreateDrgAgent()
  662. {
  663.     char szObjectId[ 100 ];
  664.  
  665.     if( !WinQueryObject( AGENT_OBJECT_ID ) )
  666.     {
  667.         char    szFullDllPath[ CCHMAXPATH ];
  668.         PCH     pchBackslash;
  669.         PTIB    ptib;
  670.         PPIB    ppib;
  671.  
  672.         // Load the WPS object's dll from the same directory that the .exe
  673.         // was loaded from. This allows you to start drgpmwps from a directory
  674.         // with a lot of icons and not worry about where the WPS object's dll
  675.         // is.
  676.  
  677.         DosGetInfoBlocks( &ptib, &ppib );
  678.         DosQueryModuleName( ppib->pib_hmte, sizeof szFullDllPath,szFullDllPath);
  679.         pchBackslash = strrchr( szFullDllPath, '\\' );
  680.         if( pchBackslash )
  681.         {
  682.             strcpy( pchBackslash + 1, AGENT_DLL_NAME );
  683.             strcat( szFullDllPath, ".dll" );
  684.         }
  685.         else
  686.             strcpy( szFullDllPath, AGENT_DLL_NAME );
  687.  
  688.         // If the WinRegisterObjectClass fails, chances are you moved the DLL
  689.         // to the LIBPATH because you didn't trust my program <g>. In that
  690.         // case we use the non-fully-qualified dllname and try again.
  691.  
  692.         if( !WinRegisterObjectClass( AGENT_CLASS_NAME, szFullDllPath ) )
  693.             if( !WinRegisterObjectClass( AGENT_CLASS_NAME, AGENT_DLL_NAME ) )
  694.                 Msg( "\nWinRegisterObjectClasst rc(%X)", HABERR( hab ) );
  695.  
  696.         // Create the WPS object with the given object id. If this were a real
  697.         // program you would want to also create it with NOTVISIBLE=YES so the
  698.         // user doesn't know about the agent.
  699.  
  700.         sprintf( szObjectId, "OBJECTID=%s", AGENT_OBJECT_ID );
  701.  
  702.         hObjAgent = WinCreateObject( AGENT_CLASS_NAME, " Drag Agent",
  703.                                      szObjectId, "<WP_DESKTOP>",
  704.                                      CO_FAILIFEXISTS );
  705.         if( !hObjAgent )
  706.             Msg( "\nWinCreateObject rc(%X)", HABERR( hab ) );
  707.     }
  708. }
  709.  
  710. /**********************************************************************/
  711. /*------------------------- DestroyDrgAgent --------------------------*/
  712. /*                                                                    */
  713. /*  DESTROY THE WPS AGENT OBJECT AND DEREGISTER ITS CLASS             */
  714. /*                                                                    */
  715. /*  PARMS: nothing                                                    */
  716. /*                                                                    */
  717. /*  NOTES:                                                            */
  718. /*                                                                    */
  719. /*  RETURNS: nothing                                                  */
  720. /*                                                                    */
  721. /*--------------------------------------------------------------------*/
  722. /**********************************************************************/
  723. void DestroyDrgAgent()
  724. {
  725.     HOBJECT hObj = WinQueryObject( AGENT_OBJECT_ID );
  726.  
  727.     if( hObj )
  728.         WinDestroyObject( hObj );
  729.     else
  730.         Msg( "Coudn't locate agent object to destroy it" );
  731.  
  732.     WinDeregisterObjectClass( AGENT_CLASS_NAME );
  733. }
  734.  
  735. /**********************************************************************/
  736. /*------------------------------- Msg --------------------------------*/
  737. /*                                                                    */
  738. /*  DISPLAY A MESSAGE TO THE USER.                                    */
  739. /*                                                                    */
  740. /*  PARMS: a message in printf format with its parms                  */
  741. /*                                                                    */
  742. /*  NOTES:                                                            */
  743. /*                                                                    */
  744. /*  RETURNS: nothing                                                  */
  745. /*                                                                    */
  746. /*--------------------------------------------------------------------*/
  747. /**********************************************************************/
  748. void Msg( PSZ szFormat,... )
  749. {
  750.     PSZ     szMsg;
  751.     va_list argptr;
  752.  
  753.     szMsg = (PSZ) malloc( MESSAGE_SIZE );
  754.     if( szMsg )
  755.     {
  756.         va_start( argptr, szFormat );
  757.         vsprintf( szMsg, szFormat, argptr );
  758.         va_end( argptr );
  759.  
  760.         szMsg[ MESSAGE_SIZE - 1 ] = 0;
  761.  
  762.         WinAlarm( HWND_DESKTOP, WA_WARNING );
  763.         WinMessageBox(  HWND_DESKTOP, HWND_DESKTOP, szMsg,
  764.                         "PM/WPS Drag/Drop Sample Program", 1,
  765.                         MB_OK | MB_MOVEABLE );
  766.         free( szMsg );
  767.     }
  768.     else
  769.     {
  770.         DosBeep( 1000, 1000 );
  771.         return;
  772.     }
  773. }
  774.  
  775. /*************************************************************************
  776.  *                     E N D     O F     S O U R C E                     *
  777.  *************************************************************************/
  778.