Skip to content

Commit af622b2

Browse files
committed
update to 1.0
- more consistent command line - support replacement to verb name - remove explicit debug options - update build script
1 parent fd8f11e commit af622b2

File tree

6 files changed

+149
-117
lines changed

6 files changed

+149
-117
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
x64
33
Release
44
Debug
5-
build
5+
build32
6+
build64
67
*.vcxproj.user

ExecuteCommandVerb.cpp

Lines changed: 96 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ class __declspec(uuid(MYUUID))
121121
IFACEMETHODIMP SetSelection(IShellItemArray *psia)
122122
{
123123
HRESULT hr = SetInterface(&_psia, psia);
124-
setSelection_succeeded = SUCCEEDED(hr);
124+
files_selected = SUCCEEDED(hr);
125125
return S_OK;
126126
}
127127

@@ -132,8 +132,9 @@ class __declspec(uuid(MYUUID))
132132
}
133133

134134
// IInitializeCommand
135-
IFACEMETHODIMP Initialize(PCWSTR /* pszCommandName */, IPropertyBag * /* ppb */)
135+
IFACEMETHODIMP Initialize(PCWSTR pszCommandName, IPropertyBag * /* ppb */)
136136
{
137+
pszCommandName_field = pszCommandName;
137138
// The verb name is in pszCommandName, this handler can varry its behavior
138139
// based on the command name (implementing different verbs) or the
139140
// data stored under that verb in the registry can be read via ppb
@@ -158,88 +159,99 @@ class __declspec(uuid(MYUUID))
158159
WCHAR uuid_wide[50];
159160
size_t converted;
160161
mbstowcs_s(&converted, uuid_wide, MYUUID, sizeof(MYUUID));
161-
162-
bool is_debug = pszCmdLine_field[0] == '-' || pszCmdLine_field[0] == 'd';//only "-Embedding" or "d" --> debug
163-
if (!setSelection_succeeded) {//directory mode
164-
if (is_debug) {
165-
MessageBox(NULL, pszName0, uuid_wide, MB_OK | MB_SETFOREGROUND);
162+
DWORD count=0;
163+
if (files_selected) _psia->GetCount(&count);
164+
CComPtr<IShellItem2> psi;
165+
PWSTR pszName = pszName0;
166+
bool is_debug = pszCmdLine_field[0] == '-';//"-Embedding"
167+
if (is_debug) {
168+
if (!files_selected) {//directory mode
169+
std::wstring msg = L"Verb name: " + pszCommandName_field + L"\nDirectory: " + pszName0;
170+
MessageBox(NULL, msg.c_str(), uuid_wide, MB_OK | MB_SETFOREGROUND);
166171
}
167172
else {
168-
run_cmd_pipe([this](HANDLE stdIn) {
169-
DWORD written = 0;
170-
WideCharToMultiByte(CP_UTF8, 0, pszName0, -1, mbfile, MAX_PATH_CHARS * 4, NULL, NULL);//to UTF-8
171-
WriteFile(stdIn, mbfile,(DWORD) strlen(mbfile), &written, NULL);
172-
WriteFile(stdIn, L"\n", 1, &written, NULL);//newline
173-
});
173+
GetItemAt(_psia, 0, IID_PPV_ARGS(&psi));//the first item
174+
psi->GetDisplayName(SIGDN_FILESYSPATH, &pszName);
175+
176+
CComPtr<IShellItem2> psi2;
177+
WCHAR* pszName2 = new WCHAR[MAX_PATH_CHARS];
178+
GetItemAt(_psia, count - 1, IID_PPV_ARGS(&psi2));//the last item
179+
psi2->GetDisplayName(SIGDN_FILESYSPATH, &pszName2);
180+
181+
WCHAR* szMsg = new WCHAR[MAX_PATH_CHARS * 2 + 400];
182+
std::wstring msg = L"Verb name: " + pszCommandName_field + L"\nItems: " + std::to_wstring(count) + L"\nFirst item: " + pszName + L"\nLast item: " + pszName2;
183+
MessageBox(NULL, msg.c_str(), uuid_wide, MB_OK | MB_SETFOREGROUND);
184+
delete[] pszName2;
185+
delete[] szMsg;
174186
}
175187
return;
176188
}
177-
DWORD count;
178-
_psia->GetCount(&count);
179-
CComPtr<IShellItem2> psi;
180-
181-
PWSTR pszName = pszName0;
182-
//HRESULT hr ;
183-
//HRESULT hr2;
184-
if (is_debug) {
185-
//debug; show dialog
186-
GetItemAt(_psia, 0, IID_PPV_ARGS(&psi));//the first item
187-
psi->GetDisplayName(SIGDN_FILESYSPATH, &pszName);
188-
189-
CComPtr<IShellItem2> psi2;
190-
WCHAR* pszName2 = new WCHAR[MAX_PATH_CHARS];
191-
GetItemAt(_psia, count - 1, IID_PPV_ARGS(&psi2));//the last item
192-
psi2->GetDisplayName(SIGDN_FILESYSPATH, &pszName2);
193-
194-
WCHAR* szMsg = new WCHAR[MAX_PATH_CHARS * 2 + 400];
195-
StringCchPrintf(szMsg, MAX_PATH_CHARS * 2 + 400, L"arg:[%s], %d item(s), first item: [%s], last item: [%s]", pszCmdLine_field, count, pszName, pszName2);
196-
MessageBox(NULL, szMsg, uuid_wide, MB_OK | MB_SETFOREGROUND);
197-
delete[] pszName2;
198-
delete[] szMsg;
199-
189+
pszCmdLine_field[wcslen(pszCmdLine_field) - 11] = 0;//ignore " -Embedding"
190+
bool hidden = pszCmdLine_field[1] == L'h';
191+
std::wstring ws = pszCmdLine_field + (hidden ? 3 : 2);//remove options at the beginning
192+
size_t pref_pos = ws.find(L' ');
193+
if (pref_pos == std::wstring::npos) return;//fatal (no prefix)
194+
std::wstring pref = ws.substr(0, pref_pos);//the prefix, like "$$"
195+
ws.erase(0, pref_pos + 1); //remove "$$ " at the beginning
196+
197+
auto verb_len = pszCommandName_field.size();
198+
//create file list string
199+
std::wstring files = L"";
200+
if (!files_selected) {//directory background
201+
files = files + L"\"" + pszName0 + L"\"";
200202
}
201-
else {//command specified
202-
pszCmdLine_field[wcslen(pszCmdLine_field) - 11] = 0;//ignore " -Embedding"
203-
204-
if (pszCmdLine_field[0] == 'a') {//"ExecuteCommand.exe a xxxxx somecommand -some-arg xxxxx
205-
std::wstring args=L"";
206-
for (DWORD i = 0; i < count; i++) {
207-
GetItemAt(_psia, i, IID_PPV_ARGS(&psi));
208-
psi->GetDisplayName(SIGDN_FILESYSPATH, &pszName);
209-
args = args+L"\"" + pszName + L"\" ";
210-
}
211-
args.pop_back();//remove the trailing space
212-
auto arglen = args.length();
213-
std::wstring ws = pszCmdLine_field+2;//remove "a " at the beginning
214-
215-
size_t pos = ws.find(L' ');
216-
if (pos == std::wstring::npos) return;
217-
218-
std::wstring x = ws.substr(0, pos);//xxxxx
219-
ws.erase(0, pos + 1); //remove "xxxxx " at the beginning
220-
221-
//replace all "xxxxx"s in ws
222-
std::wstring::size_type i = 0;
223-
while (1) {
224-
i = ws.find(x, i);
225-
if (i == std::wstring::npos) break;
226-
ws.replace(i, x.size(), args);
227-
i += arglen;
228-
}
229-
WCHAR* wchar = new WCHAR[ws.size() + 1]; // +1 for the null-terminator
230-
std::copy(ws.begin(), ws.end(), wchar);
231-
wchar[ws.size()] = L'\0';
232-
233-
STARTUPINFO si = { sizeof(STARTUPINFO) };
234-
PROCESS_INFORMATION pi;
235-
si.dwFlags = STARTF_USESHOWWINDOW;
236-
si.wShowWindow = TRUE;
237-
CreateProcess(NULL, wchar, NULL, NULL, FALSE, (x[0] == L'h') ? CREATE_NO_WINDOW : 0, NULL, NULL, &si, &pi);
238-
CloseHandle(pi.hProcess);
239-
CloseHandle(pi.hThread);
240-
return;
203+
else {
204+
for (DWORD i = 0; i < count; i++) {
205+
GetItemAt(_psia, i, IID_PPV_ARGS(&psi));
206+
psi->GetDisplayName(SIGDN_FILESYSPATH, &pszName);
207+
files = files + L"\"" + pszName + L"\" ";
208+
}
209+
files.pop_back();//remove the trailing space
210+
}
211+
auto files_len = files.length();
212+
213+
//replace prefixed strings in ws
214+
std::wstring::size_type i = 0;
215+
while (1) {
216+
i = ws.find(pref, i);
217+
if (i == std::wstring::npos) break;
218+
if (ws[i + pref.size()] == L'v') {
219+
ws.replace(i, pref.size() + 1, pszCommandName_field);
220+
i += verb_len;
221+
}
222+
else if (ws[i + pref.size()] == L'f') {
223+
ws.replace(i, pref.size() + 1, files);
224+
i += files_len;
241225
}
242-
run_cmd_pipe([count, this, &pszName, &psi](HANDLE stdIn) {
226+
else {//skip
227+
i += pref.size();
228+
}
229+
}
230+
WCHAR* wchar = new WCHAR[ws.size() + 1]; // +1 for the null-terminator
231+
std::copy(ws.begin(), ws.end(), wchar);
232+
wchar[ws.size()] = L'\0';
233+
234+
if (pszCmdLine_field[0] == 'a') {//argument mode
235+
STARTUPINFO si = { sizeof(STARTUPINFO) };
236+
PROCESS_INFORMATION pi;
237+
si.dwFlags = STARTF_USESHOWWINDOW;
238+
si.wShowWindow = TRUE;
239+
CreateProcess(NULL, wchar, NULL, NULL, FALSE, hidden ? CREATE_NO_WINDOW : 0, NULL, NULL, &si, &pi);
240+
CloseHandle(pi.hProcess);
241+
CloseHandle(pi.hThread);
242+
return;
243+
}
244+
//pipe mode
245+
if (!files_selected) {//directory background
246+
run_cmd_pipe(wchar, hidden, [this](HANDLE stdIn) {
247+
DWORD written = 0;
248+
WideCharToMultiByte(CP_UTF8, 0, pszName0, -1, mbfile, MAX_PATH_CHARS * 4, NULL, NULL);//to UTF-8
249+
WriteFile(stdIn, mbfile, (DWORD)strlen(mbfile), &written, NULL);
250+
WriteFile(stdIn, L"\n", 1, &written, NULL);//newline
251+
});
252+
}
253+
else {
254+
run_cmd_pipe(wchar, hidden, [count, this, &pszName, &psi](HANDLE stdIn) {
243255
DWORD written = 0;
244256
for (DWORD i = 0; i < count; i++) {
245257
GetItemAt(_psia, i, IID_PPV_ARGS(&psi));
@@ -248,11 +260,10 @@ class __declspec(uuid(MYUUID))
248260
WriteFile(stdIn, mbfile, (DWORD)strlen(mbfile), &written, NULL);
249261
WriteFile(stdIn, L"\n", 1, &written, NULL);//newline
250262
}
251-
});
252-
263+
});
253264
}
254265
}
255-
void run_cmd_pipe(std::function<void(HANDLE)> writer_func) {
266+
void run_cmd_pipe(WCHAR* cmdline, bool hidden, std::function<void(HANDLE)> writer_func) {
256267

257268
//create pipe
258269
HANDLE hPipe1[2];
@@ -269,12 +280,12 @@ class __declspec(uuid(MYUUID))
269280
si.hStdInput = hChildRead;
270281
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
271282
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
272-
//if (pszCmdLine_field[0] == 'h') si.wShowWindow = SW_HIDE; // hide window
283+
//if (hidden) si.wShowWindow = SW_HIDE; // hide window
273284

274285
PROCESS_INFORMATION pi;
275286
ZeroMemory(&pi, sizeof(pi));
276287
//ignore first 2 chars & optionally hide window
277-
CreateProcess(NULL, &pszCmdLine_field[2], NULL, NULL, TRUE, (pszCmdLine_field[0] == L'h') ? CREATE_NO_WINDOW : 0, NULL, NULL, &si, &pi);
288+
CreateProcess(NULL, cmdline, NULL, NULL, TRUE, hidden ? CREATE_NO_WINDOW : 0, NULL, NULL, &si, &pi);
278289
CloseHandle(pi.hProcess);
279290
CloseHandle(pi.hThread);
280291
CloseHandle(hChildRead);
@@ -288,7 +299,8 @@ class __declspec(uuid(MYUUID))
288299
~CExecuteCommandVerb()
289300
{
290301
}
291-
WCHAR* pszCmdLine_field;
302+
PWSTR pszCmdLine_field;
303+
std::wstring pszCommandName_field;
292304
long _cRef;
293305
CComPtr<IShellItemArray> _psia;
294306
CComPtr<IUnknown> _punkSite;
@@ -299,7 +311,7 @@ class __declspec(uuid(MYUUID))
299311

300312
CHAR mbfile[MAX_PATH_CHARS * 4];
301313
WCHAR pszName0[MAX_PATH_CHARS];
302-
bool setSelection_succeeded = false;
314+
bool files_selected = false;
303315
};
304316

305317
// this is called to invoke the verb but this call must not block the caller. to accomidate that

0 commit comments

Comments
 (0)