Delphi - Using OLE causes error in Word - delphi

Delphi XE6. I have an application for text snippets, which are stored in a local Database (ABS DB). Some snippets may be straight text, others may include formatting. If the snippets include formatting, the snippets are MS Word format.
The user can view the snippets in two ways, inside my app, or by calling MS-Word, and having the snippet loaded there automatically, - IT IS THE SAME SNIPPET ..
Issue: If the snippet is loaded into a TOLEContainer in my app, it displays fine without a problem... If the snippet gets spawned off into MSWord, I get an error...
"We're sorry. We can't open because we found a problem with its contents." I click on OK, and then get "Word found unreadable content in . Do you want to recover the contents of this document?..." I clik OK, and everything displays fine.
My general processing flow for the "spawn off MS WORD" is...
// FN is a temp file name
FileStream := TFileStream.Create(FN, fmCreate);
BlobStream := dm_text.tEntries.CreateBlobStream(dm_text.tEntries.FieldByName('ANSWER_FMT'), bmRead);
FileStream.CopyFrom(BlobStream, BlobStream.Size);
BlobStream.Free;
FileStream.Free;
// Now open default association, which will be Word
ShellExecute(Handle, 'open', PWideChar(FN), nil, nil, SW_SHOWNORMAL);
This flow is nearly identical for the In place viewing... other than a few commands for the TOleContainer.
OleWord.Enabled := True;
FileStream := TFileStream.Create(FN, fmCreate);
BlobStream := tEntries.CreateBlobStream(tEntries.FieldByName('ANSWER_FMT'), bmRead);
FileStream.CopyFrom(BlobStream, BlobStream.Size);
BlobStream.Free;
FileStream.Free;
OleWord.LoadFromFile(FN);
OleWord.DoVerb(ovInPlaceActivate);
Any ideas why this is happening? This happens on MULTIPLE versions of MSWord.
ADDITIONAL INFO:
Both routines look at the same data, pulled from the exact same row/column in my DB. What I do is create a TEMP file, and then load either via TOleContainer, which loads it fine, or via ShellExecute, which gives an error. However, if I manually load the TEMP file for the OLE Container into MSWord, I get the same error.
So - possibilities...
1). My data is corrupted, i.e. how I save it is wrong...but Word can correct it.
2). I have a setting somehow so that OLEContainer doesn't show the error but Word does.

