Skip to content

Commit

Permalink
Updated CHANGES file.
Browse files Browse the repository at this point in the history
Moved `ActionExecute::StartProcess()` private.
Fixed a bad copy paste for `ActionExecute::SetVerb()` and `ActionExecute::GetVerb()`.
Updated documentation for verb attribute of <exec> element.
Fixed missing closing quotes in logs of ActionExecute::Execute().
Created TestObjectFactory.testParseActionExecute() unit tests to validate parsing.
For issue #56.
  • Loading branch information
end2endzone committed Nov 1, 2020
1 parent d0de816 commit 23e3df9
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Changes for 0.5.0
* Fixed issue #51: Action "Open command prompt here" from default.xml configuration does not work.
* Fixed issue #52: Define a specific property for use as separator for handling multiple file selection.
* Fixed issue #55: Menu name maximum length limit and escape string.
* Fixed issue #56: Not implemented administrator mode.
* Fixed issue #58: More useful features: class and pattern attributes for validity / visibility.
* Fixed issue #61: Support for WIX installer.
* Fixed issue #66: Github don't identify the repository LICENSE as MIT.
Expand Down
24 changes: 23 additions & 1 deletion UserManual.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
![ShellAnything logo](docs/ShellAnything-splashscreen.jpg?raw=true)
![ShellAnything logo](docs/ShellAnything-splashscreen.jpg?raw=true)


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



#### verb attribute: ####

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.

Verbs are specific to a file type but some are supported by multiple types. Commonly available verbs include:
| Verb | Description |
|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| edit | Launches an editor and opens the document for editing. |
| find | Initiates a search starting from the executed directory. |
| open | Launches an application. If this file is not an executable file, its associated application is launched. |
| print | Prints the document file. |
| properties | Displays the object's properties. |
| 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. |

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) :
```xml
<exec path="C:\Windows\notepad.exe" arguments="C:\Windows\System32\drivers\etc\hosts" verb="runas" />
```
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).



### &lt;open&gt; action ###

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.
Expand Down
21 changes: 11 additions & 10 deletions include/shellanything/ActionExecute.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,11 @@ namespace shellanything
virtual ~ActionExecute();

/// <summary>
/// Execute an application.
/// </summary>
/// <param name="iContext">The current context of execution.</param>
/// <returns>Returns true if the execution is successful. Returns false otherwise.</returns>
virtual bool Execute(const Context& iContext) const;

/// <summary>
/// Execute an application with RapidAssist method.
/// Execute an application.
/// </summary>
/// <param name="iContext">The current context of execution.</param>
/// <returns>Returns true if the execution is successful. Returns false otherwise.</returns>
virtual bool StartProcess(const Context & iContext) const;
virtual bool Execute(const Context& iContext) const;

/// <summary>
/// Getter for the 'path' parameter.
Expand Down Expand Up @@ -91,7 +84,15 @@ namespace shellanything
/// <summary>
/// Setter for the 'verb' parameter.
/// </summary>
void SetVerb(const std::string& iArguments);
void SetVerb(const std::string& iVerb);

private:
/// <summary>
/// Execute an application with RapidAssist method.
/// </summary>
/// <param name="iContext">The current context of execution.</param>
/// <returns>Returns true if the execution is successful. Returns false otherwise.</returns>
virtual bool StartProcess(const Context & iContext) const;

private:
std::string mPath;
Expand Down
10 changes: 5 additions & 5 deletions src/ActionExecute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,24 +71,24 @@ namespace shellanything
info.nShow = SW_SHOWDEFAULT;
info.lpFile = pathW.c_str();

LOG(INFO) << "Exec: '" << path;
LOG(INFO) << "Exec: '" << path << "'.";

if (!verb.empty())
{
info.lpVerb = verbW.c_str(); // Verb
LOG(INFO) << "Verb: '" << verb;
LOG(INFO) << "Verb: '" << verb << "'.";
}

if (!arguments.empty())
{
info.lpParameters = argumentsW.c_str(); // Arguments
LOG(INFO) << "Arguments: '" << arguments;
LOG(INFO) << "Arguments: '" << arguments << "'.";
}

