home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / drgfil.zip / drgfiles.c next >
C/C++ Source or Header  |  1993-07-31  |  31KB  |  683 lines

  1. /*********************************************************************
  2.  *                                                                   *
  3.  * MODULE NAME :  drgfiles.c             AUTHOR:  Rick Fishman       *
  4.  * DATE WRITTEN:  07-28-93                                           *
  5.  *                                                                   *
  6.  * HOW TO RUN THIS PROGRAM:                                          *
  7.  *                                                                   *
  8.  *  Just enter DRGFILES on the command line.                         *
  9.  *                                                                   *
  10.  * MODULE DESCRIPTION:                                               *
  11.  *                                                                   *
  12.  *  Root module for DRGFILES.EXE, a program that demonstrates using  *
  13.  *  Drag/Drop on OS/2 2.x with the DrgDragFiles and                  *
  14.  *  DrgAcceptDroppedFiles API's. These API's are provided by OS/2 as *
  15.  *  an attempt to make Drag/Drop easier than using a full-blown      *
  16.  *  Drag/Drop implementation using lower-level D/D API's. The        *
  17.  *  limitations that are imposed on users of these higher-level API's*
  18.  *  are as follows:                                                  *
  19.  *                                                                   *
  20.  *  - only filenames can be dragged/dropped                          *
  21.  *  - source printing of dragged files is not supported              *
  22.  *     (the printer will try and print your file but it doesn't let  *
  23.  *      your program print it)                                       *
  24.  *  - source shredding of dragged files is not supported             *
  25.  *     (the shredder will try and delete your file but it doesn't let*
  26.  *      your program participate so your program doesn't know it has *
  27.  *      been deleted if the shredder was successful)                 *
  28.  *  - only 1 image is allowed under the mouse pointer during the drag*
  29.  *  - there are currenty many bugs in this API pair that cause       *
  30.  *      PMDRAG.DLL to trap (as of 2.1GA in September 1993) if more   *
  31.  *      than 1 file is dropped or rendering is done. Therefore I've  *
  32.  *      only been able to get it to work reliably by dragging one    *
  33.  *      file at a time and not rendering.                            *
  34.  *                                                                   *
  35.  *  This program has 2 global variables that control its operation.  *
  36.  *  They are both set to values that allow the program to run without*
  37.  *  trapping. You may want to try and change the values when a new   *
  38.  *  version of the operating system is released since the bugs may   *
  39.  *  be fixed in new releases.                                        *
  40.  *                                                                   *
  41.  *     fRender: This is set to FALSE, meaning the DM_RENDERFILE and  *
  42.  *              DM_FILERENDERED messages are not used so that the    *
  43.  *              DrgDragFiles API takes care of all copying and       *
  44.  *              moving of files. If this is set to TRUE, currently   *
  45.  *              you will get PMDRAG.DLL traps when the file(s) is    *
  46.  *              dropped because of an Operating System bug.          *
  47.  *                                                                   *
  48.  *     flSelType: This is set to CCS_SINGLESEL, putting the container*
  49.  *                in single-select mode which only allows the user to*
  50.  *                drag one file. If you set this to CCS_EXTENDSEL,   *
  51.  *                you will be able to drag more than one file but    *
  52.  *                dropping the files will cause a trap in PMDRAG.DLL *
  53.  *                after the first file is dropped and before the     *
  54.  *                second one is dropped. Again, this is an Operating *
  55.  *                System bug.                                        *
  56.  *                                                                   *
  57.  *  If your application can live with these limitations, this is an  *
  58.  *  easy way to implement direct manipulation.                       *
  59.  *                                                                   *
  60.  *  I also have samples for full-blown Drag/Drop implementations.    *
  61.  *  Some of them are:                                                *
  62.  *                                                                   *
  63.  *   DRGDROP.ZIP  - Does Drag/Drop but no rendering. Monitors the    *
  64.  *                  Drag/Drop process by displaying the D/D          *
  65.  *                  structures while the drag is going on.           *
  66.  *   DRGRENDR.ZIP - Does Drag/Drop with rendering. All rendering     *
  67.  *                  takes place on the main thread.                  *
  68.  *   DRGTHRND.ZIP - Does Drag/Drop with rendering. All rendering     *
  69.  *                  takes place on secondary threads.                *
  70.  *                                                                   *
  71.  * OTHER MODULES:                                                    *
  72.  *                                                                   *
  73.  *  srcwin.c - contains code for the source window.                  *
  74.  *  trgwin.c - contains code for the target window.                  *
  75.  *                                                                   *
  76.  * NOTES:                                                            *
  77.  *                                                                   *
  78.  *  I hope this code proves useful for other PM programmers. The     *
  79.  *  more of us the better!                                           *
  80.  *                                                                   *
  81.  * HISTORY:                                                          *
  82.  *                                                                   *
  83.  *  07-28-93 - Program coding started.                               *
  84.  *                                                                   *
  85.  *  Rick Fishman                                                     *
  86.  *  Code Blazers, Inc.                                               *
  87.  *  4113 Apricot                                                     *
  88.  *  Irvine, CA. 92720                                                *
  89.  *  CIS ID: 72251,750                                                *
  90.  *                                                                   *
  91.  *********************************************************************/
  92.  
  93. #pragma strings(readonly)   // used for debug version of memory mgmt routines
  94.  
  95. /*********************************************************************/
  96. /*------- Include relevant sections of the OS/2 header files --------*/
  97. /*********************************************************************/
  98.  
  99. #define  INCL_DOSERRORS
  100. #define  INCL_DOSFILEMGR
  101. #define  INCL_DOSMISC
  102. #define  INCL_WINERRORS
  103. #define  INCL_WINFRAMEMGR
  104. #define  INCL_WINPOINTERS
  105. #define  INCL_WINSTDCNR
  106. #define  INCL_WINSYS
  107. #define  INCL_WINWINDOWMGR
  108.  
  109. #define  GLOBALS_DEFINED    // extern globals instantiated
  110.  
  111. /**********************************************************************/
  112. /*----------------------------- INCLUDES -----------------------------*/
  113. /**********************************************************************/
  114.  
  115. #include <os2.h>
  116. #include <stdarg.h>
  117. #include <stdio.h>
  118. #include <stdlib.h>
  119. #include <string.h>
  120. #include "drgfiles.h"
  121.  
  122. /*********************************************************************/
  123. /*------------------- APPLICATION DEFINITIONS -----------------------*/
  124. /*********************************************************************/
  125.  
  126. #define MESSAGE_SIZE        1024
  127.  
  128. /**********************************************************************/
  129. /*---------------------------- STRUCTURES ----------------------------*/
  130. /**********************************************************************/
  131.  
  132. typedef struct _OPCONVERT                       // Used to convert an operation
  133. {                                               //   type to text that can be
  134.   int i;                                        //   displayed
  135.   PSZ sz;
  136.  
  137. } OPCONVERT, *POPCONVERT;
  138.  
  139. /**********************************************************************/
  140. /*----------------------- FUNCTION PROTOTYPES ------------------------*/
  141. /**********************************************************************/
  142.  
  143. int  main              ( void );
  144. BOOL ProgInit          ( void );
  145. void GetCurrentPath    ( void );
  146. BOOL GetTempDir        ( void );
  147. BOOL ValidateDirectory ( PSZ pszDirectory );
  148. BOOL CreateWindows     ( HAB hab );
  149. BOOL SizeAndShowWindows( HAB hab );
  150. void ProgTerm          ( HAB hab );
  151. void DeleteTempFiles   ( void );
  152.  
  153. /**********************************************************************/
  154. /*------------------------ GLOBAL VARIABLES --------------------------*/
  155. /**********************************************************************/
  156.  
  157. OPCONVERT ocOperation[] =
  158. {
  159.     { DFF_MOVE,    "Move" },
  160.     { DFF_COPY,    "Copy" },
  161.     { DFF_DELETE,  "Delete" }
  162. };
  163.  
  164. #define OP_TYPES   (sizeof( ocOperation ) / sizeof( OPCONVERT ))
  165.  
  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.     HAB  hab;
  183.     HMQ  hmq = NULLHANDLE;
  184.     QMSG qmsg;
  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.         if( ProgInit() )
  207.             if( CreateWindows( hab ) )
  208.                 while( WinGetMsg( hab, &qmsg, NULLHANDLE, 0, 0 ) )
  209.                     WinDispatchMsg( hab, &qmsg );
  210.     }
  211.     else if( hab )
  212.         Msg( "WinCreateMsgQueue RC(%X)", HABERR( hab ) );
  213.  
  214.     ProgTerm( hab );
  215.  
  216.     if( hmq )
  217.         WinDestroyMsgQueue( hmq );
  218.  
  219.     if( hab )
  220.         WinTerminate( hab );
  221.  
  222. #ifdef __DEBUG_ALLOC__
  223.     _dump_allocated( -1 );
  224. #endif
  225.  
  226.     return 0;
  227. }
  228.  
  229. /**********************************************************************/
  230. /*---------------------------- ProgInit ------------------------------*/
  231. /*                                                                    */
  232. /*  PERFORM PROGRAM INITIALIZATION.                                   */
  233. /*                                                                    */
  234. /*  PARMS: anchor block handle                                        */
  235. /*                                                                    */
  236. /*  NOTES:                                                            */
  237. /*                                                                    */
  238. /*  RETURNS: TRUE or FALSE if successful or not                       */
  239. /*                                                                    */
  240. /*--------------------------------------------------------------------*/
  241. /**********************************************************************/
  242. BOOL ProgInit()
  243. {
  244.     GetCurrentPath();
  245.  
  246.     return GetTempDir();
  247. }
  248.  
  249. /**********************************************************************/
  250. /*------------------------- GetCurrentPath ---------------------------*/
  251. /*                                                                    */
  252. /*  STORE THE CURRENT DRIVE/DIRECTORY.                                */
  253. /*                                                                    */
  254. /*  PARMS: nothing                                                    */
  255. /*                                                                    */
  256. /*  NOTES: This stores the current drive:\directory\  that is used    */
  257. /*         to create draggable files in.                              */
  258. /*                                                                    */
  259. /*  RETURNS: nothing                                                  */
  260. /*                                                                    */
  261. /*--------------------------------------------------------------------*/
  262. /**********************************************************************/
  263. void GetCurrentPath()
  264. {
  265.     PBYTE  pbCurrent = szCurrentPath;
  266.     INT    cbBuf = sizeof szCurrentPath, cbUsed;
  267.     ULONG  ulDrive, ulCurrDriveNo, ulDriveMap, cbPath;
  268.     APIRET rc;
  269.  
  270.     // Fill in the drive letter, colon, and backslash
  271.  
  272.     rc = DosQueryCurrentDisk( &ulCurrDriveNo, &ulDriveMap );
  273.  
  274.     if( !rc )                                // Use 'current' drive
  275.     {
  276.         *(pbCurrent++) = (BYTE) (ulCurrDriveNo + ('A' - 1));
  277.         *(pbCurrent++) = ':';
  278.         *(pbCurrent++) = '\\';
  279.     }
  280.     else
  281.     {                                        // API failed - use drive C:
  282.         strcpy( pbCurrent, "C:\\" );
  283.         pbCurrent += 3;                      // Incr our place in the buffer
  284.     }
  285.  
  286.     cbUsed = pbCurrent - szCurrentPath;      // How many bytes left?
  287.  
  288.     // Fill in the current directory
  289.  
  290.     ulDrive = *szCurrentPath - 'A' + 1;      // Get drive number from letter
  291.     cbPath = cbBuf - cbUsed;                 // How many bytes left?
  292.  
  293.     rc = DosQueryCurrentDir( ulDrive, pbCurrent, &cbPath );
  294.                                              // Get 'current' directory
  295.     if( szCurrentPath[ strlen( szCurrentPath ) - 1 ] != '\\' )
  296.         strcat( szCurrentPath, "\\" );       // Add trailing backslash
  297. }
  298.  
  299. /**********************************************************************/
  300. /*--------------------------- GetTempDir -----------------------------*/
  301. /*                                                                    */
  302. /*  FIND THE PROPER DIRECTORY TO USE AS A PLACE TO STORE TEMP FILES.  */
  303. /*                                                                    */
  304. /*  PARMS: nothing                                                    */
  305. /*                                                                    */
  306. /*  NOTES: This temporary directory will be used to store dropped     */
  307. /*         files in. We will use the directory pointed to by the      */
  308. /*         'TEMP' environment variable first. If not found, we will   */
  309. /*         try the 'TMP' environment variable. If neither is found    */
  310. /*         we will create a 'TEMP' subdirectory off the current       */
  311. /*         directory and use that one.                                */
  312. /*                                                                    */
  313. /*  RETURNS: TRUE or FALSE if successful or not                       */
  314. /*                                                                    */
  315. /*--------------------------------------------------------------------*/
  316. /**********************************************************************/
  317. BOOL GetTempDir( void )
  318. {
  319.     PSZ    pszDir = NULL;
  320.     APIRET rc;
  321.     BOOL   fSuccess = FALSE;
  322.  
  323.     rc = DosScanEnv( "TEMP", (const char **) &pszDir );
  324.  
  325.     if( !rc && ValidateDirectory( pszDir ) )
  326.         fSuccess = TRUE;
  327.     else
  328.     {
  329.         rc = DosScanEnv( "TMP", (const char **) &pszDir );
  330.  
  331.         if( !rc && ValidateDirectory( pszDir ) )
  332.             fSuccess = TRUE;
  333.     }
  334.  
  335.     if( fSuccess )
  336.         strncpy( szTempDir, pszDir, sizeof szTempDir );
  337.     else
  338.     {
  339.         strcpy( szTempDir, szCurrentPath );
  340.         strcat( szTempDir, "TEMP" );
  341.         rc = DosCreateDir( szTempDir, NULL );
  342.         if( rc && rc != ERROR_ACCESS_DENIED ) // ACCESS_DENIED if already exists
  343.             Msg( "Got a %u return code trying to create the %s directory to "
  344.                  "store dropped files in", rc, szTempDir );
  345.         else
  346.             fSuccess = TRUE;
  347.     }
  348.  
  349.     return fSuccess;
  350. }
  351.  
  352. /*********************************************************************/
  353. /*------------------------ ValidateDirectory ------------------------*/
  354. /*                                                                   */
  355. /*  CHECK ON THE VALIDITY OF A DIRECTORY NAME.                       */
  356. /*                                                                   */
  357. /*  PARMS: pointer to directory name                                 */
  358. /*                                                                   */
  359. /*  NOTES: This function uses DosFindFirst as a mechanism for        */
  360. /*         validating a directory name. It is assumed that if        */
  361. /*         DosFindFirst() gets an error that directory name cannot   */
  362. /*         be used.                                                  */
  363. /*                                                                   */
  364. /*  RETURNS: TRUE or FALSE if a valid directory or not.              */
  365. /*                                                                   */
  366. /*-------------------------------------------------------------------*/
  367. /*********************************************************************/
  368. BOOL ValidateDirectory( PSZ pszDirectory )
  369. {
  370.     BOOL         fValid = TRUE;
  371.     HDIR         hdir = HDIR_SYSTEM;
  372.     FILEFINDBUF3 ffb;
  373.     ULONG        ulFiles = 1;
  374.     APIRET       rc;
  375.     CHAR         abBuf[ CCHMAXPATH ];
  376.  
  377.     // We check for the validity of the directory by essentially doing a
  378.     // 'dir d:\directory\*.*'
  379.  
  380.     (void) strcpy( abBuf, pszDirectory );
  381.  
  382.     if( abBuf[ strlen( abBuf ) - 1 ] != '\\' )
  383.         strcat( abBuf, "\\" );
  384.  
  385.     (void) strcat( abBuf, "*.*" );
  386.  
  387.     rc = DosFindFirst( abBuf, &hdir, FILE_NORMAL | FILE_DIRECTORY, &ffb,
  388.                        sizeof( ffb ), &ulFiles, FIL_STANDARD );
  389.  
  390.     if( hdir )
  391.         DosFindClose( hdir );
  392.  
  393.     if( rc )
  394.         fValid = FALSE;
  395.  
  396.     return fValid;
  397. }
  398.  
  399.  
  400. /**********************************************************************/
  401. /*------------------------- CreateWindows ----------------------------*/
  402. /*                                                                    */
  403. /*  CREATE ALL APPLICATION WINDOWS                                    */
  404. /*                                                                    */
  405. /*  PARMS: anchor block handle                                        */
  406. /*                                                                    */
  407. /*  NOTES:                                                            */
  408. /*                                                                    */
  409. /*  RETURNS: TRUE or FALSE if successful or not                       */
  410. /*                                                                    */
  411. /*--------------------------------------------------------------------*/
  412. /**********************************************************************/
  413. BOOL CreateWindows( HAB hab )
  414. {
  415.     BOOL fSuccess = TRUE;
  416.  
  417.     // Load the icon that will be used for the container records.
  418.  
  419.     hptrCnrRec = WinLoadPointer( HWND_DESKTOP, 0, ID_RESOURCES );
  420.     if( !hptrCnrRec )
  421.     {
  422.         Msg( "WinLoadPointer RC(%X)", HABERR( hab ) );
  423.         fSuccess = FALSE;
  424.     }
  425.  
  426.     // Create 2 windows. One will act as the 'drag' window, the other as the
  427.     // 'drop' window. The user will then be able to drag the icons from the
  428.     // 'drag' window to the 'drop' window.
  429.  
  430.     if( fSuccess )
  431.     {
  432.         hwndDrag = srcCreateWindow( hab );
  433.         if( hwndDrag )
  434.         {
  435.             hwndDrop = targCreateWindow( hab );
  436.             if( !hwndDrop )
  437.                 fSuccess = FALSE;
  438.         }
  439.         else
  440.             fSuccess = FALSE;
  441.     }
  442.  
  443.     if( fSuccess )
  444.         fSuccess = SizeAndShowWindows( hab );
  445.  
  446.     if( !fSuccess )
  447.     {
  448.         if( hwndDrag )
  449.         {
  450.             WinDestroyWindow( hwndDrag );
  451.             hwndDrag = NULLHANDLE;
  452.         }
  453.  
  454.         if( hwndDrop )
  455.         {
  456.             WinDestroyWindow( hwndDrop );
  457.             hwndDrop = NULLHANDLE;
  458.         }
  459.     }
  460.  
  461.     return fSuccess;
  462. }
  463.  
  464. /**********************************************************************/
  465. /*----------------------- SizeAndShowWindows -------------------------*/
  466. /*                                                                    */
  467. /*  SIZE AND SHOW ALL WINDOWS AT THE SAME TIME.                       */
  468. /*                                                                    */
  469. /*  PARMS: anchor block handle                                        */
  470. /*                                                                    */
  471. /*  NOTES:                                                            */
  472. /*                                                                    */
  473. /*  RETURNS: TRUE or FALSE if successful or not                       */
  474. /*                                                                    */
  475. /*--------------------------------------------------------------------*/
  476. /**********************************************************************/
  477. BOOL SizeAndShowWindows( HAB hab )
  478. {
  479.     SWP  aswp[ 2 ];
  480.     BOOL fSuccess;
  481.     LONG cxDesktop = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
  482.     LONG cyDesktop = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
  483.  
  484.     memset( &aswp, 0, sizeof aswp );
  485.  
  486.     // Set the windows up so they are on the left and right halves of the
  487.     // display. The debug window will be on the top third of the display and
  488.     // the container window will be on the bottom third of the display.
  489.  
  490.     // Left-hand 'drag' container window
  491.     aswp[ 0 ].hwnd = hwndDrag;
  492.     aswp[ 0 ].x    = 0;
  493.     aswp[ 0 ].y    = 0;
  494.     aswp[ 0 ].cx   = cxDesktop / 2;
  495.     aswp[ 0 ].cy   = cyDesktop / 3;
  496.     aswp[ 0 ].hwndInsertBehind = HWND_TOP;
  497.     aswp[ 0 ].fl   = SWP_MOVE | SWP_SIZE | SWP_SHOW | SWP_ACTIVATE | SWP_ZORDER;
  498.  
  499.     // Right-hand 'drop' container window
  500.     aswp[ 1 ].hwnd = hwndDrop;
  501.     aswp[ 1 ].x    = cxDesktop / 2;
  502.     aswp[ 1 ].y    = 0;
  503.     aswp[ 1 ].cx   = cxDesktop / 2;
  504.     aswp[ 1 ].cy   = cyDesktop / 3;
  505.     aswp[ 1 ].fl   = SWP_MOVE | SWP_SIZE | SWP_SHOW;
  506.  
  507.     fSuccess = WinSetMultWindowPos( hab, aswp, 2 );
  508.     if( fSuccess )
  509.     {
  510.         // The container was set up as the client window of the frame. We
  511.         // need to set focus to it - otherwise it will not accept keystrokes
  512.         // right away.
  513.  
  514.         WinSetFocus( HWND_DESKTOP,
  515.                      WinWindowFromID( hwndDrag, FID_CLIENT ) );
  516.     }
  517.  
  518.     return fSuccess;
  519. }
  520.  
  521. /**********************************************************************/
  522. /*---------------------------- ProgTerm ------------------------------*/
  523. /*                                                                    */
  524. /*  PERFORM TERMINATION PROCESSING FOR THIS PROGRAM.                  */
  525. /*                                                                    */
  526. /*  PARMS: nothing                                                    */
  527. /*                                                                    */
  528. /*  NOTES:                                                            */
  529. /*                                                                    */
  530. /*  RETURNS: nothing                                                  */
  531. /*                                                                    */
  532. /*--------------------------------------------------------------------*/
  533. /**********************************************************************/
  534. void ProgTerm()
  535. {
  536.     if( hwndDrag )
  537.         WinDestroyWindow( hwndDrag );
  538.  
  539.     if( hwndDrop )
  540.         WinDestroyWindow( hwndDrop );
  541.  
  542.     if( hptrCnrRec )
  543.         WinDestroyPointer( hptrCnrRec );
  544.  
  545.     DeleteTempFiles();
  546. }
  547.  
  548. /**********************************************************************/
  549. /*------------------------- DeleteTempFiles --------------------------*/
  550. /*                                                                    */
  551. /*  DELETE THE TEMPORARY FILES USED BY THIS PROGRAM.                  */
  552. /*                                                                    */
  553. /*  PARMS: nothing                                                    */
  554. /*                                                                    */
  555. /*  NOTES: These temporary files are created in the current directory */
  556. /*         and inserted into the 'drag' container. They are zero-     */
  557. /*         length files.                                              */
  558. /*                                                                    */
  559. /*  RETURNS: nothing                                                  */
  560. /*                                                                    */
  561. /*--------------------------------------------------------------------*/
  562. /**********************************************************************/
  563. void DeleteTempFiles()
  564. {
  565.     FILEFINDBUF3 ffb;
  566.     HDIR         hdir = HDIR_SYSTEM;
  567.     ULONG        cFiles = 1;
  568.     char         szTempFileSpec[ CCHMAXPATH ];
  569.     APIRET       rc;
  570.  
  571.     strcpy( szTempFileSpec, BASE_TEMPFILE_NAME );
  572.     strcat( szTempFileSpec, ".*" );
  573.  
  574.     rc = DosFindFirst( szTempFileSpec, &hdir, FILE_NORMAL,
  575.                        &ffb, sizeof ffb, &cFiles, FIL_STANDARD );
  576.     while( !rc )
  577.     {
  578.         DosDelete( ffb.achName );
  579.         rc = DosFindNext( hdir, &ffb, sizeof ffb, &cFiles );
  580.     }
  581. }
  582.  
  583. /**********************************************************************/
  584. /*---------------------------- DragError -----------------------------*/
  585. /*                                                                    */
  586. /*  PROCESS A DM_DRAGERROR MESSAGE.                                   */
  587. /*                                                                    */
  588. /*  PARMS: error code,                                                */
  589. /*         operation that error occured on,                           */
  590. /*         HSTR that contains the dragged filename                    */
  591. /*                                                                    */
  592. /*  NOTES: PM sends this to a drag/drop window if a file operation    */
  593. /*         failed.                                                    */
  594. /*                                                                    */
  595. /*  RETURNS: reply                                                    */
  596. /*                                                                    */
  597. /*--------------------------------------------------------------------*/
  598. /**********************************************************************/
  599. MRESULT DragError( USHORT usError, USHORT usOperation, HSTR hstrFile )
  600. {
  601.     ULONG  cbMsg;
  602.     APIRET rc;
  603.     char   szFileName[ CCHMAXPATH ];
  604.     char   szCPError[ 200 ];
  605.     char   szOp[ 25 ];
  606.     int    i;
  607.  
  608.     // This error is generated if the file already exists in the current
  609.     // directory. It shouldn't be generated on a copy but it is - this is
  610.     // yet another bug in the DrgDragFiles protocol.
  611.  
  612.     if( usError == ERROR_ACCESS_DENIED || usError == ERROR_SHARING_VIOLATION )
  613.         return (MRESULT) DME_REPLACE;
  614.  
  615.     *szOp = 0;
  616.  
  617.     memset( szCPError, 0, sizeof szCPError );
  618.  
  619.     rc = DosGetMessage( NULL, 0, szCPError, sizeof szCPError, usError,
  620.                         "OSO001.MSG", &cbMsg );
  621.     if( rc == ERROR_MR_MID_NOT_FOUND )
  622.         DosGetMessage( NULL, 0, szCPError, sizeof szCPError, usError,
  623.                        "OSO001H.MSG", &cbMsg );
  624.  
  625.     DrgQueryStrName( hstrFile, sizeof szFileName, szFileName );
  626.  
  627.     for( i = 0; i < OP_TYPES; i++ )
  628.         if( ocOperation[ i ].i == usOperation )
  629.         {
  630.             strcpy( szOp, ocOperation[ i ].sz );
  631.             break;
  632.         }
  633.  
  634.     Msg( "Drag of %s failed on a '%s' operation with a return code of %u. This "
  635.          "return code means: %s", szFileName, szOp, usError, szCPError );
  636.  
  637.     return (MRESULT) DME_IGNOREABORT;
  638. }
  639.  
  640. /**********************************************************************/
  641. /*------------------------------- Msg --------------------------------*/
  642. /*                                                                    */
  643. /*  DISPLAY A MESSAGE TO THE USER.                                    */
  644. /*                                                                    */
  645. /*  PARMS: a message in printf format with its parms                  */
  646. /*                                                                    */
  647. /*  NOTES:                                                            */
  648. /*                                                                    */
  649. /*  RETURNS: nothing                                                  */
  650. /*                                                                    */
  651. /*--------------------------------------------------------------------*/
  652. /**********************************************************************/
  653. void Msg( PSZ szFormat,... )
  654. {
  655.     PSZ     szMsg;
  656.     va_list argptr;
  657.  
  658.     szMsg = (PSZ) malloc( MESSAGE_SIZE );
  659.     if( szMsg )
  660.     {
  661.         va_start( argptr, szFormat );
  662.         vsprintf( szMsg, szFormat, argptr );
  663.         va_end( argptr );
  664.  
  665.         szMsg[ MESSAGE_SIZE - 1 ] = 0;
  666.  
  667.         WinAlarm( HWND_DESKTOP, WA_WARNING );
  668.         WinMessageBox(  HWND_DESKTOP, HWND_DESKTOP, szMsg,
  669.                         "Container Drag/Drop Sample Program", 1,
  670.                         MB_OK | MB_MOVEABLE );
  671.         free( szMsg );
  672.     }
  673.     else
  674.     {
  675.         DosBeep( 1000, 1000 );
  676.         return;
  677.     }
  678. }
  679.  
  680. /*************************************************************************
  681.  *                     E N D     O F     S O U R C E                     *
  682.  *************************************************************************/
  683.