home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / Pascal / BPASCAL.700 / D12 / SHELLDEM.ZIP / SHELLDEM.PAS next >
Encoding:
Pascal/Delphi Source File  |  1992-10-01  |  10.6 KB  |  358 lines

  1. {***************************************************}
  2. {                                                   }
  3. {   Windows 3.1 ShellAPI / Drag-and-Drop            }
  4. {   Demonstration Program                           }
  5. {   Copyright (c) 1992 by Borland International     }
  6. {                                                   }
  7. {***************************************************}
  8.  
  9. program ShellDemo;
  10.  
  11. {
  12.  This demo program implements a simple program-manager type application
  13.  using Drag & Drop and the SHELL API calls.
  14.  
  15.  Open this program on the Windows 3.1 desktop, and then drag files from the
  16.  File Manager onto this application's window.  The dropped-in files will 
  17.  appear as Icons in the window's client area, and double-clicking on those
  18.  Icons will execute the corresponding program.
  19. }
  20.  
  21. uses Strings, WinTypes, WinProcs, OWindows, ODialogs, Win31, ShellAPI, BWCC;
  22.  
  23. {$R SHELLDEM}
  24.  
  25. const
  26.  
  27. { Resource IDs }
  28.  
  29.   id_Menu  = 100;
  30.   id_About = 100;
  31.   id_Instr = 101;   { Instructions }
  32.   id_Icon  = 100;
  33.  
  34. { Menu command IDs }
  35.  
  36.   cm_HelpAbout = 300;
  37.   cm_HelpInstr = 301;
  38.  
  39. type
  40.  
  41. { Filename string }
  42.  
  43.   TFilename = array[0..255] of Char;
  44.  
  45. { Application main window }
  46.  
  47.   PDropTargetWin = ^TDropTargetWin;
  48.   TDropTargetWin = object(TWindow)
  49.     destructor Done; virtual;
  50.  
  51.     procedure GetWindowClass(var AWndClass: TWndClass); virtual;
  52.     function  GetClassName: PChar; virtual;
  53.     procedure SetupWindow; virtual;
  54.  
  55.     procedure WMDropFiles(var Msg: TMessage);
  56.       virtual wm_First + wm_DropFiles;
  57.  
  58.     procedure CMHelpAbout(var Msg: TMessage);
  59.       virtual cm_First + cm_HelpAbout;
  60.     procedure CMHelpInstructions(var Msg: TMessage);
  61.       virtual cm_First + cm_HelpInstr;
  62.  
  63. { Override this function in descendant classes to change behavior: }
  64.  
  65.     procedure DropAFile(FileName: PChar; DropX, DropY: Integer); virtual;
  66.   end;
  67.  
  68. { Icon Window }
  69.  
  70.   PIconWindow = ^TIconWindow;
  71.   TIconWindow = object(TWindow)
  72.     AppIcon   : HIcon;
  73.     HasOwnIcon: Boolean;  { True if icon found, False if default used }
  74.     Path      : PChar;
  75.     X, Y      : Integer;
  76.  
  77.     constructor Init(AParent: PWindowsObject; ATitle: PChar; DropX, DropY: Integer);
  78.     destructor  Done; virtual;
  79.  
  80.     procedure Paint(PaintDC: HDC; var PaintInfo: TPaintStruct); virtual;
  81.     procedure GetWindowClass(var AWndClass: TWndClass); virtual;
  82.     function  GetClassName: PChar; virtual;
  83.  
  84.     procedure WMQueryDragIcon(var Msg: TMessage);
  85.       virtual wm_First + wm_QueryDragIcon;
  86.     procedure WMQueryOpen(var Msg: TMessage);
  87.       virtual wm_First + wm_QueryOpen;
  88.     procedure WMSysCommand(var Msg: TMessage);
  89.       virtual wm_First + wm_SysCommand;
  90.   end;
  91.  
  92. { Application object }
  93.  
  94.   TShellApp = object(TApplication)
  95.     procedure InitMainWindow; virtual;
  96.   end;
  97.  
  98. { Initialized globals }
  99.  
  100. const
  101.   DemoTitle: PChar = 'Shell Demo Program';
  102.  
  103. { Global variables }
  104.  
  105. var
  106.   App: TShellApp;
  107.  
  108.  
  109. { TIconWindow Methods }
  110.  
  111. { Constructs an instance of an IconWindow.  These are child windows to the
  112.   main ShellAPI window which represent dropped files.  IconWindows always
  113.   represent themselves as Iconic.  The Icon to be used is extracted from
  114.   the application (as represented by its Title); if none can be found, the
  115.   idi_Question icon is used.  The IconWindow positions itself at the given
  116.   location.
  117. }
  118. constructor TIconWindow.Init(AParent: PWindowsObject; ATitle: PChar; DropX, DropY: Integer);
  119. var
  120.   FileName: PChar;
  121.   Temp    : TFilename;
  122.   ExeHdl  : THandle;
  123. begin
  124.   TWindow.Init(AParent, ATitle);
  125.   Attr.Style := Attr.Style or (ws_Minimize or ws_Child);
  126.  
  127. { Set the Path data field to the full pathname for later use in executing
  128.   the program.  The passed-in title contains the complete path name of the
  129.   file, which we just copy.  Then, strip off just the filename portion, and
  130.   use that as the actual title for the icon.
  131. }
  132.   Path    := StrNew(ATitle);
  133.   FileName:= StrRScan(Path, '\');
  134.  
  135.   if FileName <> nil then
  136.     SetCaption(@FileName[1]);  { Skip past the '\' }
  137.  
  138. { Extract an Icon from the executable file.  If none is found, then just
  139.   use idi_Question.
  140. }
  141.   ExeHdl := FindExecutable(Path, '.\', Temp);
  142.  
  143.   if ExeHdl <= 32 then
  144.     AppIcon := 0
  145.   else
  146.     AppIcon := ExtractIcon(HInstance, Temp, 0);
  147.  
  148.   if AppIcon <= 1 then
  149.   begin
  150.     AppIcon   := LoadIcon(0, idi_Question);
  151.     HasOwnIcon:= True;
  152.   end
  153.   else
  154.     HasOwnIcon:= False;
  155.  
  156. { Set the x/y position of drop (in Parent coordinates).  This is
  157.   not used in this demo app, but is included to support variations
  158.   through writing descendants.
  159. }
  160.   X := DropX;
  161.   Y := DropY;
  162. end;
  163.  
  164. { Destroys an instance of the IconWindow.  Frees the AppIcon (unless the
  165.   standard idi_Question was used), and disposes of the Path name string.
  166. }
  167. destructor TIconWindow.Done;
  168. begin
  169.   if HasOwnIcon then
  170.     FreeResource(AppIcon);
  171.   StrDispose(Path);
  172.   TWindow.Done;
  173. end;
  174.  
  175. { Redefines GetWindowClass to give this application a NULL Icon.  This
  176.   is necessary so that Windows gives this application a chance to paint
  177.   its own icon when the window is Iconic.  When the hIcon field of AWndClass
  178.   is NULL, this window will receive wm_QueryDragIcon messages.
  179. }
  180. procedure TIconWindow.GetWindowClass(var AWndClass: TWndClass);
  181. begin
  182.   TWindow.GetWindowClass(AWndClass);
  183.   AWndClass.hIcon := 0;
  184. end;
  185.  
  186. { Returns the class name of this window.  This is necessary since we
  187.   redefine the inherited GetWindowClass method, above.
  188. }
  189. function TIconWindow.GetClassName: PChar;
  190. begin
  191.   GetClassName := 'TIconWindow';
  192. end;
  193.  
  194. { Responds to double-clicks on the Icon by executing the associated program.
  195.   Windows sends an iconified window a wm_QueryOpen message when
  196.   double-clicked. Overriding here allows us to completely redefine that
  197.   behavior. Uses the Path data field as the name of the program to execute.
  198. }
  199. procedure TIconWindow.WMQueryOpen(var Msg: TMessage);
  200. begin
  201.   ShellExecute(HWindow, nil, Path, '', '.\', sw_ShowNormal);
  202.  
  203.   Msg.Result := 0;  { Indicate that the message was handled }
  204. end;
  205.  
  206. { Returns the application's icon when the iconified window is dragged.  With
  207.   AWndClass.hIcon set to NULL, Windows asks for this whenever the drag is 
  208.   about to happen.
  209. }
  210. procedure TIconWindow.WMQueryDragIcon(var Msg: TMessage);
  211. begin
  212.   Msg.Result := AppIcon;
  213. end;
  214.  
  215. { Captures and filters out some variations on wm_SysCommand to prevent an
  216.   annoying 'beep' on single clicks on the icon.
  217. }
  218. procedure TIconWindow.WMSysCommand(var Msg: TMessage);
  219. begin
  220.   case (Msg.WParam and $FFF0) of
  221.     sc_MouseMenu: Msg.Result := 0;   { Indicate that the message was handled }
  222.     sc_KeyMenu  : Msg.Result := 0;
  223.   else
  224.     DefWndProc(Msg);
  225.   end;
  226. end;
  227.  
  228. { Responds to repaints of the window when requested.  With AWndClass.hIcon
  229.   set to NULL, Windows will let the window paint itself even when iconic.
  230.   NOTE that this is the 'new' way to draw you own icon, as opposed to 
  231.   wm_PaintIcon in Win3.0.
  232. }
  233. procedure TIconWindow.Paint(PaintDC: HDC; var PaintInfo: TPaintStruct);
  234. begin
  235.   DefWindowProc(HWindow, wm_IconEraseBkgnd, PaintDC, 0);
  236.   DrawIcon(PaintDC, 0, 0, AppIcon);
  237. end;
  238.  
  239.  
  240. { TDropTargetWin Methods }
  241.  
  242. { Destroys an instance of the Drop Target window.  Informs Windows that
  243.   this application will no longer accept Drop-File requests, then invokes
  244.   the ancestral destructor to complete the shutdown of the window.
  245. }
  246. destructor TDropTargetWin.Done;
  247. begin
  248.   DragAcceptFiles(HWindow, False);
  249.   TWindow.Done;
  250. end;
  251.  
  252. { Redefines GetWindowClass to give this application its own Icon, and
  253.   to identify the menu for this application.
  254. }
  255. procedure TDropTargetWin.GetWindowClass(var AWndClass: TWndClass);
  256. begin
  257.   TWindow.GetWindowClass(AWndClass);
  258.   AWndClass.hIcon        := LoadIcon(AWndClass.hInstance, MakeIntResource(id_Icon));
  259.   AWndClass.lpszMenuName := MakeIntResource(id_Menu);
  260.   AWndClass.hBrBackground:= GetStockObject(LtGray_Brush);
  261. end;
  262.  
  263. { Returns the class name of this window.  This is necessary since we
  264.   redefine the inherited GetWindowClass method, above.
  265. }
  266. function TDropTargetWin.GetClassName: PChar;
  267. begin
  268.   GetClassName := 'TDropTargetWin';
  269. end;
  270.  
  271. { Completes the initialization of the Icon window, by informing Windows
  272.   that this window will accept Drop-File requests.  This is deferred to
  273.   SetupWindow since it requires a valid window handle.  Note that
  274.   Shell.dll will flip the ws_Ex_AcceptFiles style bit for this window.
  275.  
  276.   Also posts the Instructions dialog automatically upon startup.
  277. }
  278. procedure TDropTargetWin.SetupWindow;
  279. begin
  280.   TWindow.SetupWindow;
  281.   DragAcceptFiles(HWindow, True);
  282.  
  283.   PostMessage(HWindow, wm_Command, cm_HelpInstr, 0);
  284. end;
  285.  
  286. { Responds to the dropping of a file onto this window.  Obtains the
  287.   dropped in file name(s), then calls the DropAFile method for each 
  288.   dropped file name.  The actual handling of the dropped file happens
  289.   there; it is separated from this method for ease of redefinition by
  290.   descendants.
  291. }
  292. procedure TDropTargetWin.WMDropFiles(var Msg: TMessage);
  293. var
  294.   DropPt     : TPoint;
  295.   hDrop      : THandle;
  296.   NumDropped : Integer;
  297.   DroppedName: TFilename;
  298.   I          : Integer;
  299. begin
  300.   hDrop := Msg.WParam;
  301.   DragQueryPoint(hDrop, DropPt);
  302.  
  303. { By passing in exactly these parameters, we get the number of files
  304.   (and directories) being dropped.
  305. }
  306.   NumDropped := DragQueryFile(hDrop, Word(-1), nil, 0);
  307.  
  308. { This time we pass in the 'real' parameters and SHELL.DLL will fill
  309.   in the path to the file (or directory).  Do so for each dropped file.
  310. }
  311.   for I := 0 to NumDropped-1 do
  312.   begin
  313.     DragQueryFile(hDrop, I, DroppedName, SizeOf(DroppedName));
  314.     DropAFile(DroppedName, DropPt.X, DropPt.Y);
  315.   end;
  316.  
  317.   DragFinish(hDrop);
  318. end;
  319.  
  320. { Actually handles the dropping of a file at a given point, by creating the
  321.   TIconWindow to represent that file.  Descendant classes can alter the be-
  322.   havior of this application by simply redefining this method.
  323. }
  324. procedure TDropTargetWin.DropAFile(FileName: PChar; DropX, DropY: Integer);
  325. begin
  326.   Application^.MakeWindow(New(PIconWindow, Init(@Self, FileName, DropX, DropY)));
  327. end;
  328.  
  329. { Posts the About Box for the Shell API Demo.
  330. }
  331. procedure TDropTargetWin.CMHelpAbout(var Msg: TMessage);
  332. begin
  333.   Application^.ExecDialog(New(PDialog, Init(@Self, PChar(id_About))));
  334. end;
  335.  
  336. { Posts the Instructions Box for the Shell API Demo.
  337. }
  338. procedure TDropTargetWin.CMHelpInstructions(var Msg: TMessage);
  339. begin
  340.   Application^.ExecDialog(New(PDialog, Init(@Self, PChar(id_Instr))));
  341. end;
  342.  
  343.  
  344. { TShellApp Methods }
  345.  
  346. procedure TShellApp.InitMainWindow;
  347. begin
  348.   MainWindow := New(PDropTargetWin, Init(nil, Application^.Name));
  349. end;
  350.  
  351. { Main program }
  352.  
  353. begin
  354.   App.Init(DemoTitle);
  355.   App.Run;
  356.   App.Done;
  357. end.
  358.