From: "Jill Marquiss"
This answers those really interesting questions of{--------------------Straight from the type library--------------- WORDDEC.INC} Const // OlAttachmentType olByValue = 1; olByReference = 4; olEmbeddedItem = 5; olOLE = 6; // OlDefaultFolders olFolderDeletedItems = 3; olFolderOutbox = 4; olFolderSentMail = 5; olFolderInbox = 6; olFolderCalendar = 9; olFolderContacts = 10; olFolderJournal = 11; olFolderNotes = 12; olFolderTasks = 13; // OlFolderDisplayMode olFolderDisplayNormal = 0; olFolderDisplayFolderOnly = 1; olFolderDisplayNoNavigation = 2; // OlInspectorClose olSave = 0; olDiscard = 1; olPromptForSave = 2; // OlImportance olImportanceLow = 0; olImportanceNormal = 1; olImportanceHigh = 2; // OlItems olMailItem = 0; olAppointmentItem = 1; olContactItem = 2; olTaskItem = 3; olJournalItem = 4; olNoteItem = 5; olPostItem = 6; // OlSensitivity olNormal = 0; olPersonal = 1; olPrivate = 2; olConfidential = 3; // OlJournalRecipientType; olAssociatedContact = 1; // OlMailRecipientType; olOriginator = 0; olTo = 1; olCC = 2; olBCC = 3 ; Const wdGoToBookmark = -1; wdGoToSection = 0; wdGoToPage = 1; wdGoToTable = 2; wdGoToLine = 3; wdGoToFootnote = 4; wdGoToEndnote = 5; wdGoToComment = 6; wdGoToField = 7; wdGoToGraphic = 8; wdGoToObject = 9; wdGoToEquation = 10; wdGoToHeading = 11; wdGoToPercent = 12; wdGoToSpellingError = 13; wdGoToGrammaticalError = 14; wdGoToProofreadingError = 15; wdGoToFirst = 1; wdGoToLast = -1; wdGoToNext = 2; //this is interesting wdGoToRelative = 2; //how can these two be the same wdGoToPrevious = 3; wdGoToAbsolute = 1;
Function GetWordUp(StartType : string):Boolean; Function InsertPicture(AFileName : String) : Boolean; Function InsertContactInfo(MyId : TMyId; MyContId : TMyContId): Boolean; Function GetOutlookUp(ItemType : Integer): Boolean; Function MakeOutLookContact(MyId : TMyId; MyContId : TMyContId) : Boolean; Function ImportOutlookContact : Boolean; Function GetOutlookFolderItemCount : Integer; Function GetThisOutlookItem(AnIndex : Integer) : Variant; Function FindMyOutlookItem(AFilter : String; var AItem : Variant) :Boolean; Function FindNextMyOutlookItem(var AItem : Variant) : Boolean; Function CloseOutlook : Boolean; Type TTreeData = class(TObject) Public ItemId : String; end;
{$I worddec.inc} {literal crap translated from type libraries} Var myRegistry : TRegistry; GotWord : Boolean; WhereIsWord : String; WordDoneMessage : Integer; Basically : variant; Wordy: Variant; MyDocument : Variant; MyOutlook : Variant; MyNameSpace : Variant; MyFolder : Variant; MyAppointment : Variant; Function GetWordUp(StartType : string):Boolean; // to start word the "right" way for me // if you start word, you own word and I wanted it to remain after I closed var i : integer; AHwnd : Hwnd; AnAnswer : Integer; temp : string; MyDocumentsCol : Variant; TemplatesDir : Variant; OpenDialog1 : TopenDialog; begin result := false; myRegistry := Tregistry.Create; myRegistry.RootKey := HKEY_LOCAL_MACHINE; // no word 8, no function If myRegistry.KeyExists('SOFTWARE\Microsoft\Office\8.0\Word') then GotWord := true Else GotWord := false; If GotWord then //where the heck is it? If myRegistry.OpenKey('SOFTWARE\Microsoft\Office\8.0', false) then begin WhereisWord := myRegistry.ReadString('BinDirPath'); MyRegistry.CloseKey; end else GotWord := false; If GotWord then //where are those pesky templates? Begin MyRegistry.RootKey := HKEY_CURRENT_USER; If myRegistry.OpenKey('SOFTWARE\Microsoft\Office\8.0\Common\FileNew\SharedTemplates', false) then Begin TemplatesDir := myRegistry.ReadString(Nothing); MyRegistry.CloseKey; end Else Begin Warning('Ole setup','The workgroup templates have not been setup'); GotWord := false; end; End; myRegistry.free; If not gotword then Begin Warning('Ole Handler', 'Word is not installed'); exit; end; //this is the class name for the last two versions of word's main window temp := 'OpusApp'; AHwnd := FindWindow(pchar(temp),nil); If (AHwnd = 0) then //it isn't running and I don't wanna start it by automation Begin Temp := WhereisWord + '\winword.exe /n'; AnAnswer := WinExec(pchar(temp), 1); If (AnAnswer < 32) then Begin Warning('Ole Handler', 'Unable to find WinWord.exe'); Exit; End; End; Application.ProcessMessages; {If you use Word.Application, you get your own instance} {If you use Word.Document, you get the running instance} {this makes a trash document (for me, anyway) and I chuck it out later} try {and make a new document} Basically := CreateOleObject('Word.Document.8'); except Warning('Ole Handler', 'Could not start Microsoft Word.'); Result := False; Exit; end; Try {get the app variant from that new document} Wordy := Basically.Application; Except Begin Warning('Ole Handler', 'Could not access Microsoft Word.'); Wordy := UnAssigned; Basically := UnAssigned; Exit; end; end; Application.ProcessMessages; Wordy.visible := false; MyDocumentsCol := Wordy.Documents; {If its just my throw away document or I wanted a brand new one} If (MyDocumentsCol.Count = 1) or (StartType = 'New') then Begin OpenDialog1 := TOpenDialog.Create(Application); OpenDialog1.filter := 'WordTemplates|*.dot|Word Documents|*.doc'; OpenDialog1.DefaultExt := '*.dot'; OpenDialog1.Title := 'Select your template'; OpenDialog1.InitialDir := TemplatesDir; If OpenDialog1.execute then Begin Wordy.ScreenUpdating:= false; MyDocumentsCol := wordy.Documents; MyDocumentsCol.Add(OpenDialog1.Filename, False); OpenDialog1.free; end Else begin OpenDialog1.Free; Wordy.visible := true; Wordy := Unassigned; Basically := Unassigned; Exit; end; end Else {get rid of my throwaway} MyDocument.close(wdDoNotSaveChanges); {now I either have a new document based on a template the user selected or I have their current document} MyDocument := Wordy.ActiveDocument; Result := true; Application.ProcessMessages; end; Function InsertPicture(AFileName : String) : Boolean; var MyShapes : Variant; MyRange : variant; begin Result := True; If GetWordUp('Current')then Try Begin MyRange := MyDocument.Goto(wdgotoline, wdgotolast); MyRange.EndOf(wdParagraph, wdMove); MyRange.InsertBreak(wdPageBreak); MyShapes := MyDocument.InlineShapes; MyShapes.AddPicture(afilename, false, true, MyRange); end; Finally begin Wordy.ScreenUpdating:= true; Wordy.visible := true; Wordy := Unassigned; Basically := UnAssigned; Application.ProcessMessages; end; end else Result := False; end; Function InsertContactInfo(MyId : TMyId; MyContId : TMyContId) : Boolean; var MyCustomProps : Variant; begin { personally, I store stuff in document properties and then give out a toolbar macro to allow the user to "set" the properties in their template or current document. this has three advantages that I know of (and no defects that I'm aware of) 1. The user can place the location of the info in the document either before or after this function runs 2. A custom property can be placed any number of times inside the same document 3. A user can map the properties in their Outlook or search on them using that abismal file open in Word} Result := true; If GetWordUp('New')then Try Begin MyCustomProps := MyDocument.CustomDocumentProperties; MyCustomProps.add(cpId, false, msoPropertyTypeString, MyId.Id); MyCustomProps.add(cpOrganizationName, false, msoPropertyTypeString, MyId.OrganizationName); MyCustomProps.add(cpAddress1, false, msoPropertyTypeString,MyId.Address1); MyCustomProps.add(cpAddress2, false, msoPropertyTypeString, MyId.Address2); MyCustomProps.add(cpCity, false, msoPropertyTypeString, MyId.City); MyCustomProps.add(cpStProv, false, msoPropertyTypeString, MyId.StProv); MyCustomProps.add(cpCountry, false, msoPropertyTypeString,MyId.City); MyCustomProps.add(cpPostal, false, msoPropertyTypeString, MyId.Country); MyCustomProps.add(cpAccountId, false, msoPropertyTypeString, MyId.AccountId); MyCustomProps.add(cpFullName, false, msoPropertyTypeString, MyContId.FullName); MyCustomProps.add(cpSalutation, false, msoPropertyTypeString, MyContId.Salutation); MyCustomProps.add(cpTitle, false, msoPropertyTypeString,MyContId.Title); If (MyContId.workPhone = Nothing) or (MycontId.WorkPhone = ASpace) then MyCustomProps.add(cpPhone, false, msoPropertyTypeString, MyId.Phone ) else MyCustomProps.add(cpPhone, false, msoPropertyTypeString, MyContId.WorkPhone ); If (MyContId.Fax = Nothing) or (MycontId.Fax = ASpace) then MyCustomProps.add(cpFax, false, msoPropertyTypeString, MyId.Fax) else MyCustomProps.add(cpFax, false, msoPropertyTypeString,MyContId.Fax); If (MyContId.EMail = Nothing) or (MycontId.Email = ASpace) then MyCustomProps.add(cpEmail, false, msoPropertyTypeString, MyId.Email) else MyCustomProps.add(cpEmail, false, msoPropertyTypeString, MyContId.Email); MyCustomProps.add(cpFirstName, false, msoPropertyTypeString,MyContId.FirstName); MyCustomProps.add( cpLastName, false, msoPropertyTypeString, MyContId.LastName); MyDocument.Fields.Update; end; Finally begin Wordy.ScreenUpdating:= true; Wordy.visible := true; Wordy := Unassigned; Basically := UnAssigned; Application.ProcessMessages; end; end Else Result := false; end; Function GetOutlookUp(ItemType : Integer): Boolean; Const AppointmentItem = 'Calendar'; TaskItem = 'Tasks'; ContactItem = 'Contacts'; JournalItem = 'Journal'; NoteItem = 'Notes'; var MyFolders : Variant; MyFolders2 : variant; MyFolders3 : variant; MyFolder2 : Variant; MyFolder3 : variant; MyUser : Variant; MyFolderItems : Variant; MyFolderItems2 : Variant; MyFolderItems3 : Variant; MyContact : Variant; i, i2, i3 : Integer; MyTree : TCreateCont; MyTreeData : TTreeData; RootNode, MyNode, MyNode2 : ttreeNode; ThisName : String; Begin {this is really ugly........ There is some really wierd thing going on in the object model for outlook so excuse this folder.folder.folder stuff cause the "right way" doesn't work for folders and this does} {user picks folder from treeview} Result := False; Case ItemType of olAppointmentItem : ThisName := AppointmentItem; olContactItem : ThisName := ContactItem; olTaskItem : ThisName := TaskItem; olJournalItem : ThisName := JournalItem; olNoteItem : ThisName := NoteItem; Else ThisName := 'Unknown'; End; try MyOutlook := CreateOleObject('Outlook.Application'); except warning('Ole Interface','Could not start Outlook.'); Exit; end; {this is the root folder} MyNameSpace := MyOutlook.GetNamespace('MAPI'); MyFolderItems := MyNameSpace.Folders; MyTree := TCreateCont.create(Application); {Really unfortunate, but a user can create something other than the default folder for the kind of thing you're interested in - so this goes down a coupla levels in the folder chain} MyTree.Caption := 'Select ' + ThisName + ' Folder'; With MyTree do If MyFolderItems.Count > 0 then For i := 1 to MyFolderItems.Count do begin MyFolder := MyNameSpace.Folders(i); MyTreeData := TTreeData.create; MyTreeData.ItemId := MyFolder.EntryId; RootNode := TreeView1.Items.AddObject(nil, MyFolder.Name, MyTreeData); MyFolders2 := MyNameSpace.folders(i).Folders; If MyFolders2.Count > 0 then for i2 := 1 to MyFolders2.Count do begin MyFolder2 := MyNameSpace.folders(i).Folders(i2); If (MyFolder2.DefaultItemType = ItemType) or (MyFolder2.Name = ThisName) then Begin MyTreeData := TTreeData.create; MyTreeData.ItemId := MyFolder2.EntryId; {this is what you need to directly point at the folder} MyNode := Treeview1.Items.addChildObject(RootNode, MyFolder2.Name, MyTreeData); MyFolders3 := MyNameSpace.folders(i).Folders(i2).Folders; If MyFolders3.Count > 0 then for i3 := 1 to MyFolders3.Count do begin MyFolder3 := MyNameSpace.folders(i).Folders(i2).Folders(i3); If (MyFolder3.DefaultItemType = ItemType) then Begin MyTreeData := TTreeData.create; MyTreeData.ItemId := MyFolder3.EntryId; MyNode2 := Treeview1.Items.addChildObject(MyNode, MyFolder3.Name, MyTreeData); end; end; end; end; end; If MyTree.TreeView1.Items.Count = 2 then {there is only the root and my designated folder} MyFolder := MyNameSpace.GetFolderFromID(TTreeData(MyTree.TreeView1.Items[1].Data).ItemId ) Else begin MyTree.Treeview1.FullExpand; MyTree.ShowModal; If MyTree.ModalResult = mrOk then Begin If MyTree.Treeview1.Selected <> nil then MyFolder := MyNameSpace.GetFolderFromID(TTreeData(MyTree.Treeview1.Selected.Data).ItemId ); end else Begin MyOutlook := UnAssigned; For i:= MyTree.Treeview1.Items.Count -1 downto 0 do TTreeData(MyTree.Treeview1.Items[i].Data).free; MyTree.release; exit; end; end; For i:= MyTree.Treeview1.Items.Count -1 downto 0 do TTreeData(MyTree.Treeview1.Items[i].Data).free; MyTree.release; Result := true; end; Function MakeOutlookContact(MyId : TMyId; MyContId : TMyContId) : boolean; var MyContact : Variant; begin Result := false; If not GetOutlookUp(OlContactItem) then exit; MyContact := MyFolder.Items.Add(olContactItem); MyContact.Title := MyContId.Honorific; MyContact.FirstName := MyContId.FirstName; MyContact.MiddleName := MycontId.MiddleInit; MyContact.LastName := MycontId.LastName; MyContact.Suffix := MyContId.Suffix; MyContact.CompanyName := MyId.OrganizationName; MyContact.JobTitle := MyContId.Title; MyContact.OfficeLocation := MyContId.OfficeLocation; MyContact.CustomerId := MyId.ID; MyContact.Account := MyId.AccountId; MyContact.BusinessAddressStreet := MyId.Address1 + CRLF + MyId.Address2; MyContact.BusinessAddressCity := MyId.City; MyContact.BusinessAddressState := MyId.StProv; MyContact.BusinessAddressPostalCode := MyId.Postal; MyContact.BusinessAddressCountry := MyId.Country; If (MyContId.Fax = Nothing) or (MyContId.Fax = ASpace) then MyContact.BusinessFaxNumber := MyId.Fax Else MyContact.BusinessFaxNumber := MyContId.Fax; If (MyContId.WorkPhone = Nothing) or (MyContId.WorkPhone = ASpace) then MyContact.BusinessTelephoneNumber := MyId.Phone Else MyContact.BusinessTelephoneNumber := MyContId.WorkPhone; MyContact.CompanyMainTelephoneNumber := MyId.Phone; MyContact.HomeFaxNumber := MyContId.HomeFax; MyContact.HomeTelephoneNumber := MyContId.HomePhone; MyContact.MobileTelephoneNumber := MyContId.MobilePhone; MyContact.OtherTelephoneNumber := MyContId.OtherPhone; MyContact.PagerNumber := MyContId.Pager; MyContact.Email1Address := MyContId.Email; MyContact.Email2Address := MyId.Email; Result := true; Try MyContact.Save; Except Result := false; end; MyOutlook := Unassigned; end; Function GetThisOutlookItem(AnIndex : Integer) : Variant; Begin Result := myFolder.Items(AnIndex); end; Function GetOutlookFolderItemCount : Integer; Var myItems : Variant; Begin Try MyItems := MyFolder.Items; Except Begin Result := 0; exit; end; end; Result := MyItems.Count; end; Function FindMyOutlookItem(AFilter : String; var AItem : Variant) : Boolean; Begin {this is another real PAIN - nil variant} Result := true; Try AItem := myFolder.Items.Find(AFilter); Except Begin aItem := MyFolder; Result := false; end; End; End; Function FindNextMyOutlookItem(var AItem : Variant) : Boolean; Begin Result := true; Try AItem := myFolder.Items.FindNext; Except Begin AItem := myFolder; Result := false; end; End; End; Function CloseOutlook : Boolean; begin Try MyOutlook := Unassigned; Except End; Result := true; end;
unit UImpContact; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, UMain, StdCtrls, Buttons, ComCtrls, ExtListView; type TFindContact = class(TForm) ContView1: TExtListView; SearchBtn: TBitBtn; CancelBtn: TBitBtn; procedure SearchBtnClick(Sender: TObject); procedure CancelBtnClick(Sender: TObject); procedure ContView1DblClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } public { Public declarations } end; var FindContact: TFindContact; implementation Uses USearch; {$R *.DFM} procedure TFindContact.SearchBtnClick(Sender: TObject); begin If ContView1.Selected <> nil then ContView1DblClick(nil); end; procedure TFindContact.CancelBtnClick(Sender: TObject); begin CloseOutlook; ModalResult := mrCancel; end; procedure TFindContact.ContView1DblClick(Sender: TObject); var MyContact : variant; begin If ContView1.Selected <> nil then Begin MyContact := GetThisOutlookItem(StrToInt(ContView1.Selected.subitems[2])); With StartForm.MyId do If Not GetData(MyContact.CustomerId) then begin InitData; If MyContact.CustomerId <> '' then Id := MyContact.CustomerId Else Id := MyContact.CompanyName; If DoesIdExist(Startform.MyId.Id) then begin Warning('Data Handler', 'Can not establish unique Id' + CRLF + 'Edit CustomerId in Outlook and then try again'); CloseOutlook; ModalResult := mrCancel; Exit; end; OrganizationName := MyContact.CompanyName; IdType := 1; AccountId := MyContact.Account; Address1 := MyContact.BusinessAddressStreet; City := MyContact.BusinessAddressCity; StProv := MyContact.BusinessAddressState ; Postal := MyContact.BusinessAddressPostalCode; Country := MyContact.BusinessAddressCountry; Phone := MyContact.CompanyMainTelephoneNumber; Insert; end; With StartForm.MyContId do begin InitData; ContIdId := StartForm.MyId.Id; Honorific := MyContact.Title ; FirstName := MyContact.FirstName ; MiddleInit := MyContact.MiddleName ; LastName := MyContact.LastName ; Suffix := MyContact.Suffix ; Fax := MyContact.BusinessFaxNumber ; WorkPhone := MyContact.BusinessTelephoneNumber; HomeFax := MyContact.HomeFaxNumber ; HomePhone := MyContact.HomeTelephoneNumber ; MobilePhone := MyContact.MobileTelephoneNumber ; OtherPhone := MyContact.OtherTelephoneNumber ; Pager := MyContact.PagerNumber ; Email := MyContact.Email1Address ; Title := MyContact.JobTitle; OfficeLocation := MyContact.OfficeLocation ; Insert; End; end; CloseOutlook; ModalResult := mrOk; end; procedure TFindContact.FormCreate(Sender: TObject); var MyContact : Variant; MyCount : Integer; i : Integer; AnItem : TListItem; begin If not GetOutlookUp(OlContactItem) then exit; MyCount := GetOutlookFolderItemCount ; For i := 1 to MyCount do begin MyContact := GetThisOutlookItem(i); AnItem := ContView1.Items.Add; AnItem.Caption := MyContact.CompanyName; AnItem.SubItems.add(MyContact.FirstName); AnItem.Subitems.Add(MyContact.LastName); AnItem.SubItems.Add(inttostr(i)); End; end; procedure TFindContact.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := cafree; end; end.
From: johan@lindgren.pp.se
This is a VERY simple test that I made myself to get started with OLE. I was asked to add OLE support to a program I made and this is what I did to have a program to test that my own OLE server worked.This creates the oleobject upon creation and then whenever you press a button it calls a procedure in the oleserver.
unit oletestu; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } ttsesed : variant; end; var Form1: TForm1; implementation uses oleauto; {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin ttsesed := createoleobject('ttdewed.ttsesole'); end; procedure TForm1.Button1Click(Sender: TObject); begin ttsesed.openeditfile; end; procedure TForm1.Button2Click(Sender: TObject); begin ttsesed.appshow; end; end.
From: Darek Maluchnik <embrio@plearn.edu.pl>
Assuming that you have Word2(6)/Delphi1 or 32bit Word/Delphi2.Try:
Declare Function StringFromDelphi Lib "c:\sample\test.dll" As String Sub MAIN mystring$ = StringFromDelphi Insert mystring$ End Sub
library Test; (* test.dpr in c:\sample *) uses Testform in 'TESTFORM.PAS'; exports StringFromDelphi; begin end.
unit Testform; (* testform.pas in c:\sample *) interface uses WinTypes, WinProcs, Forms, Classes, Controls, StdCtrls, SysUtils; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); end; var Form1: TForm1; function StringFromDelphi : PChar; export; {$ifdef WIN32} stdcall; {$endif} implementation {$R *.DFM} function StringFromDelphi: Pchar; var StringForWord : array[0..255] of char; begin Application.CreateForm(TForm1, Form1); Form1.ShowModal; Result:=StrPCopy(StringForWord, Form1.Button1.caption); end; procedure TForm1.Button1Click(Sender: TObject); begin close; end; end.
There is a text in PCMagazine Vol12.No22 on accessing DLL functions from Word. You can get it (DLLACCES) from PCMag web site.
Try the following:
MsWord := CreateOleObject('Word.Basic'); MsWord.FileNewDefault; MsWord.TogglePortrait;
I have found the following works well D2 -> Word 97, using "Bookmark" fields in Word.
.. .. .. implementation uses OleAuto; .. .. .. var V : Variant ; .. .. .. V := 0; // at some point just to initialise .. .. .. some functions if V = 0 then begin V := CreateOLEObject('Word.Application'); V.WordBasic.AppShow; end; // this example assumes we are filling in some bookmark // fields on a "standard letter", from a query that has previously // been executed, in a data module called pnm_data (OK , should // have used a with...block !) V.WordBasic.Fileopen('Your Word Doc name'); V.WordBasic.EditBookmark('Title',0,0,0,1); V.WordBasic.Insert(Title); V.WordBasic.EditBookmark('FirstName',0,0,0,1); V.WordBasic.Insert(FirstName + ' '); V.WordBasic.EditBookmark('LastName',0,0,0,1); V.WordBasic.Insert(pnm_data.ContactsQuery1Fam_Name.AsString + ' '); V.WordBasic.EditBookmark('Address1',0,0,0,1); V.WordBasic.Insert(pnm_data.ContactsQuery1Address1.AsString + ' '); V.WordBasic.EditBookmark('Address2',0,0,0,1); V.WordBasic.Insert(pnm_data.ContactsQuery1Address2.AsString + ' '); V.WordBasic.EditBookmark('Address3',0,0,0,1); V.WordBasic.Insert(pnm_data.ContactsQuery1Address3.AsString + ' '); V.WordBasic.EditBookmark('Title1',0,0,0,1); V.WordBasic.Insert(Title); V.WordBasic.EditBookmark('LastName1',0,0,0,1); V.WordBasic.Insert(pnm_data.ContactsQuery1Fam_Name.AsString + ' '); (You could V.WordBasic.PrintDefault; if you want to tell Word to print it as well....and many other commands, like saving, changing font etc can be done) ....etc
To disable the AutoOpen Macro, you can execute this command
WordBasic.DisableAutoMacros
Function TAutoMerge.ProcessMerge(FSource, FData, FOutput : string) : boolean; var MSWord : Variant; i, NumDocs : integer; Found : boolean; s, LastOLECommand : string; begin ProcessMerge := False; try LastOLECommand := 'Creating OLE Object.'; MSWord := CreateOLEObject('Word.Basic'); LastOLECommand := 'Show MS Word.'; MSWord.AppShow; Application.ProcessMessages; LastOLECommand := 'Open document file >' + FSource + '<.'; MSWord.FileOpen(Name := FSource, ConfirmConversions := 0, ReadOnly := 1, AddToMru := 0, PasswordDoc := '', PasswordDot := '', Revert := 0, WritePasswordDoc := '', WritePasswordDot := ''); LastOLECommand := 'Screen updating = false.'; MSWord.ToolsOptionsSpelling(AutomaticSpellChecking := 0); LastOLECommand := 'Set background printing to off.'; MSWord.ToolsOptionsPrint(Background := 0); Application.ProcessMessages; LastOLECommand := 'Open Data file >' + FData + '<.'; MSWord.MailMergeOpenDataSource(Name := FData, ConfirmConversions := 0, ReadOnly := 1, LinkToSource := 1, AddToMru := 0, PasswordDoc := '', PasswordDot := '', WritePasswordDoc := '', WritePasswordDot := '', Connection := '', SQLStatement := '', SQLStatement1 := '', Revert := 1); LastOLECommand := 'Start the Mail Merge.'; MSWord.MailMerge(CheckErrors := 2, Destination := 1, MergeRecords:= 0, From := '', To := '', Suppression := 0, MailSubject := '', MailAsAttachment := 0, MailAddress := ''); LastOLECommand := 'Set up for SendKeys to select printer.'; Application.ProcessMessages; MSWord.AppShow; s := '{home}%l{enter}{home}%n' + FOutput + '{tab}{enter}{home}{enter}'; // sdd 1.1 MSWord.SendKeys(s, -1); MSWord.MailMergeToPrinter; Application.ProcessMessages; ProcessMerge := True; LastOLECommand := 'All done with merge.'; except on EOleException do begin inc(TotalOLEErrors); lblStatus.caption := LastOLECommand; if (TotalOLEErrors >= TOTALOLEERRORS_MAX) then begin s := 'There has been at least one OLE error(' + IntToStr(TotalOLEErrors) + '), the last one was >' + LastOLECommand + '<.'; ShowMessage(s); end; end end; end;
From: "James D. Rofkar" <jim_rofkar%lotusnotes1@instinet.com>
For those of you who are sick and tired of mucking around with ReportSmith, only to find limitations, drawbacks, etc. And have grown tired of trying to find that perfect WYSIWYG report generator.
Well...
Chances are you've got a good one already. It's called MS-Word! That's right! Use Word for report generation. It's actually quite easy with OLE Automation. I know that word (OLE) scares some of you, but check-out this code:
var Word: Variant; begin Word := CreateOleObject('Word.Basic'); with Word do begin {Pure WordBASIC commands follow...} FileNew('Normal'); Insert('This is the first line'#13); Insert('This is the second line'#13); FileSaveAs('c:\temp\test.txt', 3); end; end;
Simple, isn't it? If you notice, there's no need for SendMessage(), or PostMessage(), or DDE, or Word's C-API, or some proprietary DOS-based batch programming that requires text files to be written. In fact, none of that junk!
Another benefit of OLE Automation is that it doesn't require the darned app to launch. That's right! Word does not show-up using this technique. Instead, just the WordBASIC engine is used. The speed improvements and lower memory footprint kick the livin' crap out of the techniques listed in the previous paragraph.
A wild side-benefit is that if you startup Word while your program is using OLE Automation, you can watch it work. Yup! Word realizes that "documents" are opened and being editing, and hence, displays them like regular old Word documents.
Now all you need to do is generate a Word template with Bookmarks! Then, using the WordBASIC commands "EditBookmark .Goto" and "Insert", you're ready to rock!
I've given-up on report generators. They suck compared to Word's WYSIWYG output!
>GOGA wrote in message <01bd3178$eeb640c0$0d8457c2@goga.aif.msk.su>... >>Can someone please tell me some basic function to control excel from delphi >>with ole automation. Check UNDU and back issues of Delphi Informant. Also http://vzone.virgin.net/graham.marshall/excel.htm#excel.htm
I can't remember exactly which sample(s) I managed to piece this together from, but this sample code will create and format an Excel spreadsheet based on the contents of a DBGrid generated from an SQL query. And it will apply some formatting. This sample is working code that runs in D3 with Excel 97:
procedure TfrmBlank.btnExcelClick(Sender: TObject); var XL, XArr: Variant; i : Integer; j : Integer; begin {note the ComObj (example OleAuto not correct) in the uses} // Create an array of query element size XArr:=VarArrayCreate([1,EmailQuery.FieldCount],varVariant); XL:=CreateOLEObject('Excel.Application'); // Ole object creation XL.WorkBooks.add; XL.visible:=true; j := 1; EmailQuery.First; while not EmailQuery.Eof do begin i:=1; while i<=EmailQuery.FieldCount do begin XArr[i] := EmailQuery.Fields[i-1].Value; i := i+1; end; XL.Range['A'+IntToStr(j), CHR(64+EmailQuery.FieldCount)+IntToStr(j)].Value := XArr; EmailQuery.Next; j := j + 1; end; XL.Range['A1',CHR(64+EmailQuery.FieldCount)+IntToStr(j)].select; // XL.cells.select; // Select everything XL.Selection.Font.Name:='Garamond'; XL.Selection.Font.Size:=10; XL.selection.Columns.AutoFit; XL.Range['A1','A1'].select; end;
From: "K. Brown" <brownk@mops.wl.com>
unit oleword; // Need a form with a button, memo, and edit component. // Written for MSWord 8. // Also need to create a test document d:\test.doc interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, OLEAuto, ShellAPI, StdCtrls; type TForm1 = class(TForm) Memo1: TMemo; Edit1: TEdit; Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } MSWord: Variant; // WordVersion: Byte; end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); var Test, Test1: Integer; AString: Variant; begin MSWord := CreateOLEObject('Word.Application'); //Word 8 MSWord.Documents.Open (FileName:='d:\test.doc', ReadOnly:=True); MSWord.Visible := 1; //Uncomment if you wish to show the file; Test := MSWord.FontNames.Count; For Test1 := 1 To Test do begin AString := MSWord.FontNames.Item(Test1) ; Memo1.Lines.Add(AString); end; MSWord.ActiveDocument.Range(Start:=0, End:=0); MSWord.ActiveDocument.Range.InsertAfter(Text:='Title'); MSWord.ActiveDocument.Range.InsertParagraphAfter; MSWord.ActiveDocument.Range.Font.Name := 'Arial'; MSWord.ActiveDocument.Range.Font.Size := 24; AString := MSWord.ActiveDocument.Range.Font.Name; Edit1.Text := AString; end; end.