mIRC Homepage
This morning my laptop had a BSoD, and upon trying to run mIRC when I logged on, I was surprised to discover that my mirc.ini had completely wiped itself and restored itself to a default mirci.ini (which is even more odd because I always delete the default files), and that my servers.ini had deleted all servers.

Other files like control.ini, popups.ini and toolbar.ini were fine.

Is there any reason why this would have happened?
This is a common issue that happens with running applications when windows crashes. It will especially happen with applications that are constantly reading and writing to a file at the time of the crash. mIRC will always recreate mirc.ini, servers.ini, and any other settings files if it is unable to load them for some reason.

Other common reasons for file loss are anti-virus/security software incorrectly thinking that mIRC and/or its files may be trojan/virus-related and deleting them without telling you. This can also happen when Windows restarts and the anti-virus/security software performs a startup scan.
Ah, so it's not a mIRC issue.

I was just taken aback since this laptop crashes at least three times as a week and this has never happened before...
I should point out that never in my 20+ years of using Windows have I run into another application (besides mIRC) that has corrupted a configuration file during a system reset / crash / etc. -- on the other hand, I've had mIRC corrupt the ini file on at least 5+ known occasions (the most recent a few weeks ago.

Although this is technically not specific in theory to mIRC, it is very specific in practice to mIRC's implementation alone. This is is really not common in other applications (the linked Google search targets generic data loss, most likely for unsaved work, which is very different from this specific use case. You'll note that none of those search results actually refer to corrupted applications, just user data, and many of those results are specific to corruption at the hardware level), and if other applications did this, they should expect to receive bug reports about it and eventually fix the root cause. That is to say, mIRC could be doing more to at least mitigate this issue if not outright resolve it. The sad part here is that all the hand-waving about this being a "common Windows issue" completely glosses over how easy it is to mitigate/fix the issue altogether, regardless of how innate it is to the OS (though I disagree with the premise).

Although I don't know the exact technique mIRC uses, I can make educated guesses that part of the problem comes from the likelihood that mIRC is constantly opening mirc.ini for writing, rewriting the entire ini file in one shot (i.e., opening the file in truncate mode) and then holding on the handle for a "while" without flushing written contents to disk. If that's the case, a simple fsync() (or FlushFileBuffers() in WINAPI) would mostly solve the problem in most cases except where Windows crashes between writing and flushing, which should be exceedingly rare. If mIRC flushes as soon as it writes, this should never be a problem. If mIRC is not already doing this, it should. File contents are never corrupted if mIRC is only opening a file for reading (or not modifying the buffer). Again, I am probably wrong about some of the details, but I do know that this has never been an issue for any other program I've used that writes configuration (namely, all of them).

I personally think this issue deserves more attention and legitimacy as a real problem. Users in various support channels complain about this fairly often-- often enough that it should be resolved or at least mitigated by changing mIRC's file handling routines to be more robust.
If you have been using mIRC for many years and you have only seen it corrupt the ini file on so few occasions during that time, and it is one of your most used applications, that seems to imply that it is pretty reliable. At such a low rate of incidence, statistically those few occasions where the files were lost could be attributable to almost anything eg. Windows issues, background applications, anti-virus/security software, and so on.

mIRC opens, writes, closes, and flushes all files to disk immediately.

mIRC saves files in a two step process. It creates a temporary file first, saves all settings to it, and only if that is successful, with no errors, does it then delete mirc.ini and rename the temporary file to mirc.ini. If there is an error of any kind during the process, it leaves the original mirc.ini untouched. This is the safest way to update files.

In this case, both the mirc.ini and servers.ini were corrupted which implies that something else has happened. When Windows is in a low resource state and Windows and/or applications are unable to allocate memory or save files to disk, and end up freezing/crashing because of the low resource state, almost anything can happen unfortunately.

That said, as I have never been able to reproduce this myself, if someone can find a set of steps that reproduce this reliably while forcing a Windows BSOD (note that this really could result in file corruption in Windows or other applications), I will try to follow your set of steps to reproduce it.
Even if there may be additional problems at play in some cases, after a quick look we can only conclude that mIRC is not doing what it should be. Collective pulled a system call trace which quite clearly shows that mIRC leaves a "hole" during which an unclean system shutdown can result in the loss of mirc.ini. In particular, mIRC's procedure to update mirc.ini can be represented in pseudocode as follows:

