How to read a file that is in use by other process? - delphi

I have an application that have a log system that create a file and keep it handle with a TFileStream, that is created with this way:
FFileStream := TFileStream.Create(FFilename, fmOpenWrite);
Ok. When I try to open this file with notepad, no problem, with notepad++ no problem. When I try to load the file with other application that I created it raise my an error that says the file is in used by other process.
I tried TStringList, LoadFromFile and TFileStream.Create(LFile, fmOpenRea);.
Some one knows how I can read this like the notepad and notepad++?
Tks.

Erik got there first but uses fmShareDenyNone which would allow other processes to write to the same file. If you only want to allow reading by other processes, use:
FFileStream := TFileStream.Create(FFilename, fmOpenWrite or fmShareDenyWrite);

Use fmOpenWrite or fmShareDenyNone to enable sharing.

I am using Delphi7 and I was experiencing, that TFileStream sometimes fail to open a file for reading, while it is only locked for writing. (Before one would start nagging about the sharing parameters of the TFileStream class; I know about them, and set them right.) While I was not yet able to find out the reasons of this clearly buggy behavior, I found that it can be worked around by using some other means of file handling:
While the file can not be opened with TFileStream - even with the right sharing settings (yes, I know what I am doing) - it could easily be opened using the appropriate WinAPI calls: CreateFile/ReadFile/SetFilePointer/CloseHandle wrapped in the Windows unit.

Related

Delphi: Play mp4 file using DSPack

I have been playing around with DSPack, it can play avi and wmv files, but it is not playing mp4 files. i have installed ffdshow codec but still it wont play any other format. I read somewhere that i need to use ffdshow filter, but there is very limited documentation on how to do so... Can someone help me out here?
Edit
Thats the error i get when playing any other format
raised exception class EDirectShowException with message 'C ($80040265).'. Process stopped. Use Step or Run to continue.
and thats the function which pops the exception
function CheckDSError(HR: HRESULT): HRESULT;
var Excep: EDirectShowException;
begin
Result := HR;
if Failed(HR) then
begin
Excep := EDirectShowException.Create(format(GetErrorString(HR)+' ($%x).',[HR]));
Excep.ErrorCode := HR;
raise Excep;
end;
end;
Edit
I installed the haali demultiplexer, it was a self installer after installation i still get the same error. and the gdcl demultiplexer, those are two dll files, any suggestions on how to use them?
PS: I have never worked with codecs and/or this kind of stuff, so sorry for being so thick, And i am using Windows 7 x64
I can successfully play *.mp4 files with the "DSVideoWinDowEx\PlayWin" demo application that ships with DSPack. Windows 7 includes the mp4 codec, so this should not be an issue. Make sure that you're not running your application in debug mode, because many codecs refuse to work if a debugger is active.
The Haalie Media Splitter is not used for my test *.mp4 files. But it uses the AC3Filter. So your problem could also be a missing audio codec.
If that doesn't fix the issue then the question might be: "Why does it not work on your PC?"
In order to further narrow down the issue try playing the video with GraphEdit or GraphStudio and see if that works. These tools will also show the filter graph that is used. You can also show the FilterGraph that is used in your DSPack application.
If you install a DirectShow filter (codec) on your system, it will be used automatically by DirectShow/DSPack. You could register a filter in the system manually by calling regsvr32 "path_to_codec.ax", but this is usually done by the installer. It is possible to manually use a filter in DirectShow, but most of the time this is not needed.
lavfilters provide everything you will need with source splitters and decoders. It's open source, actively developed and based on ffmpeg. If you can't playback the mp4 after installing lavfilters then I would say there is a problem with the mp4 itself. In this case use something like ffprobe to inspect the file or post a link to the file.

How to write a file that is being read?

