Skip to content

Commit

Permalink
Modifies 'About' dialog to be more friendly (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hsilgos authored Jul 6, 2019
1 parent cbf1985 commit 2d9aa3f
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 16 deletions.
2 changes: 2 additions & 0 deletions NppSaveAsAdmin/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*.suo
bin/
bin64/
bin_debug/
bin64_debug/
vs.proj/.vs/*
vs.proj/Debug
vs.proj/Release
Expand Down
38 changes: 38 additions & 0 deletions NppSaveAsAdmin/src/NppPluginDemo.rc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@

#include "plugin/SaveAsAdminVersion.hpp"

#include "Resource.h"

LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

VS_VERSION_INFO VERSIONINFO
FILEVERSION SAVE_AS_ADMIN_VERSION_DIGITAL
PRODUCTVERSION SAVE_AS_ADMIN_VERSION_DIGITAL
Expand Down Expand Up @@ -49,3 +53,37 @@ BEGIN
END
END
END


/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_ABOUT_SAVE_AS_ADMIN DIALOGEX 0, 0, 303, 185
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Save as Admin plugin"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
DEFPUSHBUTTON "Close",IDCLOSE,126,164,50,14,WS_GROUP
CONTROL "Custom1",IDC_SCINTILLA,"Scintilla",WS_TABSTOP,0,7,291,153
END


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_ABOUT_SAVE_AS_ADMIN, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 296
TOPMARGIN, 7
BOTTOMMARGIN, 178
END
END
#endif // APSTUDIO_INVOKED
179 changes: 171 additions & 8 deletions NppSaveAsAdmin/src/PluginDefinition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#include "PluginDefinition.h"
#include "Resource.h"
#include "menuCmdID.h"
#include "plugin/SaveAsAdminVersion.hpp"

Expand All @@ -31,11 +32,13 @@ FuncItem funcItem[nbFunc];
// The data of Notepad++ that you can use in your plugin commands
//
NppData nppData;
HINSTANCE module_handle;

//
// Initialize your plugin data here
// It will be called while plugin loading
void pluginInit(HANDLE /*hModule*/) {
void pluginInit(HINSTANCE hModule) {
module_handle = hModule;
}

//
Expand All @@ -46,6 +49,7 @@ void pluginCleanUp() {}

void do_injection();
void un_do_injection();
bool is_admin_app_exists();

//
// Initialization of your plugin commands
Expand Down Expand Up @@ -91,12 +95,171 @@ bool setCommand(size_t index,
//----------------------------------------------//
//-- STEP 4. DEFINE YOUR ASSOCIATED FUNCTIONS --//
//----------------------------------------------//
void about() {
std::wstringstream info;
info << L"Notepad++ SaveAsAdmin plugin" << std::endl;
info << L"Version: " << SAVE_AS_ADMIN_VERSION_UNICODE << std::endl;
info << L"Author: Khnykin Yauheni" << std::endl;
info << L"Email: [email protected]" << std::endl;

::MessageBox(NULL, info.str().c_str(), TEXT("About"), MB_OK);
std::string make_about_text() {
std::stringstream info;
info << "Notepad++ SaveAsAdmin plugin" << std::endl;
info << "Version: " << SAVE_AS_ADMIN_VERSION << std::endl;
info << "Author: Khnykin Yauheni" << std::endl;

if (is_admin_app_exists()) {
info << std::endl
<< "Allows to save file as administrator with UAC prompt."
<< std::endl;
info << "Just save file as you usually do with menu, hotkey, etc."
<< std::endl;
} else {
info << std::endl
<< "Something went wrong! Importand files are missed, please try to "
"reinstall."
<< std::endl;
}

info << std::endl
<< "Plugin sources: https://github.com/Hsilgos/nppsaveasadmin"
<< std::endl;
info << "Issue reports: https://github.com/Hsilgos/nppsaveasadmin/issues"
<< std::endl;
return info.str();
}

constexpr WPARAM SCINTILLA_STYLE_LINK = 2;

struct LinkInfo {
size_t position;
std::string link;
};

std::vector<LinkInfo> find_links(
const std::string& text,
const std::vector<std::string>& link_prefixes) {
std::vector<LinkInfo> result;
for (const std::string& prefix : link_prefixes) {
auto position = text.find(prefix);
while (position != std::string::npos) {
auto end_position = text.find_first_of(" \n", position);
if (end_position == std::string::npos) {
end_position = text.size();
}

LinkInfo link_info;
link_info.position = position;
link_info.link = text.substr(position, end_position - position);

result.push_back(link_info);

position = text.find(prefix, end_position);
}
}
return result;
}

void apply_links(HWND hDlg,
int scintilla_id,
const std::string& text,
const std::vector<std::string>& link_prefixes) {
for (const LinkInfo& link_info : find_links(text, link_prefixes)) {
SendDlgItemMessage(hDlg, scintilla_id, SCI_STARTSTYLING, link_info.position,
0);
SendDlgItemMessage(hDlg, scintilla_id, SCI_SETSTYLING,
link_info.link.size(), SCINTILLA_STYLE_LINK);
}
}

std::string find_link_at_position(
const std::string& text,
std::uint32_t position,
const std::vector<std::string>& link_prefixes) {
for (const LinkInfo& link_info : find_links(text, link_prefixes)) {
if (position >= link_info.position &&
position < link_info.position + link_info.link.size()) {
return link_info.link;
}
}

return std::string();
}

const std::vector<std::string> link_prefixes = {"https://", "mailto:"};

void init_scintilla(HWND hDlg) {
const std::string about_text = make_about_text();
SendDlgItemMessage(hDlg, IDC_SCINTILLA, SCI_SETTEXT, 0,
reinterpret_cast<LPARAM>(about_text.c_str()));
SendDlgItemMessage(hDlg, IDC_SCINTILLA, SCI_SETREADONLY, TRUE, 0);
SendDlgItemMessage(hDlg, IDC_SCINTILLA, SCI_SETHSCROLLBAR, FALSE, 0);

SendDlgItemMessage(hDlg, IDC_SCINTILLA, SCI_SETHOTSPOTACTIVEFORE, TRUE,
0xFF0000);
SendDlgItemMessage(hDlg, IDC_SCINTILLA, SCI_STYLESETHOTSPOT,
SCINTILLA_STYLE_LINK, TRUE);

apply_links(hDlg, IDC_SCINTILLA, about_text, link_prefixes);
}

void center_dialog(HWND hDlg) {
const HWND hwndOwner = GetParent(hDlg);

RECT rect_owner;
GetWindowRect(hwndOwner, &rect_owner);

RECT rect_dlg;
GetWindowRect(hDlg, &rect_dlg);

RECT result_rect;
CopyRect(&result_rect, &rect_owner);

OffsetRect(&rect_dlg, -rect_dlg.left, -rect_dlg.top);
OffsetRect(&result_rect, -result_rect.left, -result_rect.top);
OffsetRect(&result_rect, -rect_dlg.right, -rect_dlg.bottom);

SetWindowPos(hDlg, HWND_TOP, rect_owner.left + (result_rect.right / 2),
rect_owner.top + (result_rect.bottom / 2), 0, 0, SWP_NOSIZE);
}

// Message handler for about box.
INT_PTR CALLBACK about_dlg_proc(HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam) {
switch (message) {
case WM_INITDIALOG: {
center_dialog(hDlg);
init_scintilla(hDlg);

return (INT_PTR)TRUE;
}

case WM_NOTIFY: {
if (wParam == IDC_SCINTILLA) {
const SCNotification* notification =
reinterpret_cast<SCNotification*>(lParam);
switch (notification->nmhdr.code) {
case SCN_HOTSPOTCLICK:
case SCN_HOTSPOTDOUBLECLICK: {
const std::string link = find_link_at_position(
make_about_text(), notification->position, link_prefixes);
ShellExecuteA(NULL, "open", link.c_str(), NULL, NULL,
SW_SHOWNORMAL);
break;
}
}
}

break;
}

case WM_COMMAND:
if (LOWORD(wParam) == IDCLOSE || LOWORD(wParam) == IDCANCEL) {
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}

void about() {
DialogBox(module_handle, MAKEINTRESOURCE(IDD_ABOUT_SAVE_AS_ADMIN),
nppData._nppHandle, about_dlg_proc);
}
2 changes: 1 addition & 1 deletion NppSaveAsAdmin/src/PluginDefinition.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const int nbFunc = 1;
// Initialization of your plugin data
// It will be called while plugin loading
//
void pluginInit(HANDLE hModule);
void pluginInit(HINSTANCE hModule);

//
// Cleaning of your plugin
Expand Down
23 changes: 23 additions & 0 deletions NppSaveAsAdmin/src/Resource.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by test_resources.rc
//
#define IDC_MYICON 2
#define IDD_TESTRESOURCES_DIALOG 102
#define IDD_ABOUTBOX 103
#define IDD_ABOUT_SAVE_AS_ADMIN 103
#define IDR_MAINFRAME 128
#define IDC_SCINTILLA 1001
#define IDC_STATIC -1

// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 129
#define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 110
#endif
#endif
18 changes: 11 additions & 7 deletions NppSaveAsAdmin/src/plugin/NppSaveAsAdmin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,19 @@ void un_do_injection() {
g_save_as_admin_impl.reset();
}

std::wstring get_module_path(HANDLE hModule) {
bool is_admin_app_exists() {
return file_exists(g_admin_app_path);
}

std::wstring get_module_path(HINSTANCE hModule) {
using Buffer = std::array<TCHAR, 2048>;
Buffer module_file = { { 0 } };
const int result_size =
GetModuleFileName(static_cast<HMODULE>(hModule), module_file.data(), static_cast<DWORD>(module_file.size()));
return std::wstring(module_file.data(), result_size);
}

std::wstring get_admin_app_path(HANDLE hModule) {
std::wstring get_admin_app_path(HINSTANCE hModule) {
std::wstring module_path = get_module_path(hModule);
const auto sep_position = module_path.find_last_of(L"\\/");
if (sep_position != std::wstring::npos) {
Expand All @@ -48,14 +52,14 @@ std::wstring get_admin_app_path(HANDLE hModule) {

//////////////////////////////////////////////////////////////////////////

BOOL APIENTRY DllMain(HANDLE hModule, DWORD reasonForCall, LPVOID /*lpReserved*/) {
BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD reasonForCall, LPVOID /*lpReserved*/) {
switch (reasonForCall) {
case DLL_PROCESS_ATTACH:
pluginInit(hModule);

g_admin_app_path = get_admin_app_path(hModule);
if (!g_admin_app_path.empty()) {
pluginInit(hModule);
do_injection();
}
do_injection();

break;

case DLL_PROCESS_DETACH:
Expand Down

0 comments on commit 2d9aa3f

Please sign in to comment.