Code:
tmp1 = genMircIniTmpName();
// ..create and fill tmp1 with new mirc.ini contents here, and close it..
tmp2 = genMircIniTmpName();
MoveFile("mirc.ini", tmp2);
DeleteFile(tmp2);
MoveFile(tmp1, "mirc.ini");


Why mIRC renames the old file before deleting it is anybody's guess, but between the two MoveFile calls there is a brief period of time during which there is no mirc.ini on the file system - there will be one or two temporary files, but as far as we know, mIRC does not try to recover those files on startup if it finds no mirc.ini file.

Instead, what mIRC should be doing, is use something like ReplaceFile(), or at least MoveFileEx() with MOVEFILE_REPLACE_EXISTING, so that the old mirc.ini is atomically replaced with the new one. At least in that case, the file system can do its job of ensuring that in all cases, either the old or the new mirc.ini will be present on disk after a system crash.

Edit: as for reproducibility, just let mIRC crash right before the second MoveFile() call. No BSOD needed.

For completeness, below is Collective's system call trace. The comments are mine.

Quote:
11:39:14.9233914 mirc.exe 11000 CreateFile E:\mIRC\mirc82882.tm_ SUCCESS Desired Access: Generic Read/Write, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0, OpenResult: Created 00:00:06.9969309
11:39:14.9243209 mirc.exe 11000 ReadFile E:\mIRC\mirc82882.tm_ END OF FILE Offset: 0, Length: 2, Priority: Normal 00:00:06.9978604
11:39:14.9243583 mirc.exe 11000 WriteFile E:\mIRC\mirc82882.tm_ SUCCESS Offset: 0, Length: 3,760, Priority: Normal 00:00:06.9978978
11:39:14.9244117 mirc.exe 11000 WriteFile E:\mIRC\mirc82882.tm_ SUCCESS Offset: 3,760, Length: 1 00:00:06.9979512
11:39:14.9252286 mirc.exe 11000 WriteFile E:\mIRC\mirc82882.tm_ SUCCESS Offset: 3,761, Length: 4,144, Priority: Normal 00:00:06.9987681
11:39:14.9256091 mirc.exe 11000 WriteFile E:\mIRC\mirc82882.tm_ SUCCESS Offset: 7,905, Length: 2,114 00:00:06.9991486
11:39:14.9256325 mirc.exe 11000 CloseFile E:\mIRC\mirc82882.tm_ SUCCESS 00:00:06.9991720
11:39:14.9258079 MsMpEng.exe 976 CreateFileMapping E:\mIRC\mirc82882.tm_ FILE LOCKED WITH WRITERS SyncType: SyncTypeCreateSection, PageProtection: 00:00:06.9993474
11:39:14.9258273 MsMpEng.exe 976 QueryStandardInformationFile E:\mIRC\mirc82882.tm_ SUCCESS AllocationSize: 16,384, EndOfFile: 10,019, NumberOfLinks: 1, DeletePending: False, Directory: False 00:00:06.9993668
11:39:14.9287327 mirc.exe 11000 QueryOpen E:\mIRC\mirc82882.tm_ SUCCESS CreationTime: 22/05/2016 11:39:14, LastAccessTime: 22/05/2016 11:39:14, LastWriteTime: 22/05/2016 11:39:14, ChangeTime: 22/05/2016 11:39:14, AllocationSize: 12,288, EndOfFile: 10,019, FileAttributes: A 00:00:07.0022722
11:39:14.9287971 mirc.exe 11000 QueryDirectory E:\mIRC\mirc82882.tm_ SUCCESS Filter: mirc82882.tm_, 1: mirc82882.tm_ 00:00:07.0023366
11:39:14.9288770 mirc.exe 11000 QueryOpen E:\mIRC\mirc82882.tm_ SUCCESS CreationTime: 22/05/2016 11:39:14, LastAccessTime: 22/05/2016 11:39:14, LastWriteTime: 22/05/2016 11:39:14, ChangeTime: 22/05/2016 11:39:14, AllocationSize: 12,288, EndOfFile: 10,019, FileAttributes: A 00:00:07.0024165
11:39:14.9289222 mirc.exe 11000 QueryOpen E:\mIRC\mirc.ini SUCCESS CreationTime: 12/03/2015 18:57:00, LastAccessTime: 22/05/2016 05:37:21, LastWriteTime: 22/05/2016 05:37:21, ChangeTime: 22/05/2016 05:37:21, AllocationSize: 12,288, EndOfFile: 10,018, FileAttributes: A 00:00:07.0024617
11:39:14.9289681 mirc.exe 11000 QueryOpen E:\mIRC\mirc.ini SUCCESS CreationTime: 12/03/2015 18:57:00, LastAccessTime: 22/05/2016 05:37:21, LastWriteTime: 22/05/2016 05:37:21, ChangeTime: 22/05/2016 05:37:21, AllocationSize: 12,288, EndOfFile: 10,018, FileAttributes: A 00:00:07.0025076
# MoveFileW start
11:39:14.9290127 mirc.exe 11000 CreateFile E:\mIRC\mirc.ini SUCCESS Desired Access: Read Attributes, Delete, Synchronize, Disposition: Open, Options: Synchronous IO Non-Alert, Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened 00:00:07.0025522
11:39:14.9290451 mirc.exe 11000 QueryAttributeTagFile E:\mIRC\mirc.ini SUCCESS Attributes: A, ReparseTag: 0x0 00:00:07.0025846
11:39:14.9290612 mirc.exe 11000 QueryBasicInformationFile E:\mIRC\mirc.ini SUCCESS CreationTime: 12/03/2015 18:57:00, LastAccessTime: 22/05/2016 05:37:21, LastWriteTime: 22/05/2016 05:37:21, ChangeTime: 22/05/2016 05:37:21, FileAttributes: A 00:00:07.0026007
11:39:14.9291271 mirc.exe 11000 SetRenameInformationFile E:\mIRC\mirc.ini SUCCESS ReplaceIfExists: False, FileName: E:\mIRC\mirc180652.tm_ 00:00:07.0026666
11:39:14.9292512 mirc.exe 11000 CloseFile E:\mIRC\mirc180652.tm_ SUCCESS 00:00:07.0027907
# MoveFileW end
# DeleteFileW start
11:39:14.9293209 mirc.exe 11000 CreateFile E:\mIRC\mirc180652.tm_ SUCCESS Desired Access: Read Attributes, Delete, Disposition: Open, Options: Non-Directory File, Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened 00:00:07.0028604
11:39:14.9293622 mirc.exe 11000 QueryAttributeTagFile E:\mIRC\mirc180652.tm_ SUCCESS Attributes: A, ReparseTag: 0x0 00:00:07.0029017
11:39:14.9293879 mirc.exe 11000 SetDispositionInformationFile E:\mIRC\mirc180652.tm_ SUCCESS Delete: True 00:00:07.0029274
11:39:14.9294170 mirc.exe 11000 CloseFile E:\mIRC\mirc180652.tm_ SUCCESS 00:00:07.0029565
# DeleteFileW end
# MoveFileW start
11:39:14.9295472 mirc.exe 11000 CreateFile E:\mIRC\mirc82882.tm_ SUCCESS Desired Access: Read Attributes, Delete, Synchronize, Disposition: Open, Options: Synchronous IO Non-Alert, Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened 00:00:07.0030867
11:39:14.9295701 mirc.exe 11000 QueryAttributeTagFile E:\mIRC\mirc82882.tm_ SUCCESS Attributes: A, ReparseTag: 0x0 00:00:07.0031096
11:39:14.9295870 mirc.exe 11000 QueryBasicInformationFile E:\mIRC\mirc82882.tm_ SUCCESS CreationTime: 22/05/2016 11:39:14, LastAccessTime: 22/05/2016 11:39:14, LastWriteTime: 22/05/2016 11:39:14, ChangeTime: 22/05/2016 11:39:14, FileAttributes: A 00:00:07.0031265
11:39:14.9296519 mirc.exe 11000 SetRenameInformationFile E:\mIRC\mirc82882.tm_ SUCCESS ReplaceIfExists: False, FileName: E:\mIRC\mirc.ini 00:00:07.0031914
11:39:14.9297761 mirc.exe 11000 CloseFile E:\mIRC\mirc.ini SUCCESS 00:00:07.0033156
# MoveFileW end
11:39:14.9298752 mirc.exe 11000 QueryDirectory E:\mIRC\mirc.ini SUCCESS Filter: mirc.ini, 1: mirc.ini 00:00:07.0034147
Thanks for looking into this, however this behaviour is by design. There are some contexts where a DeleteFile() is queued and may not be processed immediately by Windows, resulting in side-effects if an application tries to access the file soon afterwards, so mIRC specifically forces an immediate move of the original file. This was implemented a long time ago to resolve issues related to DeleteFile().

