Project source
Form source (Pascal)
Form source (DFM)
Project source: uoSource.dpr |
program uoSource; {Test application for UnitOOPS OLE Drag and Drop Components. The name is intentionally kept short as DDE server application names appear to be limited to 8 characters. In fmDDELinkTest.pas, the DDE links are constructed so that you can rename this server to whatever you like, i.e., the name is not hard-coded. Last modified: 11/27/98} uses Forms, fmDDELinkTest in 'fmDDELinkTest.pas' {Form1}; {$R *.RES} begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end.Back to top |
Form source: fmDDELinkTest.pas |
unit fmDDELinkTest; { UnitOOPS OLE Drag and Drop Components - Example for dragging auto-updating DDE fields to MS Word. Works around problems with using the DDEAUTO field in NT4 pre-SP4 versions by using the DDE field combined with OLE automation to update the field. Last modified: 11/27/98} interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, uoole, DdeMan, ExtCtrls, ComCtrls; type TForm1 = class(TForm) UOTextSource1: TUOTextSource; Panel1: TPanel; Button2: TButton; uoTestItem: TDdeServerItem; uoTestServer: TDdeServerConv; Panel2: TPanel; Label1: TLabel; Memo1: TMemo; Panel4: TPanel; Timer1: TTimer; uoTime: TDdeServerItem; Label2: TLabel; Label3: TLabel; CheckBox1: TCheckBox; procedure FormCreate(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Panel1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure UOTextSource1BeforeDrop(Sender: TObject; Donor: TComponent; var dropText: String; var cancelDrop: Boolean); procedure Timer1Timer(Sender: TObject); private { Private declarations } procedure UpdateDDEItemText; public { Public declarations } end; var Form1: TForm1; {$R *.dfm} implementation uses ShellAPI, ComObj, ActiveX; procedure TForm1.FormCreate(Sender: TObject); begin Panel4.Caption := FormatDateTime(longTimeFormat, now); UpdateDDEItemText; end; procedure TForm1.UpdateDDEItemText; // Update the DDE Server items. Word has 2 different DDE macros: // DDE, which inserts a non-updating field (you have to update the // field by pressing F9 to pick up changes) or DDEAUTO which insearts // an auto-updating field. Due to some buggy behavior of Word in // NT4/SP3 and earlier (but reportedly fixed in SP4), the auto-updating // DDE connection breaks almost immediately, making it unacceptable for // end-user deployment. (The same works as designed in Excel, etc). // Here, we work around this by a) inserting DDE rather than DDEAUTO // fields (see, e.g., TForm1.Panel1MouseDown, below) and b) "pressing F9" // (i.e., updating the Word document fields) using OLE automation. var msword: variant; activeWindow: variant; begin // Give each DDE Server item its new value. uoTestItem.Text := Memo1.Lines.Text; uoTime.Text := Panel4.Caption; // Now, update the fields in the MSWord document. This is the simplest // possible implementation, and it only updates the fields in the active // document. // Any of the following calls could fail (e.g., Word not running, no // active window, etc), in which case an EOleSysError exception will be // thrown. Handle this error condition silently. try // Get the open MSWord instance, if any. msword := GetActiveOleObject('Word.Application'); // Get the active window. activewindow := msword.Activewindow; // Update all fields in the document in the active window activeWindow.Document.Fields.Update; except // Silently handle OLE exceptions without showing them to the user on EOleSysError do; end; end; procedure TForm1.Button2Click(Sender: TObject); begin // Update the Word fields now (don't wait for timer). UpdateDDEItemText; end; procedure TForm1.Panel1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); // Shared handler for the OnMouseDown event of both Panel1 and Panel4, each // of which initiates a drag. Hint: In applications where you're setting the // TUOTextSource.Text property explicitly (i.e., where you don't have a // DonorComponent), you typically only need one of them, since only a single // drag can happen at a time. var sItem: string; begin // Start the drag if DragDetect((Sender as TWinControl).Handle, POINT(X, Y)) then begin // For Panel1, we drag the text. For Panel4, we drag the time. if (Sender = Panel1) then sItem := uoTestItem.Name else sItem := uoTime.Name; with UOTextSource1 do begin // Clear the custom format data array CustomFormatData.Clear; // Add the custom format to allow dragging RTF. We drag the RTF that // inserts a DDE field into Word. NOT a DDEAUTO, since they don't work // right in NT prior to SP4 - just a DDE, and we'll update as necessary // later using OLE automation. CustomFormatData.AddFormat('Rich Text Format', Format('{\field{\*\fldinst { DDE %s %s %s \\* MERGEFORMAT }}}', [ChangeFileExt(ExtractFilename(Application.ExeName), ''), // DDE Server name uoTestServer.Name, // DDE Topic - same for both items on the form sItem // Item = name of item component ])); // If the drop is successful, we need to update the DDE item if Execute then UpdateDDEItemText; end; // with end; end; procedure TForm1.UOTextSource1BeforeDrop(Sender: TObject; Donor: TComponent; var dropText: String; var cancelDrop: Boolean); // The drop is about to happen. Cancel if we're not over a MSWord // document window. const WordWindowClassName = '_WwG'; // window class for Word editing window var aPt: TPoint; aHWnd: HWnd; S: string; begin // See what's immediately under the mouse, and // if it's not Word, cancel the drop. GetCursorPos(aPt); // Where are we? aHWnd := WindowFromPoint(aPt); // What's underneath? SetLength(s, 255); GetClassName(aHWnd, PChar(s), 255); // Get its class name SetLength(s, StrLen(PChar(s))); // Cancel the drop if not Word cancelDrop := (AnsiCompareText(s, WordWindowClassName) <> 0); end; procedure TForm1.Timer1Timer(Sender: TObject); // Handle a tick of the timer var aDt: TDateTime; h, m, s, ms: word; begin aDt := now; // Update the time caption every tick (1 second) Panel4.Caption := FormatDateTime(longTimeFormat, aDt); // Only update the live (Word) timers every 10 seconds DecodeTime(aDt, h, m, s, ms); if CheckBox1.Checked and ((s mod 10) = 0) then UpdateDDEItemText; end; initialization OleInitialize(nil); finalization OleUninitialize; end.Back to top |
Form source: fmDDELinkTest.dfm |
object Form1: TForm1 Left = 295 Top = 246 BorderStyle = bsDialog Caption = 'Test of dragging a live DDE link to MS Word' ClientHeight = 254 ClientWidth = 436 Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object Label3: TLabel Left = 208 Top = 56 Width = 136 Height = 13 Caption = '...to link the text in this memo' end object Panel1: TPanel Left = 8 Top = 56 Width = 185 Height = 89 BorderWidth = 10 Caption = 'Drag from here to Word...' TabOrder = 0 OnMouseDown = Panel1MouseDown end object Button2: TButton Left = 216 Top = 184 Width = 169 Height = 25 Caption = 'Update Word fields now' TabOrder = 1 OnClick = Button2Click end object Panel2: TPanel Left = 0 Top = 0 Width = 436 Height = 41 Align = alTop BevelOuter = bvNone BorderWidth = 3 Caption = 'Panel2' TabOrder = 2 object Label1: TLabel Left = 3 Top = 3 Width = 430 Height = 35 Align = alClient Caption = 'Drag from either of the left-hand panels to Word to get a live D' + 'DE link. Check the checkbox to get automatic updates (both text' + ' and time) every 10 seconds.' WordWrap = True end end object Memo1: TMemo Left = 208 Top = 72 Width = 220 Height = 73 Lines.Strings = ( 'testing 1, 2, 3...' 'testing 1, 2, 3...') TabOrder = 3 end object Panel4: TPanel Left = 8 Top = 157 Width = 185 Height = 89 Caption = 'time' Font.Charset = ANSI_CHARSET Font.Color = clRed Font.Height = -19 Font.Name = 'Arial' Font.Style = [fsItalic] ParentFont = False TabOrder = 4 OnMouseDown = Panel1MouseDown object Label2: TLabel Left = 1 Top = 1 Width = 183 Height = 26 Align = alTop Alignment = taCenter Caption = 'Drag this time to MS Word for 10-second updates' Font.Charset = ANSI_CHARSET Font.Color = clBlack Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] ParentFont = False WordWrap = True end end object CheckBox1: TCheckBox Left = 216 Top = 160 Width = 201 Height = 17 Caption = 'Automatic update every 10 seconds' State = cbChecked TabOrder = 5 end object UOTextSource1: TUOTextSource OnBeforeDrop = UOTextSource1BeforeDrop DropEffects = [deCopy] Left = 16 Top = 32 end object uoTestItem: TDdeServerItem ServerConv = uoTestServer Left = 192 Top = 32 end object uoTestServer: TDdeServerConv Left = 112 Top = 32 end object Timer1: TTimer OnTimer = Timer1Timer Left = 72 Top = 32 end object uoTime: TDdeServerItem ServerConv = uoTestServer Left = 152 Top = 32 end endBack to top |