if (!basedir.empty())
{
info.lpDirectory = basedirW.c_str(); // Default directory
LOG(INFO) << "Basedir: '" << basedir;
LOG(INFO) << "Basedir: '" << basedir << "'.";
}

BOOL success = ShellExecuteExW(&info);
Expand Down Expand Up @@ -198,7 +198,7 @@ namespace shellanything

const std::string& ActionExecute::GetVerb() const
{
return mArguments;
return mVerb;
}

void ActionExecute::SetVerb(const std::string& iVerb)
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ set(CONFIGURATION_TEST_FILES ""
${CMAKE_CURRENT_SOURCE_DIR}/test_files/TestConfigManager.testFileModifications.xml
${CMAKE_CURRENT_SOURCE_DIR}/test_files/TestConfigManager.testParentWithoutChildren.xml
${CMAKE_CURRENT_SOURCE_DIR}/test_files/TestConfiguration.testLoadProperties.xml
${CMAKE_CURRENT_SOURCE_DIR}/test_files/TestObjectFactory.testParseActionExecute.xml
${CMAKE_CURRENT_SOURCE_DIR}/test_files/TestObjectFactory.testParseActionFile.xml
${CMAKE_CURRENT_SOURCE_DIR}/test_files/TestObjectFactory.testParseActionMessage.xml
${CMAKE_CURRENT_SOURCE_DIR}/test_files/TestObjectFactory.testParseActionPrompt.xml
Expand Down
1 change: 1 addition & 0 deletions test/TestConfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ namespace shellanything { namespace test
"test_files\\TestConfigManager.testFileModifications.xml",
"test_files\\TestConfigManager.testParentWithoutChildren.xml",
"test_files\\TestConfiguration.testLoadProperties.xml",
"test_files\\TestObjectFactory.testParseActionExecute.xml",
"test_files\\TestObjectFactory.testParseActionFile.xml",
"test_files\\TestObjectFactory.testParseActionPrompt.xml",
"test_files\\TestObjectFactory.testParseDefaults.xml",
Expand Down
86 changes: 86 additions & 0 deletions test/TestObjectFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "TestObjectFactory.h"
#include "shellanything/ConfigManager.h"
#include "shellanything/Context.h"
#include "shellanything/ActionExecute.h"
#include "shellanything/ActionFile.h"
#include "shellanything/ActionPrompt.h"
#include "shellanything/ActionMessage.h"
Expand Down Expand Up @@ -74,6 +75,23 @@ namespace shellanything { namespace test
return NULL;
}
//--------------------------------------------------------------------------------------------------
ActionExecute * GetFirstActionExecute(Menu * m)
{
if (!m)
return NULL;

Action::ActionPtrList actions = m->GetActions();
for(size_t i=0; i<actions.size(); i++)
{
Action * action = actions[i];
ActionExecute * action_execute = dynamic_cast<ActionExecute *>(action);
if (action_execute)
return action_execute;
}

return NULL;
}
//--------------------------------------------------------------------------------------------------
ActionFile * GetFirstActionFile(Menu * m)
{
if (!m)
Expand Down Expand Up @@ -283,6 +301,74 @@ namespace shellanything { namespace test
ASSERT_TRUE( ra::filesystem::DeleteFile(template_target_path.c_str()) ) << "Failed deleting file '" << template_target_path << "'.";
}
//--------------------------------------------------------------------------------------------------
TEST_F(TestObjectFactory, testParseActionExecute)
{
ConfigManager & cmgr = ConfigManager::GetInstance();

static const std::string path_separator = ra::filesystem::GetPathSeparatorStr();

//copy test template file to a temporary subdirectory to allow editing the file during the test
std::string test_name = ra::testing::GetTestQualifiedName();
std::string template_source_path = std::string("test_files") + path_separator + test_name + ".xml";
std::string template_target_path = std::string("test_files") + path_separator + test_name + path_separator + "tmp.xml";

//make sure the target directory exists
std::string template_target_dir = ra::filesystem::GetParentPath(template_target_path);
ASSERT_TRUE( ra::filesystem::CreateDirectory(template_target_dir.c_str()) ) << "Failed creating directory '" << template_target_dir << "'.";

//copy the file
ASSERT_TRUE( ra::filesystem::CopyFile(template_source_path, template_target_path) ) << "Failed copying file '" << template_source_path << "' to file '" << template_target_path << "'.";

//wait to make sure that the next files not dated the same date as this copy
ra::timing::Millisleep(1500);

//setup ConfigManager to read files from template_target_dir
cmgr.ClearSearchPath();
cmgr.AddSearchPath(template_target_dir);
cmgr.Refresh();

//ASSERT the file is loaded
Configuration::ConfigurationPtrList configs = cmgr.GetConfigurations();
ASSERT_EQ( 1, configs.size() );

//ASSERT all menus are available
Menu::MenuPtrList menus = cmgr.GetConfigurations()[0]->GetMenus();
ASSERT_EQ( 4, menus.size() );

//assert all menus have a file element as the first action
ActionExecute * exec00 = GetFirstActionExecute(menus[00]);
ActionExecute * exec01 = GetFirstActionExecute(menus[01]);
ActionExecute * exec02 = GetFirstActionExecute(menus[02]);
ActionExecute * exec03 = GetFirstActionExecute(menus[03]);

ASSERT_TRUE( exec00 != NULL );
ASSERT_TRUE( exec01 != NULL );
ASSERT_TRUE( exec02 != NULL );
ASSERT_TRUE( exec03 != NULL );

//assert menu00 attributes
ASSERT_EQ("C:\\Windows\\System32\\calc.exe", exec00->GetPath());

//assert menu01 attributes
//<exec path="C:\Windows\notepad.exe" basedir="C:\Program Files\7-Zip" arguments="License.txt" />
ASSERT_EQ("C:\\Windows\\notepad.exe", exec01->GetPath());
ASSERT_EQ("C:\\Program Files\\7-Zip", exec01->GetBaseDir());
ASSERT_EQ("License.txt", exec01->GetArguments());

//assert menu02 attributes
//<exec path="C:\Windows\notepad.exe" arguments="C:\Windows\System32\drivers\etc\hosts" verb="runas" />
ASSERT_EQ("C:\\Windows\\notepad.exe", exec02->GetPath());
ASSERT_EQ("C:\\Windows\\System32\\drivers\\etc\\hosts", exec02->GetArguments());
ASSERT_EQ("runas", exec02->GetVerb());

//assert menu03 attributes
//<!-- missing path attribute --> <exec arguments="C:\Windows\System32\drivers\etc\hosts" verb="runas" />
ASSERT_EQ("", exec03->GetPath());

//cleanup
ASSERT_TRUE( ra::filesystem::DeleteFile(template_target_path.c_str()) ) << "Failed deleting file '" << template_target_path << "'.";
}
//--------------------------------------------------------------------------------------------------
TEST_F(TestObjectFactory, testParseActionFile)
{
ConfigManager & cmgr = ConfigManager::GetInstance();
Expand Down
30 changes: 30 additions & 0 deletions test/test_files/TestObjectFactory.testParseActionExecute.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<shell>
<menu name="menu00">
<actions>
<exec path="C:\Windows\System32\calc.exe" />
</actions>
</menu>

<menu name="menu01">
<actions>
<exec path="C:\Windows\notepad.exe" basedir="C:\Program Files\7-Zip" arguments="License.txt" />
</actions>
</menu>

<menu name="menu02">
<actions>
<exec path="C:\Windows\notepad.exe" arguments="C:\Windows\System32\drivers\etc\hosts" verb="runas" />
</actions>
</menu>

<menu name="menu03">
<actions>
<!-- missing path attribute -->
<exec arguments="C:\Windows\System32\drivers\etc\hosts" verb="runas" />
</actions>
</menu>

</shell>
</root>

0 comments on commit 23e3df9

Please sign in to comment.