While I appreciate you looking into this, the only real way to track this down would be to find a way to reproduce it by inducing a BSOD, since that seems to be the specific situation which causes it and which I have not been able to reproduce.
You shouldn't be directly deleting mirc.ini at all, you should be writing a new file and then using ReplaceFile() to move it over to mirc.ini.

There is nothing left to be tracked down. You could easily reproduce this problem yourself simply by inserting an exit(0) into the existing code and looking at the results - the problem is what happens when the code doesn't complete, not why it doesn't complete (whether it's power loss, a BSOD, or something else).
I talked to you about this issue myself on numerous occasion, in private or in here, I'm glad this is brought up again. It's unclear how often/much you use mIRC yourself, but I think you should really trust us in this case. This issue has been happening daily since I started using mIRC, and I only started in 2006, I'm sure it happened before. There is no need for a BSOD to get this to occur.
The typical step for people who report this on scripting channels is to simply turn off the computer with the switch, instead of using the standard way using Windows. Of course just doing this won't make it happen, but it's how users typically experience it.
Originally Posted By: Khaled
Thanks for looking into this, however this behaviour is by design. There are some contexts where a DeleteFile() is queued [..]

You're missing the point. mIRC should not be calling DeleteFile() at all here. It should atomically replace the existing file with the new file, and there are API calls to do that. mIRC is currently not using them. mIRC should be using them. If for some reason these API calls fail, mIRC could still fall back to the old, less safe behavior.

Originally Posted By: Khaled
the only real way to track this down would be to find a way to reproduce it by inducing a BSOD, since that seems to be the specific situation which causes it and which I have not been able to reproduce.

No, that is simply not true. Robustness against system crashes starts with robustness against application crashes. The best thing that an application can do to protect itself from problems resulting from a system crash, is to make sure that at all times, the file system contains a state from which the application can recover. In mIRC's case, that means that at the very least there should always be a valid mirc.ini in the file system. This may not be sufficient to prevent all cases of corruption, but it is a necessary condition.

Right now, mIRC is playing fast and loose with mirc.ini, which may result in its effective loss.

You could ignore the clear problem in front of you and try to figure out exactly what is going on with BSODs, or you could let mIRC do the right thing right now and see if that doesn't already resolve the problem in the majority of the (many, many) current cases. This really shouldn't be a hard decision.
This has also happened to me on numerous occasions. And while it's not often, it is still rather annoying.

The last time was when my laptop cut itself off whilst I was sleeping (cutting off, meaning the equivelent of just pulling the plug.)

But, it's obviously not going to be a sure way of reproducing as there's other ways that could cause it.

However it would be nice to see this fixed.
I am pretty sure I looked into ReplaceFile() many years ago when I reviewed the Windows File APIs but probably decided not to use it because the files must all be on the same volume, which is one of the issues that was resolved with the current implementation after users reported file-saving issues in contexts like network shares, USB drives, and so on. At the time, it was probably also not clear whether ReplaceFile() was an atomic operation. I have found several discussions about it and it sounds like it might be atomic, although it does not say this in the documentation. That said, I will look at it again to see if it makes any difference. One potential issue is that if it fails for some reason, it can leave files in different states that will require a separate call to DeleteFile(), MoveFile(), or both. In any case, it will very likely take several version releases to iron out any issues with using ReplaceFile() as past experience with the File APIs has shown that they can behave unexpectedly (such as queuing a file delete instead of an immediate file delete). Thanks for your feedback everyone.
Quote:
You shouldn't be directly deleting mirc.ini at all, you should be writing a new file and then using ReplaceFile() to move it over to mirc.ini.

mIRC already does what you are suggesting. It writes the output to a temporary file and if that succeeds, it then moves the original file to a separate temporary file, deletes that, and renames the updated file to mirc.ini. The reason for this is that a call to DeleteFile() can pend, which means that Windows will not perform it immediately, which can interfere with subsequent API calls. At least, this was an issue in Windows XP.
What I suggested was to not use DeleteFile. mIRC does use DeleteFile, so it's not doing what I suggested. Your reply suggests that you still do not understand the problem, so I will attempt to explain it another way.

Firstly, forget about DeleteFile altogether. This issue would exist even if you weren't using it, because you're renaming mirc.ini to something else, which is as good as deleting for the purpose of this bug. Once you have performed this rename, there is no longer a mirc.ini in the mIRC folder. If execution stops there, either due to a BSOD or a power cut, the file is gone as far as mIRC (and most end-users) are concerned.

This is not acceptable. mIRC should not be renaming mirc.ini. mIRC should not be deleting mirc.ini. mIRC should leave mirc.ini alone until it is ready to atomically replace it with a new version. ReplaceFile is recommended by Microsoft for exactly this situation. A brief survey of GitHub suggests that MoveFileEx with MOVEFILE_REPLACE_EXISTING is also a common solution, and it was suggested by Sat above.

When you implement one of these options, then and only then will mIRC be doing what I am suggesting.

Very well, thank you for the clarification.
Okay, I have had some time to look into this issue a little more. Some observations:

1) I just noticed that the bug report states that both mirc.ini and servers.ini were empty after a BSOD. However, mIRC can update only one file at a time. If mIRC had been terminated half way through a DeleteFile/MoveFile, it should have affected only one file.

