Drag & Drop Delphi XE5 - delphi

I use Delphi XE5 and have to realize the possibility for the user to drag different files (docx, xlsx, pictures (jpeg, gif, ...), E-Mails, ... into a component. The component should show the filename or the header of the E-Mail.
Than i want to save this file into a Blob-field in the SQL-Server Database.
Can anyone tell me whats the best possibility if possible with a short example.
Can i realize this with the standard delphi components or is it necessary to install special components.

Your component needs to be derived from TWinControl (TCustomControl, etc) so it has its own HWND to drag things onto. Then:
if you just want to capture dragged filenames, your component can process the WM_DROPFILES window message. This is a legacy message, but it still works. However, it only works when dragging physical files from the file system onto your window. For more advanced scenarios (dragging virtual data, dragging data from other apps, etc), you need to...
a. implement the IDropTarget interface instead. Write an object that implements IDropTarget, or use a third-party implementation such as from Ander's Melander's Drag&Drop suite.
b. register that object for your component's HWND using RegisterDragDrop() after it has been created (the best place to do that in in your component's overridden CreateWnd() method), and unregister the object using RevokeDragDrop() when the HWND is being destroyed (such as in the overridden DestroyWnd() method).
c. when the user drags something onto your component's window, your IDropTarget.DragEnter() implementation will be called. Examine the provided IDataObject to see if it holds a data format + transport scheme that you support (there can be multiple combinations at one time). Each piece of data will be identified by a unique clipboard format identifier, and a TYMED value indicating how the data is transferred. Some clipboard formats are pre-defined (see Shell Clipboard Formats), and some can be registered dynamically at runtime (see RegisterClipboardformat()). If you find a combination that you support, return DROPEFFECT_COPY to accept the drag, otherwise return DROPEFFECT_NONE to reject the drag.
d. if the user drops something onto your component's window (if accepted by DragEnter()), your IDropTarget.Drop() implementation will be called. Extract the data from the provided IDataObject and use it as needed. When dropping physical files, you will receive their paths+names and/or their ITEMIDLIST identifiers, then you can open and read the files as needed. When dropping virtual data/files, you will get the actual data instead (which is usually transferred as a block of memory in an HGLOBAL that you can access using GlobalLock(), or as an IStream interface, but there are other possibilities available).
See MSDN for more details:
Transferring Shell Objects with Drag-and-Drop and the Clipboard
Shell Data Object
Handling Shell Data Transfer Scenarios

Related

Delphi : in CreateForm, how to tell which component creation is slow

In my program, the creation of the main form is slow : I have identified that it hangs for around two seconds just before the form's OnCreate event is called. So I suspect this is happening while the components are created.
Since this form has several frames, I wonder if there is a way to "profile" component creation in order to see where I can improve. I suspect the lag comes from the opening of a database table that should not be open at that time (rather later, after some filtering is in place).
If there is a way get an event triggered before/after each component creation, I could do the profiling myself (with codesite for example).
Or maybe it is possible to do the component creation manually ?
Here is a quick and dirty way to work out where the delay is:
Take a copy of the Classes unit source code and place it in your project's source folder. This will ensure that this unit is compiled into your program rather than the one supplied with Delphi.
Modify the code in the constructor of TComponent. All streamed components pass through here during creation. Add code to log the class name, e.g. using CodeSite for instance.
Run your program, and then inspect the resulting log to identify the delay.
If you have many components then just knowing the class might not narrow it down. You might inject logging code into TComponent.SetName instead which will let you log the component's name. However, the basic idea is simple enough, and you should be able to apply it to your setting in order to find out the information you need.

How to get enabled property of a control?

In Delphi it is possible to get the process name and class name of any control which is clicked system wide via windows api.
process name:
GetWindowThreadProcessId(Hwnd, ProcessId)
by process ID one can get to the process name
class name:
SetLength(ClassName, 255);
SetLength(ClassName, GetClassName(Hwnd, pchar(ClassName), 255));
Is there an easy way similar to the ones mentioned above to get a control's enabled property? (without using UIAutomation)
If you have the window handle for a control, then the IsWindowEnabled function will tell you whether it is enabled.
Keep in mind that that is acting on the window at the API level, not the Delphi VCL level. In Delphi, there can be controls that do not have window handles (anything that descends from TGraphicControl, which includes TLabel and TSpeedButton), so IsWindowEnabled obviously can't tell you anything about those controls.
Delphi does not provide any facility for querying information about arbitrary Delphi controls from other processes. If you need something like that, then you'll have to arrange for the external process to respond to commands of your choosing. That is, you will need to be in control of both programs so that you can put code in them both to cooperate.
If GetWindowThreadProcessId and GetClassName are already telling you the information you want, then IsWindowEnabled will work just fine because they all have the same limitation regarding Delphi VCL controls.

How to force Help and Printer Setup Dialogs to be displayed on the same monitor as the running application?

