• R/O
  • SSH
  • HTTPS

wrapexec: Commit


Commit MetaInfo

Revisão11 (tree)
Hora2010-08-17 01:02:05
Autoropa

Mensagem de Log

v1.03

Mudança Sumário

Diff

--- tags/v1.03/wrapexec.cpp (nonexistent)
+++ tags/v1.03/wrapexec.cpp (revision 11)
@@ -0,0 +1,1666 @@
1+/*
2+ Wrapper of Execute
3+
4+ by opa
5+*/
6+
7+#include <string>
8+#include <list>
9+#include <map>
10+#include <algorithm>
11+#include <cstdio>
12+#include <dir>
13+#include <io>
14+
15+#include <windows.h>
16+#include <shlobj.h>
17+#include <lmcons.h>
18+
19+#define PGM "wrapexec"
20+#define PGM_DEBUG PGM ": "
21+#define PGM_INFO PGM ": "
22+#define PGM_WARN PGM " warning: "
23+#define PGM_ERR PGM " error: "
24+#define VERSTR "1.03"
25+
26+#define CREDIT2009 "Copyright (c) 2009,2010 by opa"
27+
28+typedef signed char schar;
29+typedef unsigned char uchar;
30+typedef signed int sint;
31+typedef unsigned int uint;
32+typedef signed long slong;
33+typedef unsigned long ulong;
34+
35+using namespace std;
36+
37+char
38+ credit[] = PGM " version " VERSTR " " CREDIT2009;
39+bool
40+ error = false;
41+sint
42+ rcode = 0;
43+
44+////////////////////////////////////////////////////////////////////////
45+
46+template <class BidirectionalIterator, class T>
47+BidirectionalIterator rfind(BidirectionalIterator first, BidirectionalIterator last, const T &value)
48+{
49+ while(first != last){
50+ --last;
51+ if(*last == value)
52+ break;
53+ }
54+
55+ return last;
56+}
57+
58+template <class BidirectionalIterator, class Predicate>
59+BidirectionalIterator rfind_if(BidirectionalIterator first, BidirectionalIterator last, Predicate pred)
60+{
61+ while(first != last){
62+ --last;
63+ if(pred(*last))
64+ break;
65+ }
66+
67+ return last;
68+}
69+
70+inline bool isnotwspace(wchar_t c)
71+{
72+ return !iswspace(c);
73+}
74+
75+inline bool isbackslash(wchar_t c)
76+{
77+ return c == L'\\' || c == L'/';
78+}
79+
80+bool file_is_exist(const wchar_t *filename)
81+{
82+#if 1
83+ _wffblk ff;
84+ sint r;
85+
86+ r = _wfindfirst(filename, &ff, FA_NORMAL + FA_HIDDEN + FA_SYSTEM);
87+ _wfindclose(&ff);
88+
89+ return r == 0;
90+#else
91+ return _waccess(filename, 0) == 0;
92+#endif
93+}
94+
95+inline bool file_is_exist(const wstring &filename)
96+{
97+ return file_is_exist(filename.c_str());
98+}
99+
100+bool _file_is_readable(const wchar_t *filename)
101+{
102+ FILE
103+ *fp = _wfopen(filename, L"rb");
104+
105+ if(fp != NULL){
106+ fclose(fp);
107+ return true;
108+ }
109+
110+ return false;
111+}
112+
113+bool file_is_readable(const wchar_t *filename)
114+{
115+ if(!file_is_exist(filename))
116+ return false;
117+
118+ return _file_is_readable(filename);
119+}
120+
121+inline bool file_is_readable(const wstring &filename)
122+{
123+ return file_is_readable(filename.c_str());
124+}
125+
126+inline bool file_is_executable(const wstring &filename)
127+{
128+ return file_is_readable(filename.c_str());
129+}
130+
131+////////////////////////////////////////////////////////////////////////
132+
133+class String : public wstring {
134+ typedef String Self;
135+ typedef wstring Super;
136+
137+public:
138+ String();
139+ String(const Super &s);
140+ String(const wchar_t *s);
141+ String(const_iterator b, const_iterator e);
142+ String(const char *s);
143+ ~String();
144+
145+ string to_ansi() const;
146+ Self to_upper() const;
147+ Self trim() const;
148+ bool isdoublequote() const;
149+ Self doublequote() const;
150+ Self doublequote_del() const;
151+
152+ Self &operator=(const Self &s);
153+ Self &operator=(const wchar_t *s);
154+ Self &operator=(const char *s);
155+
156+ Self &operator+=(const Self &s) { append(s); return *this; }
157+ Self &operator+=(const wchar_t *s) { append(s); return *this; }
158+ Self &operator+=(const char *s);
159+
160+ Self &assign_from_ansi(const char *s);
161+ Self &assign_from_ansi(const string &s) { return assign_from_ansi(s.c_str()); }
162+ Self &assign_from_utf8(const char *s);
163+ Self &assign_from_utf8(const string &s) { return assign_from_utf8(s.c_str()); }
164+ Self &assign_from_env(const Self &name);
165+ Self &printf(Self format, ...);
166+
167+ // filename operator
168+ bool have_path() const;
169+ bool have_ext() const;
170+ bool isbackslash() const;
171+ Self backslash() const;
172+ Self subext(const Self &ext) const;
173+ Self drivename() const;
174+ Self dirname() const;
175+ Self basename() const;
176+};
177+
178+typedef list<String> Strings;
179+
180+String::String() {}
181+String::String(const String::Super &s) : Super(s) {}
182+String::String(const wchar_t *s) : Super(s) {}
183+String::String(const_iterator b, const_iterator e) : Super(b, e) {}
184+String::String(const char *s) { assign_from_ansi(s); }
185+String::~String() {}
186+String &String::operator=(const String &s) { assign(s); return *this; }
187+String &String::operator=(const wchar_t *s) { assign(s); return *this; }
188+String &String::operator=(const char *s) { assign_from_ansi(s); return *this; }
189+String &String::operator+=(const char *s) { append(String(s)); return *this; }
190+String operator+(const String &s1, const char *s2) { return s1 + String(s2); }
191+String operator+(const char *s1, const String &s2) { return String(s1) + s2; }
192+bool operator==(const String &s1, const char *s2) { return s1 == String(s2); }
193+bool operator==(const char *s1, const String &s2) { return String(s1) == s2; }
194+
195+string String::to_ansi() const
196+{
197+ sint
198+ siz = WideCharToMultiByte(CP_ACP, 0, c_str(), size(), NULL, 0, NULL, NULL);
199+ char
200+ *buf = new char[siz+1];
201+
202+ fill(buf, buf + siz+1, 0);
203+
204+ WideCharToMultiByte(CP_ACP, 0, c_str(), size(), buf, siz, NULL, NULL);
205+
206+ string
207+ r(buf);
208+
209+ delete [] buf;
210+
211+ return r;
212+}
213+
214+String String::to_upper() const
215+{
216+ Self
217+ r(*this);
218+
219+ for(iterator i = r.begin() ; i != r.end() ; ++i)
220+ *i = towupper(*i);
221+
222+ return r;
223+}
224+
225+String String::trim() const
226+{
227+ const_iterator
228+ b = begin(),
229+ e = end();
230+
231+ b = ::find_if(b, e, isnotwspace);
232+ e = ::rfind_if(b, e, isnotwspace);
233+
234+ if(e != end() && isnotwspace(*e))
235+ ++e;
236+
237+ return Self(b, e);
238+}
239+
240+bool String::isdoublequote() const
241+{
242+ // BUG:
243+ // 単に先頭と最後の文字が " かどうかを判定しているだけなので、文字列の途中に " があった場合などを考慮していない。
244+
245+ if(size() >= 2 && *begin() == L'"' && *(end()-1) == L'"')
246+ return true;
247+
248+ return false;
249+}
250+
251+String String::doublequote() const
252+{
253+ Self
254+ r;
255+
256+ if(isdoublequote()){
257+ r.append(*this);
258+ }else{
259+ r.reserve(size() + 2);
260+ r.append(1, L'"');
261+ r.append(*this);
262+ r.append(1, L'"');
263+ }
264+
265+ return r;
266+}
267+
268+String String::doublequote_del() const
269+{
270+ if(isdoublequote())
271+ return String(begin()+1, end()-1);
272+ else
273+ return String(*this);
274+}
275+
276+String &String::assign_from_ansi(const char *s)
277+{
278+ sint
279+ size = MultiByteToWideChar(CP_ACP, 0, s, -1, NULL, 0);
280+ wchar_t
281+ *buf = new wchar_t[size+1];
282+
283+ fill(buf, buf + size+1, 0);
284+
285+ MultiByteToWideChar(CP_ACP, 0, s, -1, buf, size);
286+
287+ assign(buf);
288+
289+ delete [] buf;
290+
291+ return *this;
292+}
293+
294+String &String::assign_from_utf8(const char *s)
295+{
296+ sint
297+ size = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0);
298+ wchar_t
299+ *buf = new wchar_t[size+1];
300+
301+ fill(buf, buf + size+1, 0);
302+
303+ MultiByteToWideChar(CP_UTF8, 0, s, -1, buf, size);
304+
305+ assign(buf);
306+
307+ delete [] buf;
308+
309+ return *this;
310+}
311+
312+String &String::assign_from_env(const String &name)
313+{
314+ wchar_t
315+ *g = _wgetenv(name.c_str());
316+
317+ if(g)
318+ assign(g);
319+ else
320+ clear();
321+
322+ return *this;
323+}
324+
325+String &String::printf(String format, ...) // vaを使う必要上、Stringは値渡し
326+{
327+ wchar_t
328+ buf[1024+1];
329+ va_list
330+ va;
331+ sint
332+ size;
333+
334+ va_start(va, format);
335+ size = wvsprintf(buf, format.c_str(), va);
336+ va_end(va);
337+
338+ assign(buf, buf + size);
339+
340+ return *this;
341+}
342+
343+bool String::have_path() const
344+{
345+ return ::find(begin(), end(), L':') != end() || ::find_if(begin(), end(), ::isbackslash) != end();
346+}
347+
348+bool String::have_ext() const
349+{
350+ const_iterator
351+ b = begin();
352+
353+ b = ::rfind_if(b, end(), ::isbackslash);
354+ if(b != end() && ::isbackslash(*b))
355+ ++b;
356+
357+ b = ::find(b, end(), L'.');
358+ if(b != end() && *b == L'.')
359+ return true;
360+
361+ return false;
362+}
363+
364+bool String::isbackslash() const
365+{
366+ return size() > 0 && ::isbackslash(*(end()-1));
367+}
368+
369+String String::backslash() const
370+{
371+ String
372+ r(*this);
373+
374+ if(size() > 0 && !isbackslash())
375+ r.append(1, L'\\');
376+
377+ return r;
378+}
379+
380+String String::subext(const String &ext) const
381+{
382+ const_iterator
383+ e = ::rfind(begin(), end(), L'.');
384+
385+ if(e != end() && *e != L'.')
386+ e = end();
387+
388+ return Self(begin(), e).append(ext);
389+}
390+
391+String String::drivename() const
392+{
393+ if(size() >= 2 && iswalpha((*this)[0]) && (*this)[1] == L':')
394+ return Self(begin(), begin() + 2);
395+
396+ return Self();
397+}
398+
399+String String::dirname() const
400+{
401+ const_iterator
402+ e = ::rfind_if(begin(), end(), ::isbackslash);
403+
404+ if(e != end() && ::isbackslash(*e))
405+ ++e;
406+
407+ return Self(begin(), e);
408+}
409+
410+String String::basename() const
411+{
412+ const_iterator
413+ b = begin(),
414+ e = end();
415+
416+ b = ::rfind_if(b, e, ::isbackslash);
417+ if(b != end() && ::isbackslash(*b))
418+ ++b;
419+
420+ e = ::rfind(b, e, L'.');
421+ if(e != end() && *e != L'.')
422+ e = end();
423+
424+ return Self(b, e);
425+}
426+
427+////////////////////////////////////////////////////////////////////////
428+
429+#if defined(__CONSOLE__)
430+
431+void _putcxxx(const char *s, FILE *fp)
432+{
433+ fputs(s, fp);
434+ fputc('\n', fp);
435+}
436+
437+#else // __CONSOLE__
438+
439+String
440+ putcxxx_string;
441+
442+void _putcxxx(const char *s, FILE *)
443+{
444+ if(putcxxx_string.size() > 0)
445+ putcxxx_string += "\r\n";
446+
447+ putcxxx_string += s;
448+}
449+
450+#endif // __CONSOLE__
451+
452+inline void putcout(const char *s)
453+{
454+ _putcxxx(s, stdout);
455+}
456+
457+inline void putcerr(const char *s)
458+{
459+ _putcxxx(s, stderr);
460+}
461+
462+void _putcxxx(const String &s, FILE *fp)
463+{
464+ _putcxxx(s.to_ansi().c_str(), fp);
465+}
466+
467+inline void putcout(const String &s)
468+{
469+ _putcxxx(s, stdout);
470+}
471+
472+inline void putcerr(const String &s)
473+{
474+ _putcxxx(s, stderr);
475+}
476+
477+void _putcxxx(const char *s1, const String &s2, FILE *fp)
478+{
479+ _putcxxx(String().assign_from_ansi(s1) + s2, fp);
480+}
481+
482+inline void putcout(const char *s1, const String &s2)
483+{
484+ _putcxxx(s1, s2, stdout);
485+}
486+
487+inline void putcerr(const char *s1, const String &s2)
488+{
489+ _putcxxx(s1, s2, stderr);
490+}
491+
492+bool case_ignore_equal(const String &s1, const String &s2)
493+{
494+ return s1.to_upper() == s2.to_upper();
495+}
496+
497+////////////////////////////////////////////////////////////////////////
498+
499+class IniFileStream {
500+ typedef IniFileStream Self;
501+ typedef ifstream Super;
502+
503+private:
504+ FILE
505+ *_fp;
506+ String
507+ _filename;
508+
509+ bool skip_bom();
510+ Self &get(sint &ch) { ch = fgetc(_fp); return *this; }
511+ Self &unget(sint ch) { ungetc(ch, _fp); return *this; }
512+
513+public:
514+ IniFileStream() : _fp(NULL) {}
515+ IniFileStream(const String &filename) : _fp(NULL) { open(filename); }
516+
517+ static String determine_filename(const String &exename);
518+ const String &filename() const { return _filename; }
519+ void open(const String &filename);
520+ void close();
521+ bool is_open() const { return _fp != NULL; }
522+ bool good() const { return _fp != NULL && !feof(_fp); }
523+ bool eof() const { return _fp == NULL || feof(_fp); }
524+ bool getline(String &s);
525+
526+ static bool is_comment(const String &s);
527+ static bool is_section(const String &s);
528+ static bool is_section(const String &s, const String &section_name);
529+ static bool is_key(const String &s, const String &key_name);
530+ static bool get_value_bool(const String &s);
531+ static String get_value_String(const String &s);
532+};
533+
534+bool IniFileStream::skip_bom()
535+{
536+ // BUG:
537+ // fe fe ... のようなファイルの場合、二つ目のfeしかunget()されない
538+
539+ sint
540+ c;
541+
542+ if(!eof()){
543+ get(c);
544+ if(c == 0xef){
545+ if(!eof()){
546+ get(c);
547+ if(c == 0xbb){
548+ if(!eof()){
549+ get(c);
550+ if(c == 0xbf)
551+ return true; // UTF8
552+ }
553+ }
554+ }
555+#if 0 // UTF16には対応していない
556+ }else if(c == 0xfe){
557+ if(!eof()){
558+ get(c);
559+ if(c == 0xff)
560+ return true; // UTF16BE
561+ }
562+ }else if(c == 0xff){
563+ if(!eof()){
564+ get(c);
565+ if(c == 0xfe)
566+ return true; // UTF16LE
567+ }
568+#endif
569+ }
570+ unget(c);
571+ }
572+
573+ return false;
574+}
575+
576+String IniFileStream::determine_filename(const String &exename)
577+{
578+ String
579+ r;
580+
581+ if(file_is_readable(r = exename.subext(".ini")))
582+ return r;
583+
584+ if(file_is_readable(r = exename.subext(".bat")))
585+ return r;
586+
587+ return exename.subext(".ini"); /* default (but not found) */
588+}
589+
590+void IniFileStream::open(const String &fn)
591+{
592+ close();
593+
594+ _fp = _wfopen(fn.c_str(), L"rt");
595+
596+ if(_fp != NULL){
597+ _filename = fn;
598+ skip_bom();
599+ }
600+}
601+
602+void IniFileStream::close()
603+{
604+ if(_fp != NULL){
605+ fclose(_fp);
606+ _fp = NULL;
607+ }
608+}
609+
610+bool IniFileStream::is_comment(const String &s)
611+{
612+ return s.size()==0 || s[0]==L'#' || s[0]==L';' || s[0]==L'@';
613+}
614+
615+bool IniFileStream::is_section(const String &s)
616+{
617+ if(s.size() >= 2 && *s.begin() == L'[' && *(s.end()-1) == L']')
618+ return true;
619+
620+ return false;
621+}
622+
623+bool IniFileStream::is_section(const String &s, const String &section_name)
624+{
625+ if(!is_section(s))
626+ return false;
627+
628+ return String(s.begin()+1, s.end()-1).trim().to_upper() == section_name;
629+}
630+
631+bool IniFileStream::is_key(const String &s, const String &key_name)
632+{
633+ String::const_iterator
634+ f = find(s.begin(), s.end(), L'=');
635+ String
636+ key_c(s.begin(), f);
637+
638+ return key_c.trim().trim().to_upper() == key_name;
639+}
640+
641+bool IniFileStream::get_value_bool(const String &s)
642+{
643+ String::const_iterator
644+ f = find(s.begin(), s.end(), L'=');
645+
646+ if(f == s.end())
647+ return true; // 「=」がない → キーのみで値の記述なし → trueを返す
648+
649+ String
650+ value(f+1, s.end());
651+ bool
652+ r = false;
653+
654+ value = value.trim().to_upper();
655+
656+ if(value == "TRUE" || value == "YES" || value == "ON"){
657+ r = true;
658+ }else if(value == "FALSE" || value == "NO" || value == "OFF"){
659+ r = false;
660+ }else{
661+ putcerr(PGM_ERR "invalid value: ", value);
662+ error = true;
663+ rcode = -1;
664+ }
665+
666+ return r;
667+}
668+
669+String IniFileStream::get_value_String(const String &s)
670+{
671+ String::const_iterator
672+ f = find(s.begin(), s.end(), L'=');
673+
674+ if(f == s.end())
675+ return String(); // 「=」がない → 空文字列を返す
676+
677+ return String(f+1, s.end());
678+}
679+
680+bool IniFileStream::getline(String &s)
681+{
682+ s.clear();
683+
684+ if(!good())
685+ return false;
686+
687+ string
688+ tmp;
689+
690+ tmp.reserve(200);
691+ for(int c ; (c = fgetc(_fp)) != EOF ; tmp += c)
692+ if(c == '\n')
693+ break;
694+
695+ s.assign_from_utf8(tmp);
696+ s = s.trim();
697+
698+ return true;
699+}
700+
701+////////////////////////////////////////////////////////////////////////
702+
703+class WindowsAPI {
704+public:
705+ static bool CreateProcess(const String &cmd, DWORD CreationFlags, const String &wd, LPSTARTUPINFO si, LPPROCESS_INFORMATION pi);
706+ static String GetClipboardText();
707+ static String GetCommandLine() { return ::GetCommandLine(); }
708+ static String GetComputerName();
709+ static String GetModuleFileName(HMODULE Module = 0);
710+ static String GetTempPath();
711+ static String GetUserName();
712+ static String SHGetSpecialFolder(sint nFolder);
713+};
714+
715+bool WindowsAPI::CreateProcess(const String &cmd, DWORD CreationFlags, const String &wd, LPSTARTUPINFO si, LPPROCESS_INFORMATION pi)
716+{
717+ bool
718+ r;
719+ wchar_t
720+ *cmd_c_str;
721+
722+ cmd_c_str = new wchar_t[cmd.size()+1];
723+ copy(cmd.begin(), cmd.end(), cmd_c_str);
724+ cmd_c_str[cmd.size()] = 0;
725+
726+ r = ::CreateProcess(NULL, cmd_c_str, NULL, NULL, TRUE, CreationFlags, NULL, (wd.size()>0 ? wd.c_str() : NULL), si, pi);
727+
728+ delete [] cmd_c_str;
729+
730+ return r;
731+}
732+
733+String WindowsAPI::GetClipboardText()
734+{
735+ String
736+ r;
737+ HANDLE
738+ h;
739+
740+ if(::OpenClipboard(NULL) == 0)
741+ return String();
742+
743+ if((h = ::GetClipboardData(CF_UNICODETEXT)) != NULL){
744+ r.assign((wchar_t *)::GlobalLock(h));
745+ ::GlobalUnlock(h);
746+ }
747+
748+ if(::CloseClipboard() == 0)
749+ return String();
750+
751+ // 改行文字等はスペースに置換する
752+ for(String::iterator i = r.begin() ; i != r.end() ; ++i)
753+ if(iswspace(*i))
754+ *i = L' ';
755+
756+ return r;
757+}
758+
759+String WindowsAPI::GetComputerName()
760+{
761+ wchar_t
762+ buf[MAX_COMPUTERNAME_LENGTH+1];
763+ DWORD
764+ size = sizeof buf / sizeof(wchar_t);
765+
766+ if(::GetComputerName(buf, &size) == 0)
767+ return String();
768+
769+ return String(String::iterator(buf), String::iterator(buf + size));
770+}
771+
772+String WindowsAPI::GetModuleFileName(HMODULE Module)
773+{
774+ wchar_t
775+ buf[MAX_PATH+1];
776+ DWORD
777+ size = sizeof buf / sizeof(wchar_t);
778+
779+ size = ::GetModuleFileName(Module, buf, size);
780+
781+ if(size == 0)
782+ return String();
783+
784+ return String(buf, buf + size);
785+}
786+
787+String WindowsAPI::GetTempPath()
788+{
789+ String
790+ r;
791+ DWORD
792+ size = ::GetTempPath(0, NULL);
793+ wchar_t
794+ *buf = new wchar_t[size];
795+
796+ ::GetTempPath(size, buf);
797+ r.assign(buf);
798+ delete [] buf;
799+
800+ return r;
801+}
802+
803+String WindowsAPI::GetUserName()
804+{
805+ wchar_t
806+ buf[UNLEN+1];
807+ DWORD
808+ size = sizeof buf / sizeof(wchar_t);
809+
810+ if(::GetUserName(buf, &size) == 0)
811+ return String();
812+
813+ return String(String::iterator(buf), String::iterator(buf + size - 1));
814+}
815+
816+String WindowsAPI::SHGetSpecialFolder(sint nFolder)
817+{
818+ wchar_t
819+ buf[MAX_PATH+1];
820+
821+ memset(buf, 0, sizeof buf);
822+
823+ SHGetSpecialFolderPath(0, buf, nFolder, 0);
824+
825+ return String(buf);
826+}
827+
828+String get_given_option(const String &cmd)
829+{
830+ // コマンドライン文字列から、コマンド名を除いた残りの部分(コマンドに与えるパラメータの部分)を返す
831+
832+ bool
833+ in_quote = false;
834+
835+ for(String::const_iterator i = cmd.begin() ; i != cmd.end() ; ++i){
836+ wchar_t
837+ c = *i;
838+
839+ if(!in_quote)
840+ if(iswspace(c))
841+ return String(i, cmd.end());
842+
843+ if(c == L'"')
844+ in_quote = in_quote ? false : true;
845+ }
846+
847+ return String();
848+}
849+
850+////////////////////////////////////////////////////////////////////////
851+
852+class ExecuteInfo {
853+ typedef ExecuteInfo Self;
854+
855+private:
856+ Strings
857+ _exStrings,
858+ _export_env;
859+ String
860+ _exename,
861+ _ininame,
862+ _target,
863+ _cwd,
864+ _arg,
865+ _chdir;
866+ bool
867+ _verbose,
868+ _internal,
869+ _use_path,
870+ _gui,
871+ _wait,
872+ _hide,
873+ _maximize,
874+ _minimize;
875+
876+ static String getenv(const String &name);
877+ static sint putenv(const String &name, const String &val);
878+ static String get_shell_name();
879+ static String system_escape(const String &s);
880+ static bool search_path(String &cmd, const String &selfname);
881+ sint system(const String &cmd, const String &arg);
882+ sint create_process(const String &cmd);
883+
884+public:
885+ ExecuteInfo();
886+
887+ const Strings &exs() const { return _exStrings; }
888+ const Strings &export_env() const { return _export_env; }
889+ const String &exename() const { return _exename; }
890+ const String &ininame() const { return _ininame; }
891+ const String &target() const { return _target; }
892+ const String &cwd() const { return _cwd; }
893+ const String &arg() const { return _arg; }
894+ const String &chdir() const { return _chdir; }
895+ bool verbose() const { return _verbose; }
896+ bool internal() const { return _internal; }
897+ bool use_path() const { return _use_path; }
898+ bool gui() const { return _gui; }
899+ bool wait() const { return _wait; }
900+ bool hide() const { return _hide; }
901+ bool maximize() const { return _maximize; }
902+ bool minimize() const { return _minimize; }
903+
904+ void add_exs(const String &s);
905+ void add_export_env(const String &s);
906+ const String &exename(const String &s);
907+// const String &ininame(const String &s);
908+ const String &target(const String &s);
909+ const String &arg(const String &s);
910+ const String &chdir(const String &s);
911+ bool verbose(bool v) { return _verbose = v; }
912+ bool internal(bool v) { return _internal = v; }
913+ bool use_path(bool v) { return _use_path = v; }
914+ bool gui(bool v) { return _gui = v; }
915+ bool wait(bool v) { return _wait = v; }
916+ bool hide(bool v) { return _hide = v; }
917+ bool maximize(bool v) { return _maximize = v; }
918+ bool minimize(bool v) { return _minimize = v; }
919+
920+ sint execute();
921+ String expand(const String &s) const;
922+ String expand_value(const String &key) const;
923+ void verbose_out(const String &s);
924+};
925+
926+typedef list<ExecuteInfo>
927+ ExecuteInfos;
928+
929+ExecuteInfo::ExecuteInfo()
930+{
931+ _arg = "${ARG}";
932+ _chdir = "";
933+ _verbose = false;
934+ _internal = false;
935+ _use_path = false;
936+ _gui = false;
937+ _wait = false;
938+ _hide = false;
939+ _maximize = false;
940+ _minimize = false;
941+}
942+
943+String ExecuteInfo::getenv(const String &name)
944+{
945+ return String().assign_from_env(name);
946+}
947+
948+sint ExecuteInfo::putenv(const String &name, const String &val)
949+{
950+ return _wputenv((name + L'=' + val).c_str());
951+}
952+
953+String ExecuteInfo::get_shell_name()
954+{
955+ wchar_t
956+ *g = _wgetenv(L"COMSPEC");
957+
958+ if(g)
959+ return String(g);
960+ else
961+ return String("cmd.exe");
962+}
963+
964+bool ExecuteInfo::search_path(String &cmd, const String &selfname)
965+{
966+ String
967+ path,
968+ path1,
969+ pathext,
970+ pathext1,
971+ fn;
972+ String::iterator
973+ b, e,
974+ bb, ee;
975+ bool
976+ cmd_have_path = cmd.have_path(),
977+ cmd_have_ext = cmd.have_ext();
978+
979+ path.assign_from_env("PATH");
980+ pathext.assign_from_env("PATHEXT");
981+
982+ if(!cmd_have_path){
983+ for(e = path.begin(), b = e ; e != path.end() ; b = e + 1){
984+ e = find(b, path.end(), L';');
985+ path1.assign(b, e);
986+ path1 = path1.trim();
987+ if(path1.size() > 0){
988+ path1 = path1.backslash();
989+ if(!cmd_have_ext){
990+ if(file_is_exist(path1 + cmd + ".*")){
991+ for(ee = pathext.begin(), bb = ee ; ee != pathext.end() ; bb = ee + 1){
992+ ee = find(bb, pathext.end(), L';');
993+ pathext1.assign(bb, ee);
994+ pathext1 = pathext1.trim();
995+ if(pathext1.size() > 0){
996+ fn = path1 + cmd + pathext1;
997+ if(fn.to_upper() != selfname && file_is_executable(fn)){
998+ cmd = fn;
999+ return true;
1000+ }
1001+ }
1002+ }
1003+ }
1004+ }else{
1005+ fn = path1 + cmd;
1006+ if(fn.to_upper() != selfname && file_is_executable(fn)){
1007+ cmd = fn;
1008+ return true;
1009+ }
1010+ }
1011+ }
1012+ }
1013+ }else{
1014+ if(!cmd_have_ext){
1015+ if(file_is_exist(cmd + ".*")){
1016+ for(ee = pathext.begin(), bb = ee ; ee != pathext.end() ; bb = ee + 1){
1017+ ee = find(bb, pathext.end(), L';');
1018+ pathext1.assign(bb, ee);
1019+ pathext1 = pathext1.trim();
1020+ if(pathext1.size() > 0){
1021+ fn = cmd + pathext1;
1022+ if(fn.to_upper() != selfname && file_is_executable(fn)){
1023+ cmd = fn;
1024+ return true;
1025+ }
1026+ }
1027+ }
1028+ }
1029+ }else{
1030+ if(cmd.to_upper() != selfname && file_is_executable(cmd)){
1031+ return true;
1032+ }
1033+ }
1034+ }
1035+
1036+ return false;
1037+}
1038+
1039+void ExecuteInfo::add_exs(const String &s)
1040+{
1041+ String
1042+ x = s.trim().doublequote_del();
1043+
1044+ if(x.size() > 0)
1045+ _exStrings.push_back(x);
1046+}
1047+
1048+void ExecuteInfo::add_export_env(const String &s)
1049+{
1050+ String
1051+ x = s.trim();
1052+
1053+ if(x.size() > 0)
1054+ _export_env.push_back(x);
1055+}
1056+
1057+const String &ExecuteInfo::exename(const String &s)
1058+{
1059+ wchar_t
1060+ buf[MAX_PATH + 1];
1061+
1062+ // 空文字列も許す (但し、有り得ない)
1063+ _exename = s.trim();
1064+ _ininame = IniFileStream::determine_filename(_exename);
1065+ _cwd = String(_wgetcwd(buf, MAX_PATH)).backslash();
1066+
1067+ return _exename;
1068+}
1069+
1070+const String &ExecuteInfo::target(const String &s)
1071+{
1072+ // 空文字列も許す
1073+ return _target = s.trim();
1074+}
1075+
1076+const String &ExecuteInfo::arg(const String &s)
1077+{
1078+ // 空文字列も許す
1079+ return _arg = s.trim();
1080+}
1081+
1082+const String &ExecuteInfo::chdir(const String &s)
1083+{
1084+ // 空文字列も許す
1085+ return _chdir = s.trim().doublequote_del();
1086+}
1087+
1088+String ExecuteInfo::system_escape(const String &s)
1089+{
1090+ String
1091+ r;
1092+ bool
1093+ in_quote = false;
1094+
1095+ r.reserve(s.size());
1096+
1097+ for(String::const_iterator i = s.begin() ; i != s.end() ; ++i){
1098+ wchar_t
1099+ c = *i;
1100+
1101+ if(!in_quote)
1102+ if(c == L'^' || c == L'<' || c == L'>' || c == L'|' || c == L'&' || c == L'(' || c == L')' || c == L'@')
1103+ r.append(1, L'^');
1104+
1105+ r.append(1, c);
1106+
1107+ if(c == L'"')
1108+ in_quote = in_quote ? false : true;
1109+ }
1110+
1111+ return r;
1112+}
1113+
1114+sint ExecuteInfo::create_process(const String &cmd)
1115+{
1116+ String
1117+ arg,
1118+ cl;
1119+ STARTUPINFO
1120+ si;
1121+ PROCESS_INFORMATION
1122+ pi;
1123+ DWORD
1124+ CreationFlags = 0,
1125+ ExitCode = 0;
1126+ sint
1127+ r = 0;
1128+
1129+ if(internal()){
1130+ cl += get_shell_name().doublequote() + " /c" + cmd;
1131+ }else{
1132+ cl += cmd.doublequote();
1133+ }
1134+
1135+ arg = expand(_arg);
1136+ if(arg.size() > 0 && !iswspace(arg[0]))
1137+ cl.append(1,L' '); // 空白がないとコマンド名とくっついてしまうのでスペースを補う
1138+ cl += arg;
1139+
1140+ memset(&si, 0, sizeof si);
1141+ memset(&pi, 0, sizeof pi);
1142+ si.cb = sizeof si;
1143+ GetStartupInfo(&si);
1144+
1145+ si.dwFlags |= STARTF_FORCEOFFFEEDBACK;
1146+
1147+ if(maximize()){
1148+ si.wShowWindow = SW_SHOWMAXIMIZED;
1149+ si.dwFlags |= STARTF_USESHOWWINDOW;
1150+ }
1151+
1152+ if(minimize()){
1153+ si.wShowWindow = SW_SHOWMINIMIZED;
1154+ si.dwFlags |= STARTF_USESHOWWINDOW;
1155+ }
1156+
1157+// hide()
1158+
1159+ verbose_out("create process: " + cl);
1160+
1161+ fflush(stdout);
1162+ fflush(stderr);
1163+
1164+ if(WindowsAPI::CreateProcess(cl, CreationFlags, expand(_chdir), &si, &pi) == 0){
1165+ error = true;
1166+ return -2;
1167+ }
1168+
1169+ CloseHandle(pi.hThread);
1170+ if(gui() && !wait()){
1171+ CloseHandle(pi.hProcess);
1172+ }else{
1173+ WaitForSingleObject(pi.hProcess, INFINITE);
1174+ GetExitCodeProcess(pi.hProcess, &ExitCode);
1175+ CloseHandle(pi.hProcess);
1176+ r = ExitCode;
1177+ }
1178+
1179+ return r;
1180+}
1181+
1182+sint ExecuteInfo::execute()
1183+{
1184+ String
1185+ cmd,
1186+ selfname;
1187+ bool
1188+ done = false,
1189+ found;
1190+
1191+ if(verbose()){ // for speed
1192+ verbose_out("--- execute ---");
1193+ verbose_out("arg: " + arg());
1194+ verbose_out("chdir: " + chdir());
1195+
1196+ for(Strings::const_iterator i = export_env().begin() ; i != export_env().end() ; ++i)
1197+ verbose_out("export_env: " + *i);
1198+ for(Strings::const_iterator i = exs().begin() ; i != exs().end() ; ++i)
1199+ verbose_out("exs: " + *i);
1200+ }
1201+
1202+ if(exs().size() <= 0){
1203+ putcerr(PGM_ERR "execute command not defined");
1204+ error = true;
1205+ rcode = -3;
1206+ return 1;
1207+ }
1208+
1209+ selfname = expand_value("MY_EXENAME").to_upper();
1210+ for(Strings::const_iterator i = exs().begin() ; i != exs().end() ; ++i){
1211+ found = false;
1212+ cmd = expand(*i);
1213+
1214+ if(internal()){
1215+ verbose_out("executable: " + cmd + " (internal)");
1216+ found = true;
1217+ }else if(use_path()){
1218+ found = search_path(cmd, selfname);
1219+ }else if(cmd.to_upper() == selfname){
1220+ verbose_out("unexecutable myself: " + cmd);
1221+ }else if(file_is_executable(cmd)){
1222+ verbose_out("executable: " + cmd);
1223+ found = true;
1224+ }else{
1225+ verbose_out("unexecutable: " + cmd);
1226+ }
1227+
1228+ if(found){
1229+ target(cmd);
1230+
1231+ for(Strings::const_iterator i = export_env().begin() ; i != export_env().end() ; ++i)
1232+ putenv("WRAPEXEC_" + *i, expand_value(*i));
1233+
1234+ rcode = create_process(cmd);
1235+
1236+ // BUG: 「元に戻す」のではなく「クリアする」ということをしている
1237+ for(Strings::const_iterator i = export_env().begin() ; i != export_env().end() ; ++i)
1238+ putenv("WRAPEXEC_" + *i, "");
1239+
1240+ verbose_out(String().printf("return code: %d", rcode));
1241+ target("");
1242+ done = true;
1243+ break;
1244+ }
1245+ }
1246+
1247+
1248+ if(!done){
1249+#if defined(__CONSOLE__) || 1
1250+ rcode = 1;
1251+ putcerr("'" + system_escape(expand_value("MY_BASENAME")) +
1252+ "' is not recognized as an internal or external command,\n"
1253+ "operable program or batch file.");
1254+#else
1255+ // 存在し得ないコマンド名をcmd.exeに与えて、エラーメッセージを出させる
1256+ rcode = system(system_escape(ev("MY_BASENAME")) + "\"\b");
1257+#endif
1258+ error = true;
1259+ return 1;
1260+ }
1261+
1262+ return 0;
1263+}
1264+
1265+String ExecuteInfo::expand(const String &s) const
1266+{
1267+ String
1268+ r,
1269+ name;
1270+ wchar_t
1271+ c1, c2, c3, kokka;
1272+
1273+ for(String::const_iterator i = s.begin() ; i != s.end() ; ++i){
1274+ c1 = *i;
1275+ if(c1 == L'$'){
1276+ ++i;
1277+ if(i == s.end()){
1278+ r.append(1, c1);
1279+ goto BREAK;
1280+ }
1281+
1282+ c2 = *i;
1283+ if(c2 == L'(' || c2 == L'{' || c2 == L'['){
1284+ if(c2 == L'(')
1285+ kokka = L')';
1286+ else if(c2 == L'{')
1287+ kokka = L'}';
1288+ else if(c2 == L'[')
1289+ kokka = L']';
1290+ else
1291+ kokka = 0;
1292+
1293+ ++i;
1294+ if(i == s.end()){
1295+ r.append(1, c1);
1296+ r.append(1, c2);
1297+ goto BREAK;
1298+ }
1299+
1300+ name.clear();
1301+ while(1){
1302+ c3 = *i;
1303+ if(c3 == kokka){
1304+ r.append(expand_value(name));
1305+ break;
1306+ }else{
1307+ name.append(1, c3);
1308+ }
1309+
1310+ ++i;
1311+ if(i == s.end()){
1312+ r.append(1, c1);
1313+ r.append(1, c2);
1314+ r.append(name);
1315+ goto BREAK;
1316+ }
1317+ }
1318+ }else if(c2 == L'$'){
1319+ r.append(1, L'$');
1320+ }else{
1321+ r.append(1, c1);
1322+ r.append(1, c2);
1323+ }
1324+ }else{
1325+ r.append(1, c1);
1326+ }
1327+ }
1328+BREAK:;
1329+
1330+ return r;
1331+}
1332+
1333+String ExecuteInfo::expand_value(const String &key) const
1334+{
1335+ String
1336+ r;
1337+
1338+ if(key.empty()){
1339+ putcerr(PGM_WARN "variable name not presented");
1340+ return "";
1341+ }
1342+
1343+ if(case_ignore_equal(key, "ARG")){
1344+ r = get_given_option(WindowsAPI::GetCommandLine());
1345+ }else if(case_ignore_equal(key, "CLIPBOARD")){
1346+ r = WindowsAPI::GetClipboardText();
1347+ }else if(case_ignore_equal(key, "MY_EXENAME")){
1348+ r = _exename;
1349+ }else if(case_ignore_equal(key, "MY_ININAME")){
1350+ r = _ininame;
1351+ }else if(case_ignore_equal(key, "MY_BASENAME")){
1352+ r = _exename.basename();
1353+ }else if(case_ignore_equal(key, "MY_DIR") || case_ignore_equal(key, "MY")){
1354+ r = _exename.dirname();
1355+ }else if(case_ignore_equal(key, "MY_DRIVE")){
1356+ r = _exename.drivename();
1357+ }else if(case_ignore_equal(key, "SYS_NAME")){
1358+ r = WindowsAPI::GetComputerName(); // SOMEONESPC 等
1359+ }else if(case_ignore_equal(key, "SYS_ROOT")){
1360+ r = WindowsAPI::SHGetSpecialFolder(CSIDL_WINDOWS); // C:\WINDOWS 等
1361+ r = r.backslash();
1362+ }else if(case_ignore_equal(key, "SYS_DIR") || case_ignore_equal(key, "SYS")){
1363+ r = WindowsAPI::SHGetSpecialFolder(CSIDL_SYSTEM); // C:\WINDOWS\system32 等
1364+ r = r.backslash();
1365+ }else if(case_ignore_equal(key, "SYS_DRIVE")){
1366+ r = WindowsAPI::SHGetSpecialFolder(CSIDL_SYSTEM); // C:\WINDOWS\system32 等
1367+ r = r.drivename();
1368+ }else if(case_ignore_equal(key, "USER_NAME")){
1369+ r = WindowsAPI::GetUserName(); // someone 等
1370+ }else if(case_ignore_equal(key, "USER_DIR") || case_ignore_equal(key, "USER")){
1371+ r = WindowsAPI::SHGetSpecialFolder(CSIDL_PROFILE); // C:\Documents and Settings\someone 等
1372+ r = r.backslash();
1373+ }else if(case_ignore_equal(key, "USER_DRIVE")){
1374+ r = WindowsAPI::SHGetSpecialFolder(CSIDL_PROFILE); // C:\Documents and Settings\someone 等
1375+ r = r.drivename();
1376+ }else if(case_ignore_equal(key, "USER_DOC")){
1377+ r = WindowsAPI::SHGetSpecialFolder(CSIDL_PERSONAL); // C:\Documents and Settings\someone\My Documents 等
1378+ r = r.backslash();
1379+ }else if(case_ignore_equal(key, "USER_DESKTOP")){
1380+ r = WindowsAPI::SHGetSpecialFolder(CSIDL_DESKTOPDIRECTORY); // C:\Documents and Settings\someone\デスクトップ 等
1381+ r = r.backslash();
1382+ }else if(case_ignore_equal(key, "ALL_USER_DIR") || case_ignore_equal(key, "ALL_USER")){
1383+ r = WindowsAPI::SHGetSpecialFolder(CSIDL_COMMON_DOCUMENTS).dirname(); // C:\Documents and Settings\All Users\Documents 等
1384+ r = r.backslash();
1385+ }else if(case_ignore_equal(key, "ALL_USER_DRIVE")){
1386+ r = WindowsAPI::SHGetSpecialFolder(CSIDL_COMMON_DOCUMENTS).dirname(); // C:\Documents and Settings\All Users\Documents 等
1387+ r = r.drivename();
1388+ }else if(case_ignore_equal(key, "ALL_USER_DOC")){
1389+ r = WindowsAPI::SHGetSpecialFolder(CSIDL_COMMON_DOCUMENTS); // C:\Documents and Settings\All Users\Documents 等
1390+ r = r.backslash();
1391+ }else if(case_ignore_equal(key, "ALL_USER_DESKTOP")){
1392+ r = WindowsAPI::SHGetSpecialFolder(CSIDL_COMMON_DESKTOPDIRECTORY); // C:\Documents and Settings\All Users\デスクトップ 等
1393+ r = r.backslash();
1394+ }else if(case_ignore_equal(key, "PROGRAM_DIR") || case_ignore_equal(key, "PROGRAM")){
1395+ r = WindowsAPI::SHGetSpecialFolder(CSIDL_PROGRAM_FILES); // C:\Program Files 等
1396+ r = r.backslash();
1397+ }else if(case_ignore_equal(key, "PROGRAM_DRIVE")){
1398+ r = WindowsAPI::SHGetSpecialFolder(CSIDL_PROGRAM_FILES); // C:\Program Files 等
1399+ r = r.drivename();
1400+ }else if(case_ignore_equal(key, "TMP_DIR") || case_ignore_equal(key, "TMP")){
1401+ r = WindowsAPI::GetTempPath(); // C:\DOCUME~1\SOMEONE\LOCALS~1\Temp 等
1402+ r = r.backslash();
1403+ }else if(case_ignore_equal(key, "TMP_DRIVE")){
1404+ r = WindowsAPI::GetTempPath(); // C:\DOCUME~1\SOMEONE\LOCALS~1\Temp 等
1405+ r = r.drivename();
1406+ }else if(case_ignore_equal(key, "TARGET_NAME")){
1407+ r = _target;
1408+ }else if(case_ignore_equal(key, "TARGET_DIR") || case_ignore_equal(key, "TARGET")){
1409+ r = _target.dirname();
1410+ }else if(case_ignore_equal(key, "TARGET_DRIVE")){
1411+ r = _target.drivename();
1412+ }else if(case_ignore_equal(key, "CURRENT_DIR") || case_ignore_equal(key, "CURRENT")){
1413+ r = _cwd;
1414+ }else if(case_ignore_equal(key, "CURRENT_DRIVE")){
1415+ r = _cwd.drivename();
1416+ }else{
1417+ r = getenv(key);
1418+ if(r.size() == 0){
1419+ putcerr(PGM_WARN "variable not defined: ", key);
1420+ r = key;
1421+ }
1422+ }
1423+
1424+ return r;
1425+
1426+}
1427+
1428+void ExecuteInfo::verbose_out(const String &s)
1429+{
1430+ if(verbose())
1431+ putcout(PGM_DEBUG, s);
1432+}
1433+
1434+////////////////////////////////////////////////////////////////////////
1435+
1436+void do_help()
1437+{
1438+ putcout(credit);
1439+ putcout("");
1440+
1441+ putcout(
1442+ "available sections:\n"
1443+ " [global]\n"
1444+ " [option]\n"
1445+ " [exec]\n"
1446+ " [end]\n"
1447+ );
1448+
1449+ putcout(
1450+ "available options:\n"
1451+ " help\n"
1452+ " arg\n"
1453+ " chdir\n"
1454+ " export_env\n"
1455+ " verbose\n"
1456+ " internal\n"
1457+ " use_path\n"
1458+ " gui\n"
1459+ " wait\n"
1460+ " maximize\n"
1461+ " minimize\n"
1462+ );
1463+
1464+ putcout(
1465+ "available macros:\n"
1466+ " ARG\n"
1467+ " CLIPBOARD\n"
1468+ " MY_EXENAME\n"
1469+ " MY_ININAME\n"
1470+ " MY_BASENAME\n"
1471+ " MY_DIR (MY)\n"
1472+ " MY_DRIVE\n"
1473+ " SYS_NAME\n"
1474+ " SYS_ROOT\n"
1475+ " SYS_DIR (SYS)\n"
1476+ " SYS_DRIVE\n"
1477+ " USER_NAME\n"
1478+ " USER_DIR (USER)\n"
1479+ " USER_DRIVE\n"
1480+ " USER_DOC\n"
1481+ " USER_DESKTOP\n"
1482+ " ALL_USER_DIR (ALL_USER)\n"
1483+ " ALL_USER_DRIVE\n"
1484+ " ALL_USER_DOC\n"
1485+ " ALL_USER_DESKTOP\n"
1486+ " PROGRAM_DIR (PROGRAM)\n"
1487+ " PROGRAM_DRIVE\n"
1488+ " TMP_DIR (TMP)\n"
1489+ " TMP_DRIVE\n"
1490+ " TARGET_NAME\n"
1491+ " TARGET_DIR (TARGET)\n"
1492+ " TARGET_DRIVE\n"
1493+ " CURRENT_DIR (CURRENT)\n"
1494+ " CURRENT_DRIVE"
1495+ );
1496+}
1497+
1498+void do_inifile_option(IniFileStream &ifs, ExecuteInfo &e, const String &aline)
1499+{
1500+ if(ifs.is_key(aline, "HELP")){
1501+ do_help();
1502+ error = true; // execフェーズを実行しない
1503+ rcode = 0; // がエラーではないのでrcodeは0を返す
1504+ }else if(ifs.is_key(aline, "ARG")){
1505+ e.arg(ifs.get_value_String(aline));
1506+ }else if(ifs.is_key(aline, "CHDIR")){
1507+ e.chdir(ifs.get_value_String(aline));
1508+ }else if(ifs.is_key(aline, "IMPORT_ENV")){
1509+ putcerr(PGM_WARN "keyword IMPORT_ENV is obsolete: ", ifs.get_value_String(aline));
1510+ }else if(ifs.is_key(aline, "EXPORT_ENV")){
1511+ e.add_export_env(ifs.get_value_String(aline));
1512+ }else if(ifs.is_key(aline, "VERBOSE")){
1513+ e.verbose(ifs.get_value_bool(aline));
1514+ }else if(ifs.is_key(aline, "INTERNAL")){
1515+ e.internal(ifs.get_value_bool(aline));
1516+ }else if(ifs.is_key(aline, "USE_PATH")){
1517+ e.use_path(ifs.get_value_bool(aline));
1518+ }else if(ifs.is_key(aline, "GUI")){
1519+ e.gui(ifs.get_value_bool(aline));
1520+ }else if(ifs.is_key(aline, "WAIT")){
1521+ e.wait(ifs.get_value_bool(aline));
1522+ }else if(ifs.is_key(aline, "HIDE")){
1523+ e.hide(ifs.get_value_bool(aline));
1524+ }else if(ifs.is_key(aline, "MAXIMIZE")){
1525+ e.maximize(ifs.get_value_bool(aline));
1526+ e.minimize(false);
1527+ }else if(ifs.is_key(aline, "MINIMIZE")){
1528+ e.minimize(ifs.get_value_bool(aline));
1529+ e.maximize(false);
1530+ }else{
1531+ putcout(PGM_ERR "invalid option: ", aline);
1532+ error = true;
1533+ rcode = -4;
1534+ }
1535+}
1536+
1537+void load_inifile(ExecuteInfo &execinfo_default, ExecuteInfos &execinfos, const String &exename)
1538+{
1539+ enum section_id{
1540+ SECTION_NONE,
1541+ SECTION_END,
1542+ SECTION_GLOBAL,
1543+ SECTION_OPTION,
1544+ SECTION_EXEC,
1545+ };
1546+
1547+ execinfo_default.exename(exename);
1548+
1549+ execinfo_default.verbose_out("--- prepare ---");
1550+ execinfo_default.verbose_out("exe filename: " + execinfo_default.exename());
1551+ execinfo_default.verbose_out("ini filename: " + execinfo_default.ininame());
1552+ execinfo_default.verbose_out("cwd: " + execinfo_default.cwd());
1553+
1554+ execinfos.clear();
1555+ execinfos.push_back(execinfo_default);
1556+
1557+ String
1558+ aline;
1559+ section_id
1560+ section = SECTION_EXEC;
1561+ IniFileStream
1562+ ifs(execinfo_default.ininame());
1563+
1564+ if(!ifs.is_open()){
1565+ putcerr(PGM_ERR "ini file open failed");
1566+ error = true;
1567+ rcode = -5;
1568+ return;
1569+ }
1570+
1571+ while(ifs.getline(aline)){
1572+ if(ifs.is_comment(aline)){
1573+ ; // コメントor空行なのでスキップ
1574+ }else{
1575+ if(ifs.is_section(aline)){
1576+ if(ifs.is_section(aline, "END")){
1577+ execinfo_default.verbose_out("end section detected");
1578+ break;
1579+ }else if(ifs.is_section(aline, "GLOBAL")){
1580+ section = SECTION_GLOBAL;
1581+ }else if(ifs.is_section(aline, "OPTION")){
1582+ section = SECTION_OPTION;
1583+ if(execinfos.back().exs().size() > 0)
1584+ execinfos.push_back(execinfo_default);
1585+ else
1586+ execinfos.back() = execinfo_default;
1587+ }else if(ifs.is_section(aline, "EXEC")){
1588+ section = SECTION_EXEC;
1589+ if(execinfos.back().exs().size() > 0)
1590+ execinfos.push_back(execinfo_default);
1591+ }else{
1592+ putcerr(PGM_ERR "invalid section name: ", aline);
1593+ section = SECTION_NONE;
1594+ error = true;
1595+ rcode = -6;
1596+ }
1597+ }else{
1598+ switch(section){
1599+ case SECTION_GLOBAL:
1600+ do_inifile_option(ifs, execinfo_default, aline);
1601+ break;
1602+ case SECTION_OPTION:
1603+ do_inifile_option(ifs, execinfos.back(), aline);
1604+ break;
1605+ case SECTION_EXEC:
1606+ execinfos.back().add_exs(aline);
1607+ break;
1608+ default:
1609+ putcout(PGM_WARN "ignored: ", aline);
1610+ break;
1611+ }
1612+ }
1613+ }
1614+ }
1615+
1616+ ifs.close();
1617+}
1618+
1619+void wrapexec_main()
1620+{
1621+ ExecuteInfo
1622+ execinfo_default;
1623+ ExecuteInfos
1624+ execinfos;
1625+
1626+ load_inifile(execinfo_default, execinfos, WindowsAPI::GetModuleFileName());
1627+
1628+ for(ExecuteInfos::iterator i = execinfos.begin() ; !error && i != execinfos.end() ; ++i)
1629+ i->execute();
1630+}
1631+
1632+#if defined(__CONSOLE__)
1633+
1634+sint wmain(sint, wchar_t *[])
1635+{
1636+ wrapexec_main();
1637+
1638+ return rcode;
1639+}
1640+
1641+#else // __CONSOLE__
1642+
1643+// ダミーのメッセージを送受信することで、プログラムが動き出したことをOSに伝える
1644+void dummy_message()
1645+{
1646+ MSG msg;
1647+ PostMessage(NULL, WM_APP, 0, 0);
1648+ GetMessage(&msg, NULL, WM_APP, WM_APP);
1649+}
1650+
1651+extern "C"
1652+sint WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
1653+{
1654+ dummy_message();
1655+ putcxxx_string.clear();
1656+
1657+ wrapexec_main();
1658+
1659+ if(putcxxx_string.size() > 0)
1660+ MessageBox(0, putcxxx_string.c_str(), WindowsAPI::GetModuleFileName().basename().c_str(), MB_ICONINFORMATION + MB_OK);
1661+
1662+ return rcode;
1663+}
1664+
1665+#endif // __CONSOLE__
1666+
--- tags/v1.03/wrapexecw.ini (nonexistent)
+++ tags/v1.03/wrapexecw.ini (revision 11)
@@ -0,0 +1,19 @@
1+; wrapexec 設定ファイルの雛形
2+;
3+; Copyright (c) 2009,2010 by opa
4+
5+[option]
6+help
7+;arg = ${ARG}
8+;chdir =
9+;export_env = MY_ININAME
10+;verbose = no
11+;internal = no
12+;use_path = no
13+;gui = no
14+;wait = no
15+;maximize = yes
16+;minimize = yes
17+;use_path
18+[exec]
19+${PROGRAM}directory\theProgram.exe
--- tags/v1.03/wrapexec.ini (nonexistent)
+++ tags/v1.03/wrapexec.ini (revision 11)
@@ -0,0 +1,19 @@
1+; wrapexec 設定ファイルの雛形
2+;
3+; Copyright (c) 2009,2010 by opa
4+
5+[option]
6+help
7+;arg = ${ARG}
8+;chdir =
9+;export_env = MY_ININAME
10+;verbose = no
11+;internal = no
12+;use_path = no
13+;gui = no
14+;wait = no
15+;maximize = yes
16+;minimize = yes
17+;use_path
18+[exec]
19+${PROGRAM}directory\theProgram.exe
--- tags/v1.03/wrapexec.txt (nonexistent)
+++ tags/v1.03/wrapexec.txt (revision 11)
@@ -0,0 +1,602 @@
1+--------------------------------------------------------------------------------
2+
3+ 実行ファイルのラッパー「wrapexec」
4+
5+ by おぱ (opa)
6+
7+--------------------------------------------------------------------------------
8+
9+・概要
10+
11+ wrapexecは、他のプログラムを単に実行するだけのプログラムです。
12+ どのプログラムをどのように実行するかを、設定ファイルにより定義
13+ できます。
14+
15+
16+・このプログラムが役に立つケースの例
17+
18+ 例えば Perl で有用なツールを作ったとします。仮に、useful_script.plと
19+ いう名前をつけたとしましょう。さて、これを実行しようとするたびに、
20+ 毎回「perl useful_script.pl 云々・・・」と打つのは面倒です。
21+ そこで、wrapexec.exe を useful_script.exe という名前でコピーして
22+ 設定ファイルを記述してやると、単に「useful_script 云々・・・」と打つ
23+ だけでスクリプトを実行することができます。
24+
25+ また、スクリプトをプログラムのように扱う手法として、スクリプトの冒頭に
26+ 特別な記述を挿入し、バッチファイルにしてしまうというテクニックも
27+ よく用いられます。しかしこの場合、要するにバッチファイルですから、
28+ それを他のバッチファイルから呼ぶときは、単に「useful_script」などと
29+ 記述しても、呼び出し元のバッチファイルに戻ってきてくれません。
30+ バッチファイルであることを意識して、「call useful_script」などと
31+ 記述する必要があります。(MS-DOS時代から連綿と続く、おそるべき仕様)
32+ このような場合も、wrapexec を介して useful_script.bat を呼ぶように
33+ すれば解決します。wrapexec は普通のexeファイルですので、バッチファイル
34+ から実行された場合でも、呼び出し元のバッチファイルに制御が戻ります。
35+
36+ CUIに慣れている人は、Program Files 以下にインストールされたエディタや
37+ ツール類を、コマンドラインから実行したいと思うことが多々あると思い
38+ ます。ところが Program Files 以下には通常、PATHは通っていません。
39+ そもそも Program Files 以下は通常、ソフトウェアごとにディレクトリが
40+ 切られますので、それらひとつひとつにPATHを通していては大変なことに
41+ なってしまいます。
42+ このような場合は、どこかパスの通ったディレクトリに warpexec.exe を
43+ (word.exe でも access.exe でも適当な名前で)コピーして、そこから
44+ Program Files 以下の本物のプログラムを実行するようにすることで、
45+ あたかもそのプログラムにPATHを通したかのようなことができます。
46+
47+ 実行したいプログラムが、/bin にあるのか、/usr/bin にあるのか、それとも
48+ /usr/local/bin はたまた /opt/theSoftware/bin にあるのか といった
49+ 問題は Windows では比較的発生しにくいのですが(なぜなら、それらのいずれ
50+ でもなく、/Program Filesや/Windowsにあるから)、それでも環境や運用方法
51+ によっては、実行したいプログラムの実体がどこにあるのかが特定できない
52+ 場合があります。例えば、実行するマシンによって、perl.exe や cc.exe の
53+ 場所が異なる現場など。
54+ wrapexec は、実行するプログラムの候補を複数指定できますので、
55+ 考えられる場所をあらかじめ列挙しておくことで、それらのうちのどこかに
56+ あればそれを実行するということができます。
57+
58+ あるプログラムを実行するとき、必ずそれに先立って初期化処理を行いたい
59+ というケースがあるかと思います。例えば、常に同じ設定で起動するために、
60+ レジストリをクリアしておきたい など。
61+ wrapexec は、複数のプログラムを実行できます。本体のプログラムを実行
62+ する前に、任意のバッチファイルやスクリプトを実行して、思う存分
63+ お膳立てをすることができます。
64+
65+ このように、かように単純なプログラムでも、ことWindowsでCMD.EXEを
66+ 使っている場合はけっこう役に立ちます。
67+
68+
69+・用途
70+
71+ exeファイルに対するラッパとして使えます。他の場所にあるexeファイルを
72+ 同じオプションで実行したり、または追加のオプションを与えたり、
73+ そのexeのあるディレクトリにchdirしたうえで実行したりといったことが
74+ できます。
75+ また、GUIアプリケーションについては、最小化/最大化するよう指示を
76+ 与えたうえで起動することもできます。
77+
78+ batファイルに対するラッパとして使えます。バッチファイルを他のバッチ
79+ ファイルから実行する場合、「call バッチファイル名」としないと、
80+ 呼び出し元のバッチファイルに制御が戻らず、バッチファイルの処理が
81+ そこで終了してしまいますが、このプログラムを介してバッチファイルを
82+ 実行することにより、本体はバッチファイルでも、そうと意識せずに他の
83+ バッチファイルから実行することができます。
84+ また、callで呼び出されたバッチファイル内では、環境変数を操作したり、
85+ カレントディレクトリを変更したりすると、呼び出し元のバッチファイルの
86+ 側にもその影響が現れます。
87+ このプログラムを介してバッチファイルを実行した場合、別個のcmd.exeの
88+ 下でバッチファイルが実行されますので、上記のような副作用はありません。
89+ (逆に、そのような副作用を前提としたバッチファイルは、本プログラムを
90+ 介して実行すると、もともと意図されたようには動作しません)
91+
92+ その他のスクリプトに対するラッパとして使えます。スクリプト名と同じ
93+ 名前で本プログラムをコピーして、対象のスクリプト言語のインタプリタを
94+ 実行し、その引数には、実行したいスクリプト名を与えるよう設定します。
95+ これにより、あたかもスクリプト自体に実行属性を与えたかのように、直接
96+ 実行する(のに似た)ことができます。
97+ Perl や Ruby などのインタプリタによっては、「ファイル冒頭の特定の記述
98+ までを読み飛ばす」という機能があるものがあります。一方、本プログラムは、
99+ 「ファイルの特定の記述([end])以降を読み飛ばす」という機能があります。
100+ これを組み合わせると、本プログラムの設定ファイルと、スクリプト本体を、
101+ ひとつのファイルに記述できます。
102+
103+ これらの結果として、コマンドプロンプトがCUIのランチャになります。
104+ パスの通ったディレクトリに、よく使うアプリケーションをそれぞれラップ
105+ した本プログラムを入れておけば、プログラム名をタイプするだけで
106+ 実体はそれぞれどこか別のところにあるプログラムを一発で実行することが
107+ できます。スタートメニューや Program Files の中を探し回ったり、
108+ ネットワークのドライブ文字を慌てて調べたりする必要はありません。
109+
110+
111+・動作環境
112+
113+ WindowsNT 4.0以降 (2000/XP/Vista等)
114+
115+ 動作確認はWindowsXP上で行っています。
116+
117+
118+・使用法
119+
120+ 本プログラムは、提供時は wrapexec.exe というファイル名ですが、実際に
121+ 使用する際は、別の名前にコピーされることを想定しています。
122+ 名前はなんでもよいですが、通常は、実行したい(ラップしたい)プログラムと
123+ 同じ名前でコピーするのがよいかと思います。
124+
125+ 次にその設定ファイルを作成します(書法は後述)。コピーした本プログラムと
126+ 同じディレクトリの、同じ名前で拡張子を .ini に置き換えたファイルが、
127+ 設定ファイルとして使われます。
128+
129+ あとはそのコピーした本プログラムを実行すれば、設定ファイルに従って
130+ 目的のプログラムが実行されます。
131+
132+
133+・設定ファイル(.ini)
134+
135+ 実行ファイルの拡張子を .ini に置き変えたファイルを設定ファイルとして
136+ 読み込みます。
137+ このファイルは、UTF-8で作成する必要があります。
138+
139+ 書式は Windows でよくある、INIファイルに似たものです。
140+ [section] でセクションを宣言し、それ以降にその内容を記述します。
141+ キーワードの大文字小文字は区別されません。
142+ いくつかの箇所では、${変数名}の形式で、マクロを使用できます。(後述)
143+ 行頭および行末のスペースは無視されます。
144+ '#' または ';' または '@' で始まる行はコメントです。
145+ 行の途中の '#' ';' '@' はコメントの開始文字としては扱われません。
146+
147+ 例
148+ |
149+ |# この行はコメントです。
150+ | ; 行頭のスペースは無視されるので、この行もコメントです。
151+ |gui = true # これはコメントとは解釈されません。
152+ |
153+
154+ 使用可能なセクションは以下の通りです。
155+
156+ [option] セクション
157+ このセクションでは、プログラムを実行するときの様々な動作を、
158+ キーワード=値 の書式で記述します。「=値」は省略することもできます。
159+ 使用可能なキーワードとその意味については後述します。
160+
161+ [exec] セクション
162+ 実行したいプログラム(のいくつかの候補)を記述します。
163+ マクロ(${MY_DIR}等)を使用できます。
164+ 複数行、記述することができます。記述された順にファイルの存在チェック
165+ を行って、最初に見つかったものを実行します。
166+ ここで自分自身を指定すると、無限ループになりますので注意して下さい。
167+
168+ [global] セクション
169+ 上記の [option] [exec] セクションの組は、ひとつの設定ファイルの中に
170+ 複数個記述することができます。[option] セクションで記述した内容は、
171+ その [option] [exec] セクションの組についてだけ有効なので、複数の
172+ [option] [exec] セクションの組に共通で与えたいオプションがあるときは、
173+ この [global] セクションで記述することで、それ以降の全ての [option]
174+ セクションでそれぞれ指定したのと同じことになります。
175+
176+ [end] セクション
177+ ここで設定ファイルの読み込みを終え、これより後に何が書かれていても
178+ 無視します。
179+ 設定ファイルに、実行したいスクリプト本体を埋め込みたい時などに便利
180+ な場合があります。(←消極的)
181+
182+
183+・オプション
184+
185+ オプションには、引数に真偽値をとるものと、文字列をとるものとがあります。
186+ 真偽値をとるオプションの場合、"true" "yes" "on" が真、"false" "no"
187+ "off" が偽と解釈されます。また、引数を与えなかった場合は、真として
188+ 扱われます。
189+ 文字列をとるオプションの場合、"=" 以降がそのまま引数として解釈され
190+ ます。また、引数を与えなかった場合は、空文字列として扱われます。
191+
192+ 例
193+ |
194+ |[option]
195+ |verbose=true (真)
196+ |internal=no (偽)
197+ |gui (引数が省略されたため、真)
198+ |chdir=C:\work ("C:\work" という文字列)
199+ |
200+
201+ [option] および [global] セクションで使用可能なオプションは、
202+ 以下の通りです。
203+
204+ help
205+ 特殊なオプションです。このオプションを指定すると、簡単なヘルプを
206+ 表示して終了します。
207+ 本プログラムの性質上、コマンドラインから "--help" などとしても、本プロ
208+ グラムがヘルプを表示するようなことはなく、それはそのまま本プログラム
209+ から実行されるプログラムに渡されることになります。
210+
211+ arg (初期値:"${ARG}")
212+ 引数に文字列をとります。本プログラムから実行されるプログラムに
213+ 引数をどのように渡すかを指定します。デフォルトは "${ARG}" で、これは
214+ 本プログラムに渡された引数をそのまま渡すことを意味します。
215+ マクロ(${ARG}等)を使用できます。
216+
217+ chdir (初期値:"")
218+ 引数に文字列をとります。プログラムを実行する前にカレントディレクトリを
219+ 変更したい場合に、このオプションで移りたいディレクトリを指定します。
220+ UNCパス(\\server\share等)も指定できますが、UNCパスに直接 chdir する
221+ ことはできませんので、一時的に空いているドライブ文字を割り当てた上で、
222+ そこに chdir します。
223+ マクロ(${MY_DIR}等)を使用できます。
224+
225+ import_env (初期値:定義なし)
226+ このオプションは廃止されました。使用すると警告を表示し無視されます。
227+
228+ export_env (初期値:定義なし)
229+ 引数に文字列をとります。このオプションを使うと、後述のマクロの値を
230+ 環境変数に設定した上で、プログラムを実行できます。環境変数は、マクロの
231+ 名前の頭に "WRAPEXEC_" をつけた名前になります。例えばマクロ ${ARG} を
232+ エクスポートするには export_env=ARG と指定します。すると本プログラムへ
233+ 渡された引数が、環境変数 WRAPEXEC_ARG に設定されます。
234+ このオプションは複数個指定できます。
235+
236+ verbose (初期値:false)
237+ 引数に真偽値をとります。値が真の場合、内部処理の状況と状態を逐一
238+ 表示します。設定ファイルの動作確認の際に使用すると役立つことが
239+ あります。
240+
241+ internal (初期値:false)
242+ 引数に真偽値をとります。値が真の場合、実行されるプログラムは
243+ cmd.exe の内部コマンドであるとみなされます。例えば、echo や set を
244+ 実行したい場合、これらは cmd.exe の内部コマンドですので、ファイルとして
245+ echo.exe や set.exe があるわけではありません。
246+ 本プログラムは通常、実行しようとするファイルが実際に存在することを
247+ 確認してから実行しますので、そのままでは echo や set が実行できません。
248+ (プログラムが見つからない旨のエラーメッセージが出力されます)
249+ そのような場合、このオプションを指定すると、ファイルの存在チェックを
250+ 省略して実行します。
251+
252+ gui (初期値:false)
253+ 引数に真偽値をとります。値が真の場合、実行されるプログラムは
254+ Windows の GUI のプログラムとみなされ、下記の wait オプションが真で
255+ ない限り、実行されたプログラムの終了を待たず、本プログラムは
256+ すぐ終了します。
257+
258+ wait (初期値:false)
259+ 引数に真偽値をとります。本オプションは、前述のオプション gui が真の
260+ 場合のみ意味を持ちます。値が真の場合、本プログラムから実行された
261+ プログラムが終了するまで、そのまま待機します。(通常、本プログラムは
262+ すぐ終了します)
263+
264+ maximize (初期値:false)
265+ 引数に真偽値をとります。本オプションは、前述のオプション gui が真の
266+ 場合のみ意味を持ちます。値が真の場合、ウィンドウを最大化して起動する
267+ よう、実行されるプログラムに指示します。
268+ これを指定すると、minimize が false になります。
269+
270+ minimize (初期値:false)
271+ 引数に真偽値をとります。本オプションは、前述のオプション gui が真の
272+ 場合のみ意味を持ちます。値が真の場合、ウィンドウを最小化して起動する
273+ よう、実行されるプログラムに指示します。
274+ これを指定すると、maximize が false になります。
275+
276+ use_path (初期値:false)
277+ 実行したいプログラム名にパスや拡張子が明示されていない場合に、
278+ それぞれ環境変数 PATH および PATHEXT を参照してサーチします。
279+ Windowsの通常のサーチ方法とは異なり、カレントディレクトリは
280+ 探しません。また自分自身を見つけても、スキップして次を探します。
281+
282+ hide (初期値:false)
283+ 使用していません。指定しても何も起こりません。
284+
285+
286+・マクロ
287+
288+ 設定ファイル中のいくつかの場所では、${名称} の形式で、マクロ展開を
289+ 使用することができます。
290+ 「${」という文字列そのものを表すには、「$${」と記述します。
291+ 「${名称}」の他、「$(名称)」「$[名称]」の書式も使用できますが、
292+ 「$名称」の書式は使用できません。必ず括弧で括る必要があります。
293+ マクロ展開は一度だけ行われ、展開された文字列が再びマクロ展開される
294+ ことはありません。
295+
296+ 標準で使用できるマクロは以下の通りです。
297+
298+ ARG
299+ 本プログラムに与えられたコマンドライン引数。(プログラム名以降の部分)
300+ プログラム名と引数の間のスペースも含まれることに注意して下さい。
301+ 例えば、"wrapexec.exe FooBarBaz" として実行した場合、${ARG} は
302+ " FooBarBaz" に展開されます。
303+ コマンドラインで与えられた、スペースの個数や特殊記号、UNICODE文字等も
304+ そのまま忠実に再現して同じものが展開されます。
305+
306+ CLIPBOARD
307+ プログラム実行時のクリップボードの値。
308+ クリップボードの内容がテキスト以外だった場合は、空文字列となります。
309+ 改行やタブ文字などのホワイトスペース文字は、スペースに置換されます。
310+
311+ MY_EXENAME
312+ 自分自身 (wrapexec.exe) のフルパスファイル名。
313+ 例 : D:\somewhere\wrapexec.exe
314+
315+ MY_ININAME
316+ 設定ファイルのフルパスファイル名。
317+ 例 : D:\somewhere\wrapexec.ini
318+
319+ MY_BASENAME
320+ 自分自身 (wrapexec.exe) のベース名(ドライブ名、パス名、拡張子を除いた
321+ 名前)。
322+ 例 : wrapexec
323+
324+ MY_DIR (別名 : MY)
325+ 自分自身 (wrapexec.exe) のパス名。(ドライブ名および末尾の'\'を含む)
326+ 例 : D:\somewhere\
327+
328+ MY_DRIVE
329+ 自分自身 (wrapexec.exe) のあるドライブ名。
330+ 例 : D:
331+
332+ SYS_NAME
333+ コンピュータ名。
334+ 例 : SOMEONESPC
335+
336+ SYS_ROOT
337+ システムのルートディレクトリ。
338+ 例 : C:\WINDOWS\
339+
340+ SYS_DIR (別名 : SYS)
341+ システムディレクトリ。
342+ 例 : C:\WINDOWS\system32\
343+
344+ SYS_DRIVE
345+ システムドライブ。
346+ 例 : C:
347+
348+ USER_NAME
349+ ユーザ名。
350+ 例 : someone
351+
352+ USER_DIR (別名 : USER)
353+ ユーザのプロファイルのディレクトリ。
354+ 例 : C:\Documents and Settings\someone\
355+
356+ USER_DRIVE
357+ ユーザのプロファイルのあるドライブ。
358+ 例 : C:
359+
360+ USER_DOC
361+ ユーザのマイドキュメントのディレクトリ。
362+ 例 : C:\Documents and Settings\someone\My Documents\
363+
364+ USER_DESKTOP
365+ ユーザのデスクトップのディレクトリ。
366+ 例 : C:\Documents and Settings\someone\デスクトップ\
367+
368+ ALL_USER_DIR (別名 : ALL_USER)
369+ 共通のプロファイルのディレクトリ。
370+ 例 : C:\Documents and Settings\All Users\
371+
372+ ALL_USER_DRIVE
373+ 共通のプロファイルのあるドライブ。
374+ 例 : C:
375+
376+ ALL_USER_DOC
377+ 共有ドキュメントのディレクトリ。
378+ 例 : C:\Documents and Settings\All Users\Documents\
379+
380+ ALL_USER_DESKTOP
381+ 共通のデスクトップのディレクトリ。
382+ 例 : C:\Documents and Settings\All Users\デスクトップ\
383+
384+ PROGRAM_DIR (別名 : PROGRAM)
385+ プログラムフォルダのディレクトリ。
386+ 例 : C:\Program Files\
387+
388+ PROGRAM_DRIVE
389+ プログラムフォルダのあるドライブ。
390+ 例 : C:
391+
392+ TMP_DIR (別名 : TMP)
393+ テンポラリディレクトリ。
394+ 例 : C:\DOCUME~1\SOMEONE\LOCALS~1\Temp\
395+
396+ TMP_DRIVE
397+ テンポラリディレクトリのあるドライブ。
398+ 例 : C:
399+
400+ TARGET_NAME
401+ 本プログラムから実行されるプログラムのフルパスファイル名。
402+ 例 : C:\WINDOWS\system32\cmd.exe
403+
404+ TARGET_DIR (別名 : TARGET)
405+ 本プログラムから実行されるプログラムのあるディレクトリ。
406+ 例 : C:\WINDOWS\system32\
407+
408+ TARGET_DRIVE
409+ 本プログラムから実行されるプログラムのあるドライブ。
410+ 例 : C:
411+
412+ CURRENT_DIR (別名 : CURRENT)
413+ 本プログラムが実行された時点でのカレントディレクトリ。
414+ 例 : D:\home\user1\
415+
416+ CURRENT_DRIVE
417+ 本プログラムが実行された時点でのカレントドライブ。
418+ 例 : D:
419+
420+ 上記の他、環境変数をマクロ展開に使用することができます。
421+ ${COMSPEC} など。
422+
423+ 個々の環境での具体的な値は、オプション verbose を真と設定すると
424+ 確認することができます。
425+
426+
427+・設定ファイル記述例
428+
429+ Perlスクリプト theScript.pl を実行する例
430+ |
431+ |[option]
432+ |arg = -- "${MY_DIR}theScript.pl"${ARG}
433+ |[exec]
434+ |c:\Perl\bin\perl.exe
435+ |
436+
437+ 設定ファイルの後半に書かれた Rubyスクリプトを実行する例
438+ |
439+ |[option]
440+ |arg = -x -- "${MY_ININAME}"${ARG}
441+ |[exec]
442+ |c:\Ruby\bin\ruby.exe
443+ |[end]
444+ |#! /usr/bin/ruby
445+ |p "Hello World!"
446+ |
447+
448+ Program Files の奥底にある MyFavoriteEditor.exe を最大化状態で実行する例
449+ |
450+ |[option]
451+ |maximize
452+ |[exec]
453+ |${PROGRAM}folder\to\program\MyFavoriteEditor.exe
454+ |
455+
456+ どこかにある gypsy.exe を実行する例
457+ |
458+ |[exec]
459+ |${SYS}gypsy.exe
460+ |${PROGRAM}gypsy\gypsy.exe
461+ |c:\somewhere\gypsy.exe
462+ |c:\anotherwhere\gypsy.exe
463+ |\\server\shere\gypsy.exe
464+ |
465+
466+ レジストリをクリアしてから 目的のプログラムを実行する例
467+ |
468+ |[option]
469+ |arg=${MY_DIR}initialize.reg
470+ |[exec]
471+ |${SYS_ROOT}regedit.exe
472+ |[exec]
473+ |target.exe
474+ |
475+
476+ 名前順でソートする dir コマンドの例
477+ |
478+ |[option]
479+ |internal
480+ |arg=/on${ARG}
481+ |[exec]
482+ |dir
483+ |
484+
485+
486+・使用上の注意
487+
488+ 本プログラムはなるべく意図した通りに動作するよう心がけて作成していま
489+ すが、設定ファイルの誤りやその他の原因で、意図せぬプログラムを意図せぬ
490+ オプションで実行してしまうことが、絶対にないとはいえません。必ず充分な
491+ 動作確認を行ったうえで使用してください。
492+
493+ 本プログラムはその目的上、設定ファイルを書き換えることにより多様な動作
494+ をさせられるため、その取り扱いには注意して下さい。万一、悪意ある第三者に
495+ 設定ファイルを改竄された場合の影響は計り知れません。
496+
497+
498+・欠点
499+
500+ 普通にプログラムを実行するより、ややメモリを多く消費します。
501+ 本プログラム および適宜実行される cmd.exe が、それぞれメモリを消費
502+ するためです。
503+
504+
505+・既知のバグおよび今後の課題
506+
507+ ・[課題] 設定ファイルのインクルード機能。
508+ ・[課題] gui=on の場合、開くウィンドウの位置を指定可能にする。
509+ ・[課題] ウィンドウを表示しないでプログラムを実行する機能。
510+ ・[課題] ${xxx:yyy=zzz}のような置換や部分文字列参照などの機能。
511+ ・[課題] 何らかの方法での条件分岐。
512+ ・[課題] ボリュームラベルやシリアル番号をキーにしたマクロ。
513+ ・[課題] 設定ファイルの改竄防止機構。
514+
515+
516+・謝辞
517+
518+ 記載の社名、製品名は各社の商標または登録商標です。
519+
520+ このプログラムは、Borland C++ でコンパイルされています。
521+
522+ このプログラムは、UPX で圧縮されています。
523+
524+
525+・サポート
526+
527+ このプログラムの公式webページは
528+ http://sourceforge.jp/projects/wrapexec/ です。
529+
530+ ダウンロードは
531+ http://sourceforge.jp/projects/wrapexec/releases/ から行えます。
532+
533+ サポートは SourceForge.JP 内のフォーラム
534+ http://sourceforge.jp/projects/wrapexec/forums/ で行います。
535+
536+
537+・著作権表示およびライセンス
538+
539+ Copyright (c) 2009,2010 by opa
540+ All rights reserved.
541+
542+ ソースコード形式かバイナリ形式か、変更するかしないかを問わず、以下の
543+ 条件を満たす場合に限り、再頒布および使用が許可されます。
544+
545+ ・ソースコードを再頒布する場合、上記の著作権表示、本条件一覧、および
546+  下記免責条項を含めること。
547+ ・バイナリ形式で再頒布する場合、頒布物に付属のドキュメント等の資料に、
548+  上記の著作権表示、本条件一覧、および下記免責条項を含めること。
549+ ・書面による特別の許可なしに、本ソフトウェアから派生した製品の宣伝
550+  または販売促進に、作者(おぱ)または貢献者の名前を使用しないこと。
551+
552+ 本ソフトウェアは、著作権者および貢献者によって「現状のまま」提供されて
553+ おり、明示黙示を問わず、商業的な使用可能性、および特定の目的に対する
554+ 適合性に関する暗黙の保証も含め、またそれに限定されない、いかなる保証も
555+ ありません。著作権者も貢献者も、事由の如何を問わず、また損害発生の
556+ 原因如何を問わず、かつ責任の根拠が契約であるか厳格責任であるか
557+ (過失その他の)不法行為であるかを問わず、仮にそのような損害が発生する
558+ 可能性を知らされていたとしても、本ソフトウェアの使用によって発生した
559+ (代替品または代用サービスの調達、使用の喪失、データの喪失、利益の喪失、
560+ 業務の中断も含め、またそれに限定されない)直接損害、間接損害、偶発的な
561+ 損害、特別損害、懲罰的損害、または結果損害について、一切責任を負わない
562+ ものとします。
563+
564+
565+・変更履歴
566+
567+ ・新規作成。(2009/05/27 version 1.00)
568+
569+ ・内部で使用するコンテナをvector<>主体からlist<>主体に変更。
570+ ・バイナリサイズの削減を試みた。
571+ ・いくつかの処理の効率化と高速化。
572+ ・行頭の @ もコメント開始文字として扱うようにした。
573+ ・セクション [eof] を [end] に変更。
574+ ・GUIプログラム版の wrapexecw.exe を同梱するようにした。
575+ ・オプション hide 追加。
576+ ・オプション use_path 追加。(2010/03/10 version 1.01)
577+
578+ ・誤って、主処理をコメントアウトしてしまっていたのを修正。
579+  (2010/03/11 version 1.02)
580+
581+ ・マクロの展開結果を予め全種類用意するのではなく、必要なもののみ都度
582+  展開するようにした。これにより高速化しました。
583+ ・SHGetSpecialFolderLocation() ではなく SHGetSpecialFolderPath() を
584+  使うようにした。
585+ ・オプション import_env で明示的に環境変数を取り込まなくともよい
586+  ようにした。併せてこのオプションを廃止した。
587+ ・オプション hide を廃止。
588+ ・起動時にSTARTUPINFOを取得して、例えば最小化オプションつきで起動
589+  されたときは、ターゲットを最小化オプションつきで起動するようにした。
590+ ・mingw32サポートを止めた。
591+ ・wrapexecwにおいては標準出力が使用できないので、メッセージボックスで
592+  表示を行うようにした。
593+ ・マクロ TARGET_*族および CURRENT_*族を追加。
594+ ・アイコンの微調整および変更。(2010/08/17 version 1.03)
595+
596+
597+--------
598+ 制作・著作
599+
600+ wrapexec@ken16.net
601+
602+ おぱ (opa)
Show on old repository browser