2) I came across the following reports where using ReplaceFile() and MoveFileEx() still resulted in corrupt files after a BSOD or power failure:

http://stackoverflow.com/questions/31710431/how-to-reliably-overwrite-a-file-in-windows
http://stackoverflow.com/questions/6525943/cause-of-corrupted-file-contents

As the point of switching to ReplaceFile() is to resolve this issue, I decided to do a little more testing.

I created a version of mIRC that supports the following modes for replacing files, set by a command line switch when mIRC is run:

mode0 Original DeleteFile()/MoveFile().
mode1 ReplaceFile() (with backup file and REPLACEFILE_IGNORE_MERGE_ERRORS | REPLACEFILE_WRITE_THROUGH).
mode2 MoveFileEx() (with MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH).
mode3 Alternative to mode0 that renames the original mirc.ini to a temporary file, renames the replacement to mirc.ini, and then deletes the original.

I then created a perl script that repeatedly runs mIRC in each mode. When mIRC starts, it repeatedly updates mirc.ini using the mode specified on the command line. The perl script waits for one second and then forcefully terminates mIRC. It then checks to see if mirc.ini still exists and if its size matches a reference file. If mirc.ini is lost or corrupted, it is reset to the reference file.

lost: number of times mirc.ini was lost.
min: shortest number of runs before mirc.ini was lost.
max: longest number of runs before mirc.ini was lost.
mean: average number of runs before mirc.ini was lost.

