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

  1. /*********************************************************************
  2.  *                                                                   *
  3.  * MODULE NAME :  drag.c                 AUTHOR:  Rick Fishman       *
  4.  * DATE WRITTEN:  07-16-93                                           *
  5.  *                                                                   *
  6.  * MODULE DESCRIPTION:                                               *
  7.  *                                                                   *
  8.  *  Part of the 'DRGTHRND' drag/drop sample program.                 *
  9.  *                                                                   *
  10.  *  This module handles all the rendering for the target window.     *
  11.  *                                                                   *
  12.  * NOTES:                                                            *
  13.  *                                                                   *
  14.  * FUNCTIONS AVALABLE TO OTHER MODULES:                              *
  15.  *                                                                   *
  16.  *   targCreateWindow                                                *
  17.  *                                                                   *
  18.  *                                                                   *
  19.  * HISTORY:                                                          *
  20.  *                                                                   *
  21.  *  07-16-93 - Program coded.                                        *
  22.  *                                                                   *
  23.  *  Rick Fishman                                                     *
  24.  *  Code Blazers, Inc.                                               *
  25.  *  4113 Apricot                                                     *
  26.  *  Irvine, CA. 92720                                                *
  27.  *  CIS ID: 72251,750                                                *
  28.  *                                                                   *
  29.  *********************************************************************/
  30.  
  31. #pragma strings(readonly)   // used for debug version of memory mgmt routines
  32.  
  33. /*********************************************************************/
  34. /*------- Include relevant sections of the OS/2 header files --------*/
  35. /*********************************************************************/
  36.  
  37. #define  INCL_DOSERRORS
  38. #define  INCL_DOSPROCESS
  39. #define  INCL_WINDIALOGS
  40. #define  INCL_WINERRORS
  41. #define  INCL_WINFRAMEMGR
  42. #define  INCL_WINMENUS
  43. #define  INCL_WINSTDCNR
  44. #define  INCL_WINSTDDRAG
  45. #define  INCL_WINWINDOWMGR
  46.  
  47. /**********************************************************************/
  48. /*----------------------------- INCLUDES -----------------------------*/
  49. /**********************************************************************/
  50.  
  51. #include <os2.h>
  52. #include <process.h>
  53. #include <stdio.h>
  54. #include <stdlib.h>
  55. #include <string.h>
  56. #include "drgthrnd.h"
  57.  
  58. /*********************************************************************/
  59. /*------------------- APPLICATION DEFINITIONS -----------------------*/
  60. /*********************************************************************/
  61.  
  62. #define STACKSIZE 0xE000                      // Stacksize for secondary threads
  63.  
  64. /**********************************************************************/
  65. /*---------------------------- STRUCTURES ----------------------------*/
  66. /**********************************************************************/
  67.  
  68. typedef struct _WINSTARTUP
  69. {
  70.     ULONG cb;
  71.     HWND  hwndFrame;
  72. } WINSTARTUP, *PWINSTARTUP;
  73.  
  74. /**********************************************************************/
  75. /*----------------------- FUNCTION PROTOTYPES ------------------------*/
  76. /**********************************************************************/
  77.  
  78. void    TargetThread      ( void *pvHwndFrame );
  79. void    DoTheDrop         ( HWND hwndRender, HWND hwndFrame,
  80.                             PDRAGINFO pDragInfo );
  81. BOOL    ProcessDroppedItem( HWND hwndRender, PDRAGINFO pDragInfo,
  82.                             PDRAGITEM pDragItem, PDRAGTRANSFER pDragXfer );
  83. void    FindTempFile      ( PSZ szTempFileName );
  84. MRESULT RenderComplete    ( HWND hwndFrame, PDRAGTRANSFER pDragXfer,
  85.                             USHORT fsRender );
  86.  
  87. FNWP wpTarget;
  88.  
  89. /**********************************************************************/
  90. /*------------------------ GLOBAL VARIABLES --------------------------*/
  91. /**********************************************************************/
  92.  
  93. char szDroppedOnCnrTitle[] = "Open a table by double-clicking on it!";
  94.  
  95. /**********************************************************************/
  96. /*------------------------ targCreateWindow --------------------------*/
  97. /*                                                                    */
  98. /*  CREATE A WINDOW IN ANOTHER THREAD THAT WILL PROCESS THE RENDERING */
  99. /*  FOR THE TARGET.                                                   */
  100. /*                                                                    */
  101. /*  PARMS: frame window handle                                        */
  102. /*                                                                    */
  103. /*  NOTES:                                                            */
  104. /*                                                                    */
  105. /*  RETURNS: nothing                                                  */
  106. /*                                                                    */
  107. /*--------------------------------------------------------------------*/
  108. /**********************************************************************/
  109. HWND targCreateWindow( HWND hwndFrame )
  110. {
  111.     HWND hwndRender = NULLHANDLE;
  112.     TID  tid;
  113.  
  114.     // Start the thread. Then wait for the thread's window to be created, at
  115.     // which point it will post a UM_WINDOW_CREATED message to this thread.
  116.     // We take over the message queue not just to catch this message but so
  117.     // that the message queue will not be tied up while this message is being
  118.     // created. It does act as a cheap semaphore mechanism though...
  119.  
  120.     tid = _beginthread( TargetThread, NULL, STACKSIZE, (void *) hwndFrame );
  121.  
  122.     if( (int) tid != -1 )
  123.     {
  124.         HAB  hab = ANCHOR( hwndFrame );
  125.         QMSG qmsg;
  126.  
  127.         while( WinGetMsg( hab, &qmsg, NULLHANDLE, 0, 0 ) )
  128.             if( qmsg.msg == UM_WINDOW_CREATED )
  129.             {
  130.                 hwndRender = (HWND) qmsg.mp1;
  131.                 break;
  132.             }
  133.             else
  134.                 WinDispatchMsg( hab, &qmsg );
  135.     }
  136.     else
  137.         Msg( "_beginthread for target window failed!" );
  138.  
  139.     return hwndRender;
  140. }
  141.  
  142. /**********************************************************************/
  143. /*-------------------------- TargetThread ----------------------------*/
  144. /*                                                                    */
  145. /*  THREAD THAT HANDLES THE RENDERING ON THE TARGET WINDOW SIDE.      */
  146. /*                                                                    */
  147. /*  PARMS: frame window handle (this is passes as a void pointer to   */
  148. /*               satisfy the requirements of _beginthread())          */
  149. /*                                                                    */
  150. /*  NOTES: The UM_WINDOW_CREATED message is our way of letting the    */
  151. /*         creator of this thread know the window handle of the render*/
  152. /*         object window. It is our way of 'returning' that window    */
  153. /*         handle. We place it in mp1 of that message. If anything    */
  154. /*         happens to hurt the creation of that window we will pass   */
  155. /*         back a NULL in mp1.                                        */
  156. /*                                                                    */
  157. /*  RETURNS: nothing                                                  */
  158. /*                                                                    */
  159. /*--------------------------------------------------------------------*/
  160. /**********************************************************************/
  161. #define TARGET_CLASS "ThisIsTheTargetClass"
  162.  
  163. void TargetThread( void *pvHwndFrame )
  164. {
  165.     HAB  hab = WinInitialize( 0 );
  166.     HMQ  hmq;
  167.     HWND hwndFrame = (HWND) pvHwndFrame;
  168.  
  169.     if( hab )
  170.         hmq = WinCreateMsgQueue( hab, 0 );
  171.     else
  172.     {
  173.         WinPostMsg( hwndFrame, UM_WINDOW_CREATED, NULL, NULL );
  174.         DosBeep( 1000, 100 );
  175.         fprintf( stderr, "WinInitialize failed!" );
  176.     }
  177.  
  178.     if( hmq )
  179.     {
  180.         WINSTARTUP WinStartup;
  181.         HWND       hwndObj;
  182.  
  183.         // Pass the frame window handle to the render window - it will need that
  184.         // handle to get at the frame window's window word. Remember that when
  185.         // passing a pointer to a structure via the pCtlData parameter, the
  186.         // first USHORT must be the size of the structure.
  187.  
  188.         WinStartup.cb        = sizeof WinStartup;
  189.         WinStartup.hwndFrame = hwndFrame;
  190.  
  191.         WinRegisterClass( hab, TARGET_CLASS, wpTarget, 0, sizeof( void * ) );
  192.  
  193.         hwndObj = WinCreateWindow( HWND_OBJECT, TARGET_CLASS, NULL, 0, 0, 0, 0,
  194.                                    0, NULLHANDLE, HWND_TOP, 1, &WinStartup,
  195.                                    NULL );
  196.         if( hwndObj )
  197.         {
  198.             QMSG qmsg;
  199.  
  200.             WinPostMsg( hwndFrame, UM_WINDOW_CREATED, MPFROMHWND( hwndObj ),
  201.                         NULL );
  202.             while( WinGetMsg( hab, &qmsg, NULLHANDLE, 0, 0 ) )
  203.                 WinDispatchMsg( hab, &qmsg );
  204.  
  205.             WinDestroyWindow( hwndObj );
  206.         }
  207.         else
  208.         {
  209.             WinPostMsg( hwndFrame, UM_WINDOW_CREATED, NULL, NULL );
  210.             Msg( "WinCreateWindow( hwndObj ) RC(%X)", HABERR( hab ) );
  211.         }
  212.     }
  213.     else if( hab )
  214.     {
  215.         WinPostMsg( hwndFrame, UM_WINDOW_CREATED, NULL, NULL );
  216.         Msg( "WinCreateMsgQueue RC(%X)", HABERR( hab ) );
  217.     }
  218.  
  219.     if( hmq )
  220.         WinDestroyMsgQueue( hmq );
  221.  
  222.     if( hab )
  223.         WinTerminate( hab );
  224.  
  225.     _endthread();
  226. }
  227.  
  228. /**********************************************************************/
  229. /*---------------------------- wpTarget ------------------------------*/
  230. /*                                                                    */
  231. /*  WINDOW PROCEDURE FOR THE TARGET RENDERING OBJECT WINDOW.          */
  232. /*                                                                    */
  233. /*  PARMS: standard window procedure parameters                       */
  234. /*                                                                    */
  235. /*  NOTES:                                                            */
  236. /*                                                                    */
  237. /*  RETURNS: nothing                                                  */
  238. /*                                                                    */
  239. /*--------------------------------------------------------------------*/
  240. /**********************************************************************/
  241. MRESULT EXPENTRY wpTarget( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  242. {
  243.     HWND hwndFrame = (HWND) WinQueryWindowULong( hwnd, 0 );
  244.  
  245.     switch( msg )
  246.     {
  247.         case WM_CREATE:
  248.         {
  249.             WinSetWindowULong( hwnd, 0, ((PWINSTARTUP) mp1)->hwndFrame );
  250.             break;
  251.         }
  252.  
  253.         // The main thread sends this to use after it knows we are created. It
  254.         // is our signal to start the drop processing.
  255.  
  256.         case UM_DO_THE_DROP:
  257.             DoTheDrop( hwnd, hwndFrame, (PDRAGINFO) mp1 );
  258.             return 0;
  259.  
  260.         // The source posts this to us when it is done rendering.
  261.  
  262.         case DM_RENDERCOMPLETE:
  263.             return RenderComplete( hwndFrame, (PDRAGTRANSFER) mp1,
  264.                                    SHORT1FROMMP( mp2 ) );
  265.     }
  266.  
  267.     return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  268. }
  269.  
  270. /**********************************************************************/
  271. /*---------------------------- DoTheDrop -----------------------------*/
  272. /*                                                                    */
  273. /*  DO WHAT IS NECESSARY TO HANDLE THE DROP.                          */
  274. /*                                                                    */
  275. /*  PARMS: rendering window's handle,                                 */
  276. /*         frame window handle,                                       */
  277. /*         pointer to the DRAGINFO structure                          */
  278. /*                                                                    */
  279. /*  NOTES:                                                            */
  280. /*                                                                    */
  281. /*  RETURNS: nothing                                                  */
  282. /*                                                                    */
  283. /*--------------------------------------------------------------------*/
  284. /**********************************************************************/
  285. void DoTheDrop( HWND hwndRender, HWND hwndFrame, PDRAGINFO pDragInfo )
  286. {
  287.     PDRAGITEM     pDragItem;
  288.     PDRAGTRANSFER pDragXfer;
  289.     PINSTANCE     pi = INSTDATA( hwndFrame );
  290.     int           i, cItemsToRender, cItemsRendered;
  291.  
  292.     if( !DrgAccessDraginfo( pDragInfo ) )
  293.     {
  294.         Msg( "DoTheDrop DrgAccessDraginfo RC(%X)", HWNDERR( hwndRender ) );
  295.         return;
  296.     }
  297.  
  298.     cItemsToRender = cItemsRendered = pDragInfo->cditem;
  299.  
  300.     // We allocate an array of DRAGTRANSFER structures. One by one each will
  301.     // be passed on a DM_RENDER message. On DM_RENDERCOMPLETE messages we will
  302.     // free each one. PM takes care of freeing the whole array after it gets
  303.     // back as many DrgFreeDragTransfer's as were allocated here.
  304.  
  305.     pDragXfer = DrgAllocDragtransfer( pDragInfo->cditem );
  306.     if( !pDragXfer )
  307.     {
  308.         Msg( "DoTheDrop DrgAllocDragtransfer RC(%X)", HWNDERR( hwndRender ) );
  309.         return;
  310.     }
  311.  
  312.     // Disable the Close option of the system menu while the rendering is
  313.     // going on. Otherwise the background threads could get hosed.
  314.  
  315.     WinSendDlgItemMsg( hwndFrame, FID_SYSMENU, MM_SETITEMATTR,
  316.                        MPFROM2SHORT( SC_CLOSE, TRUE ),
  317.                        MPFROM2SHORT( MIA_DISABLED, MIA_DISABLED ) );
  318.  
  319.     // Process each DragItem. First get a pointer to it, then call a function
  320.     // that starts the rendering happening.
  321.  
  322.     for( i = 0; i < pDragInfo->cditem; i++ )
  323.     {
  324.         pDragItem = DrgQueryDragitemPtr( pDragInfo, i );
  325.  
  326.         if( pDragItem )
  327.         {
  328.             if( !ProcessDroppedItem( hwndRender, pDragInfo, pDragItem,
  329.                                      pDragXfer + i ) )
  330.                 --cItemsRendered;
  331.         }
  332.         else
  333.         {
  334.             Msg( "DoTheDrop DrgQueryDragitemPtr RC(%X)", HWNDERR(hwndRender) );
  335.             --cItemsRendered;
  336.         }
  337.     }
  338.  
  339.     if( !cItemsRendered )
  340.     {
  341.         // Clean up after ourselves if we weren't able to do
  342.         // any rendering. Normally this cleanup would be done
  343.         // under the last DM_RENDERCOMPLETE message but we don't
  344.         // get those messages if we aren't rendering.
  345.  
  346.         dragTargetCleanup( hwndFrame );
  347.     }
  348.     else if( cItemsToRender != cItemsRendered )
  349.     {
  350.         // Only *some* items were'nt rendered. Since we don't want any race
  351.         // conditions with the cDragItems counter, disable thread switching
  352.         // while we check/change it. If the rendering for all items that got
  353.         // sent DM_RENDER messages is complete, the target resources wouldn't
  354.         // have been freed because the counter wouldn't have been zero, so we
  355.         // need to free them in this case.
  356.  
  357.         DosEnterCritSec();
  358.         if( pi->cDragItems )
  359.         {
  360.             pi->cDragItems -= (cItemsToRender - cItemsRendered);
  361.             DosExitCritSec();
  362.         }
  363.         else
  364.         {
  365.             DosExitCritSec();
  366.             dragTargetCleanup( hwndFrame );
  367.         }
  368.     }
  369. }
  370.  
  371. /**********************************************************************/
  372. /*------------------------ ProcessDroppedItem ------------------------*/
  373. /*                                                                    */
  374. /*  PROCESS A DRAGITEM THAT HAS BEEN DROPPED ON US                    */
  375. /*                                                                    */
  376. /*  PARMS: rendering window handle,                                   */
  377. /*         pointer to the DRAGINFO structure,                         */
  378. /*         pointer to DRAGITEM structure,                             */
  379. /*         pointer to DRAGTRANSFER structure to use on DM_RENDER msg  */
  380. /*                                                                    */
  381. /*  NOTES:                                                            */
  382. /*                                                                    */
  383. /*  RETURNS: TRUE or FALSE if item was sent a DM_RENDER message       */
  384. /*                                                                    */
  385. /*--------------------------------------------------------------------*/
  386. /**********************************************************************/
  387. BOOL ProcessDroppedItem( HWND hwndRender, PDRAGINFO pDragInfo,
  388.                          PDRAGITEM pDragItem, PDRAGTRANSFER pDragXfer )
  389. {
  390.     PSZ       pszString, pszLoc;
  391.     ULONG     cbString;
  392.     BOOL      fRenderSent = TRUE;
  393.     char      szTempFileName[ CCHMAXPATH ];
  394.  
  395.     // We will ask the source to 'render' into a temporary file. This next
  396.     // function gets a temporary file name to use.
  397.  
  398.     FindTempFile( szTempFileName );
  399.  
  400.     // Form a 'database:table' string by combining the database found in
  401.     // hstrContainerName with the table found in hstrSourceName.
  402.  
  403.     cbString = DrgQueryStrNameLen( pDragItem->hstrContainerName ) +
  404.                DrgQueryStrNameLen( pDragItem->hstrSourceName ) +
  405.                2;  // Null terminator plus colon
  406.  
  407.     pszString = pszLoc = _alloca( cbString );
  408.  
  409.     DrgQueryStrName( pDragItem->hstrContainerName, cbString, pszLoc );
  410.     strcat( pszString, ":" );
  411.     pszLoc += strlen( pszString );
  412.     cbString -= strlen( pszString );
  413.     DrgQueryStrName( pDragItem->hstrSourceName, cbString, pszLoc );
  414.  
  415.     // Fill in the DRAGTRANSFER structure. This structure is used throughout
  416.     // the rendering process and is exchanged between the source and the
  417.     // target.
  418.  
  419.     memset( pDragXfer, 0, sizeof( DRAGTRANSFER ) );
  420.     pDragXfer->cb               = sizeof( DRAGTRANSFER );
  421.  
  422.     // hwndClient identifies the target window
  423.  
  424.     pDragXfer->hwndClient       = hwndRender;
  425.     pDragXfer->pditem           = pDragItem;
  426.  
  427.     // hstrSelectedRMF is the Rendering Mechanism/Format used during the
  428.     // rendering. Remember that the hstrRMF field of the DRAGITEM structure
  429.     // can contain multiple mechanisms and formats. When we get down to the
  430.     // rendering stage we can use only one. In this program we only ever
  431.     // offered one so we use the same one that was placed in DRAGITEM.hstrRMF.
  432.     // In the real world we would first put the most native mechanism/format
  433.     // combination into hstrSelectedRMF and send the source a DM_RENDER. If the
  434.     // source responded to the DM_RENDER by returning DMFL_RENDERRETRY, we would
  435.     // then use the 'next best' RMF and try again by sending another DM_RENDER
  436.     // with the new hstrSelectedRMF. We'd do this until one was agreed upon.
  437.  
  438.     pDragXfer->hstrSelectedRMF  = DrgAddStrHandle( DRAG_RMF );
  439.  
  440.     // hstrRenderToName is the file name that we are asking the source to
  441.     // render into. In this program the source will copy the rows from the
  442.     // requested database:table into this file.
  443.  
  444.     pDragXfer->hstrRenderToName = DrgAddStrHandle( szTempFileName );
  445.  
  446.     // usOperation is where we'd indicate 'copy' or 'move'. In this program we
  447.     // will only do a logical copy operation so this field isn't even looked at.
  448.     // Typically this will stay the same as the usOperation field in the
  449.     // DRAGINFO field because that contains the last operation selected by the
  450.     // user.
  451.  
  452.     pDragXfer->usOperation      = pDragInfo->usOperation;
  453.  
  454.     // ulTargetInfo is a convenient place to store something between render
  455.     // messages.
  456.  
  457.     pDragXfer->ulTargetInfo     = 0;
  458.  
  459.     // Initialize this to 0. The source will place something in here if it
  460.     // returns FALSE from DM_RENDER.
  461.  
  462.     pDragXfer->fsReply          = 0;
  463.  
  464.     // If the source wanted to be notified before a render is to be sent,
  465.     // do it. The source in this program uses this message to create an object
  466.     // window in another thread to do the rendering. It then places the object
  467.     // window handle in pDragItem->hwndItem, thus overwriting what is currently
  468.     // there - the source frame window handle.
  469.  
  470.     if( !(pDragItem->fsControl & DC_PREPARE) ||
  471.         (pDragItem->fsControl & DC_PREPARE &&
  472.          DrgSendTransferMsg( pDragItem->hwndItem, DM_RENDERPREPARE,
  473.                              pDragXfer, NULL )) )
  474.     {
  475.         // Tell the source to render
  476.  
  477.         MRESULT mr = DrgSendTransferMsg( pDragItem->hwndItem, DM_RENDER,
  478.                                          pDragXfer, NULL );
  479.  
  480.         // MRESULT will be NULL if the source could not render
  481.  
  482.         if( !mr )
  483.         {
  484.             // If the source wants us to retry with another mechanism, tell it
  485.             // 'no' because all we can handle is DRM_FISHMAN.
  486.  
  487.             if( pDragXfer->fsReply & DMFL_RENDERRETRY )
  488.                 DrgPostTransferMsg( pDragItem->hwndItem, DM_RENDERCOMPLETE,
  489.                                     pDragXfer, DMFL_RENDERFAIL, 0, FALSE );
  490.  
  491.             // If the source wants us to render, tell it 'no way'. It is the one
  492.             // that requested rendering in the first place.
  493.  
  494.             if( pDragXfer->fsReply & DMFL_NATIVERENDER )
  495.                 DrgSendTransferMsg( pDragItem->hwndItem, DM_ENDCONVERSATION,
  496.                                     MPFROMLONG( pDragItem->ulItemID ),
  497.                                     MPFROMLONG( DMFL_TARGETFAIL ) );
  498.         }
  499.     }
  500.     else
  501.     {
  502.         // If we don't send a DM_RENDER message, we'll never get a
  503.         // DM_RENDERCOMPLETE. Since cleanup for these resources usually gets
  504.         // done under that message, we'll need to do it here in this case.
  505.  
  506.         DrgDeleteStrHandle( pDragXfer->hstrSelectedRMF );
  507.         DrgDeleteStrHandle( pDragXfer->hstrRenderToName );
  508.         DrgFreeDragtransfer( pDragXfer );
  509.         fRenderSent = FALSE;
  510.     }
  511.  
  512.     return fRenderSent;
  513. }
  514.  
  515. /**********************************************************************/
  516. /*-------------------------- FindTempFile ----------------------------*/
  517. /*                                                                    */
  518. /*  FIND AN AVAILABLE TEMPORARY FILE NAME.                            */
  519. /*                                                                    */
  520. /*  PARMS: pointer to buffer to hold filename                         */
  521. /*                                                                    */
  522. /*  NOTES: This is a rudimentary method for getting a temporary file  */
  523. /*         name. Usually you'd want to check the TEMP or TMP          */
  524. /*         environment variables first and use that as the directory  */
  525. /*         in which to place the temporary files. For a sample        */
  526. /*         program, this will do fine. Basically we just get use      */
  527. /*         the current path and a base filename and figure out an     */
  528. /*         extension by finding the first available one.              */
  529. /*                                                                    */
  530. /*  RETURNS: nothing                                                  */
  531. /*                                                                    */
  532. /*--------------------------------------------------------------------*/
  533. /**********************************************************************/
  534. void FindTempFile( PSZ pszTempFileName )
  535. {
  536.     PSZ         pszFileExt;
  537.     FILESTATUS3 fs;
  538.     int         i;
  539.     APIRET      rc;
  540.     FILE        *fhTemp;
  541.  
  542.     strcpy( pszTempFileName, szCurrentPath );
  543.     strcat( pszTempFileName, BASE_TEMPFILE_NAME );
  544.     strcat( pszTempFileName, "." );
  545.  
  546.     pszFileExt = pszTempFileName + strlen( pszTempFileName );
  547.  
  548.     for( i = 0; i < 1000; i++ )
  549.     {
  550.         _itoa( i, pszFileExt, 10 );
  551.  
  552.         rc = DosQueryPathInfo( pszTempFileName, FIL_STANDARD, &fs, sizeof fs );
  553.         if( rc == ERROR_FILE_NOT_FOUND || rc == ERROR_PATH_NOT_FOUND )
  554.         {
  555.             // Create the file so it exists and we won't try and use it for the
  556.             // next temporary file.
  557.  
  558.             fhTemp = fopen( pszTempFileName, "w" );
  559.             fclose( fhTemp );
  560.             break;
  561.         }
  562.     }
  563.  
  564.     if( i >= 1000 )
  565.         Msg( "Can't get a temporary file name!!!" );
  566. }
  567.  
  568. /**********************************************************************/
  569. /*------------------------- RenderComplete ---------------------------*/
  570. /*                                                                    */
  571. /*  PROCESS A DM_RENDERCOMPLETE MESSAGE                               */
  572. /*                                                                    */
  573. /*  PARMS: frame window handle,                                       */
  574. /*         pointer to a DRAGTRANSFER structure,                       */
  575. /*         flags describing the render operation                      */
  576. /*                                                                    */
  577. /*  NOTES: This is a TARGET window message sent by the source when it */
  578. /*         has completed the rendering.                               */
  579. /*                                                                    */
  580. /*  RETURNS: zero                                                     */
  581. /*                                                                    */
  582. /*--------------------------------------------------------------------*/
  583. /**********************************************************************/
  584. MRESULT RenderComplete( HWND hwndFrame, PDRAGTRANSFER pDragXfer,
  585.                         USHORT fsRender )
  586. {
  587.     BOOL      fSuccess = TRUE;
  588.     ULONG     flStatus = DMFL_TARGETSUCCESSFUL;
  589.     PINSTANCE pi = INSTDATA( hwndFrame );
  590.  
  591.     // If the source responded with RENDEROK, that means we can count on the
  592.     // hstrRenderToFile file containing the data from the table in the database.
  593.     // In that case we insert a record into the 'drop' container that will
  594.     // represent that rendered file. The user can double-click on that icon and
  595.     // bring up a listbox with the file dumped into it.
  596.  
  597.     if( fsRender & DMFL_RENDEROK )
  598.     {
  599.         PSZ          pszLoc;
  600.         RECORDINSERT ri;
  601.         PCNRREC      pCnrRec;
  602.  
  603.         memset( &ri, 0, sizeof( RECORDINSERT ) );
  604.         ri.cb                 = sizeof( RECORDINSERT );
  605.         ri.pRecordOrder       = (PRECORDCORE) CMA_END;
  606.         ri.pRecordParent      = (PRECORDCORE) NULL;
  607.         ri.zOrder             = (USHORT) CMA_TOP;
  608.         ri.cRecordsInsert     = 1;
  609.         ri.fInvalidateRecord  = TRUE;
  610.  
  611.         pCnrRec = WinSendDlgItemMsg( hwndFrame, FID_CLIENT, CM_ALLOCRECORD,
  612.                                      MPFROMLONG( EXTRA_BYTES ),
  613.                                      MPFROMLONG( 1 ) );
  614.         if( pCnrRec )
  615.         {
  616.             DrgQueryStrName( pDragXfer->pditem->hstrContainerName,
  617.                          sizeof( pCnrRec->szTableName ), pCnrRec->szTableName );
  618.             strcat( pCnrRec->szTableName, ":" );
  619.             pszLoc = pCnrRec->szTableName + strlen( pCnrRec->szTableName );
  620.             DrgQueryStrName( pDragXfer->pditem->hstrSourceName,
  621.                              sizeof( pCnrRec->szTableName ) -
  622.                                     (pszLoc - pCnrRec->szTableName), pszLoc );
  623.  
  624.             DrgQueryStrName( pDragXfer->hstrRenderToName,
  625.                              sizeof( pCnrRec->szRenderedFileName ),
  626.                              pCnrRec->szRenderedFileName );
  627.  
  628.             pCnrRec->flAttr       = RECATTR_OPENABLE;
  629.             pCnrRec->mrc.pszIcon  = (PSZ) &pCnrRec->szTableName;
  630.             pCnrRec->mrc.hptrIcon = hptrOpenMe;
  631.  
  632.             if( !WinSendDlgItemMsg( hwndFrame, FID_CLIENT, CM_INSERTRECORD,
  633.                                     MPFROMP( pCnrRec ), MPFROMP( &ri ) ) )
  634.             {
  635.                 fSuccess = FALSE;
  636.                 Msg( "RenderComplete CM_INSERTRECORD RC(%X)",
  637.                      HWNDERR( hwndFrame ) );
  638.             }
  639.         }
  640.         else
  641.         {
  642.             fSuccess = FALSE;
  643.             Msg( "RenderComplete CM_ALLOCRECORD RC(%X)", HWNDERR( hwndFrame ) );
  644.         }
  645.     }
  646.     else
  647.         fSuccess = FALSE;
  648.  
  649.     if( fSuccess )
  650.     {
  651.         CNRINFO cnri;
  652.  
  653.         cnri.cb           = sizeof( CNRINFO );
  654.         cnri.pszCnrTitle  = szDroppedOnCnrTitle;
  655.         WinSendDlgItemMsg( hwndFrame, FID_CLIENT, CM_SETCNRINFO,
  656.                            MPFROMP( &cnri ), MPFROMLONG( CMA_CNRTITLE ) );
  657.     }
  658.     else
  659.     {
  660.         char szRenderToName[ CCHMAXPATH ];
  661.  
  662.         // Delete the temporary file if the render failed.
  663.  
  664.         DrgQueryStrName( pDragXfer->hstrRenderToName, sizeof szRenderToName,
  665.                          szRenderToName );
  666.         DosDelete( szRenderToName );
  667.         flStatus = DMFL_TARGETFAIL;
  668.     }
  669.  
  670.     // Tell the source that we're all done here. At this point the Drag/Drop
  671.     // is finally done.
  672.  
  673.     DrgSendTransferMsg( pDragXfer->pditem->hwndItem, DM_ENDCONVERSATION,
  674.                         MPFROMLONG( pDragXfer->pditem->ulItemID ),
  675.                         MPFROMLONG( flStatus ) );
  676.  
  677.     // It is the target's responsibility to delete the string handles.
  678.  
  679.     DrgDeleteStrHandle( pDragXfer->hstrSelectedRMF );
  680.     DrgDeleteStrHandle( pDragXfer->hstrRenderToName );
  681.  
  682.     // Both the source and target must free the DRAGTRANSFER structure. The
  683.     // source will have done this before it sent us the DM_RENDERCOMPLETE
  684.     // message.
  685.  
  686.     DrgFreeDragtransfer( pDragXfer );
  687.  
  688.     // We need to keep a running total to know when all items in the drop have
  689.     // been processed. When that happens, it is time to free the resources that
  690.     // were allocated to the drop as a whole rather than to an indidvidual item.
  691.  
  692.     if( --pi->cDragItems == 0 )
  693.         dragTargetCleanup( hwndFrame );
  694.  
  695.     return 0;
  696. }
  697.  
  698. /*************************************************************************
  699.  *                     E N D     O F     S O U R C E                     *
  700.  *************************************************************************/
  701.