My application reads a TextFile of floating point numbers slowly. From time to time circumstances change and the file has to be rewritten. Some example code:
procedure TAMI_Column_Selector.read_continuously (file_name: string);
var infile: TextFile;
f: Double;
begin
AssignFile (infile, file_name);
Reset (infile);
try
while not EOF (infile) do
begin
Read (infile, f);
process (f); // this may take quite some time, seconds or even minutes
end; // while
finally
CloseFile (infile);
end; // try..finally
end; // read_continuously //
How can I write a file that is open for reading? More specifically:
how can I write a file that is open for reading?
how to prevent a crash when the application tries to read a file that at that moment
is being written
how does my application know that the file has been rewritten?
I think I could solve the first to questions be reading the file into memory and read that (is there a TextFile that can be written to and read from memory)? Then still remains how I can test a file has been written over.
Anyone having an (elegant) solution to this problem?
Thanks in advance.
Using Delphi XE on windows 7
To write to a file that's also open for reading, there's generally not anything special the writer needs to do. If everyone else who has the file open has allowed writing to the file, then the intended writer can open the file for writing, write to the file, and close it. If the others haven't allowed writing to the file, then the intended writer won't be allowed to open the file in the first place, and there's nothing it can do about it.
How to open a file for reading while also allowing writing depends on the opening method being used. With CreateFile, the dwDesiredAccess parameter is the usual GENERIC_READ, and the dwShareMode parameter is FILE_SHARE_READ or FILE_SHARE_WRITE. If you're using a TFileStream, then the mode parameter of the constructor should be fmOpenWrite or fmShareDenyNone. If you're using AssignFile and Reset, then you'd need to set the FileMode global variable, but that doesn't support any sharing modes, so you can't use Pascal-style I/O.
Reading a file that is at the same time being written does not inherently cause a crash. It certainly doesn't cause problems at the OS level. If your program crashes, it's because it wasn't written to anticipate reading failures. When you read something, check the API result to confirm that you read as many bytes as you requested. You can also have the reading and writing applications communicate with each other. You might use a synchronization object to serialize access to the file, or the writer might send the reader a signal to indicate that the file has changed, and that the previous read might not be accurate anymore. It's up to you to work the details.
If the reader is going to keep a copy of the file in memory, then it probably doesn't need to bother sharing write access. Instead, it can open the file and only share read access, make a copy of the file in memory, and the close the file. The writer can then open the file without any worries of trampling on the reader process because there's nothing to trample. It can notify the reader that something changed, and the reader can either reload the entire file or just load the part that changed. (The writer will have to tell the reader which part changed, though; there's no other way for the reader to detect that without reading the entire file and seeing how it differs from the memory copy.)
Another way to keep writes from interfering with reads is to use transactions. Transactional NTFS is being phased out, though. Microsoft has published a list of alternatives, so you can try to find something that matches your needs.

IsUPXCompressed Problem

The function to determine if an exe file has been compressed (written by RRUZ) is excellent except I found a problem with the code. If the function IsUPXCompressed is called then you try to run upx, UPX can not save the file it modifies. There is something not sharing rights correctly in the function. I have tested this for several hours. If I do not call the method then UPX can write the files with no problem. If you call it then try to run UPX it will not save the file. UPX reports an IOException Permission denied error when trying to write the file.
Can anyone spot something wrong in the code that would cause this problem?
I posted this again because after 24 hours no one seem to see my posts about it at its original locastion: Method to determine if an exe file has been compressed with UPX
Thank-you
#RRUZ's code doesn't close either the file mapping or the file handle used to create it.
After the end of the for.. loop in the code, add the following two three lines:
UnmapViewOfFile(pBaseAddress);
CloseHandle(hFileMap);
CloseHandle(hFile);
No need to test them first, as the prior code exited if either of the function calls to open the handles doesn't succeed. (There should probably be try..finally protection of the two opening calls, but I'll leave that to RRUZ to correct in his original post.)

Creating a file in Delphi with write permission for any user

This might be a dumb question, but I don't seem to be able to create a textfile that is writeable by all the users on a machine, they are always owned by the currently logged in user.
Any ideas? Should I be using TextFile or TFileStream?
I think OP wants to know where to create file writable by all users.
If so, Windows ideology dictates what such files should be created in directory returned by SHGetFolderPath(CSIDL_COMMON_DOCUMENTS) or probabably CSIDL_COMMON_APPDATA
If you create a file it will simply inherit the permissions of its parent container, in other words the folder in which it resides. So you simply need to create it in a folder which has the necessary rights.
What do you mean by "Writable by all the users on a machine" ?
Do you mean you create a file by one user, then another user comes and tries to write into that file, and it fails?
Or do you mean a user creates a file, and other users who are simultaneously connected to the same machine (via terminal sessions) cannot write into the file while the first user is writing in it?
If it is the first case, where is the file saved? Is it in a folder which all users have write access to it?
If it is the second case, you can open the file for read/write without locking it:
var
Stream : TFileStream;
begin
Stream := TFileStream.Create('D:\MyFile',fmOpenReadWrite + fmShareDenyNone);
try
finally
Stream.Free;
end;
end;
Take note with such a code, multiple users might overwrite each other!
Are you talking about NTFS permissions for the file? If yes, you need to look Delphi wrapper for NT security API, and using that API change file security settings to allow Everyone group access the file. If you are just talking about shared access while the file is opened), vcldeveloper above has given the answer.

