Avatar of Ron_de_Weijze
Ron_de_Weijze
 asked on

RichEdit accepting drag-drop files (Delphi 7)

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?

procedure TForm1.RichEditURL1Change(Sender: TObject);
var
  exStyle : DWord;
begin
  exStyle:=ExStyle or WS_EX_ACCEPTFILES;
  SetWindowLong(Form1.RichEditURL1.Handle, GWL_EXSTYLE, ExStyle);
end;

Open in new window

Editors IDEsDelphi

Avatar of undefined
Last Comment
Ron_de_Weijze

8/22/2022 - Mon
SteveBay

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:

OleContainer.CreateLinkToFile( DroppedFileName , False);

I know there are other ways to do this as well, however I am not well versed in them.
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
Lukasz Zielinski

RichEdit can display rtf files but does not understand all formating commands that .doc extension has so it treats them as regular text, if you want open office file exactly as you see it in one of office applications you should use, as SteveBay suggested, OleContainer here's link to some of my PAQs:
https://www.experts-exchange.com/questions/23295670/How-to-loacte-Excel-spreadsheet-within-Delphi7-form-using-Excel-server-component.html
https://www.experts-exchange.com/questions/23332058/Example-code-needed-to-link-OleContainer-to-ExcelApplication.html

and here some drag'n'drop code:
https://www.experts-exchange.com/questions/23022892/Quick-Launch-Bar-inside-Delphi-App.html

ziolko.
Freddy1990

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?
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Lukasz Zielinski

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

ziolko.
Your help has saved me hundreds of hours of internet surfing.
fblack61
Ron_de_Weijze

ASKER
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.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Lukasz Zielinski

.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):

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

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

if word is not installed on the client machine, use another way:
- see MS Word Document at Scalabium : http://www.scalabium.com/
- http://users.iafrica.com/d/da/dart/zen/ZenMain.html


load the file in a webbrowser)
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
Lukasz Zielinski

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

ziolko.
Ron_de_Weijze

ASKER
( The following is from MSDN, http://msdn.microsoft.com/en-us/library/bb774371(VS.85).aspx )

--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.

BOOL InsertObject(HWND hRichEdit, LPCTSTR pszFileName)
{
    HRESULT hr;

    // Get the IRichEditOle interface.
    LPRICHEDITOLE pRichEditOle;
    SendMessage(hRichEdit, EM_GETOLEINTERFACE, 0, (LPARAM)&pRichEditOle);
    if (pRichEditOle == NULL)
    {
        return FALSE;
    }

    // Create structured storage.
    LPLOCKBYTES pLockBytes = NULL;

    hr = CreateILockBytesOnHGlobal(NULL, TRUE, &pLockBytes);
    if (FAILED(hr))
    {
        return FALSE;
    }

    LPSTORAGE pStorage;
    hr = StgCreateDocfileOnILockBytes(pLockBytes,
        STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE,
        0, &pStorage);
    if (FAILED(hr))
    {
        return FALSE;
    }

    // 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);

    // Set up object info.
    REOBJECT reobject = { sizeof(REOBJECT)};
    hr = pObject->GetUserClassID(&clsid);
    if (FAILED(hr))
    {
        pObject->Release();
        return FALSE;
    }
    reobject.clsid = clsid;
    reobject.cp = REO_CP_SELECTION;
    reobject.dvaspect = DVASPECT_CONTENT;
    reobject.dwFlags = REO_RESIZABLE | REO_BELOWBASELINE;
    reobject.dwUser = 0;
    reobject.poleobj = pObject;
    reobject.polesite = pClientSite;
    reobject.pstg = pStorage;
    SIZEL sizel = { 0 };
    reobject.sizel = sizel;

    // 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);

    // Clean up.
    pObject->Release();
    pRichEditOle->Release();

    if (FAILED(hr))
    {
        return FALSE;
    }
    return TRUE;
}

I will try implement the above through Delphi. If you see any shortcuts and would let me know I that would be most helpful.

ASKER CERTIFIED SOLUTION
Lukasz Zielinski

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
Ron_de_Weijze

ASKER
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..
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.