When mIRC is set to update mirc.ini 150 times a second, the results after 3500 runs (per mode) were:

mode0 lost:328 min:1 max:52 mean:11 loss rate:9.37%
mode1 lost:133 min:1 max:93 mean:26 loss rate:3.80%
mode2 lost:0 min:0 max:0 mean:0 loss rate:0.00%
mode3 lost:182 min:1 max:128 mean:19 loss rate:5.20%

When mIRC is set to update mirc.ini 50 times a second, the results after 3500 runs (per mode) were:

mode0 lost:120 min:1 max:203 mean:29 loss rate:3.43%
mode1 lost:67 min:1 max:196 mean:52 loss rate:1.91%
mode2 lost:1 min:1098 max:1098 mean:1098 loss rate:0.03%
mode3 lost:66 min:1 max:244 mean:53 loss rate:1.89%

When mIRC is set to update mirc.ini 10 times a second, the results after 3500 runs (per mode) were:

mode0 lost:30 min:11 max:432 mean:114 loss rate:0.86%
mode1 lost:16 min:4 max:701 mean:179 loss rate:0.46%
mode2 lost:0 min:0 max:0 mean:0 loss rate:0.00%
mode3 lost:15 min:18 max:1061 mean:230 loss rate:0.43%

mIRC normally only updates mirc.ini once or twice a second.

