The Delphi VCL TFileOpenDialog has a property called ClientGUID. Embarcadero documentation says it:
...holds a GUID associated with a dialog's persisted state. Persisted
states for a dialog can include such things as its position and
size...
But that is all it says. I would like to know more. My testing shows that the dialog Size and Position do persist between application sessions so they are being stored somewhere.
But where is this information being stored? (I have searched the registry and hard drives for the GUIDs I have been testing but cannot find them anywhere.)
And, is it only Size and Position or do other properties also persist? (If it is only Size and Position then it's not really very useful to me.)
I also asked this question on Experts Exchange and the answer given there is that the persisted properties are stored in the Windows Registry in this key:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\CIDSizeMRU
The values stored there are binary, which explains why the initial text searches for my GUID failed.
My testing shows that the persisted properties for FileOpenDialog include size, position and path. There may be be more but I don't know.
Related
Hi I need to drag an image from one application to another. Both are Delphi FMX applications. I was successful in doing it within one application but now need to transfer between two separate applications, ie no memory sharing. I would be happy to save all info into a file and transfer the file name in the operation. I do detect the dragover event in the receiving application but the data property is nil and I don't know how to populate it with a useful value.
I am using Windows 10, Delphi XE10.3
Any example, explanation will be helpful
Thank you
Did you find an answer?
I am trying something similar. Andreas is right about proper OLE, but it will be a lot of work to implement in FireMonkey.
The problem is that FireMonkey, on Windows, only interprets external drags of files (by their name and path) or unicode text. It can accept other external drags, but extracts no information so it is useless.
Look in FMX.Platform.Win.
TWinFropTarget.GetDataObject() is the culprit.
PlatformWin.FDragAndDropActive is true for internal drags and false for external.
External drags of CF_HDROP (filenames) and CF_UNICODETEXT (unicode text) only are interpreted.
To implement yourself steps would be
Roll your own IDropTarget.
Register it with Windows. See TPlatformWin.CreateWindow(), call to RegisterDragDrop()
Create a mechanism for freeing it, which is all TWinWindowHandle.FWinDropTarget does, but FWinDropTarget is private.
Hook it up to the form or component that will receive the drop.
Enhance GetDataObject, or whatever replacement you have decided, to interpret the external drags that are of interest. This requires more research.
Above generally covers the receiver.
The sender requires yet more research for how to initialise a Drag Drop of the content of interest in Windows.
Repeat for other platforms as required!
Drag and Drop component suite for VCL, https://torry.net/pages.php?id=233, probably has a lot of the code to do this, although I have not looked at it.
If anyone tries this, please update this thread.
Andreas and my answers are about dragging the image itself. In the question you suggest that sending the filename would be acceptable. Following further research to solve my own issue I can give you the categoric answer for this solution, which avoids would be significantly less work.
Drag Drop, as you already know, involves a Source, a Target and Data.
Fire Monkey Drag Drop implementation for internal drags (i.e. within the application) uses its own data format, namely the Data record. For internal drags only the Data.Source property is populated.
For external drags (i.e. between applications, whether FMX or not) OLE has to be used for the data.
All drags can be received by all open applications. But unless OLE data has been set by the Source the Destination will be unable to interpret what the drag is or where it is from. Your question states "I do detect the dragover event in the receiving application but the data property is nil". You are experiencing the situation I am describing.
Delphi FMX will interpret and decode OLE data received for Files and Text content. Files is a list of filenames with paths, not the files themselves. Other OLE content is ignored, such as image. See my previous answer for how to enhance FMX to interpret other OLE content.
Delphi FMX does not set OLE data. Therefore to implement drag drop from a Fire Monkey application to another application, including another Fire Monkey application, it is necessary to write you own start drag code which populates OLE data. In my previous answer this is written more briefly as "The sender requires yet more research for how to initialise a Drag Drop of the content of interest in Windows."
Such Drag Start code would be called from OnMouseDown event of the Source control. For Windows I think
create a COleDataSource
set the data
call its DoDragDrop method
I have not tried it because my application will not be a Source of inter-application drags.
I would like to be able to read the original text of a component (published) property at runtime after it has been (potentially) changed.
The context is that I'm writing an extension of a translation library that we used in our application. That library is old and not supported by the supplier any more so I am on my own to make it work.
Unfortunately, the way the library is coded makes it impossible to use from an ISAPI Dll (for instance, in an Intraweb application). The dictionary part works but the automated translation component does not (mostly because it tries to overwrite some code section in memory). I'm therefore trying to salvage the parts that works (form translation tools and dictionary storage) while rewriting the part that doesn't (well, only the elements that I'm interested in, really).
I'm, however, stopped by the fact that, once a component text property has been translated, it will not match the original text any more and won't be found in the dictionary.
That code is supposed to work in Delphi 7 although I'm planning to migrate it to XE5 as soon as I have enough time for that.
"Once a component text property has been translated, it will not match
the original text any more and won't be found in the dictionary."
Can you keep a separate lookup map yourself, of translated content to original? Add to this any time a string is replaced with its translated content. That way you can go back and forth between the original and translated at will.
In XE5, the easiest way would be to use a TDictionary. In D7, you may have to roll your own container.
You can make a procedure that save the original values to a List or some array, then call that procedure in the Form's Loaded method (you have to override it, and don't forget to call inherited at the end of it.) Then search for the directory entry in that list. The Form's Loaded method is called after all the components is loaded from the DFM but before the FormCreate. So here you can find all the original properties.
From what I understand, what you want is to get back the value of string properties as they are stored in the DFM at compile time.
So, I guess the most reliable way to do so would be from the DFM itself. As far as I know, DFMs are always stored inside the binaries as resources (though there might be some exceptions...). I looked into doing something similar a while ago. I didn't manage to make it work as R&D time ran out (I only had a couple of hours), but if you want to look into it, I'd start with
TCustomForm.Create
InitInheritedComponent
InternalReadComponentRes
TStream.ReadComponent
TReader.ReadRootComponent
Maybe someone can confirm whether this approach can work or not and what are the caveat, but until then, I think it's a valid research direction for you.
I'd like to get information about a third party application's controls such as a list of its properties and their values: something like RTTI information but for a third-party Delphi application.
I see that this is possible. For example TestComplete has the ObjectSpy window which can give many useful information about the control, including RTTI information. How can this be done ?
Edit: To explain why I'm investigating this issue... I'm a registered user of TestComplete/TestExecute and I do like... most of it. I can get over the minor things but the one major problem for me is their license verification system which requires me to have a physical computer (not a virtual machine) always on just for the sake of running a license server so that TestExecute can run at night. As I have basic testing needs (compare screenshots and check basic Delphi component's properties) I wondered how hard it would be to make my own private very simple "TestExecute-like" application.
To go further, I suggest you these relevant resources found here on SO
Writing a very basic debugger (The accepted answer along with its comment thread are all valuable).
Is it possible to access memory from an application to another ? How? (Excerpt from the accepted answer: It is possible. Just use the Windows API functions WriteProcessMemory/ReadProcessMemory. Pass in the handle of the process and the pointer to the data).
Search the memory of another process (The excellent accepted answer also forwards to another valuable resource delphi-code-coverage by Christer Fahlgren and Nick Ring).
StackWalk of other process in delphi? (Check Barry Kelly's answer !!!, the same for the one from the AsmProfiler author !!!).
I strongly suggest you to port to Delphi this c++ project entitled Get Process Info with NtQueryInformationProcess: A hands on experience on using ReadProcessMemory to access the CommandLine used to launch another process.
Last Edit:
NtQuerySystemInformation Delphi Example.
RRUZ's answer to Delphi - get what files are opened by an application as suggested by LU RD.
When we want to take another application which is compiled with debug information and get stuff out of it at runtime, what we are dealing with is the problem of "how to write my own custom debugger/profiler/automated-test kernel".
TestComplete and other AutomatedQA programs contain a Debugger and Profiler Kernel which can start up, run and remotely control apps, and parse their Debug information in several formats, including the TurboDebugger TD32 information attached to these executables. Their profiling kernel also can see each object as it is created, and can iterate the RTTI-like debug information to determine that an object that was created is of a particular class type, and then see what properties exist in that object.
Now, TestComplete adds on top of the AQTime-level of stuff, the ability to introspect Window handles, and intuit from Window Handles, the Delphi class Names that are behind it. However, it's much easier for you (or me) to write a program which can tell you that the mouse is over a window handle that belongs to a TPanel, than to know which version of Delphi created that particular executable, what version of TPanel that is, then, and what properties it would contain, and to read those values back from a running program, which requires that you implement your own "debugger engine". I am not aware of any open source applications that you could even use to get a start writing your own debugger, and you certainly can't use the ones that are inside AQTime/TestComplete, or the one inside Delphi itself, in your own apps.
I could not write you a sample program to do this, but even if I could, it would require a lot of third-party library support. To see the window classes for a window handle which your mouse is over, look for how to implement something like the MS Spy++ utility.
An easy case is if your mouse is mousing over a window inside your own application. For that, see this about.com link, which simply uses RTTI.
When opening a form which contains an inherited TImageList in Delphi (2010 in this case, but it may do it for other versions), the IDE invariably (I can't find any rhyme or rhythm to it) adds the image data again to the inherited form. This then increases the size of the executable. any one know why, and how I can stop it happening? I repeat, the image has not changed.
This is a known issue with TImageList, and there's not much you can do about it except to keep deleting the garbage data again. (BeyondCompare can be very useful here, especially in conjunction with source control.) If you want to see it fixed, please vote for the QC report on it.
What I do is put the imagelist on a data module and then add it to the forms uses clause. The form designer will be able to see the image list
This isn't a "solution" to the problem, but more an explanation of what is going on. The image data for a given image list is stored as a binary blob of data. This blob of data is obtained from the underlying IMAGELIST implementation from the comctl32.dll.
What is likely happening is that for some reason the Windows implementation down in comctl32.dll is streaming the image data differently between the "ancestor" instance and the "descendant" instance. To Windows, there is no relationship between these two instances.
The way form-inheritance works is that it does a property-by-property comparison between the "descendant" and the "ancestor" while streaming to determine if a given property should be written to the form. Because the image data is an opaque blob of goo, all we can do is a byte-for-byte comparison between what the TImageList instance on the ancestor writes and what the TImageList instance on the descendant writes. If only one byte were different, the streaming system has no choice but to write the data from the descendant instance on the presumption that something changed. For instance (and I don't really know the details since it is opaque), if the blob of goo contained a timestamp, it is conceivable that each time it is written the data would be different.
My recommendation: never keep images in .dfm files. Always put them in resource files and regain control of your app.
Over time I've rolled my own formats for saving and loading object properties but on having to revisit this I'm wondering about using Delphi's own text DFM format. I know tha this is really an 'internal' format, but the reader for it now seems pretty well defined and it copes with all types of property. Has anyone any comments about possible pitfalls?
I wouldn't really say that DFM is an 'internal format'. Sure Delphi uses it internally for forms and datamodules, but TReader and TWriter classes that perform streaming are publicly accessible and even documented. So they are clearly intended for end users as well.
Now, the possible problem is when you save a stream and later one of the classes in the stream changes so that the stream is not compatible any more. You may have seen this in Delphi if you attempt to open a form saved in D2007+ in D7 (missing property). But even if it happens, it's not too hard to resolve. You will get an exception that will report the exact property that is causing the problem. You also have to register all classes that you want to stream with RegisterClass.
DFM can be stored in binary or text format. Even if you store it Binary you can convert it to Text (using ObjectBinaryToText), once in text format, it's easy to fix.
So, the problems you may get happen due to incompatible changes in the structure, but those have nothing to do with DFM mechanism itself, and would also happen using any other streaming mechanism.
As for longevity, you can still open DFM's saved with D1 in the latest Delphi. So as long as you keep backward compatibility in mind, you have nothing to fear.
In conclusion, the choice of any particular format, DFM, XML, JSON, your own... doesn't really affect longevity. They all require same level of compatibility.
The reasons for choosing the format have more to do with decisions regarding:
interoperability with other apps/services
size/speed/human readability
But you didn't mention any of those in the question.
So I suggest using DFM over roll your own, as it would mean less code to maintain.