@@ -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" \n Directory: " + 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" \n Items: " + std::to_wstring (count) + L" \n First item: " + pszName + L" \n Last 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