Notes:

1) The test was performed on Windows 7 with an SSD, so the results are likely to be different on other versions of Windows and on slower, non-SSD drives.

2) The results are unlikely to be applicable to a BSOD or power failure situation, where OS-level caching and drive-level caching are involved, eg. some drives tell the OS that the data has been committed to disk when it is actually still in the drive cache.

3) Mode2 showed almost no file loss. The perl script and implementation in mIRC were checked and looked correct. This appears to be a valid result. The results were the same without MOVEFILE_WRITE_THROUGH for MoveFileEx() and without REPLACEFILE_WRITE_THROUGH for ReplaceFile(), which the documentation says is not supported. The effects of the write-through options might only be apparent on slower, non-SSD drives.

4) When anti-virus software is enabled, ReplaceFile() becomes inceasingly slower than the other modes as the replacement file size increases. With a replacement exe file of 5MB in size, it was ten times slower. Anti-virus software also occasionally locked files and prevented a file replace from completing. The above tests were performed with anti-virus disabled.

5) In both mode0 and mode3, there is a moment when mirc.ini does not exist. However, mode0 performs a delete first, which is more involved due to the DeleteFile() pending issue, and then a rename, while mode3 performs two successive renames, which are much faster, and then a delete. This is probably why mode3 performs at about the same level as ReplaceFile() at lower update rates.

Overall, it looks like using MoveFileEx() is the best option. However, as other software developers who use it still see file loss in a BSOD or power failure situation, it is not clear how much it will help in those contexts. I will be releasing a beta with this change for testing soon.
Wow. Very nice. Your tests make painfully clear that ReplaceFile() is not at all doing what we thought it would..

Originally Posted By: Khaled
2) The results are unlikely to be applicable to a BSOD or power failure situation, where OS-level caching and drive-level caching are involved, eg. some drives tell the OS that the data has been committed to disk when it is actually still in the drive cache.

My guess is still that atomic overwriting renames (ie MoveFileEx()) will already help a lot, even if this still won't be safe in 100% of the BSOD cases.

At least on *NIX, the rule is to call fsync() on the new file before rename()'ing it, in order to prevent that the file ends up being renamed before its data have made it to disk (thus resulting in an empty/corrupted file after an untimely system crash). The Windows equivalent of fsync() appears to be FlushFileBuffers(). I don't know enough about how NTFS journaling works to say whether it helps to call FlushFileBuffers() before the CloseHandle() + MoveFileEx(). In any case, FlushFileBuffers() is probably the last and only thing you can add to improve the BSOD situation further from the application side. If it doesn't have too much of a performance penalty, it might be worth adding just in case.

Edit: just to make sure, FlushFileBuffers() would always be more of an improvement than MOVEFILE_WRITE_THROUGH, as the concern here is about the consistency of the update, not its durability. That is: it is important that mirc.ini is always in a good shape on disk; it is not so important when the whole mirc.ini update actually makes it to disk.

Originally Posted By: Khaled
3) Mode2 showed almost no file loss.

I'm surprised and slightly concerned that with MoveFileEx() there was still one loss case at all though. With only the application crashing, there should be no way that the file gets lost. Do you have any more details about what happened there? Was the file actually lost, empty, corrupted..?
Quote:
FlushFileBuffers() would always be more of an improvement than MOVEFILE_WRITE_THROUGH, as the concern here is about the consistency of the update

