diff --git a/NppPluginDemo.cpp b/NppPluginDemo.cpp index 837dfda..2d460b3 100755 --- a/NppPluginDemo.cpp +++ b/NppPluginDemo.cpp @@ -16,6 +16,7 @@ //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "PluginDefinition.h" +#include "Notepad_plus_msgs.h" extern FuncItem funcItem[nbFunc]; extern NppData nppData; @@ -68,13 +69,31 @@ extern "C" __declspec(dllexport) FuncItem * getFuncsArray(int *nbF) extern "C" __declspec(dllexport) void beNotified(SCNotification *notifyCode) { - switch (notifyCode->nmhdr.code) + switch (notifyCode->nmhdr.code) { case NPPN_SHUTDOWN: - { commandMenuCleanUp(); - } - break; + break; + + case NPPN_FILEOPENED: + OnFileOpened((UINT_PTR)notifyCode->nmhdr.idFrom); + break; + + case NPPN_BUFFERACTIVATED: + OnBufferActivated((UINT_PTR)notifyCode->nmhdr.idFrom); + break; + + case NPPN_FILEBEFORESAVE: + OnFileBeforeSave((UINT_PTR)notifyCode->nmhdr.idFrom); + break; + + case NPPN_FILESAVED: + OnFileSaved((UINT_PTR)notifyCode->nmhdr.idFrom); + break; + + case NPPN_FILECLOSED: + OnFileClosed((UINT_PTR)notifyCode->nmhdr.idFrom); + break; default: return; diff --git a/PluginDefinition.cpp b/PluginDefinition.cpp index d290463..8edc1c1 100755 --- a/PluginDefinition.cpp +++ b/PluginDefinition.cpp @@ -17,6 +17,9 @@ #include "PluginDefinition.h" #include "menuCmdID.h" +#include "Scintilla.h" +#include "Notepad_plus_msgs.h" +#include // // Globals @@ -24,6 +27,20 @@ HINSTANCE hInstance = NULL; unsigned char cryptkey[MAX_CRYPT_KEY]; +// Per-buffer cached keys for auto encrypt/decrypt of .ctxt files +static std::map g_bufferKeys; +// Buffer currently mid-save (encrypted, awaiting post-save decrypt) +static UINT_PTR g_pendingDecryptBuffer = 0; +// Buffer pre-encrypted by EncryptSaveAsCtxt — tells OnFileBeforeSave to skip +// re-encrypting (NPPM_SAVECURRENTFILEAS fires BEFORESAVE with the old path, +// so the path-based check in the hook would miss it anyway). +static UINT_PTR g_skipNextBeforeSaveEncrypt = 0; +// Buffers opened as .ctxt awaiting lazy decrypt-on-view (set on FILEOPENED, +// consumed on BUFFERACTIVATED). Lets file-open complete without blocking +// on a modal prompt; the popup only appears when the user actually views +// the document. +static std::set g_pendingOpenDecrypt; + // // Fwd decl // @@ -32,6 +49,7 @@ void DecryptDoc() { CryptDoc(CryptAction::Decrypt); } void EncryptSelection() { CryptSelection(CryptAction::Encrypt); } void DecryptSelection() { CryptSelection(CryptAction::Decrypt); } LRESULT CALLBACK DlgProcCryptKey(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK DlgProcCryptKeySingle(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam); void StrCrypt(unsigned char *buf1, size_t buf1len, unsigned char *buf2, size_t buf2len, unsigned char *key, CryptAction action); std::wstring widen(const std::string& str); std::string narrow(const std::wstring& str); @@ -81,7 +99,8 @@ void commandMenuInit() setCommand(1, TEXT("Decrypt Document"), DecryptDoc, NULL, false); setCommand(2, TEXT("Encrypt Selected Text"), EncryptSelection, NULL, false); setCommand(3, TEXT("Decrypt Selected Text"), DecryptSelection, NULL, false); - setCommand(4, TEXT("About SecurePad"), AboutDlg, NULL, false); + setCommand(4, TEXT("Encrypt && Save As .ctxt..."), EncryptSaveAsCtxt, NULL, false); + setCommand(5, TEXT("About SecurePad"), AboutDlg, NULL, false); } // @@ -122,8 +141,12 @@ void CryptDoc(CryptAction action) size_t textLength = 0L, textLengthOut = 0L; TCHAR *textBuf = NULL, *textBufOut = NULL; - // Prompt for crypt key - INT_PTR ret = DialogBox(hInstance, MAKEINTRESOURCE(IDD_DLGKEY), nppData._nppHandle, reinterpret_cast(DlgProcCryptKey)); + // Prompt for crypt key — encrypt = confirm (two fields), decrypt = single field + INT_PTR ret; + if (action == CryptAction::Encrypt) + ret = DialogBox(hInstance, MAKEINTRESOURCE(IDD_DLGKEY), nppData._nppHandle, reinterpret_cast(DlgProcCryptKey)); + else + ret = DialogBox(hInstance, MAKEINTRESOURCE(IDD_DLGKEY_SINGLE), nppData._nppHandle, reinterpret_cast(DlgProcCryptKeySingle)); if(ret == 0) { @@ -187,8 +210,12 @@ void CryptSelection(CryptAction action) size_t textLength = 0L, textLengthOut = 0L; TCHAR *textBuf = NULL, *textBufOut = NULL; - // Prompt for crypt key - INT_PTR ret = DialogBox(hInstance, MAKEINTRESOURCE(IDD_DLGKEY), nppData._nppHandle, reinterpret_cast(DlgProcCryptKey)); + // Prompt for crypt key — encrypt = confirm (two fields), decrypt = single field + INT_PTR ret; + if (action == CryptAction::Encrypt) + ret = DialogBox(hInstance, MAKEINTRESOURCE(IDD_DLGKEY), nppData._nppHandle, reinterpret_cast(DlgProcCryptKey)); + else + ret = DialogBox(hInstance, MAKEINTRESOURCE(IDD_DLGKEY_SINGLE), nppData._nppHandle, reinterpret_cast(DlgProcCryptKeySingle)); if(ret == 0) { @@ -249,7 +276,7 @@ void CryptSelection(CryptAction action) void AboutDlg() { - ::MessageBox(NULL, TEXT("SecurePad can be used to securely encrypt plaintext documents with a key of your choice. Be careful, once encrypted you will only be able to decrypt with the key you used!\r\n\r\nAny questions please visit www.dominictobias.com."), TEXT("SecurePad v2.4"), MB_OK); + ::MessageBox(NULL, TEXT("SecurePad can be used to securely encrypt plaintext documents with a key of your choice. Be careful, once encrypted you will only be able to decrypt with the key you used!\r\n\r\nAny questions please visit www.dominictobias.com."), TEXT("SecurePad v2.5"), MB_OK); } // =============================================== @@ -335,6 +362,64 @@ LRESULT CALLBACK DlgProcCryptKey(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM / return FALSE; } +// =============================================== +// Dialog for single-field key entry (decrypt) +// =============================================== + +LRESULT CALLBACK DlgProcCryptKeySingle(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM /*lParam*/) +{ + switch (msg) + { + case WM_DESTROY: + case WM_CLOSE: + EndDialog(hWndDlg, 0); + return TRUE; + + case WM_INITDIALOG: + SetFocus(GetDlgItem(hWndDlg, IDC_EDIT_PASS)); + break; + + case WM_COMMAND: + { + if (LOWORD(wParam) == IDOK) + { + TCHAR box[MAX_CRYPT_KEY] = { 0 }; + SendMessage(GetDlgItem(hWndDlg, IDC_EDIT_PASS), WM_GETTEXT, sizeof(box), (LPARAM)box); + + LRESULT keyLen = SendMessage(GetDlgItem(hWndDlg, IDC_EDIT_PASS), WM_GETTEXTLENGTH, 0, 0); + + if (keyLen == 0) + { + MessageBox(nppData._nppHandle, TEXT("Enter a key."), TEXT("Please try again"), MB_OK); + break; + } + if (keyLen > MAX_CRYPT_KEY) + { + TCHAR buf[128]; + _stprintf(buf, TEXT("The key was too long! (key=%Id, max=%d)"), keyLen, MAX_CRYPT_KEY); + MessageBox(nppData._nppHandle, buf, TEXT("Please try again"), MB_OK); + break; + } + + memset(&cryptkey, 0, sizeof(cryptkey)); + std::string narrowKey = narrow(box); + memcpy(cryptkey, narrowKey.c_str(), + narrowKey.size() > MAX_CRYPT_KEY ? MAX_CRYPT_KEY : narrowKey.size()); + + EndDialog(hWndDlg, 1); + } + else if (LOWORD(wParam) == IDCANCEL) + { + EndDialog(hWndDlg, 0); + return TRUE; + } + break; + } + } + + return FALSE; +} + // =============================================== // Blowfish cypher // =============================================== @@ -434,4 +519,278 @@ std::string narrow(const std::wstring& str) for( size_t i=0 ; i(DlgProcCryptKey)); + if (ret == 0) return false; + memset(keyOut, 0, keyOutSize); + size_t copyLen = strlen((const char*)cryptkey); + if (copyLen > keyOutSize) copyLen = keyOutSize; + memcpy(keyOut, cryptkey, copyLen); + return true; +} + +// Reuses IDD_DLGKEY_SINGLE dialog (single field). For decrypt flows where the +// user already knows the key — no confirmation needed. +bool PromptForKeyOnce(unsigned char* keyOut, size_t keyOutSize) +{ + INT_PTR ret = DialogBox(hInstance, MAKEINTRESOURCE(IDD_DLGKEY_SINGLE), nppData._nppHandle, + reinterpret_cast(DlgProcCryptKeySingle)); + if (ret == 0) return false; + memset(keyOut, 0, keyOutSize); + size_t copyLen = strlen((const char*)cryptkey); + if (copyLen > keyOutSize) copyLen = keyOutSize; + memcpy(keyOut, cryptkey, copyLen); + return true; +} + +// Encrypt/decrypt current document with provided key (no prompt). +void CryptCurrentDocWithKey(CryptAction action, const unsigned char* key) +{ + int currentEdit = -1; + HWND hView = NULL; + size_t textLength = 0, textLengthOut = 0; + TCHAR *textBuf = NULL, *textBufOut = NULL; + + SendMessage(nppData._nppHandle, NPPM_GETCURRENTSCINTILLA, 0, (LPARAM)¤tEdit); + hView = (currentEdit == 0) ? nppData._scintillaMainHandle : nppData._scintillaSecondHandle; + + textLength = (size_t)SendMessage(hView, SCI_GETTEXTLENGTH, 0, 0); + if (textLength == 0) return; + + textLength++; + textLengthOut = textLength; + if (action == CryptAction::Encrypt) textLengthOut *= 2; + + while (textLength % 8 != 0) textLength++; + textBuf = (TCHAR*)VirtualAlloc(NULL, textLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + + while (textLengthOut % 8 != 0) textLengthOut++; + textBufOut = (TCHAR*)VirtualAlloc(NULL, textLengthOut, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + + SendMessage(hView, SCI_GETTEXT, textLength, (LPARAM)textBuf); + + // StrCrypt takes non-const key — copy into mutable buffer + unsigned char keyBuf[MAX_CRYPT_KEY] = { 0 }; + size_t keyLen = strlen((const char*)key); + if (keyLen > MAX_CRYPT_KEY) keyLen = MAX_CRYPT_KEY; + memcpy(keyBuf, key, keyLen); + + StrCrypt((unsigned char*)textBuf, textLength, (unsigned char*)textBufOut, + textLengthOut, keyBuf, action); + + SendMessage(hView, SCI_SETTEXT, 0, (LPARAM)textBufOut); + + if (textBuf) VirtualFree(textBuf, 0, MEM_RELEASE); + if (textBufOut) VirtualFree(textBufOut, 0, MEM_RELEASE); +} + +// Lazy: only mark the buffer as needing decrypt. Do NOT prompt here — that +// would block NPPN_FILEOPENED processing and block batch opens (cmdline, +// session restore, "open recent"). Prompt happens on first BUFFERACTIVATED. +void OnFileOpened(UINT_PTR bufferId) +{ + std::wstring path; + if (!GetBufferPath(bufferId, path)) return; + if (!IsCtxtPath(path.c_str())) return; + g_pendingOpenDecrypt.insert(bufferId); +} + +// Fires when a buffer becomes the visible tab. Lazy-decrypts pending .ctxt +// buffers here so the prompt only appears for documents the user actually views. +void OnBufferActivated(UINT_PTR bufferId) +{ + auto it = g_pendingOpenDecrypt.find(bufferId); + if (it == g_pendingOpenDecrypt.end()) return; + g_pendingOpenDecrypt.erase(it); + + unsigned char key[MAX_CRYPT_KEY] = { 0 }; + if (!PromptForKeyOnce(key, sizeof(key))) return; + + CryptCurrentDocWithKey(CryptAction::Decrypt, key); + g_bufferKeys[bufferId] = std::string((const char*)key); + + int currentEdit = -1; + SendMessage(nppData._nppHandle, NPPM_GETCURRENTSCINTILLA, 0, (LPARAM)¤tEdit); + HWND hView = (currentEdit == 0) ? nppData._scintillaMainHandle : nppData._scintillaSecondHandle; + SendMessage(hView, SCI_SETSAVEPOINT, 0, 0); + SendMessage(hView, SCI_EMPTYUNDOBUFFER, 0, 0); +} + +void OnFileBeforeSave(UINT_PTR bufferId) +{ + // EncryptSaveAsCtxt already encrypted the buffer in-place. NP++ will write + // it as-is; FILESAVED hook still handles the post-save decrypt back. + if (g_skipNextBeforeSaveEncrypt == bufferId) + { + g_skipNextBeforeSaveEncrypt = 0; + return; + } + + std::wstring path; + if (!GetBufferPath(bufferId, path)) return; + if (!IsCtxtPath(path.c_str())) return; + + // Find or prompt for key (Save As .ctxt on a new buffer) + auto it = g_bufferKeys.find(bufferId); + unsigned char key[MAX_CRYPT_KEY] = { 0 }; + if (it == g_bufferKeys.end()) + { + if (!PromptForKey(key, sizeof(key))) + { + MessageBox(nppData._nppHandle, + TEXT("No key provided. File will be saved as plaintext."), + TEXT("SecurePad"), MB_OK | MB_ICONWARNING); + return; + } + g_bufferKeys[bufferId] = std::string((const char*)key); + } + else + { + size_t n = it->second.size(); + if (n > MAX_CRYPT_KEY) n = MAX_CRYPT_KEY; + memcpy(key, it->second.data(), n); + } + + CryptCurrentDocWithKey(CryptAction::Encrypt, key); + g_pendingDecryptBuffer = bufferId; +} + +void OnFileSaved(UINT_PTR bufferId) +{ + if (g_pendingDecryptBuffer != bufferId) return; + g_pendingDecryptBuffer = 0; + + auto it = g_bufferKeys.find(bufferId); + if (it == g_bufferKeys.end()) return; + + unsigned char key[MAX_CRYPT_KEY] = { 0 }; + size_t n = it->second.size(); + if (n > MAX_CRYPT_KEY) n = MAX_CRYPT_KEY; + memcpy(key, it->second.data(), n); + + CryptCurrentDocWithKey(CryptAction::Decrypt, key); + + int currentEdit = -1; + SendMessage(nppData._nppHandle, NPPM_GETCURRENTSCINTILLA, 0, (LPARAM)¤tEdit); + HWND hView = (currentEdit == 0) ? nppData._scintillaMainHandle : nppData._scintillaSecondHandle; + SendMessage(hView, SCI_SETSAVEPOINT, 0, 0); +} + +void OnFileClosed(UINT_PTR bufferId) +{ + g_bufferKeys.erase(bufferId); + g_pendingOpenDecrypt.erase(bufferId); + if (g_pendingDecryptBuffer == bufferId) g_pendingDecryptBuffer = 0; +} + +// Menu action: prompt for path + key, save current buffer as .ctxt (encrypted), +// leaving buffer associated with the new .ctxt path showing plaintext. +void EncryptSaveAsCtxt() +{ + // Document must be non-empty + int currentEdit = -1; + SendMessage(nppData._nppHandle, NPPM_GETCURRENTSCINTILLA, 0, (LPARAM)¤tEdit); + HWND hView = (currentEdit == 0) ? nppData._scintillaMainHandle : nppData._scintillaSecondHandle; + if (SendMessage(hView, SCI_GETTEXTLENGTH, 0, 0) == 0) + { + MessageBox(nppData._nppHandle, TEXT("The document is empty!"), TEXT("SecurePad"), MB_OK); + return; + } + + // Default filename = current name with .ctxt appended + TCHAR currentName[MAX_PATH] = { 0 }; + SendMessage(nppData._nppHandle, NPPM_GETFILENAME, MAX_PATH, (LPARAM)currentName); + + TCHAR pathBuf[MAX_PATH] = { 0 }; + if (currentName[0] != 0) + { + _tcsncpy(pathBuf, currentName, MAX_PATH - 6); + // Strip existing extension, append .ctxt + TCHAR* ext = PathFindExtension(pathBuf); + if (ext && *ext) *ext = 0; + _tcscat(pathBuf, TEXT(".ctxt")); + } + else + { + _tcscpy(pathBuf, TEXT("untitled.ctxt")); + } + + // Default directory = current file's directory + TCHAR initDir[MAX_PATH] = { 0 }; + SendMessage(nppData._nppHandle, NPPM_GETCURRENTDIRECTORY, MAX_PATH, (LPARAM)initDir); + + OPENFILENAME ofn = { 0 }; + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = nppData._nppHandle; + ofn.lpstrFilter = TEXT("SecurePad cipher (*.ctxt)\0*.ctxt\0All files (*.*)\0*.*\0"); + ofn.lpstrFile = pathBuf; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrInitialDir = initDir[0] ? initDir : NULL; + ofn.lpstrDefExt = TEXT("ctxt"); + ofn.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; + ofn.lpstrTitle = TEXT("Encrypt & Save As .ctxt"); + + if (!GetSaveFileName(&ofn)) return; + + // Force .ctxt extension if user typed something else + if (!IsCtxtPath(pathBuf)) + { + TCHAR* ext = PathFindExtension(pathBuf); + if (ext && *ext) *ext = 0; + _tcscat(pathBuf, TEXT(".ctxt")); + } + + // Prompt for password — single field (no verify) + unsigned char key[MAX_CRYPT_KEY] = { 0 }; + if (!PromptForKeyOnce(key, sizeof(key))) return; + + UINT_PTR bufferId = (UINT_PTR)SendMessage(nppData._nppHandle, NPPM_GETCURRENTBUFFERID, 0, 0); + g_bufferKeys[bufferId] = std::string((const char*)key); + + // Encrypt the buffer in-place BEFORE Save As. NPPM_SAVECURRENTFILEAS fires + // NPPN_FILEBEFORESAVE with the OLD path (pre-rename), so relying on the + // hook's path check would skip encryption and write plaintext. + CryptCurrentDocWithKey(CryptAction::Encrypt, key); + + // Suppress the hook's encrypt pass; FILESAVED still decrypts back. + g_skipNextBeforeSaveEncrypt = bufferId; + g_pendingDecryptBuffer = bufferId; + + LRESULT ok = SendMessage(nppData._nppHandle, NPPM_SAVECURRENTFILEAS, (WPARAM)FALSE, (LPARAM)pathBuf); + + if (!ok) + { + // Save failed — restore plaintext buffer and drop the cached key. + CryptCurrentDocWithKey(CryptAction::Decrypt, key); + g_pendingDecryptBuffer = 0; + g_skipNextBeforeSaveEncrypt = 0; + g_bufferKeys.erase(bufferId); + MessageBox(nppData._nppHandle, TEXT("Save failed."), TEXT("SecurePad"), MB_OK | MB_ICONERROR); + } } \ No newline at end of file diff --git a/PluginDefinition.h b/PluginDefinition.h index 778c591..331ca63 100755 --- a/PluginDefinition.h +++ b/PluginDefinition.h @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include @@ -49,7 +51,7 @@ const TCHAR NPP_PLUGIN_NAME[] = TEXT("SecurePad"); // // Here define the number of your plugin commands // -const int nbFunc = 5; +const int nbFunc = 6; // @@ -90,6 +92,19 @@ enum class CryptAction { void CryptDoc(CryptAction action); void CryptSelection(CryptAction action); +void EncryptSaveAsCtxt(); void AboutDlg(); +// Auto encrypt/decrypt hooks for .ctxt files +bool IsCtxtPath(const TCHAR* path); +bool GetBufferPath(UINT_PTR bufferId, std::wstring& outPath); +bool PromptForKey(unsigned char* keyOut, size_t keyOutSize); // confirm (two fields) +bool PromptForKeyOnce(unsigned char* keyOut, size_t keyOutSize); // single field, decrypt +void CryptCurrentDocWithKey(CryptAction action, const unsigned char* key); +void OnFileOpened(UINT_PTR bufferId); +void OnBufferActivated(UINT_PTR bufferId); +void OnFileBeforeSave(UINT_PTR bufferId); +void OnFileSaved(UINT_PTR bufferId); +void OnFileClosed(UINT_PTR bufferId); + #endif //PLUGINDEFINITION_H diff --git a/README.md b/README.md index e8f1f0e..eaf6dd6 100755 --- a/README.md +++ b/README.md @@ -14,6 +14,13 @@ SecurePad uses the powerful and secure [Blowfish cipher](https://en.wikipedia.or Changelog ========= +v2.5 +---- +Auto encrypt/decrypt for `.ctxt` files: +- Opening a `.ctxt` file prompts for the key and decrypts the buffer for editing. +- Saving a `.ctxt` file encrypts on disk while the editor keeps the plaintext view. +- New menu item **Encrypt && Save As .ctxt...** prompts for a path + key, then saves the current document as an encrypted `.ctxt` file in one step. + v2.4 ---- Fixed issue #13, regression form PR #12, completely replacing functionality with just the npp template code diff --git a/Resources.rc b/Resources.rc index 1408779..977aa07 100755 --- a/Resources.rc +++ b/Resources.rc @@ -52,8 +52,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,4,0,0 - PRODUCTVERSION 2,4,0,0 + FILEVERSION 2,5,0,0 + PRODUCTVERSION 2,5,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -70,12 +70,12 @@ BEGIN BEGIN VALUE "CompanyName", "DreamInPixels, dreaminpixels.net" VALUE "FileDescription", "SecurePad can be used to securely encrypt plaintext documents with a key of your choice" - VALUE "FileVersion", "2.4.0.0" + VALUE "FileVersion", "2.5.0.0" VALUE "InternalName", "SecurePad.dll" VALUE "LegalCopyright", "Copyright (c) 2022 dreaminpixels.net" VALUE "OriginalFilename", "SecurePad.dll" VALUE "ProductName", "SecurePad" - VALUE "ProductVersion", "2.4.0.0" + VALUE "ProductVersion", "2.5.0.0" END END BLOCK "VarFileInfo" @@ -103,6 +103,17 @@ BEGIN EDITTEXT IDC_EDIT2,26,54,150,15,ES_PASSWORD | ES_AUTOHSCROLL END +IDD_DLGKEY_SINGLE DIALOGEX 0, 0, 201, 75 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Enter Crypt Key" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,89,52,50,14 + PUSHBUTTON "Cancel",IDCANCEL,143,52,50,14 + EDITTEXT IDC_EDIT_PASS,26,23,150,15,ES_PASSWORD | ES_AUTOHSCROLL + GROUPBOX "Enter the crypt key to decrypt the text",IDC_STATIC,7,7,187,38 +END + ///////////////////////////////////////////////////////////////////////////// // diff --git a/resource1.h b/resource1.h index 9315c76..2d382e9 100755 Binary files a/resource1.h and b/resource1.h differ