It is because when using OleContainer.SaveToFile or SaveAsDocument, you are not creating a docx file, but an OleObject containing a docx file. When using OleContainer.SaveToFile with UseOldStreamFormat = True, there is even a Delphi specific header added. Word fortunatly detects this and gives you the option to restore the file.
If you want a valid word-document, then activate the OleContainer (OleContainer.DoVerb(ovPrimary) and then save the document via Word itself (OleContainer.OleObject.SaveAs(MyFileName, wdFormatDocument, EmptyParam, EmptyParam, False).
After that you can store the resulting file in your database.

Related

Load oracle blob into memory with Delphi XE2 and open with default application

I was wondering if someone could help me with the following problem.
I have uploaded a couple thousand files (MSG, PDF, DOC, DOCX, XLS, XLSX etc.) into our Oracle database as we need to start saving our files into the database.
I want to know if it is possible to basically open a selected file from the database into memory and then proceed to open the file with the default application without having to save the file onto the local disk each time.
This would mean that if a user selects to view a PDF document, it should open with Adobe Reader, a Word Document should open with Word and a MSG file should open with Outlook, etc.
I have searched through the internet and have been unsuccessful in my attempt to find information to help me in this matter.
Okay
I have managed to get a solution that works perfectly.
I just needed to add 'ShellAPI' to the uses clause at the top of the form in order for Delphi XE2 to recognize the 'ShellExecute' command.
Below is my code:
procedure Tdms_displayfiles_frm.download_btnClick(Sender: TObject);
var
blob: TStream;
filename : string;
begin
blob := dms_download_ods.CreateBlobStream(dms_download_ods.FieldByName('fil_file'), bmRead);
try
blob.Seek(0, soFromBeginning);
with TFileStream.Create('c:\Temp\' + dms_download_ods.FieldByName('fil_sequence').AsString + '_' + dms_download_ods.FieldByName('fil_filename').AsString, fmCreate) do
try
CopyFrom(blob, blob.Size)
finally
Free
end;
finally
blob.Free
end;
filename := 'c:\Temp\' + dms_download_ods.FieldByName('fil_sequence').AsString + '_' + dms_download_ods.FieldByName('fil_filename').AsString;
ShellExecute(0, nil, PChar(filename), nil, nil, SW_SHOWNORMAL);
end;
So far I tried it with the following file formats: PDF, MSG, DOC, DOCX, XLS, and XLSX and all files open with their default programs.

How to remove, or change an attached template via OleAutomation

My company has a large selection of templates which are used to generate customer correspondence. I need to modify the existing processes so that copies of generated files (template + data) are saved for later editing.
My problem is that when I open one of these saved MSWord documents, edit, then close, MSWord is insisting that changes have been made to the template (the one selected in the generation process).
I am not really sure why this is happening, but it may be that the generated document contains a reference to the template upon which it was based, but that because the template is in a remote location, MSWord is attempting to generate a new local file.
If that diagnosis is correct, then I need a method to remove the template reference from the document.
If the diagnosis is incorrect then what is the likely explanation/solution?
I have found that BOTH resultant files contain a reference to the template.
Note: Manual editing in Word has no issue. If I let the letter generate and save to disk from Winword, I can open it and manipulate it quite happily. Somewhere in the automation steps the problem is being created.
Interestingly - I have changed the save format to '.rtf' and the problem remains.
Further - it doesn't matter if I say 'Yes' to saving changes to the template, it continues to prompt me each time I open and close the document (whether I edit or not)
I have discovered that by saving the document as wdFormatXML I can see the reference to the letter template and edit it. If I do that the problem goes away.
I am now attempting to achieve the same result via automation, but with no success;
WordApp.ActiveDocument.Set_AttachedTemplate(tmplt);
Does not work for values of tmplt 'Normal.dot', varNull, 'c:\progra~1\etc\Simple.dotx' and so on. The function call tells me it cannot find the template for the first 2 of those values, or merely hangs.
I am back to my original question - how does one clear the attached template ?
I eventually figured it. My problem was down to late-binding in some way. I found that the following code worked
var
docpath : OleVariant;
fmt : OleVariant;
tmplt : OleVariant;
WordApp : WordApplication;
WordDoc : WordDocument;
begin
docpath := SaveLoggedDocToDisk(GetCurrentFileName());
WordApp := CoWordApplication.Create;
try
fmt := EDITABLE_FORMAT;
tmplt := '';
WordDoc := WordApp.Documents.Open(docpath, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, fmt, EmptyParam, EmptyParam );
WordDoc.Set_AttachedTemplate(tmplt);
The problem I had with earlier versions of this code was that
WordApp.ActiveDocument.SetAttachedTemplate(tmplt);
although it appears equivalent, was not behaving. By creating a variable of type WordDocument the routine sprang into life.

OleGraphic.LoadFromStream() Raises OLE Error 800A01E1

I have to load a jpeg file into OleGrafic. When I call OleGraphic.LoadFromStream(), it raises OLE Error 800A01E1.
I tried to identify this error, without any success.
The closest answer related to ole errors was List of all OLE error codes but I can not find 800A01E1 there.
I tried also to initialize Ole in main form. Same form that is generating this error. Without any success.
initialization
OleInitialize(nil);
finalization
oleuninitialize;
# Remy Lebeau: This code worked proper in other projects:
sFileName := OPD.FileName;
OleGraphic := TOleGraphic.Create;
fs := TFileStream.Create(sFileName, fmOpenRead Or fmSharedenyNone);
// fs.Seek(0,soFromBeginning);// := 0; Here I tried to make sure it's o.
OleGraphic.LoadFromStream(fs);
Source := TImage.Create(Nil);
Source.Picture.Assign(OleGraphic);
SrcBild := TBitmap.Create;
SrcBild.Width := Source.Picture.Width;
SrcBild.Height := Source.Picture.Height;
SrcBild.Canvas.Draw(0, 0, Source.Picture.Graphic);
DstBild := TBitmap.Create;
DstBild.Width := 200;
DstBild.Height := 100;
SmoothResize(SrcBild, DstBild);
SmoothResize is from http://www.swissdelphicenter.com/torry/showcode.php?id=1896
I cannot tell you why that image fails to load, but I can tell you the name of that error code, and how to find such codes in the future.
8-digit hexadecimal exception/hresult error codes in Windows can usually be found by prefixing them with 0x, in this case giving 0x800A01E1.
A simple search for that tells me that the name of that error code is CTL_E_INVALIDPICTURE, and that result is also listed on the underlying Win32 function, OleLoadPictureFile:
Return value
This method returns standard COM error codes in addition to the following values.
Return code Description
S_OK The method completed successfully.
CTL_E_INVALIDPICTURE Invalid picture file.
Of course, that doesn't tell you what is wrong either, but at least you now know that the likely source is the actual content of the file.
Since the documentation for the function also lists valid file formats, my guess would be to first ensure the file is one of those formats, and not just some other image file (or random data for that matter) masquerading as a JPEG or something under an incorrect filename, and then try to load that file up into some other program. Perhaps you can even just load and save the file in some tool that can rewrite the contents of image files, might fix it.
TOleGraphic.LoadFromStream() uses OleLoadPicture() internally. According to its documentation:
The stream must be in BMP (bitmap), WMF (metafile), or ICO (icon) format.
In other words, JPG is not supported.

Delphi 7 and Excel 2007 Open File Error

I am having difficulty opening a EXCEL 2007 in Delphi 7 It works for Office 2003 and below but the wonderful people at microsoft have sent an update or something and the delphi app fell over just earlier this month.
oE := GetActiveOleObject('Excel.Application');
oE.Workbooks.Open(Filename:=sFilename, UpdateLinks:=false, ReadOnly:=true); //Error
I get the following error:
'c:\Temp\Book1.xls' could not be
found. Check the spelling of the file
name, and verify that the file
location is correct.'#$A#$A'If you are
trying to open the file from your list
of most recently used files, make sure
that the file has not been renamed,
moved, or deleted'
Yet if I run the same command in VBA there is no problem.
I know this sounds stupid, but have you manually confirmed that the file exists at that location?
What exactly is the contents of sFileName, is it the full path or only the filename? When it is only the filename, maybe Excel can't find it because its current working directory is something else. If you are only passing the filename, try the full path instead.
the full code for the lookers :
uses ComObj; ..
procdure startExcel;
var
oE:Variant;
begin
try
oE := GetActiveOleObject('Excel.Application');
except
oE := CreateOleObject('Excel.Application');
end;
oE.Workbooks.Open(filename, false, false);
oE.Visible := True;
end;
source

Open an ANSI file and Save a a Unicode file using Delphi

For some reason, lately the *.UDL files on many of my client systems are no longer compatible as they were once saved as ANSI files, which is no longer compatible with the expected UNICODE file format. The end result is an error dialog which states "the file is not a valid compound file".
What is the easiest way to programatically open these files and save as a unicode file? I know I can do this by opening each one in notepad and then saving as the same file but with the "unicode" selected in the encoding section of the save as dialog, but I need to do this in the program to cut down on support calls.
This problem is very easy to duplicate, just create a *.txt file in a directory, rename it to *.UDL, then edit it using the microsoft editor. Then open it in notepad and save as the file as an ANSI encoded file. Try to open the udl from the udl editor and it will tell you its corrupt. then save it (using notepad) as a Unicode encoded file and it will open again properly.
Ok, using delphi 2009, I was able to come up with the following code which appears to work, but is it the proper way of doing this conversion?
var
sl : TStrings;
FileName : string;
begin
FileName := fServerDir+'configuration\hdconfig4.udl';
sl := TStringList.Create;
try
sl.LoadFromFile(FileName, TEncoding.Default);
sl.SaveToFile(FileName, TEncoding.Unicode);
finally
sl.Free;
end;
end;
This is very simple to do with my TGpTextFile unit. I'll put together a short sample and post it here.
It should also be very simple with the new Delphi 2009 - are you maybe using it?
EDIT: This his how you can do it using my stuff in pre-2009 Delphis.
var
strAnsi : TGpTextFile;
strUnicode: TGpTextFile;
begin
strAnsi := TGpTextFile.Create('c:\0\test.udl');
try
strAnsi.Reset; // you can also specify non-default 8-bit codepage here
strUnicode := TGpTextFile.Create('c:\0\test-out.udl');
try
strUnicode.Rewrite([cfUnicode]);
while not strAnsi.Eof do
strUnicode.Writeln(strAnsi.Readln);
finally FreeAndNil(strUnicode); end;
finally FreeAndNil(strAnsi); end;
end;
License: The code fragment above belongs to public domain. Use it anyway you like.

Resources