The only issue I am concerned about is that, as mIRC is single-threaded, write-through/flushed updates to slower, non-SSD drives may freeze the interface every time there is an update. That said, it looks like just using MoveFileEx() without write-through will help. In fact, even just using mode3 will help - it was probably the issue with the pending delete that was having the most effect.

Quote:
I'm surprised and slightly concerned that with MoveFileEx() there was still one loss case at all though. With only the application crashing, there should be no way that the file gets lost. Do you have any more details about what happened there? Was the file actually lost, empty, corrupted..?

Unfortunately I have no more details about this event. After that specific run, the perl script either did not find an mirc.ini or the mirc.ini size was incorrect. As it is such an outlier, it is possible that something else happened and that this was not due to MoveFileEx().
Originally Posted By: Khaled
The only issue I am concerned about is that, as mIRC is single-threaded, write-through/flushed updates to slower, non-SSD drives may freeze the interface every time there is an update.

That might indeed be a problem. Oh well; if it turns out that MoveFileEx() still does not solve the BSOD problems for many users, it could be a next thing to try.

Originally Posted By: Khaled
Unfortunately I have no more details about this event.

Alright. Thanks!
I should probably weigh in here and say my mIRC is installed to the mechanical hard drive on this laptop rather than the SSD (I use the SSD as little as possible), and that the settings are within the mIRC folder itself rather than using AppData, 'cause I personally found it annoying to access stuff.

Don't know if this information will have any impact on the tests you conducted, though.

Still, the mode2 result looks very promising.
Just an update after close to a year. My personal impression from #mirc channels is this change seems to have had a positive effect. As in, it appears that there are fewer people complaining about losing mirc.ini than before. Of course this is not exactly a reliable statistic, but it's something.

However, it also appears that the issue is not entirely resolved yet. With the newer mIRC versions, so far I've seen two people report loss of mirc.ini after a power failure, with (as far as I can tell) very regular system and mIRC setups and thus no other probable explanation.

As such, it might still be worth trying slightly heavier ways to preserve mirc.ini, or at the very least printing some information that may help identify the root cause. For example, if mirc.ini cannot be loaded but the default directory contains other mirc-generated files that are never installed by default (is remote.ini among those?), print some information about why mirc.ini couldn't be loaded (missing/empty/corrupted) or so. After all, with the new situation, in theory mirc.ini should never be lost. Anyway that's my 2c..
Some things that might help avoid or mitigate problems with mirc.ini vanishing:

1. Related to the problem described in this link, exempt mirc.ini or $mircdir from your virus checker, to avoid lengthening the time it takes mIRC to write to disk, shrinking the time window for something bad to happen during a crash.

Html:
https://forums.mirc.com/ubbthreads.php/topics/260688/Re:_Windows_8.1_/write_very_ve#Post260688


2. Do a little housecleaning on your own mirc.ini. I don't know whether the problem is related to the size of mirc.ini or not, but several years ago when people in #channel were having this problem, after I suggested they trim the size of their mirc.ini smaller than 8kb, it anecdotally seemed to lessen the frequency of mirc.ini getting reset.

The default mirc.ini has a long list of favorites, of which most people don't plan to ever visit many of them, so you can trim them off the list. Before pruning things, you might wish to make a backup copy of mirc.ini to have a list of these no-longer-favorites. The default list of 'favorites' has over 6 dozen channels listed, adding nearly 2kb to the filesize.

Another group of deadwood you can prune from your mirc.ini is within the [windows] section, where there can be a wchannel-$network, wstatus-$network, etc for every $network you've ever been to and never plan to visit again. Many of those lines seem to be created for no benefit, as all the wdccs-$network and wdccg-$network lines I found seem to be identical to the defaults which don't include a network name.

The [fonts] section might also contain font settings for obsolete channels. I even found mine containing font settings for query windows with specific nicks.