Opening two HTMLHelp files simultaneously in Delphi causes both help windows to hang

In Delphi, the application's main help file is assigned through the TApplication.HelpFile property. All calls to the application's help system then use this property (in conjunction with CurrentHelpFile) to determine the help file to which help calls should be routed.
In addition to TApplication.HelpFile, each form also has a TForm.HelpFile property which can be used to specify a different (separate) help file for help calls originating from that specific form.
If an application's main help window is already open however, and a help call is made display help from a secondary help file, both help windows hang. Neither of the help windows can now be accessed, and neither can be closed. The only way to get rid of the help windows is to close the application, which results in both help windows being automatically closed as well.
Example:
Application.HelpFile := 'Main Help.chm'; //assign the main help file name
Application.HelpContext(0); //dispays the main help window
Form1.HelpFile := 'Secondary Help.chm'; //assign a different help file
Application.HelpContext(0); //should display a second help window
The last line of code above opens the secondary help window (but with no content) and then both help windows hang.
My Question is this:
Is it possible to display two HTMLHelp windows at the same time, and if so, what is the procedure to be followed?
If not, is there a way to tell whether or not an application's help window is already open, and then close it programatically before displaying a different help window?
(I am Using Delphi 2007 with HTMLHelp files on Windows Vista)
UPDATE: 2008-09-18
Opening two help files at the same time does in fact work as expected using the code above. The problem seems to be with the actual help files I was using - not the code.
I tried the same code with different help files, and it worked fine.
Strangely enough, the two help files I was using each works fine on it's own - it's only when you try to open both at the same time that they hang, and only if you open them from code (in Windows explorer I can open both at the same time without a problem).
Anyway - the problem is definitely with the help files and not the code - so the original questions is now pretty much invalid.
UPDATE 2: 2008-09-18
I eventually found the cause of the hanging help windows. I will post the answer below and accept it as the correct one for future reference. I have also changed the questions title.
Oops... It seems that I cannot accept my own answer...
Please vote it up so it stays at the top.
Assuming you have two help files called "Help File 1.chm" and "Help File 2.chm" and you are opening these help files from your Delphi code.
To open Help File 1, the following code will work:
procedure TForm1.Button1Click(Sender: TObject);
begin
Application.HelpFile := 'Help File 1.chm';
Application.HelpContext(0);
end;
To open Help File 2, the following code will work:
procedure TForm1.Button1Click(Sender: TObject);
begin
Application.HelpFile := 'Help File 2.chm';
Application.HelpContext(0);
end;
But to open both files at the same time, the following code will cause both help windows to hang.
procedure TForm1.Button1Click(Sender: TObject);
begin
Application.HelpFile := 'Help File 1.chm';
Application.HelpContext(0);
Application.HelpFile := 'Help File 2.chm';
Application.HelpContext(0);
end;
SOLUTION:
The problem is caused by the fact that there are spaces in the help file names.
Removing the spaces from the file names will fix the problem.
The following code will work fine:
procedure TForm1.Button1Click(Sender: TObject);
begin
Application.HelpFile := 'HelpFile1.chm';
Application.HelpContext(0);
Application.HelpFile := 'HelpFile2.chm';
Application.HelpContext(0);
end;
I just tested that and it works, as expected, with the kind of code you tried.
Compiled in D2007/XP, ran in both XP and Vista without problem.
procedure TForm1.Button1Click(Sender: TObject);
begin
Application.HelpFile:= 'depends.chm';
Application.HelpContext(0);
HelpFile:='GExperts.chm';
Application.HelpContext(0);
end;
Both help files open and are alive and well....
Q1: Have you checked the validity of your help files?
Q2: Where did you place your code?
Tried. Just works.
Inexperienced with help files here, and even moreso with Vista, but I can offer you a possible workaround...
Build a second application whose only job is to open a help file. You can pass the help file name as a command line argument.
You can easily check from your main application whether this help application is running. This will give you full control, as you can decide whether you want to
Send a message to close the help application before opening the secondary help
Allow more than one instance of the help application to allow different help files to be open at the same time
Allow the help to remain open after your application closes, or whether you want to send a message to it to close it
You can also check whether an instance of the help application already has the requested help file open and decide whether you want to allow it to be opened a second time, or simply bring the existing instance to the foreground.
As stated, this is a workaround - if it turns out to be your only option let me know if you need code examples. Otherwise I'll keep this post clean (and save myself time in the short term) and not clutter it with unnecessary source

Resources