I try to make a RichEdit control accept drag-drop files. If a program is associated with the file type on the user's machine (for example, Microsoft Excel for an .xls file), the contents of the file are displayed in the control. Otherwise, an icon is shown, says msdn - Delphi. However, when I run this and drag/drop a doc file, I get machine symbols. What am I doing wrong?
If I understand your question correctly ... I don't think you are doing anything wrong - rather, you are getting unexpected results. I suspect that the doc file you are opening may be a MSWord Doc. Does it have a .doc extension? If it is a MSWord Doc then it probably will have a program associated with it however a TRichEdit will not be able to correctly display the contents.
It may be a MSWord Doc with the wrong program associated with it as well. i.e. WordPad - which cannot display all versions of MSWord Docs.
Ron_de_Weijze
ASKER
Hello Steve, indeed I am trying to drag/drop an MS-Word.doc file. Why would an MS-Excel file be displayed correctly (according to MSDN-Delphi) and an MS-Word file not? BTW I don't get an xls file to be displayed correctly either. Do you suspect how a file like that could display correctly?
SteveBay
If your system does indeed have an association with Word Doc and Excel Files then you could use a TOleCOntainer to display the contents rather than a TRichEdit
The code looks something like this:
You could technically write a component that'd be able to interpret the word doc or docx format, but I wouldn't recommend it, I needed to have my program output a doc document once and the documentation on the doc format that microsoft prodives isn't exactly light reading...
Ron_de_Weijze
ASKER
Thank you all very much for your suggestions and your code. However, I am afraid the RichEdit cannot be replaced. So what you are really telling me, I suppose, is that my wish cannot come through. That wonders me though, for why is it then, that I can copy from Word.doc files and paste that content WYSIWYG flawlessly?
stupid question but did you set RichEdit.PlainText := False?
and one more thing you can copy and paste from .doc to richedit but not everything will be displayed in richedit in same way as in word, simply because RichEdit can display rtf but does not support all features of doc format. same as WordPad it cannot display everything that Word can because it also supports only rtf
ziolko.
Ron_de_Weijze
ASKER
Ziolko, it is impossible that a sage asks a stupid question, but to answer it: indeed it is set to False. (And thanks for the extra info.)
Lukasz Zielinski
it is impossible that a sage asks a stupid question I wish:)
one of links that I gave earlier will make possible drag'n'drop selected text from word into your richedit, other options are use clipboard or implement your own manual accept files (also in one of links) so when file is being draged you can open it and stream-in it's contents into RichEdit.
if you could tell a little bit more what exactly you want to achieve it would be easier to give you better solution
The content of the file that is dragged into the RichEdit, must be editable, without prior selection of text or the need to open the file first and indiscriminate to its format. Or whatever comes closest.
Lukasz Zielinski
what types of files you want to drag to richedit?
ziolko.
Ron_de_Weijze
ASKER
Ideally any registered file type's content that the RichEdit kan show and save in its own format, but mainly *.doc and *.htm.
.htm is not a problem because it's just a text file but if you want all features of .doc I would suggest OleContainer which in fact will open MSWord inside your app, drawback of OleContainer is that you need Word installed on your machine.
ziolko.
Ron_de_Weijze
ASKER
The idea is to collect people's content, independent of its format, and store it in the format of the RichEdit. They need to be able to drag whichever file they have on their machine to the RE. Therefore there can only be one control on the GUI, not a series of OleContainers.
bernani
Hi,
Maybe you could use code similar to this (absolutely not optimized but only a starting point):
type
TForm1 = class(TForm)
Label1: TLabel;
procedure FormCreate(Sender: TObject);
private
{ Déclarations privées }
procedure AppMessage(var Msg: Tmsg; var Handled: Boolean);
public
{ Déclarations publiques }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
ShellApi;
procedure TForm1.AppMessage(var Msg: Tmsg; var Handled: Boolean);
const
BufferLength: DWORD = 511;
var
DroppedFilename: string;
FileIndex: DWORD;
NumDroppedFiles: DWORD;
pDroppedFilename: array[0..511] of Char;
DroppedFileLength: DWORD;
begin
if Msg.message = WM_DROPFILES then
begin
FileIndex := $FFFFFFFF;
NumDroppedFiles := DragQueryFile(Msg.WParam, FileIndex, pDroppedFilename, BufferLength);
for FileIndex := 0 to (NumDroppedFiles - 1) do
begin
DroppedFileLength := DragQueryFile(Msg.WParam, FileIndex,
pDroppedFilename, BufferLength);
DroppedFilename := StrPas(pDroppedFilename);
{
DroppedFilename contain the name of the file with complete path+file extension uppercased)
if AnsiUpperCase(ExtractFileExt(DroppedFilename)) = '.RTF' then showmessage('RTF File');
if AnsiUpperCase(ExtractFileExt(DroppedFilename)) = '.INI' then label1.Caption:=('INI File');
{replace showmessage with a procedure wich loads the file in a try .. except editor like: richedit.lines.loadfromfile(DroppedFilename)}
if AnsiUpperCase(ExtractFileExt(DroppedFilename)) = '.JPG' then showmessage('JPG File');
{replace showmessage with a procedure wich loads jpg in a try ... except: image.picture.loadfromfile(DroppedFilename)}
if AnsiUpperCase(ExtractFileExt(DroppedFilename)) = '.HTM' then showmessage('HTM File');
{idem .....}
{
Needed Improvement Tips
Use case Extension in --> for text/rtf ('.RTF','.INI','.PAS', '.TXT')
--> for html/xml ('.HTM', '.PHP', '.HTML', '.XML')
Call a procedure for loading each type of file sth like:
LoadTextFileType(String: Filename; RichEdit: TRichEdit);
LoadPictureFileType(String: Filename; Image: TImage);
}
{.....}
end;
DragFinish(Msg.WParam); { important to free memory }
Handled := true;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
DragAcceptFiles(Form1.Handle, true);
Application.OnMessage := AppMessage;
end;
end.
Explanation
The extension of the file dropped on the form (contained in DroppedFilename) is checked for his extension and according the type of extension is loaded in a richedit.
In your case, if you want load a html file in the richedit, you could
- create a webbrowser at runtime without showing it
- load the file contained in DroppedFilename into it
- copy and paste the content of the body part to richedit
- close and free the webbrowser
If you want load a doc file, you could convert the doc format to rtf
you need to check if word is installed on the client machine
if yes, load the file into word (not visible), convert the content to rtf, paste into richedit and close word
The idea is to collect people's content, independent of its format this is pretty much mission impossible to do with RichEdit, I think there are most likely two approaches. you use OleContainer to show file using associated application launched inside your olecontainer (no you don't need series of containers one is enough as it can load apropriate app based on file type using CreateObjectFromFile()) or you force your clients to use common standard and then make your app to use this common format (for instance you can tell people to save everything in rtf and then use richedit).
there's of course ShellExecute() but it will launch application associated with file extension but I guess it's not what you looking for
--Inserting Objects into Rich Edit Controls--
The following example function inserts a file object into the specified rich edit control. If a program is associated with the file type on the user's machine (for example, Microsoft Excel for an .xls file), the contents of the file are displayed in the control. Otherwise, an icon is shown.
// Set up data format.
FORMATETC formatEtc;
formatEtc.cfFormat = 0;
formatEtc.ptd = NULL;
formatEtc.dwAspect = DVASPECT_CONTENT;
formatEtc.lindex = -1;
formatEtc.tymed = TYMED_NULL;
// Get an interface to the display site.
LPOLECLIENTSITE pClientSite;
hr = pRichEditOle->GetClientSite(&pClientSite);
if (FAILED(hr))
{
return FALSE;
}
// Create the object and retrieve its IUnknown.
LPUNKNOWN pUnk;
CLSID clsid = CLSID_NULL;
hr = OleCreateFromFile(clsid, pszFileName,
IID_IUnknown, OLERENDER_DRAW, &formatEtc,
pClientSite, pStorage, (void**)&pUnk);
pClientSite->Release();
if (FAILED(hr))
{
return FALSE;
}
// Get the IOleObject interface to the object.
LPOLEOBJECT pObject;
hr = pUnk->QueryInterface(IID_IOleObject, (void**)&pObject);
pUnk->Release();
if (FAILED(hr))
{
return FALSE;
}
// Notify the object that it is contained, so reference counting
// is done correctly.
OleSetContainedObject(pObject, TRUE);
// Move the caret to the end of the text and add a CR.
SendMessage(hRichEdit, EM_SETSEL, 0, -1);
DWORD dwStart, dwEnd;
SendMessage(hRichEdit, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
SendMessage(hRichEdit, EM_SETSEL, dwEnd+1, dwEnd+1);
SendMessage(hRichEdit, EM_REPLACESEL, TRUE, (WPARAM)L"\n");
// Insert the object.
hr = pRichEditOle->InsertObject(&reobject);
Thank you all for your help! The EE rating system has changed, therefore all points went to Ziolko. He does deserve them but otherwise I would have split the points..
It may be a MSWord Doc with the wrong program associated with it as well. i.e. WordPad - which cannot display all versions of MSWord Docs.