3. mIRC could implement a backup system to allow you to restore mirc.ini from a backup, instead of just resetting back to default settings. It should be sufficient to either make the backup at regular intervals or only after non-trivial changes. It looks like mirc.ini is constantly being updated by the value of the online timer, so re-saving the backup for those changes is pointless. Just like many other programs do, mIRC could use the mirc.ini.bak backup if during startup it determines mirc.ini is defective, rather than just restoring all settings to default.

4. In lieu of mIRC creating a backup system, it's easy to script one of your own. This example creates a backup filename for each day of the week, so if you discover your settings have been reset, you can quit mIRC and copy the newest good backup on top of $mircini and restart mIRC. In this example, it makes an hourly backup of both mirc.ini and the file where global variables are saved to disk. Unless you feed it a $1 parameter, it won't make a backup unless mIRC has been running for at least an hour. This prevents a variables backup from being replaced immediately by a main variables file which was reset to default during a crash.

Code:
on *:START:{ mircini_backup }
alias mircini_backup {
  if (!$timer(mircini_backup)) timermircini_backup -o 0 3600 mircini_backup
  if ( ($uptime(mirc,3) !isnum 3600-) && (!$1) ) return
  saveini
  var %ini $nopath($mircini)
  var %bak backup_ $+ $asctime($ctime,dddd) $+ _ $+ %ini
  echo -s Making safety backup of %ini as %bak
  copy -o $qt($mircini) $qt(%bak)
  var %varsfile $readini($mircini,rfiles,n1)
  if (%varsfile != %ini) {
    var %varsbak backup_ $+ $asctime($ctime,dddd) $+ _ $+ $nopath(%varsfile)
    copy -o $qt(%varsfile) $qt(%varsbak)
  }
}

Just having 1 backup is enough to protect against the BSOD bug, since resetting mirc.ini to default removes this snippet and all Alt-R scripts from being loaded, so your backup won't get replaced by mirc.ini immediately after it's been reset. However, it also helps defend against your variables file being reset, giving you a week to notice the problem.

Edit: As for the issue of it being possible that backups made by mIRC could get corrupted just like mirc.ini, I agree that it's possible - but the chances are greatly reduced if backup saves are kept separate from when writes to mirc.ini are made. That means saveini and the equivalent routines which write to mirc.ini at shutdown should not write to the backup too. If mIRC keeps itself from writing to the backup and to mirc.ini within 60 seconds of each other, it's very unlikely that they'll both be corrupted, and people would much rather use a backup that doesn't have the last 15 minutes worth of configuration changes than having mirc.ini reset back to date of install.

Yep, good points. Some sort of backup system would definitely be a good idea I think. Most people that lose mirc.ini, for whatever reason, have nothing to fall back on and have to start from scratch. I don't think a scripted solution would help much: those who lose mirc.ini tend to have no idea that that was something that could possibly ever happen anyway.

As an additional, alternative, least-resistance kind of suggestion towards making mIRC create mirc.ini backups: I've often wondered why the installer doesn't do just that. Right now (as I understand it) the installer backs up only files that are about to be replaced, but I don't think it has to be that way. In fact it would make more sense to me if the installer backed up crucial files no matter what was being replaced at installation time [*]. Having a copy of mirc.ini from before the last upgrade is probably good enough for most people in these situations, and this change can probably easily be made in the installer without affecting anyone negatively. Note that in this case, restoring the backup after a problem would be manual, but that's still a whole lot better than having nothing.

[*] After all, a newer mIRC version may inadvertently misinterpret and mess up an older mirc.ini - at least in theory, because I don't think this has actually happened yet. But this is unrelated to the thread at hand anyway.
I would propose that mIRC create session backups of the files that it opens or modifies. That is, mirc.ini, servers.ini, urls.ini, control.ini, users.ini, vars.ini, popups.ini etc, as well as all loaded scripts and alias files. I recognize that's a lot of files, but it tends to be that all of these files can disappear.

When mIRC launches, as it searches for mirc.ini, it also checks for any mirc.ini.sessionbackup files in those same locations, and compares their last-modified date to determine which one to use. If the sessionbackup is newer than the mirc.ini it finds, or if no mirc.ini is found, then prompt the user about restoration.
© mIRC Discussion Forums