home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
High Voltage Shareware
/
high1.zip
/
high1
/
DIR24
/
DRGFIL.ZIP
/
DRGFILES.C
next >
Wrap
C/C++ Source or Header
|
1993-07-31
|
31KB
|
683 lines
/*********************************************************************
* *
* MODULE NAME : drgfiles.c AUTHOR: Rick Fishman *
* DATE WRITTEN: 07-28-93 *
* *
* HOW TO RUN THIS PROGRAM: *
* *
* Just enter DRGFILES on the command line. *
* *
* MODULE DESCRIPTION: *
* *
* Root module for DRGFILES.EXE, a program that demonstrates using *
* Drag/Drop on OS/2 2.x with the DrgDragFiles and *
* DrgAcceptDroppedFiles API's. These API's are provided by OS/2 as *
* an attempt to make Drag/Drop easier than using a full-blown *
* Drag/Drop implementation using lower-level D/D API's. The *
* limitations that are imposed on users of these higher-level API's*
* are as follows: *
* *
* - only filenames can be dragged/dropped *
* - source printing of dragged files is not supported *
* (the printer will try and print your file but it doesn't let *
* your program print it) *
* - source shredding of dragged files is not supported *
* (the shredder will try and delete your file but it doesn't let*
* your program participate so your program doesn't know it has *
* been deleted if the shredder was successful) *
* - only 1 image is allowed under the mouse pointer during the drag*
* - there are currenty many bugs in this API pair that cause *
* PMDRAG.DLL to trap (as of 2.1GA in September 1993) if more *
* than 1 file is dropped or rendering is done. Therefore I've *
* only been able to get it to work reliably by dragging one *
* file at a time and not rendering. *
* *
* This program has 2 global variables that control its operation. *
* They are both set to values that allow the program to run without*
* trapping. You may want to try and change the values when a new *
* version of the operating system is released since the bugs may *
* be fixed in new releases. *
* *
* fRender: This is set to FALSE, meaning the DM_RENDERFILE and *
* DM_FILERENDERED messages are not used so that the *
* DrgDragFiles API takes care of all copying and *
* moving of files. If this is set to TRUE, currently *
* you will get PMDRAG.DLL traps when the file(s) is *
* dropped because of an Operating System bug. *
* *
* flSelType: This is set to CCS_SINGLESEL, putting the container*
* in single-select mode which only allows the user to*
* drag one file. If you set this to CCS_EXTENDSEL, *
* you will be able to drag more than one file but *
* dropping the files will cause a trap in PMDRAG.DLL *
* after the first file is dropped and before the *
* second one is dropped. Again, this is an Operating *
* System bug. *
* *
* If your application can live with these limitations, this is an *
* easy way to implement direct manipulation. *
* *
* I also have samples for full-blown Drag/Drop implementations. *
* Some of them are: *
* *
* DRGDROP.ZIP - Does Drag/Drop but no rendering. Monitors the *
* Drag/Drop process by displaying the D/D *
* structures while the drag is going on. *
* DRGRENDR.ZIP - Does Drag/Drop with rendering. All rendering *
* takes place on the main thread. *
* DRGTHRND.ZIP - Does Drag/Drop with rendering. All rendering *
* takes place on secondary threads. *
* *
* OTHER MODULES: *
* *
* srcwin.c - contains code for the source window. *
* trgwin.c - contains code for the target window. *
* *
* NOTES: *
* *
* I hope this code proves useful for other PM programmers. The *
* more of us the better! *
* *
* HISTORY: *
* *
* 07-28-93 - Program coding started. *
* *
* Rick Fishman *
* Code Blazers, Inc. *
* 4113 Apricot *
* Irvine, CA. 92720 *
* CIS ID: 72251,750 *
* *
*********************************************************************/
#pragma strings(readonly) // used for debug version of memory mgmt routines
/*********************************************************************/
/*------- Include relevant sections of the OS/2 header files --------*/
/*********************************************************************/
#define INCL_DOSERRORS
#define INCL_DOSFILEMGR
#define INCL_DOSMISC
#define INCL_WINERRORS
#define INCL_WINFRAMEMGR
#define INCL_WINPOINTERS
#define INCL_WINSTDCNR
#define INCL_WINSYS
#define INCL_WINWINDOWMGR
#define GLOBALS_DEFINED // extern globals instantiated
/**********************************************************************/
/*----------------------------- INCLUDES -----------------------------*/
/**********************************************************************/
#include <os2.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "drgfiles.h"
/*********************************************************************/
/*------------------- APPLICATION DEFINITIONS -----------------------*/
/*********************************************************************/
#define MESSAGE_SIZE 1024
/**********************************************************************/
/*---------------------------- STRUCTURES ----------------------------*/
/**********************************************************************/
typedef struct _OPCONVERT // Used to convert an operation
{ // type to text that can be
int i; // displayed
PSZ sz;
} OPCONVERT, *POPCONVERT;
/**********************************************************************/
/*----------------------- FUNCTION PROTOTYPES ------------------------*/
/**********************************************************************/
int main ( void );
BOOL ProgInit ( void );
void GetCurrentPath ( void );
BOOL GetTempDir ( void );
BOOL ValidateDirectory ( PSZ pszDirectory );
BOOL CreateWindows ( HAB hab );
BOOL SizeAndShowWindows( HAB hab );
void ProgTerm ( HAB hab );
void DeleteTempFiles ( void );
/**********************************************************************/
/*------------------------ GLOBAL VARIABLES --------------------------*/
/**********************************************************************/
OPCONVERT ocOperation[] =
{
{ DFF_MOVE, "Move" },
{ DFF_COPY, "Copy" },
{ DFF_DELETE, "Delete" }
};
#define OP_TYPES (sizeof( ocOperation ) / sizeof( OPCONVERT ))
/**********************************************************************/
/*------------------------------ MAIN --------------------------------*/
/* */
/* PROGRAM ENTRYPOINT */
/* */
/* PARMS: nothing */
/* */
/* NOTES: */
/* */
/* RETURNS: return code */
/* */
/*--------------------------------------------------------------------*/
/**********************************************************************/
int main( void )
{
HAB hab;
HMQ hmq = NULLHANDLE;
QMSG qmsg;
// This macro is defined for the debug version of the C Set/2 Memory
// Management routines. Since the debug version writes to stderr, we
// send all stderr output to a debuginfo file.
#ifdef __DEBUG_ALLOC__
freopen( DEBUG_FILENAME, "w", stderr );
#endif
hab = WinInitialize( 0 );
if( hab )
hmq = WinCreateMsgQueue( hab, 0 );
else
{
DosBeep( 1000, 100 );
fprintf( stderr, "WinInitialize failed!" );
}
if( hmq )
{
if( ProgInit() )
if( CreateWindows( hab ) )
while( WinGetMsg( hab, &qmsg, NULLHANDLE, 0, 0 ) )
WinDispatchMsg( hab, &qmsg );
}
else if( hab )
Msg( "WinCreateMsgQueue RC(%X)", HABERR( hab ) );
ProgTerm( hab );
if( hmq )
WinDestroyMsgQueue( hmq );
if( hab )
WinTerminate( hab );
#ifdef __DEBUG_ALLOC__
_dump_allocated( -1 );
#endif
return 0;
}
/**********************************************************************/
/*---------------------------- ProgInit ------------------------------*/
/* */
/* PERFORM PROGRAM INITIALIZATION. */
/* */
/* PARMS: anchor block handle */
/* */
/* NOTES: */
/* */
/* RETURNS: TRUE or FALSE if successful or not */
/* */
/*--------------------------------------------------------------------*/
/**********************************************************************/
BOOL ProgInit()
{
GetCurrentPath();
return GetTempDir();
}
/**********************************************************************/
/*------------------------- GetCurrentPath ---------------------------*/
/* */
/* STORE THE CURRENT DRIVE/DIRECTORY. */
/* */
/* PARMS: nothing */
/* */
/* NOTES: This stores the current drive:\directory\ that is used */
/* to create draggable files in. */
/* */
/* RETURNS: nothing */
/* */
/*--------------------------------------------------------------------*/
/**********************************************************************/
void GetCurrentPath()
{
PBYTE pbCurrent = szCurrentPath;
INT cbBuf = sizeof szCurrentPath, cbUsed;
ULONG ulDrive, ulCurrDriveNo, ulDriveMap, cbPath;
APIRET rc;
// Fill in the drive letter, colon, and backslash
rc = DosQueryCurrentDisk( &ulCurrDriveNo, &ulDriveMap );
if( !rc ) // Use 'current' drive
{
*(pbCurrent++) = (BYTE) (ulCurrDriveNo + ('A' - 1));
*(pbCurrent++) = ':';
*(pbCurrent++) = '\\';
}
else
{ // API failed - use drive C:
strcpy( pbCurrent, "C:\\" );
pbCurrent += 3; // Incr our place in the buffer
}
cbUsed = pbCurrent - szCurrentPath; // How many bytes left?
// Fill in the current directory
ulDrive = *szCurrentPath - 'A' + 1; // Get drive number from letter
cbPath = cbBuf - cbUsed; // How many bytes left?
rc = DosQueryCurrentDir( ulDrive, pbCurrent, &cbPath );
// Get 'current' directory
if( szCurrentPath[ strlen( szCurrentPath ) - 1 ] != '\\' )
strcat( szCurrentPath, "\\" ); // Add trailing backslash
}
/**********************************************************************/
/*--------------------------- GetTempDir -----------------------------*/
/* */
/* FIND THE PROPER DIRECTORY TO USE AS A PLACE TO STORE TEMP FILES. */
/* */
/* PARMS: nothing */
/* */
/* NOTES: This temporary directory will be used to store dropped */
/* files in. We will use the directory pointed to by the */
/* 'TEMP' environment variable first. If not found, we will */
/* try the 'TMP' environment variable. If neither is found */
/* we will create a 'TEMP' subdirectory off the current */
/* directory and use that one. */
/* */
/* RETURNS: TRUE or FALSE if successful or not */
/* */
/*--------------------------------------------------------------------*/
/**********************************************************************/
BOOL GetTempDir( void )
{
PSZ pszDir = NULL;
APIRET rc;
BOOL fSuccess = FALSE;
rc = DosScanEnv( "TEMP", (const char **) &pszDir );
if( !rc && ValidateDirectory( pszDir ) )
fSuccess = TRUE;
else
{
rc = DosScanEnv( "TMP", (const char **) &pszDir );
if( !rc && ValidateDirectory( pszDir ) )
fSuccess = TRUE;
}
if( fSuccess )
strncpy( szTempDir, pszDir, sizeof szTempDir );
else
{
strcpy( szTempDir, szCurrentPath );
strcat( szTempDir, "TEMP" );
rc = DosCreateDir( szTempDir, NULL );
if( rc && rc != ERROR_ACCESS_DENIED ) // ACCESS_DENIED if already exists
Msg( "Got a %u return code trying to create the %s directory to "
"store dropped files in", rc, szTempDir );
else
fSuccess = TRUE;
}
return fSuccess;
}
/*********************************************************************/
/*------------------------ ValidateDirectory ------------------------*/
/* */
/* CHECK ON THE VALIDITY OF A DIRECTORY NAME. */
/* */
/* PARMS: pointer to directory name */
/* */
/* NOTES: This function uses DosFindFirst as a mechanism for */
/* validating a directory name. It is assumed that if */
/* DosFindFirst() gets an error that directory name cannot */
/* be used. */
/* */
/* RETURNS: TRUE or FALSE if a valid directory or not. */
/* */
/*-------------------------------------------------------------------*/
/*********************************************************************/
BOOL ValidateDirectory( PSZ pszDirectory )
{
BOOL fValid = TRUE;
HDIR hdir = HDIR_SYSTEM;
FILEFINDBUF3 ffb;
ULONG ulFiles = 1;
APIRET rc;
CHAR abBuf[ CCHMAXPATH ];
// We check for the validity of the directory by essentially doing a
// 'dir d:\directory\*.*'
(void) strcpy( abBuf, pszDirectory );
if( abBuf[ strlen( abBuf ) - 1 ] != '\\' )
strcat( abBuf, "\\" );
(void) strcat( abBuf, "*.*" );
rc = DosFindFirst( abBuf, &hdir, FILE_NORMAL | FILE_DIRECTORY, &ffb,
sizeof( ffb ), &ulFiles, FIL_STANDARD );
if( hdir )
DosFindClose( hdir );
if( rc )
fValid = FALSE;
return fValid;
}
/**********************************************************************/
/*------------------------- CreateWindows ----------------------------*/
/* */
/* CREATE ALL APPLICATION WINDOWS */
/* */
/* PARMS: anchor block handle */
/* */
/* NOTES: */
/* */
/* RETURNS: TRUE or FALSE if successful or not */
/* */
/*--------------------------------------------------------------------*/
/**********************************************************************/
BOOL CreateWindows( HAB hab )
{
BOOL fSuccess = TRUE;
// Load the icon that will be used for the container records.
hptrCnrRec = WinLoadPointer( HWND_DESKTOP, 0, ID_RESOURCES );
if( !hptrCnrRec )
{
Msg( "WinLoadPointer RC(%X)", HABERR( hab ) );
fSuccess = FALSE;
}
// Create 2 windows. One will act as the 'drag' window, the other as the
// 'drop' window. The user will then be able to drag the icons from the
// 'drag' window to the 'drop' window.
if( fSuccess )
{
hwndDrag = srcCreateWindow( hab );
if( hwndDrag )
{
hwndDrop = targCreateWindow( hab );
if( !hwndDrop )
fSuccess = FALSE;
}
else
fSuccess = FALSE;
}
if( fSuccess )
fSuccess = SizeAndShowWindows( hab );
if( !fSuccess )
{
if( hwndDrag )
{
WinDestroyWindow( hwndDrag );
hwndDrag = NULLHANDLE;
}
if( hwndDrop )
{
WinDestroyWindow( hwndDrop );
hwndDrop = NULLHANDLE;
}
}
return fSuccess;
}
/**********************************************************************/
/*----------------------- SizeAndShowWindows -------------------------*/
/* */
/* SIZE AND SHOW ALL WINDOWS AT THE SAME TIME. */
/* */
/* PARMS: anchor block handle */
/* */
/* NOTES: */
/* */
/* RETURNS: TRUE or FALSE if successful or not */
/* */
/*--------------------------------------------------------------------*/
/**********************************************************************/
BOOL SizeAndShowWindows( HAB hab )
{
SWP aswp[ 2 ];
BOOL fSuccess;
LONG cxDesktop = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
LONG cyDesktop = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
memset( &aswp, 0, sizeof aswp );
// Set the windows up so they are on the left and right halves of the
// display. The debug window will be on the top third of the display and
// the container window will be on the bottom third of the display.
// Left-hand 'drag' container window
aswp[ 0 ].hwnd = hwndDrag;
aswp[ 0 ].x = 0;
aswp[ 0 ].y = 0;
aswp[ 0 ].cx = cxDesktop / 2;
aswp[ 0 ].cy = cyDesktop / 3;
aswp[ 0 ].hwndInsertBehind = HWND_TOP;
aswp[ 0 ].fl = SWP_MOVE | SWP_SIZE | SWP_SHOW | SWP_ACTIVATE | SWP_ZORDER;
// Right-hand 'drop' container window
aswp[ 1 ].hwnd = hwndDrop;
aswp[ 1 ].x = cxDesktop / 2;
aswp[ 1 ].y = 0;
aswp[ 1 ].cx = cxDesktop / 2;
aswp[ 1 ].cy = cyDesktop / 3;
aswp[ 1 ].fl = SWP_MOVE | SWP_SIZE | SWP_SHOW;
fSuccess = WinSetMultWindowPos( hab, aswp, 2 );
if( fSuccess )
{
// The container was set up as the client window of the frame. We
// need to set focus to it - otherwise it will not accept keystrokes
// right away.
WinSetFocus( HWND_DESKTOP,
WinWindowFromID( hwndDrag, FID_CLIENT ) );
}
return fSuccess;
}
/**********************************************************************/
/*---------------------------- ProgTerm ------------------------------*/
/* */
/* PERFORM TERMINATION PROCESSING FOR THIS PROGRAM. */
/* */
/* PARMS: nothing */
/* */
/* NOTES: */
/* */
/* RETURNS: nothing */
/* */
/*--------------------------------------------------------------------*/
/**********************************************************************/
void ProgTerm()
{
if( hwndDrag )
WinDestroyWindow( hwndDrag );
if( hwndDrop )
WinDestroyWindow( hwndDrop );
if( hptrCnrRec )
WinDestroyPointer( hptrCnrRec );
DeleteTempFiles();
}
/**********************************************************************/
/*------------------------- DeleteTempFiles --------------------------*/
/* */
/* DELETE THE TEMPORARY FILES USED BY THIS PROGRAM. */
/* */
/* PARMS: nothing */
/* */
/* NOTES: These temporary files are created in the current directory */
/* and inserted into the 'drag' container. They are zero- */
/* length files. */
/* */
/* RETURNS: nothing */
/* */
/*--------------------------------------------------------------------*/
/**********************************************************************/
void DeleteTempFiles()
{
FILEFINDBUF3 ffb;
HDIR hdir = HDIR_SYSTEM;
ULONG cFiles = 1;
char szTempFileSpec[ CCHMAXPATH ];
APIRET rc;
strcpy( szTempFileSpec, BASE_TEMPFILE_NAME );
strcat( szTempFileSpec, ".*" );
rc = DosFindFirst( szTempFileSpec, &hdir, FILE_NORMAL,
&ffb, sizeof ffb, &cFiles, FIL_STANDARD );
while( !rc )
{
DosDelete( ffb.achName );
rc = DosFindNext( hdir, &ffb, sizeof ffb, &cFiles );
}
}
/**********************************************************************/
/*---------------------------- DragError -----------------------------*/
/* */
/* PROCESS A DM_DRAGERROR MESSAGE. */
/* */
/* PARMS: error code, */
/* operation that error occured on, */
/* HSTR that contains the dragged filename */
/* */
/* NOTES: PM sends this to a drag/drop window if a file operation */
/* failed. */
/* */
/* RETURNS: reply */
/* */
/*--------------------------------------------------------------------*/
/**********************************************************************/
MRESULT DragError( USHORT usError, USHORT usOperation, HSTR hstrFile )
{
ULONG cbMsg;
APIRET rc;
char szFileName[ CCHMAXPATH ];
char szCPError[ 200 ];
char szOp[ 25 ];
int i;
// This error is generated if the file already exists in the current
// directory. It shouldn't be generated on a copy but it is - this is
// yet another bug in the DrgDragFiles protocol.
if( usError == ERROR_ACCESS_DENIED || usError == ERROR_SHARING_VIOLATION )
return (MRESULT) DME_REPLACE;
*szOp = 0;
memset( szCPError, 0, sizeof szCPError );
rc = DosGetMessage( NULL, 0, szCPError, sizeof szCPError, usError,
"OSO001.MSG", &cbMsg );
if( rc == ERROR_MR_MID_NOT_FOUND )
DosGetMessage( NULL, 0, szCPError, sizeof szCPError, usError,
"OSO001H.MSG", &cbMsg );
DrgQueryStrName( hstrFile, sizeof szFileName, szFileName );
for( i = 0; i < OP_TYPES; i++ )
if( ocOperation[ i ].i == usOperation )
{
strcpy( szOp, ocOperation[ i ].sz );
break;
}
Msg( "Drag of %s failed on a '%s' operation with a return code of %u. This "
"return code means: %s", szFileName, szOp, usError, szCPError );
return (MRESULT) DME_IGNOREABORT;
}
/**********************************************************************/
/*------------------------------- Msg --------------------------------*/
/* */
/* DISPLAY A MESSAGE TO THE USER. */
/* */
/* PARMS: a message in printf format with its parms */
/* */
/* NOTES: */
/* */
/* RETURNS: nothing */
/* */
/*--------------------------------------------------------------------*/
/**********************************************************************/
void Msg( PSZ szFormat,... )
{
PSZ szMsg;
va_list argptr;
szMsg = (PSZ) malloc( MESSAGE_SIZE );
if( szMsg )
{
va_start( argptr, szFormat );
vsprintf( szMsg, szFormat, argptr );
va_end( argptr );
szMsg[ MESSAGE_SIZE - 1 ] = 0;
WinAlarm( HWND_DESKTOP, WA_WARNING );
WinMessageBox( HWND_DESKTOP, HWND_DESKTOP, szMsg,
"Container Drag/Drop Sample Program", 1,
MB_OK | MB_MOVEABLE );
free( szMsg );
}
else
{
DosBeep( 1000, 1000 );
return;
}
}
/*************************************************************************
* E N D O F S O U R C E *
*************************************************************************/