home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / drgthr.zip / drgthrnd.c < prev    next >
C/C++ Source or Header  |  1993-07-28  |  42KB  |  964 lines

  1. /*********************************************************************
  2.  *                                                                   *
  3.  * MODULE NAME :  drgthrnd.c             AUTHOR:  Rick Fishman       *
  4.  * DATE WRITTEN:  07-15-93                                           *
  5.  *                                                                   *
  6.  * HOW TO RUN THIS PROGRAM:                                          *
  7.  *                                                                   *
  8.  *  Just enter DRGTHRND on the command line.                         *
  9.  *                                                                   *
  10.  * MODULE DESCRIPTION:                                               *
  11.  *                                                                   *
  12.  *  Root module for DRGRENDR.EXE, a program that demonstrates using  *
  13.  *  source rendering on the drop during a Drag/Drop operation. This  *
  14.  *  program creates 2 windows, a 'drag' window and a 'drop' window.  *
  15.  *                                                                   *
  16.  *  Each window is actually a frame window with a container control  *
  17.  *  as its client window.                                            *
  18.  *                                                                   *
  19.  *  The drag window contains icons that each represent a table in    *
  20.  *  a pseudo-database (actually ASCII files that simulate a          *
  21.  *  database).                                                       *
  22.  *                                                                   *
  23.  *  The drop window starts out empty and allows you to drag an icon  *
  24.  *  from the 'drag' window to it. If you do, rendering is done       *
  25.  *  during the drop that writes the rows in the selected table to a  *
  26.  *  temporary file and adds an icon representing that temporary file *
  27.  *  to the drop window. You can then double-click on the icon in the *
  28.  *  drop window to display the contents of the temporary file.       *
  29.  *                                                                   *
  30.  *  The source window (the drag window) is the one that does the     *
  31.  *  actual rendering. By rendering, I mean it 'renders' the contents *
  32.  *  of a table in the database to a file.                            *
  33.  *                                                                   *
  34.  *  The target window (the drop window) is the one that adds the icon*
  35.  *  to its container when the source window indicates that the       *
  36.  *  rendering is complete.                                           *
  37.  *                                                                   *
  38.  *  All rendering is done in separate threads so as to not impact    *
  39.  *  the user interface while rendering is taking place. For a simpler*
  40.  *  program that doesn't use multiple threads, try DRGRENDR.EXE      *
  41.  *                                                                   *
  42.  *  When the drag window is created, it goes thru all database files *
  43.  *  and inserts an icon into the container for each 'table' that it  *
  44.  *  finds.                                                           *
  45.  *                                                                   *
  46.  *  To get an idea of how these 'database' files are structured,     *
  47.  *  have a look at the dbase_?.db files provided with this sample.   *
  48.  *                                                                   *
  49.  * OTHER MODULES:                                                    *
  50.  *                                                                   *
  51.  *  dbaccess.c - contains the code used to access the 'database'.    *
  52.  *  drag.c     - contains all drag/drop processing code.             *
  53.  *  srcrendr.c - contains all source rendering code.                 *
  54.  *  trgrendr.c - contains all target rendering code.                 *
  55.  *                                                                   *
  56.  * NOTES:                                                            *
  57.  *                                                                   *
  58.  *  This program uses multiple threads after the drop to do its      *
  59.  *  rendering. To see a simpler program that does everything on the  *
  60.  *  main thread, I've got a sample program called DRGRENDR.EXE. If   *
  61.  *  you can find that, you might be able to understand it better if  *
  62.  *  this sample gets too complex.                                    *
  63.  *                                                                   *
  64.  *  I hope this code proves useful for other PM programmers. The     *
  65.  *  more of us the better!                                           *
  66.  *                                                                   *
  67.  * HISTORY:                                                          *
  68.  *                                                                   *
  69.  *  07-15-93 - Program coding started.                               *
  70.  *                                                                   *
  71.  *  Rick Fishman                                                     *
  72.  *  Code Blazers, Inc.                                               *
  73.  *  4113 Apricot                                                     *
  74.  *  Irvine, CA. 92720                                                *
  75.  *  CIS ID: 72251,750                                                *
  76.  *                                                                   *
  77.  *********************************************************************/
  78.  
  79. #pragma strings(readonly)   // used for debug version of memory mgmt routines
  80.  
  81. /*********************************************************************/
  82. /*------- Include relevant sections of the OS/2 header files --------*/
  83. /*********************************************************************/
  84.  
  85. #define  INCL_WINERRORS
  86. #define  INCL_WINDIALOGS
  87. #define  INCL_WINFRAMEMGR
  88. #define  INCL_WINLISTBOXES
  89. #define  INCL_WINPOINTERS
  90. #define  INCL_WINSTDCNR
  91. #define  INCL_WINSTDDRAG
  92. #define  INCL_WINSYS
  93. #define  INCL_WINWINDOWMGR
  94.  
  95. #define  GLOBALS_DEFINED    // extern globals instantiated
  96.  
  97. /**********************************************************************/
  98. /*----------------------------- INCLUDES -----------------------------*/
  99. /**********************************************************************/
  100.  
  101. #include <os2.h>
  102. #include <stdarg.h>
  103. #include <stdio.h>
  104. #include <stdlib.h>
  105. #include <string.h>
  106. #include "drgthrnd.h"
  107.  
  108. /*********************************************************************/
  109. /*------------------- APPLICATION DEFINITIONS -----------------------*/
  110. /*********************************************************************/
  111.  
  112. #define PROGRAM_TITLE               "Drag/Drop Rendering Sample"
  113.  
  114. #define MESSAGE_SIZE                1024
  115.  
  116. #define TITLE_FOR_DROPCNR_FRAME     "'Drop' Container"
  117. #define TITLE_FOR_DRAGCNR_FRAME     "'Drag' Container"
  118.  
  119. #define FRAME_FLAGS                 (FCF_TASKLIST   | FCF_TITLEBAR | \
  120.                                      FCF_SYSMENU    | FCF_MINMAX   | \
  121.                                      FCF_SIZEBORDER | FCF_ICON     | \
  122.                                      FCF_ACCELTABLE)
  123.  
  124. #define CONTAINER_STYLES            (CCS_EXTENDSEL | CCS_MINIRECORDCORE | \
  125.                                      CCS_AUTOPOSITION)
  126.  
  127. /**********************************************************************/
  128. /*---------------------------- STRUCTURES ----------------------------*/
  129. /**********************************************************************/
  130.  
  131. typedef struct _LBFRAMEDATA         // LISTBOX FRAME'S WINDOW WORD DATA
  132. {
  133.     HWND    hwndCnr;                // Container window handle
  134.     PCNRREC pCnrRec;                // Record whose table is being displayed in
  135. } LBFRAMEDATA, *PLBFRAMEDATA;       //    the listbox
  136.  
  137. /**********************************************************************/
  138. /*----------------------- FUNCTION PROTOTYPES ------------------------*/
  139. /**********************************************************************/
  140.  
  141. int  main             ( void );
  142. void GetCurrentPath   ( void );
  143. BOOL CreateWindows    ( HAB hab );
  144. HWND CreateWindow     ( HAB hab, PFRAMECDATA pfcdata, ULONG idWindow,
  145.                         PSZ pszWindow, PSZ pszCnrTitle );
  146. BOOL InsertRecords    ( HWND hwndCnr );
  147. void DisplayTable     ( HWND hwndCnr, PCNRREC pCnrRec );
  148. void UserWantsToClose ( HWND hwndFrame );
  149. void DestroyWindows   ( void );
  150. void DeleteTempFiles  ( void );
  151.  
  152. FNWP wpFrame, wpLBFrame;
  153.  
  154. /**********************************************************************/
  155. /*------------------------ GLOBAL VARIABLES --------------------------*/
  156. /**********************************************************************/
  157.  
  158. PFNWP pfnwpFrame, pfnwpLBFrame;
  159.  
  160. HWND hwndDrag,           // Window that is the source of the drag
  161.      hwndDrop;           // Window that is the target of the drop
  162.  
  163. char szDragCnrTitle[] = "Take a 'table' and drop it on the other window";
  164. char szDropCnrTitle[] = "Go ahead. Drag one of those tables on me!";
  165.  
  166. /**********************************************************************/
  167. /*------------------------------ MAIN --------------------------------*/
  168. /*                                                                    */
  169. /*  PROGRAM ENTRYPOINT                                                */
  170. /*                                                                    */
  171. /*  PARMS: nothing                                                    */
  172. /*                                                                    */
  173. /*  NOTES:                                                            */
  174. /*                                                                    */
  175. /*  RETURNS: return code                                              */
  176. /*                                                                    */
  177. /*--------------------------------------------------------------------*/
  178. /**********************************************************************/
  179. int main( void )
  180. {
  181.     HAB  hab;
  182.     HMQ  hmq = NULLHANDLE;
  183.     QMSG qmsg;
  184.  
  185.     // This macro is defined for the debug version of the C Set/2 Memory
  186.     // Management routines. Since the debug version writes to stderr, we
  187.     // send all stderr output to a debuginfo file.
  188.  
  189. #ifdef __DEBUG_ALLOC__
  190.     freopen( DEBUG_FILENAME, "w", stderr );
  191. #endif
  192.  
  193.     GetCurrentPath();
  194.  
  195.     hab = WinInitialize( 0 );
  196.  
  197.     if( hab )
  198.         hmq = WinCreateMsgQueue( hab, 0 );
  199.     else
  200.     {
  201.         DosBeep( 1000, 100 );
  202.         fprintf( stderr, "WinInitialize failed!" );
  203.     }
  204.  
  205.     if( hmq )
  206.     {
  207.         if( CreateWindows( hab ) )
  208.         {
  209.             while( WinGetMsg( hab, &qmsg, NULLHANDLE, 0, 0 ) )
  210.                 WinDispatchMsg( hab, &qmsg );
  211.  
  212.             DestroyWindows();
  213.         }
  214.     }
  215.     else if( hab )
  216.         Msg( "WinCreateMsgQueue RC(%X)", HABERR( hab ) );
  217.  
  218.     if( hmq )
  219.         WinDestroyMsgQueue( hmq );
  220.  
  221.     if( hab )
  222.         WinTerminate( hab );
  223.  
  224.     DeleteTempFiles();
  225.  
  226. #ifdef __DEBUG_ALLOC__
  227.     _dump_allocated( -1 );
  228. #endif
  229.  
  230.     return 0;
  231. }
  232.  
  233. /**********************************************************************/
  234. /*------------------------- GetCurrentPath ---------------------------*/
  235. /*                                                                    */
  236. /*  STORE THE CURRENT DRIVE/DIRECTORY.                                */
  237. /*                                                                    */
  238. /*  PARMS: nothing                                                    */
  239. /*                                                                    */
  240. /*  NOTES: This stores the current drive:\directory\  that is used    */
  241. /*         to create temporary files in.                              */
  242. /*                                                                    */
  243. /*  RETURNS: nothing                                                  */
  244. /*                                                                    */
  245. /*--------------------------------------------------------------------*/
  246. /**********************************************************************/
  247. void GetCurrentPath()
  248. {
  249.     PBYTE  pbCurrent = szCurrentPath;
  250.     INT    cbBuf = sizeof szCurrentPath, cbUsed;
  251.     ULONG  ulDrive, ulCurrDriveNo, ulDriveMap, cbPath;
  252.     APIRET rc;
  253.  
  254.     // Fill in the drive letter, colon, and backslash
  255.  
  256.     rc = DosQueryCurrentDisk( &ulCurrDriveNo, &ulDriveMap );
  257.  
  258.     if( !rc )                                // Use 'current' drive
  259.     {
  260.         *(pbCurrent++) = (BYTE) (ulCurrDriveNo + ('A' - 1));
  261.         *(pbCurrent++) = ':';
  262.         *(pbCurrent++) = '\\';
  263.     }
  264.     else
  265.     {                                        // API failed - use drive C:
  266.         strcpy( pbCurrent, "C:\\" );
  267.         pbCurrent += 3;                      // Incr our place in the buffer
  268.     }
  269.  
  270.     cbUsed = pbCurrent - szCurrentPath;      // How many bytes left?
  271.  
  272.     // Fill in the current directory
  273.  
  274.     ulDrive = *szCurrentPath - 'A' + 1;      // Get drive number from letter
  275.     cbPath = cbBuf - cbUsed;                 // How many bytes left?
  276.  
  277.     rc = DosQueryCurrentDir( ulDrive, pbCurrent, &cbPath );
  278.                                              // Get 'current' directory
  279.     if( szCurrentPath[ strlen( szCurrentPath ) - 1 ] != '\\' )
  280.         strcat( szCurrentPath, "\\" );       // Add trailing backslash
  281. }
  282.  
  283. /**********************************************************************/
  284. /*------------------------- CreateWindows ----------------------------*/
  285. /*                                                                    */
  286. /*  CREATE BOTH THE SOURCE AND TARGET WINDOWS.                        */
  287. /*                                                                    */
  288. /*  PARMS: anchor block handle                                        */
  289. /*                                                                    */
  290. /*  NOTES:                                                            */
  291. /*                                                                    */
  292. /*  RETURNS: TRUE or FALSE if successful or not                       */
  293. /*                                                                    */
  294. /*--------------------------------------------------------------------*/
  295. /**********************************************************************/
  296. BOOL CreateWindows( HAB hab )
  297. {
  298.     BOOL       fSuccess = TRUE;
  299.     FRAMECDATA fcdata;
  300.  
  301.     memset( &fcdata, 0, sizeof fcdata );
  302.     fcdata.cb            = sizeof( FRAMECDATA );
  303.     fcdata.flCreateFlags = FRAME_FLAGS;
  304.  
  305.     // Create 2 windows. One will act as the 'drag' window, the other as the
  306.     // 'drop' window. The user will then be able to drag the windows from the
  307.     // 'drag' window to the 'drop' window.
  308.  
  309.     hwndDrag = CreateWindow( hab, &fcdata, ID_DRAGCNR, TITLE_FOR_DRAGCNR_FRAME,
  310.                              szDragCnrTitle );
  311.     if( hwndDrag )
  312.     {
  313.         hwndDrop = CreateWindow( hab, &fcdata, ID_DROPCNR,
  314.                                  TITLE_FOR_DROPCNR_FRAME, szDropCnrTitle );
  315.         if( !hwndDrop )
  316.             fSuccess = FALSE;
  317.     }
  318.     else
  319.         fSuccess = FALSE;
  320.  
  321.     // Load the icons that will be used for the container records.
  322.  
  323.     hptrDragMe = WinLoadPointer( HWND_DESKTOP, 0, ID_DRAGCNR );
  324.     hptrOpenMe = WinLoadPointer( HWND_DESKTOP, 0, ID_DROPCNR );
  325.  
  326.     // Insert the records into the 'drag' container.
  327.  
  328.     if( fSuccess )
  329.         fSuccess = InsertRecords( WinWindowFromID( hwndDrag, FID_CLIENT ) );
  330.  
  331.     if( fSuccess )
  332.     {
  333.         LONG cxDesktop = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
  334.         LONG cyDesktop = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
  335.  
  336.         // Set the windows up so they split the bottom half of the display. The
  337.         // left window will be the 'drag' window, the right one will be the
  338.         // 'drop' window.
  339.  
  340.         if( !WinSetWindowPos( hwndDrag, HWND_TOP, 0, 0,
  341.                               cxDesktop /2, cyDesktop / 2,
  342.                   SWP_SIZE | SWP_ZORDER | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE ) )
  343.         {
  344.             fSuccess = FALSE;
  345.             Msg( "WinSetWindowPos( hwndDrag ) RC(%X)", HABERR( hab ) );
  346.         }
  347.  
  348.         if( fSuccess &&
  349.             !WinSetWindowPos( hwndDrop, HWND_TOP, cxDesktop / 2, 0,
  350.                               cxDesktop /2, cyDesktop / 2,
  351.                               SWP_SIZE | SWP_ZORDER | SWP_MOVE | SWP_SHOW ) )
  352.         {
  353.             fSuccess = FALSE;
  354.             Msg( "WinSetWindowPos( hwndDrop ) RC(%X)", HABERR( hab ) );
  355.         }
  356.  
  357.         if( fSuccess )
  358.         {
  359.             // The container was set up as the client window of the frame. We
  360.             // need to set focus to it - otherwise it will not accept keystrokes
  361.             // right away.
  362.  
  363.             WinSetFocus( HWND_DESKTOP,
  364.                          WinWindowFromID( hwndDrag, FID_CLIENT ) );
  365.         }
  366.     }
  367.  
  368.     if( !fSuccess )
  369.     {
  370.         if( hwndDrag )
  371.         {
  372.             WinDestroyWindow( hwndDrag );
  373.             hwndDrag = NULLHANDLE;
  374.         }
  375.  
  376.         if( hwndDrop )
  377.         {
  378.             WinDestroyWindow( hwndDrop );
  379.             hwndDrop = NULLHANDLE;
  380.         }
  381.     }
  382.  
  383.     return fSuccess;
  384. }
  385.  
  386. /**********************************************************************/
  387. /*-------------------------- CreateWindow ----------------------------*/
  388. /*                                                                    */
  389. /*  CREATE A FRAME WINDOW WITH A CONTAINER AS ITS CLIENT WINDOW       */
  390. /*                                                                    */
  391. /*  PARMS: anchor block handle,                                       */
  392. /*         pointer to frame control data,                             */
  393. /*         id of the frame window,                                    */
  394. /*         window title of the frame window,                          */
  395. /*         container title                                            */
  396. /*                                                                    */
  397. /*  NOTES:                                                            */
  398. /*                                                                    */
  399. /*  RETURNS: frame window handle or NULLHANDLE if not successful      */
  400. /*                                                                    */
  401. /*--------------------------------------------------------------------*/
  402. /**********************************************************************/
  403. HWND CreateWindow( HAB hab, PFRAMECDATA pfcdata, ULONG idWindow, PSZ pszWindow,
  404.                    PSZ pszCnrTitle )
  405. {
  406.     HWND hwndFrame = NULLHANDLE, hwndCnr = NULLHANDLE;
  407.  
  408.     pfcdata->idResources = idWindow;  // Let the frame know its icon id
  409.  
  410.     // Create the container as the client window of the frame. There is no
  411.     // need for a normal client window. Because of this we must subclass the
  412.     // frame window so we can catch the messages that the container sends to
  413.     // its owner.
  414.  
  415.     hwndFrame = WinCreateWindow( HWND_DESKTOP, WC_FRAME, NULL,
  416.                                  FS_NOBYTEALIGN | WS_CLIPCHILDREN,
  417.                                  0, 0, 0, 0, NULLHANDLE, HWND_TOP,
  418.                                  idWindow, pfcdata, NULL );
  419.     if( hwndFrame )
  420.     {
  421.         pfnwpFrame = WinSubclassWindow( hwndFrame, wpFrame );
  422.  
  423.         if( pfnwpFrame )
  424.         {
  425.             hwndCnr = WinCreateWindow( hwndFrame, WC_CONTAINER, NULL,
  426.                                        WS_VISIBLE | CONTAINER_STYLES,
  427.                                        0, 0, 0, 0, hwndFrame, HWND_TOP,
  428.                                        FID_CLIENT, NULL, NULL );
  429.             if( hwndCnr )
  430.                 WinSetWindowText( hwndFrame, pszWindow );
  431.             else
  432.             {
  433.                 WinDestroyWindow( hwndFrame );
  434.                 hwndFrame = NULLHANDLE;
  435.                 Msg( "WinCreateWindow(hwndCnr,%s) RC(%X)", pszWindow,
  436.                      HABERR( hab ) );
  437.             }
  438.         }
  439.         else
  440.         {
  441.             WinDestroyWindow( hwndFrame );
  442.             hwndFrame = NULLHANDLE;
  443.             Msg( "WinSubclassWindow(%s) RC(%X)", pszWindow, HABERR( hab ) );
  444.         }
  445.     }
  446.     else
  447.         Msg( "WinCreateWindow(%s) RC(%X)", pszWindow, HABERR( hab ) );
  448.  
  449.     if( hwndFrame )
  450.     {
  451.         CNRINFO cnri;
  452.  
  453.         // Set container into Icon view and give it a read-only title
  454.  
  455.         cnri.cb           = sizeof( CNRINFO );
  456.         cnri.pszCnrTitle  = pszCnrTitle;
  457.         cnri.flWindowAttr = CV_ICON | CA_CONTAINERTITLE | CA_TITLESEPARATOR |
  458.                             CA_TITLEREADONLY;
  459.  
  460.         if( !WinSendMsg( hwndCnr, CM_SETCNRINFO, MPFROMP( &cnri ),
  461.                          MPFROMLONG( CMA_FLWINDOWATTR | CMA_CNRTITLE ) ) )
  462.         {
  463.             WinDestroyWindow( hwndFrame );
  464.             hwndFrame = NULLHANDLE;
  465.             Msg( "CM_SETCNRINFO(%S) RC(%X)", pszWindow, HABERR( hab ) );
  466.         }
  467.     }
  468.  
  469.     if( hwndFrame )
  470.     {
  471.         PINSTANCE pi;
  472.  
  473.         // Allocate memory for the instance data and set it into the
  474.         // Frame window's QWL_USER window word.
  475.  
  476.         pi = (PINSTANCE) malloc( sizeof *pi );
  477.         if( pi )
  478.         {
  479.             memset( pi, 0, sizeof *pi );
  480.             WinSetWindowPtr( hwndFrame, QWL_USER, pi );
  481.         }
  482.         else
  483.         {
  484.             WinDestroyWindow( hwndFrame );
  485.             hwndFrame = NULLHANDLE;
  486.             Msg( "Out of memory in CreateWindow!" );
  487.         }
  488.     }
  489.  
  490.     return hwndFrame;
  491. }
  492.  
  493. /**********************************************************************/
  494. /*-------------------------- InsertRecords ---------------------------*/
  495. /*                                                                    */
  496. /*  INSERT RECORDS INTO A CONTAINER                                   */
  497. /*                                                                    */
  498. /*  PARMS: container window handle                                    */
  499. /*                                                                    */
  500. /*  NOTES: We use the enumeration functions in dbaccess.c to enumerate*/
  501. /*         all the tables in all the database files (dbase_?.db).     */
  502. /*         We insert a record into the container for each table that  */
  503. /*         we find.                                                   */
  504. /*                                                                    */
  505. /*  RETURNS: TRUE if successful, FALSE if not                         */
  506. /*                                                                    */
  507. /*--------------------------------------------------------------------*/
  508. /**********************************************************************/
  509. BOOL InsertRecords( HWND hwndCnr )
  510. {
  511.     HENUMTABLES  henum = dbBeginEnumTables();
  512.     BOOL         fSuccess = TRUE;
  513.     RECORDINSERT ri;
  514.     PCNRREC      pCnrRec;
  515.     char         szTableName[ CCHMAXPATH ];
  516.  
  517.     memset( &ri, 0, sizeof( RECORDINSERT ) );
  518.     ri.cb                 = sizeof( RECORDINSERT );
  519.     ri.pRecordOrder       = (PRECORDCORE) CMA_END;
  520.     ri.pRecordParent      = (PRECORDCORE) NULL;
  521.     ri.zOrder             = (USHORT) CMA_TOP;
  522.     ri.cRecordsInsert     = 1;
  523.     ri.fInvalidateRecord  = FALSE;
  524.  
  525.     if( henum )
  526.     {
  527.         while( fSuccess )
  528.         {
  529.             if( dbGetNextTable( henum, szTableName, sizeof szTableName ) )
  530.             {
  531.                 pCnrRec = WinSendMsg( hwndCnr, CM_ALLOCRECORD,
  532.                                       MPFROMLONG( EXTRA_BYTES ),
  533.                                       MPFROMLONG( 1 ) );
  534.  
  535.                 if( pCnrRec )
  536.                 {
  537.                     strcpy( pCnrRec->szTableName, szTableName );
  538.  
  539.                     pCnrRec->flAttr       = RECATTR_DRAGGABLE;
  540.                     pCnrRec->mrc.pszIcon  = (PSZ) &pCnrRec->szTableName;
  541.                     pCnrRec->mrc.hptrIcon = hptrDragMe;
  542.  
  543.                     if( !WinSendMsg( hwndCnr, CM_INSERTRECORD,
  544.                                      MPFROMP( pCnrRec ), MPFROMP( &ri ) ) )
  545.                         Msg( "InsertRecords CM_INSERTRECORD RC(%X)",
  546.                              HWNDERR( hwndCnr ) );
  547.                 }
  548.                 else
  549.                     Msg( "InsertRecords CM_ALLOCRECORD RC(%X)",
  550.                          HWNDERR( hwndCnr ) );
  551.             }
  552.             else
  553.                 break;
  554.         }
  555.  
  556.         dbEndEnumTables( henum );
  557.  
  558.         // By setting ri.fInvalidateRecord to FALSE, we are saying not to
  559.         // display the records yet. We display them only when they are all
  560.         // inserted by waiting until we get here and do an invalidate of all
  561.         // the records at once.
  562.  
  563.         if( !WinSendMsg( hwndCnr, CM_INVALIDATERECORD, NULL, NULL ) )
  564.             Msg( "InsertRecords CM_INVALIDATERECORD RC(%X)", HWNDERR(hwndCnr) );
  565.     }
  566.  
  567.     return fSuccess;
  568. }
  569.  
  570. /**********************************************************************/
  571. /*----------------------------- wpFrame ------------------------------*/
  572. /*                                                                    */
  573. /*  SUBCLASSED FRAME WINDOW PROCEDURE.                                */
  574. /*                                                                    */
  575. /*  PARMS: normal winproc parms                                       */
  576. /*                                                                    */
  577. /*  NOTES:                                                            */
  578. /*                                                                    */
  579. /*  RETURNS: MRESULT value                                            */
  580. /*                                                                    */
  581. /*--------------------------------------------------------------------*/
  582. /**********************************************************************/
  583. MRESULT EXPENTRY wpFrame( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  584. {
  585.     // Route all DM_ messages to drag.c
  586.  
  587.     if( msg >= WM_DRAGFIRST && msg <= WM_DRAGLAST )
  588.         return dragMessage( hwnd, msg, mp1 );
  589.  
  590.     switch( msg )
  591.     {
  592.         case WM_SYSCOMMAND:
  593.             if( SHORT1FROMMP( mp1 ) == SC_CLOSE )
  594.             {
  595.                 UserWantsToClose( hwnd );
  596.                 return 0;
  597.             }
  598.  
  599.             break;
  600.  
  601.         // From the F3 accelerator key
  602.         case WM_COMMAND:
  603.             if( SHORT1FROMMP( mp1 ) == IDM_EXIT )
  604.             {
  605.                 WinPostMsg( hwnd, WM_SYSCOMMAND, MPFROMSHORT( SC_CLOSE ),
  606.                             MPFROM2SHORT( CMDSRC_ACCELERATOR, FALSE ) );
  607.                 return 0;
  608.             }
  609.  
  610.             break;
  611.  
  612.         case WM_DESTROY:
  613.         {
  614.             PINSTANCE pi = INSTDATA( hwnd );
  615.  
  616.             // Free the window word memory
  617.  
  618.             if( pi )
  619.             {
  620.                 // Destroy the rendering window if it still exists
  621.  
  622.                 if( pi->hwndRender )
  623.                     WinDestroyWindow( pi->hwndRender );
  624.  
  625.                 free( pi );
  626.             }
  627.  
  628.             // Free all container resources associated with any records that
  629.             // were inserted (note that the container is actually the client
  630.             // window.
  631.  
  632.             WinSendDlgItemMsg( hwnd, FID_CLIENT, CM_REMOVERECORD, NULL,
  633.                                MPFROM2SHORT( 0, CMA_FREE ) );
  634.             break;
  635.         }
  636.  
  637.         case WM_CONTROL:
  638.             if( SHORT1FROMMP( mp1 ) == FID_CLIENT )
  639.                 switch( SHORT2FROMMP( mp1 ) )
  640.                 {
  641.                     case CN_ENTER:
  642.                     {
  643.                         PNOTIFYRECORDENTER pnre = (PNOTIFYRECORDENTER) mp2;
  644.                         if( pnre->pRecord &&
  645.                             (((PCNRREC)pnre->pRecord)->flAttr &
  646.                                                     RECATTR_OPENABLE ))
  647.                             DisplayTable( WinWindowFromID( hwnd, FID_CLIENT ),
  648.                                           (PCNRREC) pnre->pRecord );
  649.                         return 0;
  650.                     }
  651.  
  652.                     case CN_INITDRAG:
  653.                     {
  654.                         PCNRDRAGINIT pcdi = (PCNRDRAGINIT) mp2;
  655.                         if( pcdi->pRecord &&
  656.                             (((PCNRREC)pcdi->pRecord)->flAttr &
  657.                                                     RECATTR_DRAGGABLE ))
  658.                             dragInit( hwnd, pcdi );
  659.                         return 0;
  660.                     }
  661.  
  662.                     case CN_DRAGOVER:
  663.                         return dragOver( hwnd, (PCNRDRAGINFO) mp2 );
  664.  
  665.                     case CN_DROP:
  666.                         dragDrop( hwnd, (PCNRDRAGINFO) mp2 );
  667.                         return 0;
  668.                 }
  669.  
  670.             break;
  671.     }
  672.  
  673.     return pfnwpFrame( hwnd, msg, mp1, mp2 );
  674. }
  675.  
  676. /**********************************************************************/
  677. /*-------------------------- DisplayTable ----------------------------*/
  678. /*                                                                    */
  679. /*  DISPLAY A FILE (TABLE DATA) IN A LISTBOX WITHIN A FRAME WINDOW    */
  680. /*                                                                    */
  681. /*  PARMS: container window handle,                                   */
  682. /*         pointer to container record that has info for table        */
  683. /*                                                                    */
  684. /*  NOTES: We create a frame window with a listbox as its client      */
  685. /*         window and insert all records found in a file into the     */
  686. /*         listbox. This acts as a simple file viewer.                */
  687. /*                                                                    */
  688. /*         The files being displayed are files created during the     */
  689. /*         rendering operation that occurred as a result of dragging  */
  690. /*         an icon from the drag container to the drop container.     */
  691. /*                                                                    */
  692. /*  RETURNS: nothing                                                  */
  693. /*                                                                    */
  694. /*--------------------------------------------------------------------*/
  695. /**********************************************************************/
  696. void DisplayTable( HWND hwndCnr, PCNRREC pCnrRec )
  697. {
  698.     FRAMECDATA  fcdata;
  699.     HWND        hwndFrame, hwndLB;
  700.  
  701.     // If the container record that the user double-clicked on is currently
  702.     // being displayed, set focus to that window and exit.
  703.  
  704.     if( pCnrRec->hwndDisplay )
  705.     {
  706.         WinSetActiveWindow( HWND_DESKTOP, pCnrRec->hwndDisplay );
  707.         return;
  708.     }
  709.  
  710.     (void) memset( &fcdata, 0, sizeof( FRAMECDATA ) );
  711.     fcdata.cb            = sizeof( FRAMECDATA );
  712.     fcdata.flCreateFlags = FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER |
  713.                            FCF_MINMAX;
  714.  
  715.     hwndFrame = WinCreateWindow( HWND_DESKTOP, WC_FRAME, NULL,
  716.                                  WS_CLIPCHILDREN, 100, 100, 400, 200,
  717.                                  NULLHANDLE, HWND_TOP, 1, &fcdata, NULL );
  718.     if( hwndFrame )
  719.     {
  720.         WinSetWindowPtr( hwndFrame, QWL_USER, pCnrRec );
  721.  
  722.         hwndLB = WinCreateWindow( hwndFrame, WC_LISTBOX, NULL,
  723.                                   WS_VISIBLE | LS_HORZSCROLL | LS_NOADJUSTPOS,
  724.                                   0, 0, 0, 0, hwndFrame, HWND_TOP, FID_CLIENT,
  725.                                   NULL, NULL );
  726.         if( hwndLB )
  727.         {
  728.             pfnwpLBFrame = WinSubclassWindow( hwndFrame, wpLBFrame );
  729.  
  730.             if( pfnwpLBFrame )
  731.             {
  732.                 FILE *fh;
  733.                 PLBFRAMEDATA plbfd = (PLBFRAMEDATA) malloc( sizeof *plbfd );
  734.  
  735.                 if( plbfd )
  736.                 {
  737.                     plbfd->hwndCnr = hwndCnr;
  738.                     plbfd->pCnrRec = pCnrRec;
  739.                     WinSetWindowPtr( hwndFrame, QWL_USER, plbfd );
  740.  
  741.                     WinSendMsg( hwndFrame, WM_UPDATEFRAME, NULL, NULL );
  742.                     WinSetWindowText( hwndFrame, pCnrRec->szTableName );
  743.  
  744.                     fh = fopen( pCnrRec->szRenderedFileName, "r" );
  745.                     if( fh )
  746.                     {
  747.                         char szLine[ CCHMAXPATH ];
  748.  
  749.                         while( fgets( szLine, sizeof szLine, fh ) )
  750.                         {
  751.                             if( szLine[ strlen( szLine ) - 1 ] == '\n' )
  752.                                 szLine[ strlen( szLine ) - 1 ] = 0;
  753.  
  754.                             WinSendMsg( hwndLB, LM_INSERTITEM,
  755.                                         MPFROMSHORT(LIT_END), MPFROMP(szLine) );
  756.                         }
  757.  
  758.                         fclose( fh );
  759.                     }
  760.                     else
  761.                         WinSendMsg( hwndLB, LM_INSERTITEM, MPFROMSHORT(LIT_END),
  762.                                     "Could not open file!" );
  763.  
  764.                     pCnrRec->hwndDisplay = hwndFrame;
  765.  
  766.                     // Set on the In-Use emphasis to the container record that
  767.                     // represents the table so the user knows that a listbox
  768.                     // is on his desktop that represents the table.
  769.  
  770.                     WinSendMsg( hwndCnr, CM_SETRECORDEMPHASIS,
  771.                                 MPFROMP( pCnrRec ),
  772.                                 MPFROM2SHORT( TRUE, CRA_INUSE ) );
  773.  
  774.                     WinSetWindowPos( hwndFrame, HWND_TOP, 0, 0, 0, 0,
  775.                                      SWP_SHOW | SWP_ACTIVATE | SWP_ZORDER );
  776.                 }
  777.                 else
  778.                     WinDestroyWindow( hwndFrame );
  779.             }
  780.             else
  781.                 WinDestroyWindow( hwndFrame );
  782.         }
  783.         else
  784.             WinDestroyWindow( hwndFrame );
  785.     }
  786. }
  787.  
  788. MRESULT EXPENTRY wpLBFrame( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  789. {
  790.     switch( msg )
  791.     {
  792.         case WM_SYSCOMMAND:
  793.             if( SHORT1FROMMP( mp1 ) == SC_CLOSE )
  794.                 WinDestroyWindow( hwnd );
  795.  
  796.             return 0;
  797.  
  798.         case WM_DESTROY:
  799.         {
  800.             PLBFRAMEDATA plbfd =
  801.                     (PLBFRAMEDATA) WinQueryWindowPtr( hwnd, QWL_USER );
  802.  
  803.             if( plbfd )
  804.             {
  805.                 // Take off the In-Use emphasis that was set on for the
  806.                 // container record when this listbox-frame was created.
  807.  
  808.                 WinSendMsg( plbfd->hwndCnr, CM_SETRECORDEMPHASIS,
  809.                             MPFROMP( plbfd->pCnrRec ),
  810.                             MPFROM2SHORT( FALSE, CRA_INUSE ) );
  811.                 plbfd->pCnrRec->hwndDisplay = NULLHANDLE;
  812.                 free( plbfd );
  813.             }
  814.         }
  815.     }
  816.  
  817.     return pfnwpLBFrame( hwnd, msg, mp1, mp2 );
  818. }
  819.  
  820. /**********************************************************************/
  821. /*------------------------- UserWantsToClose -------------------------*/
  822. /*                                                                    */
  823. /*  THE USER HAS SELECTED CLOSE FROM THE SYSTEM MENU.                 */
  824. /*                                                                    */
  825. /*  PARMS: frame window handle                                        */
  826. /*                                                                    */
  827. /*  NOTES: In a commercial app you'd want to quiesce the background   */
  828. /*         threads and exit as quickly as possible if the user has    */
  829. /*         selected to close the window. Here we take the easy way    */
  830. /*         out and just not allow it if the drop is still taking      */
  831. /*         place.                                                     */
  832. /*                                                                    */
  833. /*  RETURNS: nothing                                                  */
  834. /*                                                                    */
  835. /*--------------------------------------------------------------------*/
  836. /**********************************************************************/
  837. void UserWantsToClose( HWND hwndFrame )
  838. {
  839.     PINSTANCE pi = INSTDATA( hwndFrame );
  840.  
  841.     if( !pi->pSavedDragInfo )
  842.     {
  843.         // Don't let the message queue be destroyed until the user has closed
  844.         // *both* windows.
  845.  
  846.         if( (hwndFrame == hwndDrag) && hwndDrop )
  847.         {
  848.             WinDestroyWindow( hwndDrag );
  849.             hwndDrag = NULLHANDLE;
  850.             WinSetActiveWindow( HWND_DESKTOP, hwndDrop );
  851.         }
  852.         else if( (hwndFrame == hwndDrop) && hwndDrag )
  853.         {
  854.             WinDestroyWindow( hwndDrop );
  855.             hwndDrop = NULLHANDLE;
  856.             WinSetActiveWindow( HWND_DESKTOP, hwndDrag );
  857.         }
  858.         else
  859.             WinPostMsg( hwndFrame, WM_QUIT, NULL, NULL );
  860.     }
  861. }
  862.  
  863. /**********************************************************************/
  864. /*------------------------- DeleteTempFiles --------------------------*/
  865. /*                                                                    */
  866. /*  DELETE THE TEMPORARY FILES USED BY THIS PROGRAM.                  */
  867. /*                                                                    */
  868. /*  PARMS: nothing                                                    */
  869. /*                                                                    */
  870. /*  NOTES: A temporary file is created in the current directory each  */
  871. /*         time an icon is dragged from the 'drag' container to the   */
  872. /*         'drop' container. Here we delete all those temporary files.*/
  873. /*                                                                    */
  874. /*  RETURNS: nothing                                                  */
  875. /*                                                                    */
  876. /*--------------------------------------------------------------------*/
  877. /**********************************************************************/
  878. void DeleteTempFiles()
  879. {
  880.     FILEFINDBUF3 ffb;
  881.     HDIR         hdir = HDIR_SYSTEM;
  882.     ULONG        cFiles = 1;
  883.     char         szTempFileSpec[ CCHMAXPATH ];
  884.     APIRET       rc;
  885.  
  886.     strcpy( szTempFileSpec, szCurrentPath );
  887.     strcat( szTempFileSpec, BASE_TEMPFILE_NAME );
  888.     strcat( szTempFileSpec, ".*" );
  889.  
  890.     rc = DosFindFirst( szTempFileSpec, &hdir, FILE_NORMAL,
  891.                        &ffb, sizeof ffb, &cFiles, FIL_STANDARD );
  892.     while( !rc )
  893.     {
  894.         DosDelete( ffb.achName );
  895.         rc = DosFindNext( hdir, &ffb, sizeof ffb, &cFiles );
  896.     }
  897. }
  898.  
  899. /**********************************************************************/
  900. /*------------------------- DestroyWindows ---------------------------*/
  901. /*                                                                    */
  902. /*  DESTROY THE WINDOWS AND RESOURCES USED IN THIS PROGRAM.           */
  903. /*                                                                    */
  904. /*  PARMS: nothing                                                    */
  905. /*                                                                    */
  906. /*  NOTES:                                                            */
  907. /*                                                                    */
  908. /*  RETURNS: nothing                                                  */
  909. /*                                                                    */
  910. /*--------------------------------------------------------------------*/
  911. /**********************************************************************/
  912. void DestroyWindows()
  913. {
  914.     WinDestroyWindow( hwndDrag );
  915.     WinDestroyWindow( hwndDrop );
  916.  
  917.     WinDestroyPointer( hptrDragMe );
  918.     WinDestroyPointer( hptrOpenMe );
  919. }
  920.  
  921. /**********************************************************************/
  922. /*------------------------------- Msg --------------------------------*/
  923. /*                                                                    */
  924. /*  DISPLAY A MESSAGE TO THE USER.                                    */
  925. /*                                                                    */
  926. /*  PARMS: a message in printf format with its parms                  */
  927. /*                                                                    */
  928. /*  NOTES:                                                            */
  929. /*                                                                    */
  930. /*  RETURNS: nothing                                                  */
  931. /*                                                                    */
  932. /*--------------------------------------------------------------------*/
  933. /**********************************************************************/
  934. void Msg( PSZ szFormat,... )
  935. {
  936.     PSZ     szMsg;
  937.     va_list argptr;
  938.  
  939.     szMsg = (PSZ) malloc( MESSAGE_SIZE );
  940.     if( szMsg )
  941.     {
  942.         va_start( argptr, szFormat );
  943.         vsprintf( szMsg, szFormat, argptr );
  944.         va_end( argptr );
  945.  
  946.         szMsg[ MESSAGE_SIZE - 1 ] = 0;
  947.  
  948.         WinAlarm( HWND_DESKTOP, WA_WARNING );
  949.         WinMessageBox(  HWND_DESKTOP, HWND_DESKTOP, szMsg,
  950.                         "Container Drag/Drop Sample Program", 1,
  951.                         MB_OK | MB_MOVEABLE );
  952.         free( szMsg );
  953.     }
  954.     else
  955.     {
  956.         DosBeep( 1000, 1000 );
  957.         return;
  958.     }
  959. }
  960.  
  961. /*************************************************************************
  962.  *                     E N D     O F     S O U R C E                     *
  963.  *************************************************************************/
  964.