I know how to force forms to appear on the same monitor as the running application, but I do not see how to ask the Help or the Printer Setup dialogs to display on the same monitor. The Help displays where it displayed last time, but we want it to show up on the application monitor. The Printer Setup dialog always seems to appear on the primary monitor
Passing the parent form's Handle to TPrinterSetupDialog.Execute seems to do the trick.
if PrinterSetupDialog1.Execute(Self.Handle) then
//
Using Delphi 7 (where the TPrinterSetupDialog.Execute does not accept a parameter), you have two choices.
The easiest would be to create your own descendant of TPrinterSetupDialog. Execute is virtual in TCommonDialog, the ancestor of TPrinterSetupDialog, where it is overridden. You could override it in your own descendant, use the code in the TPrinterSetupDialog as a basis for your own Execute override, adding overload as well. Your overloaded Execute would accept a ParentHandle: HWND parameter, and set the PrintDlgRec.hWndOwner to that provided window handle.
I thought about trying to write this for you (or at least get it started), but there are additional things you'd have to copy from the Dialogs unit (functions that are defined in the implementation section that wrap some API calls, and the callback function that's used for the dialog's message loop), and I don't have D7 available where I'm at to even try to compile it.
The other alternative (as David Heffernan mentioned in his comment below) would be to call the Windows API PrintDlgEx directly yourself. This is discussed in MSDN, in the Print Dialog Box (Windows) topic. Once again, I don't have D7 available, so I can't really give you an example of using it from Delphi. (I checked, and don't have one tucked away anywhere.)
I'm not sure you can set the help window's position; I think that's done automatically by Windows based on the user's prior use. (I haven't been able to so so, anyway.)

Firemonkey - Message Handling

I'm currently trying to develop a project based upon Firemonkey. I'm using Firemonkey for it's UI features as the project consists of many smaller applications, each with a 3D aspect to it. I'm currently only developing/deploying to Windows with the FMX framework, but may go cross-platform at a later date.
I've gotten around most issues I've come across by building a VCL Windows application in the background to perform a very specific action, and then building an FMX frontend. However, this is only suitable when you only want to execute the application to perform that action it's designed to do, and thus can execute the application with parameters. In one of the applications, i've come upon the need to use messages (or something similar). For example, in my FMX application, if i click "button1", i want it to send a message to the background VCL application to perform "action1", rather than execute it with parameters.
A good example could be using the VCL TMediaPlayer in the background application, with the front-end FMX application being used to display the information and provide control of play, pause, etc. Such that it essentially becomes an FMX UI with VCL ability.
I've so far been unable to find anything on how messages (e.g. in VCL, they'd be done with "SendMessage" or "PostMessage" or something similar) are handled with Firemonkey, either through the local help file, or through extensive Googling. Everything i've turned up has been related to email (presumably because of the word "Message" in most of my search terms).
Can anyone point me in the right direction on how messages would be handled with Firemonkey/FMX?
Regards,
Scott Pritchard
My understanding is that Firemonkey is not based on traditional windows, so sending window messages to Firemonkey controls is not usually an option. Although some controls do use windows (most notibly, TCommonCustomForm), so you can use the FmxHandleToHWND() function in the FMX.Platform.Win unit to extract an HWND from a TFmxHandle when needed. I have no clue how to receive and custom process window messages in FMX controls, if that is even possible.
Firemonkey under Windows has access to the Win32 API, so there should be nothing stopping you from sending window messages to other windowed controls, such as your VCL UI. Include the Winapi.Windows unit in your uses clause to access Win32 API functions, just like you would in a VCL application.
UPDATE: because FireMonkey does not expose access to messages that are sent to a Form's window, you have to manually subclass the window in order to receive messages before FireMonkey sees them. You can override the Form's CreateHandle() method, call the inherited method first to create the window, then use FmxHandleToHWND() to get the HWND that you can subclass. Be sure to also override the DestroyHandle() method to remove the subclass before then calling inherited to release the HWND.
Currently, FireMonkey doesn't have a message handler that you can use to send and post messages.
There is a possibility of hooking things up using listeners like FireMonkey works internally, but none of it is documented.
So, instead, here's what I've done:
I created my own custom "message" class. I create instances of the class and add them to a thread-safe list from any thread I need to. On the main thread, I have a timer that checks the list and processes the "messages".

Application.handle from DLL

Delphi.
How from DLL to learn Handle the appendix which has caused this DLL?
That is necessary: Knowing Handle appendices, I wish in Dll to use this Handle at creation of dialogues, because dialogue created as TOpendialog.Create(nil) sometimes it appears under the main window of the basic form. And so, in DLL I would make:
application.handle:=GetExeHandle; // GetExeHandle - How to learn?
Opendialog1:=TOpendialog.Create(application);
...
So it is correct?
The only time your DLL shows a dialog box is when the host application calls a function from your DLL. Include the parent window handle as one of the function's input parameters so that the EXE can tell you which handle to use. Do not attempt to discover the handle yourself. As a library developer, you cannot guess what the host application is doing.
If you don't want to include the handle on every function call, then add an initialization function that users of the DLL need to call before any other functions. Pass the handle in the initialization and then store it in a variable in your DLL so that other functions can use the value when they need it.
Unless you use runtime packages (and you don't, or not the right ones), you are in for a world of pain.
Your library will have its' own copy not only of (T)Application but also of thread sycnhronization queue and event (and everything else).
What you are trying to do can seem to work, but it may (and it will) break anytime cause any complex dialog, regardless if VCL or WinAPI, does its' own message pumping, which will bypass the applications' idle and synchronization handling, resulting in reentrancy issues and random stalls or deadlocks.
You may try to handle a lot of the cases by copying the applications' handles, events etc. to the DLL's globals upon its' initialization (is I tried to do), but (not only) if you use anything like TApplication or TThread in the DLL, it will break sometimes.
You can avoid these problems if you use the right BPL runtime packages in your app and the library, as they will share the same namespace and globals as the application using them.

Resources