Skip to content

Instantly share code, notes, and snippets.

@antiufo
Created January 25, 2024 16:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save antiufo/136038b69e3341de8a965b13b24df105 to your computer and use it in GitHub Desktop.
Save antiufo/136038b69e3341de8a965b13b24df105 to your computer and use it in GitHub Desktop.
diff --git a/src/Edit.c b/src/Edit.c
index d605e24..172b322 100644
--- a/src/Edit.c
+++ b/src/Edit.c
@@ -1187,7 +1187,8 @@ BOOL EditLoadFile(
int* iEncoding,
int* iEOLMode,
BOOL *pbUnicodeErr,
- BOOL *pbFileTooBig)
+ BOOL *pbFileTooBig,
+ BOOL bRecovery)
{
HANDLE hFile;
@@ -1242,6 +1243,18 @@ BOOL EditLoadFile(
}
lpData = GlobalAlloc(GPTR,dwBufSize);
+
+ if (bRecovery)
+ {
+ WCHAR dummy[MAX_PATH + 40];
+ DWORD magic;
+ DWORD nameLength;
+ ReadFile(hFile, &magic, 4, NULL, NULL);
+ if (magic != RECOVERY_FILE_MAGIC_NUMBER) return FALSE;
+ ReadFile(hFile, &nameLength, 4, NULL, NULL);
+ ReadFile(hFile, &dummy, nameLength * 2 + 2, NULL, NULL);
+ }
+
bReadSuccess = ReadFile(hFile,lpData,(DWORD)GlobalSize(lpData)-2,&cbData,NULL);
dwLastIOError = GetLastError();
CloseHandle(hFile);
@@ -1435,7 +1448,10 @@ BOOL EditSaveFile(
LPCWSTR pszFile,
int iEncoding,
BOOL *pbCancelDataLoss,
- BOOL bSaveCopy)
+ BOOL bSaveCopy,
+ BOOL bRecovery,
+ LPCWSTR pszPrefix
+ )
{
HANDLE hFile;
@@ -1477,14 +1493,23 @@ BOOL EditSaveFile(
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
+ if (pszPrefix != NULL) {
+ DWORD magic = RECOVERY_FILE_MAGIC_NUMBER;
+ DWORD prefixLength = wcslen(pszPrefix);
+ WriteFile(hFile, &magic, 4, &dwBytesWritten, NULL);
+ WriteFile(hFile, &prefixLength, 4, &dwBytesWritten, NULL);
+ WriteFile(hFile, (byte*)pszPrefix, (prefixLength + 1) * 2, &dwBytesWritten, NULL);
+ }
+
+
// ensure consistent line endings
- if (bFixLineEndings) {
+ if (bFixLineEndings && !bRecovery) {
SendMessage(hwnd,SCI_CONVERTEOLS,SendMessage(hwnd,SCI_GETEOLMODE,0,0),0);
EditFixPositions(hwnd);
}
// strip trailing blanks
- if (bAutoStripBlanks)
+ if (bAutoStripBlanks && !bRecovery)
EditStripTrailingBlanks(hwnd,TRUE);
// get text
@@ -1616,8 +1641,9 @@ BOOL EditSaveFile(
if (bWriteSuccess)
{
if (!bSaveCopy)
+ {
SendMessage(hwnd,SCI_SETSAVEPOINT,0,0);
-
+ }
return TRUE;
}
diff --git a/src/Edit.h b/src/Edit.h
index bc3f59b..94586e3 100644
--- a/src/Edit.h
+++ b/src/Edit.h
@@ -77,7 +77,7 @@ char* EditGetClipboardText(HWND);
BOOL EditCopyAppend(HWND);
int EditDetectEOLMode(HWND,char*,DWORD);
BOOL EditLoadFile(HWND,LPCWSTR,BOOL,int*,int*,BOOL*,BOOL*);
-BOOL EditSaveFile(HWND,LPCWSTR,int,BOOL*,BOOL);
+BOOL EditSaveFile(HWND,LPCWSTR,int,BOOL*,BOOL,BOOL,LPCWSTR);
void EditInvertCase(HWND);
void EditTitleCase(HWND);
diff --git a/src/Helpers.c b/src/Helpers.c
index 8138467..d876210 100644
--- a/src/Helpers.c
+++ b/src/Helpers.c
@@ -353,7 +353,7 @@ BOOL bFreezeAppTitle = FALSE;
BOOL SetWindowTitle(HWND hwnd,UINT uIDAppName,BOOL bIsElevated,UINT uIDUntitled,
LPCWSTR lpszFile,int iFormat,BOOL bModified,
- UINT uIDReadOnly,BOOL bReadOnly,LPCWSTR lpszExcerpt)
+ UINT uIDReadOnly,BOOL bReadOnly,LPCWSTR lpszExcerpt,BOOL bIsRecovered)
{
WCHAR szUntitled[128];
@@ -423,6 +423,11 @@ BOOL SetWindowTitle(HWND hwnd,UINT uIDAppName,BOOL bIsElevated,UINT uIDUntitled,
lstrcat(szTitle,szUntitled);
}
+ if (bIsRecovered)
+ {
+ lstrcat(szTitle, L" [RECOVERED]");
+ }
+
if (bReadOnly && GetString(uIDReadOnly,szReadOnly,COUNTOF(szReadOnly)))
{
lstrcat(szTitle,L" ");
@@ -1656,6 +1661,7 @@ BOOL MRU_AddFile(LPMRULIST pmru,LPCWSTR pszFile,BOOL bRelativePath,BOOL bUnexpan
int i;
for (i = 0; i < pmru->iSize; i++) {
+ if (pmru->pszItems[i] == NULL) continue;
if (lstrcmpi(pmru->pszItems[i],pszFile) == 0) {
LocalFree(pmru->pszItems[i]);
break;
diff --git a/src/Helpers.h b/src/Helpers.h
index 490fac2..279207e 100644
--- a/src/Helpers.h
+++ b/src/Helpers.h
@@ -85,7 +85,7 @@ BOOL VerifyContrast(COLORREF,COLORREF);
BOOL IsFontAvailable(LPCWSTR);
-BOOL SetWindowTitle(HWND,UINT,BOOL,UINT,LPCWSTR,int,BOOL,UINT,BOOL,LPCWSTR);
+BOOL SetWindowTitle(HWND,UINT,BOOL,UINT,LPCWSTR,int,BOOL,UINT,BOOL,LPCWSTR,BOOL);
void SetWindowTransparentMode(HWND,BOOL);
diff --git a/src/Notepad2.c b/src/Notepad2.c
index 4f26aa8..4d4d025 100644
--- a/src/Notepad2.c
+++ b/src/Notepad2.c
@@ -214,8 +214,16 @@ LPMRULIST mruReplace;
DWORD dwLastIOError;
WCHAR szCurFile[MAX_PATH+40];
+WCHAR szRecoveryFile[MAX_PATH+50];
+WCHAR szRecoveryDirectory[MAX_PATH];
+DWORD iRecoveryInterval;
+BOOL bIsRecovered = FALSE;
+BOOL bNotARealSavePoint = FALSE;
FILEVARS fvCurFile;
BOOL bModified;
+BOOL bModifiedSinceLastRecoverySave;
+BOOL bIgnoreNextChangeNotificationForRecovery;
+UINT_PTR pFileRecoveryTimer = NULL;
BOOL bReadOnly = FALSE;
int iEncoding;
int iOriginalEncoding;
@@ -988,7 +996,7 @@ HWND InitInstance(HINSTANCE hInstance,LPSTR pszCmdLine,int nCmdShow)
uidsAppTitle = IDS_APPTITLE_PASTEBOARD;
SetWindowTitle(hwndMain,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
bLastCopyFromMe = FALSE;
dwLastCopyTime = 0;
@@ -1121,13 +1129,13 @@ LRESULT CALLBACK MainWndProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM lParam)
case WM_CLOSE:
- if (FileSave(FALSE,TRUE,FALSE,FALSE))
+ if (FileSaveEx(FALSE,TRUE,FALSE,FALSE,TRUE))
DestroyWindow(hwnd);
break;
case WM_QUERYENDSESSION:
- if (FileSave(FALSE,TRUE,FALSE,FALSE))
+ if (FileSaveEx(FALSE,TRUE,FALSE,FALSE,TRUE))
return TRUE;
else
return FALSE;
@@ -1280,7 +1288,7 @@ LRESULT CALLBACK MainWndProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM lParam)
lstrcpyn(szTitleExcerpt,StrEnd(&params->wchData)+1,COUNTOF(szTitleExcerpt));
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
}
}
// reset
@@ -1370,6 +1378,11 @@ LRESULT CALLBACK MainWndProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM lParam)
MsgInitMenu(hwnd,wParam,lParam);
break;
+ case WM_INITMENUPOPUP:
+ if (GetMenuItemID(wParam, 0) == IDM_FILE_RECOVERED) {
+ PopulateRecoveredFilesMenu((HMENU)wParam);
+ }
+ break;
case WM_NOTIFY:
return MsgNotify(hwnd,wParam,lParam);
@@ -2040,6 +2053,89 @@ void MsgSize(HWND hwnd,WPARAM wParam,LPARAM lParam)
}
+#define MAX_RECOVERY_MENU_ITEMS 50
+
+
+BOOL GetDisplayNameForRecoveryFile(PWCHAR destination, PWCHAR name)
+{
+ if (isdigit(name[0]))
+ {
+ // Eg. 36275755171385521050--example.txt.dat
+ PWCHAR idx = wcschr(name, '-');
+ if (idx == NULL || *(idx + 1) != '-') return FALSE;
+ wcscpy(destination, idx + 2);
+ destination[wcslen(destination) - 4] = 0;
+ return TRUE;
+ }
+ else
+ {
+ // Eg. Untitled--2017-03-07--05-44-26--10452.txt.dat
+ if (wcslen(name) <= 32) return FALSE;
+
+ wcscpy(destination, L"Untitled (");
+ wcscat(destination, name + 10);
+ wcscpy(destination + 21, name + 22);
+ destination[20] = ' ';
+ destination[23] = ':';
+ destination[26] = ')';
+ destination[27] = 0;
+ return TRUE;
+ }
+
+
+
+ return TRUE;
+}
+
+PWCHAR pRecoveryMenuItems[MAX_RECOVERY_MENU_ITEMS];
+int iRecoveryMenuItemsCount = 0;
+
+void PopulateRecoveredFilesMenu(HMENU menu)
+{
+ if (wcslen(szCurFile) == 0 && wcslen(szRecoveryFile) != 0 && (int)SendMessage(hwndEdit, SCI_GETLENGTH, 0, 0) == 0)
+ {
+ // If the current untitled, recovered file has been emptied, remove it immediately from the list.
+ SaveRecoveryFile();
+ }
+ for (size_t i = 0; i < iRecoveryMenuItemsCount; i++)
+ {
+ free(pRecoveryMenuItems[i]);
+ RemoveMenu(menu, 0, MF_BYPOSITION);
+ }
+
+ RemoveMenu(menu, 0, MF_BYPOSITION); // Delete dummy entry
+
+ WIN32_FIND_DATA findData;
+ iRecoveryMenuItemsCount = 0;
+ WCHAR szSearchPath[MAX_PATH];
+ wcscpy(szSearchPath, szRecoveryDirectory);
+ PathAppend(szSearchPath, L"*.dat");
+ HANDLE hFind = FindFirstFile(szSearchPath, &findData);
+ if (hFind != -1)
+ {
+ WCHAR szDisplayName[MAX_PATH];
+ while (TRUE)
+ {
+
+
+ if (GetDisplayNameForRecoveryFile(szDisplayName, findData.cFileName))
+ {
+ PWCHAR szCopiedName = (PWCHAR)malloc(MAX_PATH * 2);
+ wcscpy(szCopiedName, findData.cFileName);
+ pRecoveryMenuItems[iRecoveryMenuItemsCount] = szCopiedName;
+
+ AppendMenu(menu, MF_STRING | MF_ENABLED, IDM_FILE_RECOVERED + iRecoveryMenuItemsCount, szDisplayName);
+ iRecoveryMenuItemsCount++;
+ if (iRecoveryMenuItemsCount == MAX_RECOVERY_MENU_ITEMS) return;
+ }
+ if (!FindNextFile(hFind, &findData)) break;
+ }
+ }
+
+ if(iRecoveryMenuItemsCount == 0)
+ AppendMenu(menu, MF_STRING | MF_DISABLED, IDM_FILE_RECOVERED, L"(Empty)");
+
+}
//=============================================================================
//
@@ -2246,6 +2342,8 @@ void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam)
CheckCmd(hmenu,IDM_VIEW_REUSEWINDOW,i);
i = IniGetInt(L"Settings2",L"SingleFileInstance",0);
CheckCmd(hmenu,IDM_VIEW_SINGLEFILEINSTANCE,i);
+ i = IniGetInt(L"Settings2",L"AutomaticFileRecovery",1);
+ CheckCmd(hmenu, IDM_VIEW_FILERECOVERY, i);
bStickyWinPos = IniGetInt(L"Settings2",L"StickyWindowPosition",0);
CheckCmd(hmenu,IDM_VIEW_STICKYWINPOS,bStickyWinPos);
CheckCmd(hmenu,IDM_VIEW_ALWAYSONTOP,((bAlwaysOnTop || flagAlwaysOnTop == 2) && flagAlwaysOnTop != 1));
@@ -2283,6 +2381,7 @@ void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam)
EnableCmd(hmenu,IDM_VIEW_REUSEWINDOW,i);
EnableCmd(hmenu,IDM_VIEW_STICKYWINPOS,i);
EnableCmd(hmenu,IDM_VIEW_SINGLEFILEINSTANCE,i);
+ EnableCmd(hmenu,IDM_VIEW_FILERECOVERY,i);
EnableCmd(hmenu,IDM_VIEW_NOSAVERECENT,i);
EnableCmd(hmenu,IDM_VIEW_NOSAVEFINDREPL,i);
EnableCmd(hmenu,IDM_VIEW_SAVESETTINGS,i);
@@ -2392,7 +2491,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
}
break;
@@ -2756,7 +2855,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
}
}
break;
@@ -2810,7 +2909,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)
UpdateStatusbar();
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
}
break;
@@ -3661,9 +3760,9 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)
}
else
{
- // define (beh�ver bara g�ra detta en g�ng egentligen)
- //SendMessage( hwndEdit , SCI_MARKERSETBACK , 0 , 74 | (203 << 8) | (0 << 16) ); //beh�ver bara g�ra detta en g�ng egentligen
- //SendMessage( hwndEdit , SCI_MARKERDEFINE , 0 , SC_MARK_ARROWS ); //beh�ver bara g�ra detta en g�ng egentligen
+ // define (beh�ver bara g�ra detta en g�ng egentligen)
+ //SendMessage( hwndEdit , SCI_MARKERSETBACK , 0 , 74 | (203 << 8) | (0 << 16) ); //beh�ver bara g�ra detta en g�ng egentligen
+ //SendMessage( hwndEdit , SCI_MARKERDEFINE , 0 , SC_MARK_ARROWS ); //beh�ver bara g�ra detta en g�ng egentligen
if( bShowSelectionMargin )
{
@@ -4199,6 +4298,22 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)
IniSetInt(L"Settings2",L"SingleFileInstance",1);
break;
+ case IDM_VIEW_FILERECOVERY:
+ if (IniGetInt(L"Settings2", L"AutomaticFileRecovery", 0))
+ {
+ IniSetInt(L"Settings2", L"AutomaticFileRecovery", 0);
+ StopFileRecoveryTimer(TRUE);
+ wcscpy(szRecoveryFile, L"");
+ }
+ else
+ {
+ IniSetInt(L"Settings2", L"AutomaticFileRecovery", 1);
+ InitRecoveryFilePath(szCurFile,szRecoveryFile);
+ if (bModified) StartFileRecoveryTimer();
+ }
+ break;
+
+
case IDM_VIEW_ALWAYSONTOP:
if ((bAlwaysOnTop || flagAlwaysOnTop == 2) && flagAlwaysOnTop != 1) {
@@ -4230,7 +4345,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)
lstrcpy(szTitleExcerpt,L"");
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
break;
@@ -4239,7 +4354,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)
lstrcpy(szTitleExcerpt,L"");
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
break;
@@ -4248,7 +4363,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)
lstrcpy(szTitleExcerpt,L"");
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
break;
@@ -4256,7 +4371,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)
EditGetExcerpt(hwndEdit,szTitleExcerpt,COUNTOF(szTitleExcerpt));
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
break;
@@ -4775,7 +4890,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)
EditGetExcerpt(hwndEdit,szTitleExcerpt,COUNTOF(szTitleExcerpt));
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
break;
@@ -5071,6 +5186,11 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)
MessageBeep(0);
break;
+ default:
+ if (LOWORD(wParam) >= IDM_FILE_RECOVERED && LOWORD(wParam) <= IDM_FILE_RECOVERED_MAX)
+ {
+ LoadRecoveryFile(pRecoveryMenuItems[LOWORD(wParam) - IDM_FILE_RECOVERED]);
+ }
}
return(0);
@@ -5310,15 +5430,24 @@ LRESULT MsgNotify(HWND hwnd,WPARAM wParam,LPARAM lParam)
break;
case SCN_MODIFIED:
+ if (bIgnoreNextChangeNotificationForRecovery) {
+ bIgnoreNextChangeNotificationForRecovery = FALSE;
+ }else{
+ bModifiedSinceLastRecoverySave = TRUE;
+ StartFileRecoveryTimer();
+ }
+ // Fall throuh
case SCN_ZOOM:
UpdateLineNumberWidth();
break;
case SCN_SAVEPOINTREACHED:
+ if (bNotARealSavePoint) break;
bModified = FALSE;
+ StopFileRecoveryTimer(TRUE);
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
break;
case SCN_MARGINCLICK:
@@ -5333,9 +5462,11 @@ LRESULT MsgNotify(HWND hwnd,WPARAM wParam,LPARAM lParam)
case SCN_SAVEPOINTLEFT:
bModified = TRUE;
+ bModifiedSinceLastRecoverySave = TRUE;
+ StartFileRecoveryTimer();
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
break;
}
break;
@@ -5734,6 +5865,19 @@ void LoadSettings()
IniSectionGetString(pIniSection,L"DefaultDirectory",L"",
tchDefaultDir,COUNTOF(tchDefaultDir));
+ iRecoveryInterval = IniGetInt(pIniSection, L"AutomaticRecoveryInterval", 30000);
+
+ if (!IniSectionGetString(pIniSection, L"RecoveryFileDirectory", L"", szRecoveryDirectory, COUNTOF(szRecoveryDirectory)))
+ {
+ SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, szRecoveryDirectory);
+ PathAppend(szRecoveryDirectory, L"Notepad2\\Recovered Files");
+ }
+ else
+ {
+ PathAbsoluteFromApp(szRecoveryDirectory, NULL, COUNTOF(szRecoveryDirectory), TRUE);
+ }
+
+
ZeroMemory(tchFileDlgFilters,sizeof(WCHAR)*COUNTOF(tchFileDlgFilters));
IniSectionGetString(pIniSection,L"FileDlgFilters",L"",
tchFileDlgFilters,COUNTOF(tchFileDlgFilters)-2);
@@ -6790,7 +6934,7 @@ void UpdateLineNumberWidth()
//
BOOL FileIO(BOOL fLoad,LPCWSTR psz,BOOL bNoEncDetect,int *ienc,int *ieol,
BOOL *pbUnicodeErr,BOOL *pbFileTooBig,
- BOOL *pbCancelDataLoss,BOOL bSaveCopy)
+ BOOL *pbCancelDataLoss,BOOL bSaveCopy,BOOL bRecovery)
{
WCHAR tch[MAX_PATH+40];
BOOL fSuccess;
@@ -6807,13 +6951,21 @@ BOOL FileIO(BOOL fLoad,LPCWSTR psz,BOOL bNoEncDetect,int *ienc,int *ieol,
UpdateWindow(hwndStatus);
if (fLoad)
- fSuccess = EditLoadFile(hwndEdit,psz,bNoEncDetect,ienc,ieol,pbUnicodeErr,pbFileTooBig);
+ fSuccess = EditLoadFile(hwndEdit,psz,bNoEncDetect,ienc,ieol,pbUnicodeErr,pbFileTooBig,bRecovery);
else
- fSuccess = EditSaveFile(hwndEdit,psz,*ienc,pbCancelDataLoss,bSaveCopy);
+ fSuccess = EditSaveFile(hwndEdit,psz,*ienc,pbCancelDataLoss,bSaveCopy,bRecovery,bRecovery ? szCurFile : NULL);
- dwFileAttributes = GetFileAttributes(psz);
- bReadOnly = (dwFileAttributes != INVALID_FILE_ATTRIBUTES && dwFileAttributes & FILE_ATTRIBUTE_READONLY);
+ if (!bRecovery) {
+ dwFileAttributes = GetFileAttributes(psz);
+ bReadOnly = (dwFileAttributes != INVALID_FILE_ATTRIBUTES && dwFileAttributes & FILE_ATTRIBUTE_READONLY);
+ if (fSuccess && !fLoad)
+ {
+ bNotARealSavePoint = FALSE;
+ }
+ }
+ if (fSuccess && fLoad)
+ bIsRecovered = bRecovery;
StatusSetSimple(hwndStatus,FALSE);
EndWaitCursor();
@@ -6821,28 +6973,188 @@ BOOL FileIO(BOOL fLoad,LPCWSTR psz,BOOL bNoEncDetect,int *ienc,int *ieol,
return(fSuccess);
}
+unsigned long HashBytes(BYTE *data, int length)
+{
+ unsigned long hash = 5381;
+
+ for (size_t i = 0; i < length; i++)
+ {
+ int c = data[i];
+ hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+ }
+
+ return hash;
+}
+
+void InitRecoveryFilePath(PWCHAR originalFile, PWCHAR dest)
+{
+ if (IniGetInt(L"Settings2", L"AutomaticFileRecovery", 1) == 0)
+ {
+ wcscpy(dest, L"");
+ return;
+ }
+ wcscpy(dest, szRecoveryDirectory);
+ if(dest[wcslen(dest) - 1] != '\\') wcscat(dest, L"\\");
+
+
+ if (wcslen(originalFile) == 0)
+ {
+ wcscat(dest, L"Untitled--");
+ SYSTEMTIME time;
+ GetSystemTime(&time);
+ GetDateFormat(LOCALE_INVARIANT, 0, &time, L"yyyy-MM-dd--", dest + wcslen(dest), 256);
+ GetTimeFormat(LOCALE_INVARIANT, 0, &time, L"hh-mm-ss--", dest + wcslen(dest), 256);
+ srand((UINT)GetTickCount());
+ int r = abs(rand());
+ wsprintf(dest + wcslen(dest), L"%d", r);
+ wcscat(dest, L".txt.dat");
+ }
+ else
+ {
+ PWCHAR lastBackslash = wcsrchr(originalFile, '\\');
+ if (lastBackslash != NULL)
+ {
+ WCHAR buffer[MAX_PATH + 40];
+ wcscpy(buffer, originalFile);
+ wcsupr(buffer);
+
+ unsigned long hash1 = HashBytes(((byte*)buffer) + 0, wcslen(buffer) * 2 + 0);
+ unsigned long hash2 = HashBytes(((byte*)buffer) + 1, wcslen(buffer) * 2 - 1);
+
+ wsprintf(dest + wcslen(dest), L"%hu%hu--", hash1, hash2);;
+ wcscat(dest, lastBackslash + 1);
+ wcscat(dest, L".dat");
+ }
+ else
+ {
+ wcscat(dest, L"wat");
+ }
+ }
+
+
+
+
+}
+
+
+BOOL LoadRecoveryFile(PWCHAR pszRecoveryFileName)
+{
+ WCHAR szRecoveryFilePath[MAX_PATH];
+ wcscpy(szRecoveryFilePath, szRecoveryDirectory);
+ PathAppend(szRecoveryFilePath, pszRecoveryFileName);
+ BOOL bResult = FALSE;
+ HANDLE hFile = CreateFile(szRecoveryFilePath,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE) return bResult;
+ DWORD magic;
+ DWORD pathLength;
+ if (!ReadFile(hFile, &magic, 4, NULL, NULL)) goto cleanup;
+ if (magic != RECOVERY_FILE_MAGIC_NUMBER) goto cleanup;
+ if (!ReadFile(hFile, &pathLength, 4, NULL, NULL)) goto cleanup;
+ WCHAR szOriginalPath[MAX_PATH];
+ if (!ReadFile(hFile, &szOriginalPath, (pathLength + 1) * 2, NULL, NULL)) goto cleanup;
+
+ if (wcslen(szOriginalPath) != 0)
+ {
+ if (wcsicmp(szOriginalPath, szCurFile) == 0) goto cleanup;
+ }
+ else
+ {
+ if (wcsicmp(szRecoveryFilePath, szRecoveryFile) == 0) goto cleanup;
+ }
+
+ if (!FileLoadEx(FALSE, FALSE, FALSE, FALSE, szOriginalPath, szRecoveryFilePath, TRUE)) goto cleanup;
+ bResult = TRUE;
+cleanup:
+ CloseHandle(hFile);
+ return bResult;
+}
+
+BOOL SaveRecoveryFile()
+{
+ bModifiedSinceLastRecoverySave = FALSE;
+
+ int encoding = iEncoding;
+ int eol = iEOLMode;
+ BOOL cancelDataLoss = FALSE;
+
+ if (!bModified || wcslen(szCurFile) == 0 && (int)SendMessage(hwndEdit,SCI_GETLENGTH,0,0) == 0)
+ {
+ StopFileRecoveryTimer(TRUE);
+ return TRUE;
+ }
+ else
+ {
+ SHCreateDirectoryEx(NULL, szRecoveryDirectory, NULL);
+ return FileIO(FALSE, szRecoveryFile, FALSE, &encoding, &eol, NULL, NULL, &cancelDataLoss, TRUE, TRUE);
+ }
+
+}
+
+
+
+void CALLBACK FileRecoveryTimerCallback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ StopFileRecoveryTimer(FALSE);
+ SaveRecoveryFile();
+ pFileRecoveryTimer = NULL;
+}
+
+void StartFileRecoveryTimer() {
+ if (pFileRecoveryTimer != NULL) return;
+ pFileRecoveryTimer = SetTimer(hwndMain, ID_FILERECOVERYTIMER, iRecoveryInterval, FileRecoveryTimerCallback);
+}
+
+
+void StopFileRecoveryTimer(BOOL deleteRecoveryFile) {
+ bModifiedSinceLastRecoverySave = FALSE;
+ if (deleteRecoveryFile && wcslen(szRecoveryFile) != 0) {
+ DeleteFile(szRecoveryFile);
+ }
+ if (pFileRecoveryTimer != NULL)
+ {
+ KillTimer(hwndMain, pFileRecoveryTimer);
+ pFileRecoveryTimer = NULL;
+ }
+}
+
//=============================================================================
//
// FileLoad()
//
//
-BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lpszFile)
+BOOL FileLoad(BOOL bDontSave, BOOL bNew, BOOL bReload, BOOL bNoEncDetect, LPCWSTR lpszFile)
+{
+ return FileLoadEx(bDontSave,bNew,bReload,bNoEncDetect,lpszFile,NULL,FALSE);
+}
+BOOL FileLoadEx(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lpszFile,LPCWSTR lpszRecoveryPath,BOOL bAllowSaveToRecovery)
{
WCHAR tch[MAX_PATH] = L"";
WCHAR szFileName[MAX_PATH] = L"";
BOOL fSuccess;
BOOL bUnicodeErr = FALSE;
BOOL bFileTooBig = FALSE;
+ BOOL bIsRecoveredUntitledFile = wcslen(lpszFile) == 0 && lpszRecoveryPath != NULL;
if (!bDontSave)
{
- if (!FileSave(FALSE,TRUE,FALSE,FALSE))
+ if (!FileSaveEx(FALSE,TRUE,FALSE,FALSE,bAllowSaveToRecovery))
return FALSE;
+ wcscpy(szRecoveryFile, L"");
}
+ StopFileRecoveryTimer(TRUE);
+ bIsRecovered = FALSE;
if (bNew) {
lstrcpy(szCurFile,L"");
+ InitRecoveryFilePath(szCurFile, szRecoveryFile);
+ bNotARealSavePoint = FALSE;
SetDlgItemText(hwndMain,IDC_FILENAME,szCurFile);
SetDlgItemInt(hwndMain,IDC_REUSELOCK,GetTickCount(),FALSE);
if (!fKeepTitleExcerpt)
@@ -6861,7 +7173,7 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp
EditSetNewText(hwndEdit,"",0);
SetWindowTitle(hwndMain,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
// Terminate file watching
if (bResetFileWatching)
@@ -6871,7 +7183,7 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp
return TRUE;
}
- if (!lpszFile || lstrlen(lpszFile) == 0) {
+ if ((!lpszFile || lstrlen(lpszFile) == 0) && lpszRecoveryPath == NULL) {
if (!OpenFileDlg(hwndMain,tch,COUNTOF(tch),NULL))
return FALSE;
}
@@ -6881,7 +7193,7 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp
ExpandEnvironmentStringsEx(tch,COUNTOF(tch));
- if (PathIsRelative(tch)) {
+ if (PathIsRelative(tch) && !bIsRecoveredUntitledFile) {
StrCpyN(szFileName,g_wchWorkingDirectory,COUNTOF(szFileName));
PathAppend(szFileName,tch);
if (!PathFileExists(szFileName)) {
@@ -6894,14 +7206,18 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp
else
lstrcpy(szFileName,tch);
- PathCanonicalizeEx(szFileName);
- GetLongPathNameEx(szFileName,COUNTOF(szFileName));
+ if (!bIsRecoveredUntitledFile) {
+ PathCanonicalizeEx(szFileName);
+ GetLongPathNameEx(szFileName, COUNTOF(szFileName));
- if (PathIsLnkFile(szFileName))
- PathGetLnkPath(szFileName,szFileName,COUNTOF(szFileName));
+ if (PathIsLnkFile(szFileName))
+ PathGetLnkPath(szFileName, szFileName, COUNTOF(szFileName));
+ }
+
+ BOOL usedRecoveryInfo = FALSE;
// Ask to create a new file...
- if (!bReload && !PathFileExists(szFileName))
+ if (!bReload && !PathFileExists(szFileName) && lpszRecoveryPath == NULL)
{
if (flagQuietCreate || MsgBox(MBYESNO,IDS_ASK_CREATE,szFileName) == IDYES) {
HANDLE hFile = CreateFile(szFileName,
@@ -6933,10 +7249,44 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp
}
else
- fSuccess = FileIO(TRUE,szFileName,bNoEncDetect,&iEncoding,&iEOLMode,&bUnicodeErr,&bFileTooBig,NULL,FALSE);
+ {
+ WCHAR szRecoveryFileToReadFrom[MAX_PATH + 40] = L"";
+ if (bIsRecoveredUntitledFile)
+ {
+ wcscpy(szRecoveryFileToReadFrom, lpszRecoveryPath);
+ usedRecoveryInfo = TRUE;
+ }
+ else
+ {
+ InitRecoveryFilePath(szFileName, szRecoveryFileToReadFrom);
+ usedRecoveryInfo = wcslen(szRecoveryFileToReadFrom) && GetFileAttributes(szRecoveryFileToReadFrom) != INVALID_FILE_ATTRIBUTES;
+ }
+ fSuccess = FileIO(TRUE, usedRecoveryInfo ? szRecoveryFileToReadFrom : szFileName, bNoEncDetect, &iEncoding, &iEOLMode, &bUnicodeErr, &bFileTooBig, NULL, FALSE, usedRecoveryInfo);
+ if (fSuccess)
+ {
+ if (usedRecoveryInfo) {
+ bNotARealSavePoint = TRUE;
+ if (bIsRecoveredUntitledFile)
+ {
+ bReadOnly = FALSE;
+ }
+ else
+ {
+ DWORD dwFileAttributes = GetFileAttributes(szFileName);
+ bReadOnly = (dwFileAttributes != INVALID_FILE_ATTRIBUTES && dwFileAttributes & FILE_ATTRIBUTE_READONLY);
+ }
+ }
+ else
+ {
+ bNotARealSavePoint = FALSE;
+ }
+ }
+ }
if (fSuccess) {
lstrcpy(szCurFile,szFileName);
+ if (lpszRecoveryPath != NULL) wcscpy(szRecoveryFile, lpszRecoveryPath);
+ else InitRecoveryFilePath(szCurFile,szRecoveryFile);
SetDlgItemText(hwndMain,IDC_FILENAME,szCurFile);
SetDlgItemInt(hwndMain,IDC_REUSELOCK,GetTickCount(),FALSE);
if (!fKeepTitleExcerpt)
@@ -6945,7 +7295,7 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp
Style_SetLexerFromFile(hwndEdit,szCurFile);
UpdateLineNumberWidth();
iOriginalEncoding = iEncoding;
- bModified = FALSE;
+ bModified = usedRecoveryInfo;
//bReadOnly = FALSE;
SendMessage(hwndEdit,SCI_SETEOLMODE,iEOLMode,0);
MRU_AddFile(pFileMRU,szFileName,flagRelativeFileMRU,flagPortableMyDocs);
@@ -6953,7 +7303,7 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp
SHAddToRecentDocs(SHARD_PATHW,szFileName);
SetWindowTitle(hwndMain,uidsAppTitle,fIsElevated,IDS_UNTITLED,szFileName,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
// Install watching of the current file
if (!bReload && bResetFileWatching)
@@ -6985,6 +7335,8 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp
else if (!bFileTooBig)
MsgBox(MBWARN,IDS_ERR_LOADFILE,szFileName);
+ if (fSuccess && bReload) bIgnoreNextChangeNotificationForRecovery = TRUE;
+
return(fSuccess);
}
@@ -6994,12 +7346,21 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp
// FileSave()
//
//
-BOOL FileSave(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy)
+
+BOOL FileSave(BOOL bSaveAlways, BOOL bAsk, BOOL bSaveAs, BOOL bSaveCopy)
+{
+ return FileSaveEx(bSaveAlways, bAsk, bSaveAs, bSaveCopy, FALSE);
+}
+BOOL FileSaveEx(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy,BOOL bAllowSaveToRecovery)
{
WCHAR tchFile[MAX_PATH];
BOOL fSuccess = FALSE;
BOOL bCancelDataLoss = FALSE;
+ if (bIsRecovered) bAllowSaveToRecovery = TRUE;
+
+ if (wcslen(szRecoveryFile) == 0 || !IniGetInt(L"Settings2", L"AutomaticFileRecovery", 1)) bAllowSaveToRecovery = FALSE;
+
BOOL bIsEmptyNewFile = FALSE;
if (lstrlen(szCurFile) == 0) {
int cchText = (int)SendMessage(hwndEdit,SCI_GETLENGTH,0,0);
@@ -7014,11 +7375,23 @@ BOOL FileSave(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy)
}
}
- if (!bSaveAlways && (!bModified && iEncoding == iOriginalEncoding || bIsEmptyNewFile) && !bSaveAs)
+ if (!bSaveAlways && (!bModified && iEncoding == iOriginalEncoding || bIsEmptyNewFile) && !bSaveAs) {
return TRUE;
+ }
+
+ if (!bModifiedSinceLastRecoverySave && bIsEmptyNewFile && !bSaveAs && !bSaveAlways)
+ {
+ SaveRecoveryFile(); // Deletes the current empty recovery file
+ return TRUE;
+ }
+
if (bAsk)
{
+ if (bAllowSaveToRecovery)
+ {
+ return SaveRecoveryFile();
+ }
// File or "Untitled" ...
WCHAR tch[MAX_PATH];
if (lstrlen(szCurFile))
@@ -7043,7 +7416,7 @@ BOOL FileSave(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy)
if (bReadOnly) {
SetWindowTitle(hwndMain,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
if (MsgBox(MBYESNOWARN,IDS_READONLY_SAVE,szCurFile) == IDYES)
bSaveAs = TRUE;
else
@@ -7065,11 +7438,13 @@ BOOL FileSave(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy)
if (SaveFileDlg(hwndMain,tchFile,COUNTOF(tchFile),tchInitialDir))
{
- if (fSuccess = FileIO(FALSE,tchFile,FALSE,&iEncoding,&iEOLMode,NULL,NULL,&bCancelDataLoss,bSaveCopy))
+ if (fSuccess = FileIO(FALSE,tchFile,FALSE,&iEncoding,&iEOLMode,NULL,NULL,&bCancelDataLoss,bSaveCopy,FALSE))
{
if (!bSaveCopy)
{
lstrcpy(szCurFile,tchFile);
+ StopFileRecoveryTimer(TRUE);
+ InitRecoveryFilePath(szCurFile, szRecoveryFile);
SetDlgItemText(hwndMain,IDC_FILENAME,szCurFile);
SetDlgItemInt(hwndMain,IDC_REUSELOCK,GetTickCount(),FALSE);
if (!fKeepTitleExcerpt)
@@ -7089,12 +7464,13 @@ BOOL FileSave(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy)
}
else
- fSuccess = FileIO(FALSE,szCurFile,FALSE,&iEncoding,&iEOLMode,NULL,NULL,&bCancelDataLoss,FALSE);
+ fSuccess = FileIO(FALSE,szCurFile,FALSE,&iEncoding,&iEOLMode,NULL,NULL,&bCancelDataLoss,FALSE,FALSE);
if (fSuccess)
{
if (!bSaveCopy)
{
+ bIsRecovered = FALSE;
bModified = FALSE;
iOriginalEncoding = iEncoding;
MRU_AddFile(pFileMRU,szCurFile,flagRelativeFileMRU,flagPortableMyDocs);
@@ -7102,7 +7478,8 @@ BOOL FileSave(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy)
SHAddToRecentDocs(SHARD_PATHW,szCurFile);
SetWindowTitle(hwndMain,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
+ StopFileRecoveryTimer(TRUE);
// Install watching of the current file
if (bSaveAs && bResetFileWatching)
@@ -7118,7 +7495,7 @@ BOOL FileSave(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy)
SetWindowTitle(hwndMain,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile,
iPathNameFormat,bModified || iEncoding != iOriginalEncoding,
- IDS_READONLY,bReadOnly,szTitleExcerpt);
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered);
MsgBox(MBWARN,IDS_ERR_SAVEFILE,tchFile);
}
diff --git a/src/Notepad2.h b/src/Notepad2.h
index a4c71df..a1391ba 100644
--- a/src/Notepad2.h
+++ b/src/Notepad2.h
@@ -90,11 +90,17 @@ typedef struct np2params {
//==== Paste Board Timer ======================================================
#define ID_PASTEBOARDTIMER 0xA001
+//==== File Recovery Timer ======================================================
+#define ID_FILERECOVERYTIMER 0xA002
//==== Reuse Window Lock Timeout ==============================================
#define REUSEWINDOWLOCKTIMEOUT 1000
+
+
+#define RECOVERY_FILE_MAGIC_NUMBER 0x54832144
+
//==== Function Declarations ==================================================
BOOL InitApplication(HINSTANCE);
HWND InitInstance(HINSTANCE,LPSTR,int);
@@ -126,9 +132,10 @@ void UpdateToolbar();
void UpdateLineNumberWidth();
-BOOL FileIO(BOOL,LPCWSTR,BOOL,int*,int*,BOOL*,BOOL*,BOOL*,BOOL);
+BOOL FileIO(BOOL,LPCWSTR,BOOL,int*,int*,BOOL*,BOOL*,BOOL*,BOOL,BOOL);
BOOL FileLoad(BOOL,BOOL,BOOL,BOOL,LPCWSTR);
BOOL FileSave(BOOL,BOOL,BOOL,BOOL);
+BOOL FileSaveEx(BOOL,BOOL,BOOL,BOOL,BOOL);
BOOL OpenFileDlg(HWND,LPWSTR,int,LPCWSTR);
BOOL SaveFileDlg(HWND,LPWSTR,int,LPCWSTR);
@@ -138,10 +145,16 @@ LRESULT MsgCreate(HWND,WPARAM,LPARAM);
void CreateBars(HWND,HINSTANCE);
void MsgThemeChanged(HWND,WPARAM,LPARAM);
void MsgSize(HWND,WPARAM,LPARAM);
+void PopulateRecoveredFilesMenu(HMENU);
void MsgInitMenu(HWND,WPARAM,LPARAM);
LRESULT MsgCommand(HWND,WPARAM,LPARAM);
LRESULT MsgNotify(HWND,WPARAM,LPARAM);
+BOOL SaveRecoveryFile();
+void InitRecoveryFilePath(PWCHAR originalFile, PWCHAR dest);
+void CALLBACK FileRecoveryTimerCallback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
+void StartFileRecoveryTimer();
+void StopFileRecoveryTimer(BOOL deleteRecoveryFile);
/// End of Notepad2.h \\\
diff --git a/src/Notepad2.rc b/src/Notepad2.rc
index 7803b2a..652ad0c 100644
--- a/src/Notepad2.rc
+++ b/src/Notepad2.rc
@@ -119,6 +119,10 @@ BEGIN
MENUITEM "&Manage...\tAlt+F9", IDM_FILE_MANAGEFAV
END
MENUITEM "Recent (&History)...\tAlt+H", IDM_FILE_RECENT
+ POPUP "&Recovered"
+ BEGIN
+ MENUITEM "(Dummy)", IDM_FILE_RECOVERED
+ END
MENUITEM SEPARATOR
MENUITEM "E&xit\tAlt+F4", IDM_FILE_EXIT
END
@@ -321,7 +325,8 @@ BEGIN
MENUITEM "Minimi&ze To Tray", IDM_VIEW_MINTOTRAY
MENUITEM "Transparent &Mode\tCtrl+0", IDM_VIEW_TRANSPARENT
MENUITEM SEPARATOR
- MENUITEM "Single &File Instance", IDM_VIEW_SINGLEFILEINSTANCE
+ MENUITEM "Single &File Instance", IDM_VIEW_SINGLEFILEINSTANCE
+ MENUITEM "&Automatic File Recovery", IDM_VIEW_FILERECOVERY
MENUITEM "File &Change Notification...\tAlt+F5",
IDM_VIEW_CHANGENOTIFY
POPUP "Window Title Displa&y"
diff --git a/src/resource.h b/src/resource.h
index 734421a..5a935db 100644
--- a/src/resource.h
+++ b/src/resource.h
@@ -352,6 +352,7 @@
#define IDM_VIEW_MARKOCCURRENCES_CASE 40451
#define IDM_VIEW_MARKOCCURRENCES_WORD 40452
#define IDM_VIEW_AUTOCOMPLETEWORDS 40453
+#define IDM_VIEW_FILERECOVERY 40454
#define IDM_HELP_ABOUT 40500
#define IDM_TRAY_RESTORE 40600
#define IDM_TRAY_EXIT 40601
@@ -425,6 +426,9 @@
#define IDS_EXPORT_FAIL 50040
#define IDS_CMDLINEHELP 60000
+#define IDM_FILE_RECOVERED 60001
+#define IDM_FILE_RECOVERED_MAX (IDM_FILE_RECOVERED + MAX_RECOVERY_MENU_ITEMS)
+
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment