Skip to content

Commit 1af4c0c

Browse files
authored
Merge pull request #74 from end2endzone/feature-issue56
Reintegrating issue #56 into master branch.
2 parents c2e7699 + 2a14529 commit 1af4c0c

16 files changed

+805
-12
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
# their names here. Please keep the list sorted by first names.
44

55
Antoine Beauchamp <[email protected]>
6+
Mindaugas Ribaconka <[email protected]>

CHANGES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Changes for 0.5.0
99
* Fixed issue #52: Define a specific property for use as separator for handling multiple file selection.
1010
* Fixed issue #54: Icon background and dark mode.
1111
* Fixed issue #55: Menu name maximum length limit and escape string.
12+
* Fixed issue #56: Not implemented administrator mode.
1213
* Fixed issue #58: More useful features: class and pattern attributes for validity / visibility.
1314
* Fixed issue #61: Support for WIX installer.
1415
* Fixed issue #66: Github don't identify the repository LICENSE as MIT.

UserManual.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
![ShellAnything logo](docs/ShellAnything-splashscreen.jpg?raw=true)
1+
![ShellAnything logo](docs/ShellAnything-splashscreen.jpg?raw=true)
22

33

44
# Overview #
@@ -550,6 +550,28 @@ For example, the following launche `notepad.exe` and open the `License.txt` docu
550550

551551

552552

553+
#### verb attribute: ####
554+
555+
The `verb` attribute defines special directives on how to execute a file or launching the application. For example, the verb `open` or `edit` allows the user to open a document using the associated application. The attribute is optional.
556+
557+
Verbs are specific to a file type but some are supported by multiple types. Commonly available verbs include:
558+
| Verb | Description |
559+
|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
560+
| edit | Launches an editor and opens the document for editing. |
561+
| find | Initiates a search starting from the executed directory. |
562+
| open | Launches an application. If this file is not an executable file, its associated application is launched. |
563+
| print | Prints the document file. |
564+
| properties | Displays the object's properties. |
565+
| runas | Launches an application as Administrator. User Account Control (UAC) will prompt the user for consent to run the application elevated or enter the credentials of an administrator account used to run the application. |
566+
567+
For example, the following launches `notepad.exe` and open the text file `C:\Windows\System32\drivers\etc\hosts` which can only be modified with elevated privileges (as an Administrator) :
568+
```xml
569+
<exec path="C:\Windows\notepad.exe" arguments="C:\Windows\System32\drivers\etc\hosts" verb="runas" />
570+
```
571+
To get extended information about verbs, see the following Microsoft documentation article: [ShellExecute and ShellExecuteEx, Object Verbs](https://docs.microsoft.com/en-us/windows/win32/shell/launch#object-verbs).
572+
573+
574+
553575
### &lt;open&gt; action ###
554576

555577
The &lt;open&gt; element is used to open a document by the default associated application. The &lt;open&gt; element must be added under the &lt;actions&gt; element.

include/shellanything/ActionExecute.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ namespace shellanything
4444
/// </summary>
4545
/// <param name="iContext">The current context of execution.</param>
4646
/// <returns>Returns true if the execution is successful. Returns false otherwise.</returns>
47-
virtual bool Execute(const Context & iContext) const;
47+
virtual bool Execute(const Context& iContext) const;
4848

4949
/// <summary>
5050
/// Getter for the 'path' parameter.
@@ -76,10 +76,38 @@ namespace shellanything
7676
/// </summary>
7777
void SetArguments(const std::string & iArguments);
7878

79+
/// <summary>
80+
/// Getter for the 'verb' parameter.
81+
/// </summary>
82+
const std::string& GetVerb() const;
83+
84+
/// <summary>
85+
/// Setter for the 'verb' parameter.
86+
/// </summary>
87+
void SetVerb(const std::string& iVerb);
88+
89+
private:
90+
/// <summary>
91+
/// Execute an application with ShellExecuteEx method.
92+
/// This execute method supports verbs.
93+
/// </summary>
94+
/// <param name="iContext">The current context of execution.</param>
95+
/// <returns>Returns true if the execution is successful. Returns false otherwise.</returns>
96+
virtual bool ExecuteVerb(const Context & iContext) const;
97+
98+
/// <summary>
99+
/// Execute an application with RapidAssist method.
100+
/// This execute method does not supports verbs.
101+
/// </summary>
102+
/// <param name="iContext">The current context of execution.</param>
103+
/// <returns>Returns true if the execution is successful. Returns false otherwise.</returns>
104+
virtual bool ExecuteProcess(const Context & iContext) const;
105+
79106
private:
80107
std::string mPath;
81108
std::string mBaseDir;
82109
std::string mArguments;
110+
std::string mVerb;
83111
};
84112

85113
} //namespace shellanything

src/ActionExecute.cpp

Lines changed: 98 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "rapidassist/filesystem_utf8.h"
2929
#include "PropertyManager.h"
3030

31+
#include <windows.h>
3132
#pragma warning( push )
3233
#pragma warning( disable: 4355 ) // glog\install_dir\include\glog/logging.h(1167): warning C4355: 'this' : used in base member initializer list
3334
#include <glog/logging.h>
@@ -45,11 +46,81 @@ namespace shellanything
4546
{
4647
}
4748

48-
bool ActionExecute::Execute(const Context & iContext) const
49+
bool ActionExecute::Execute(const Context& iContext) const
4950
{
50-
PropertyManager & pmgr = PropertyManager::GetInstance();
51-
std::string path = pmgr.Expand(mPath);
52-
std::string basedir = pmgr.Expand(mBaseDir);
51+
PropertyManager& pmgr = PropertyManager::GetInstance();
52+
std::string verb = pmgr.Expand(mVerb);
53+
54+
//If a verb was specified, delegate to VerbExecute(). Otherwise, use ProcessExecute().
55+
if (verb.empty())
56+
return ExecuteProcess(iContext);
57+
else
58+
return ExecuteVerb(iContext);
59+
}
60+
61+
bool ActionExecute::ExecuteVerb(const Context& iContext) const
62+
{
63+
PropertyManager& pmgr = PropertyManager::GetInstance();
64+
std::string path = pmgr.Expand(mPath);
65+
std::string basedir = pmgr.Expand(mBaseDir);
66+
std::string arguments = pmgr.Expand(mArguments);
67+
std::string verb = pmgr.Expand(mVerb);
68+
69+
std::wstring pathW = ra::unicode::Utf8ToUnicode(path);
70+
std::wstring argumentsW = ra::unicode::Utf8ToUnicode(arguments);
71+
std::wstring basedirW = ra::unicode::Utf8ToUnicode(basedir);
72+
std::wstring verbW = ra::unicode::Utf8ToUnicode(verb);
73+
74+
SHELLEXECUTEINFOW info = { 0 };
75+
76+
info.cbSize = sizeof(SHELLEXECUTEINFOW);
77+
78+
info.fMask |= SEE_MASK_NOCLOSEPROCESS;
79+
info.fMask |= SEE_MASK_NOASYNC;
80+
info.fMask |= SEE_MASK_FLAG_DDEWAIT;
81+
82+
info.hwnd = HWND_DESKTOP;
83+
info.nShow = SW_SHOWDEFAULT;
84+
info.lpFile = pathW.c_str();
85+
86+
//Print execute values in the logs
87+
LOG(INFO) << "Exec: '" << path << "'.";
88+
if (!verb.empty())
89+
{
90+
info.lpVerb = verbW.c_str(); // Verb
91+
LOG(INFO) << "Verb: '" << verb << "'.";
92+
}
93+
if (!arguments.empty())
94+
{
95+
info.lpParameters = argumentsW.c_str(); // Arguments
96+
LOG(INFO) << "Arguments: '" << arguments << "'.";
97+
}
98+
if (!basedir.empty())
99+
{
100+
info.lpDirectory = basedirW.c_str(); // Default directory
101+
LOG(INFO) << "Basedir: '" << basedir << "'.";
102+
}
103+
104+
//Execute and get the pid
105+
bool success = (ShellExecuteExW(&info) == TRUE);
106+
if (!success)
107+
return false;
108+
DWORD pId = GetProcessId(info.hProcess);
109+
110+
success = (pId != ra::process::INVALID_PROCESS_ID);
111+
if (success)
112+
{
113+
LOG(INFO) << "Process created. PID=" << pId;
114+
}
115+
116+
return success;
117+
}
118+
119+
bool ActionExecute::ExecuteProcess(const Context & iContext) const
120+
{
121+
PropertyManager& pmgr = PropertyManager::GetInstance();
122+
std::string path = pmgr.Expand(mPath);
123+
std::string basedir = pmgr.Expand(mBaseDir);
53124
std::string arguments = pmgr.Expand(mArguments);
54125

55126
bool basedir_missing = basedir.empty();
@@ -94,20 +165,29 @@ namespace shellanything
94165
LOG(WARNING) << "attribute 'basedir' not specified.";
95166
}
96167

97-
//debug
168+
//Print execute values in the logs
169+
LOG(INFO) << "Exec: '" << path << "'.";
170+
if (!arguments.empty())
171+
{
172+
LOG(INFO) << "Arguments: '" << arguments << "'.";
173+
}
174+
if (!basedir.empty())
175+
{
176+
LOG(INFO) << "Basedir: '" << basedir << "'.";
177+
}
178+
179+
//Execute and get the pid
98180
uint32_t pId = ra::process::INVALID_PROCESS_ID;
99181
if (arguments_missing)
100182
{
101-
LOG(INFO) << "Running '" << path << "' from directory '" << basedir << "'.";
102183
pId = ra::process::StartProcessUtf8(path, basedir);
103184
}
104185
else
105186
{
106-
LOG(INFO) << "Running '" << path << "' from directory '" << basedir << "' with arguments '" << arguments << "'.";
107187
pId = ra::process::StartProcessUtf8(path, basedir, arguments);
108188
}
109189

110-
bool success = pId != ra::process::INVALID_PROCESS_ID;
190+
bool success = (pId != ra::process::INVALID_PROCESS_ID);
111191
if (success)
112192
{
113193
LOG(INFO) << "Process created. PID=" << pId;
@@ -146,4 +226,14 @@ namespace shellanything
146226
mArguments = iArguments;
147227
}
148228

229+
const std::string& ActionExecute::GetVerb() const
230+
{
231+
return mVerb;
232+
}
233+
234+
void ActionExecute::SetVerb(const std::string& iVerb)
235+
{
236+
mVerb = iVerb;
237+
}
238+
149239
} //namespace shellanything

src/ActionOpen.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ namespace shellanything
6969
info.nShow = SW_SHOWDEFAULT;
7070
info.lpVerb = L"open";
7171
info.lpFile = pathW.c_str();
72-
info.lpParameters = NULL; //arguments
73-
info.lpDirectory = NULL; // default directory
72+
info.lpParameters = NULL; // arguments
73+
info.lpDirectory = NULL; // Default directory
7474

7575
BOOL success = ShellExecuteExW(&info);
7676
return (success == TRUE);

src/ObjectFactory.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,14 @@ namespace shellanything
293293
action->SetBaseDir(tmp_str);
294294
}
295295

296+
//parse verb
297+
tmp_str = "";
298+
tmp_int = -1;
299+
if (ParseAttribute(element, "verb", true, true, tmp_str, error))
300+
{
301+
action->SetVerb(tmp_str);
302+
}
303+
296304
//done parsing
297305
return action;
298306
}

0 commit comments

Comments
 (0)