OSDN Git Service

Fix issue #940: Replace slow (2)
[winmerge-jp/winmerge-jp.git] / Src / Environment.cpp
1 /** 
2  * @file  Environment.cpp
3  *
4  * @brief Environment related routines.
5  */
6
7 #include "pch.h"
8 #define POCO_NO_UNWINDOWS 1
9 #include "Environment.h"
10 #include <windows.h>
11 #pragma warning (push)                  // prevent "warning C4091: 'typedef ': ignored on left of 'tagGPFIDL_FLAGS' when no variable is declared"
12 #pragma warning (disable:4091)  // VC bug when using XP enabled toolsets.
13 #include <shlobj.h>
14 #pragma warning (pop)
15 #include <sstream>
16 #include <Poco/Path.h>
17 #include <Poco/Process.h>
18 #include "paths.h"
19 #include "unicoder.h"
20
21 using Poco::Path;
22 using Poco::Process;
23
24 namespace env
25 {
26
27 /**
28  * @brief Temp path.
29  * Static string used by GetTemporaryPath() for storing temp path.
30  */
31 static String strTempPath;
32 static String strProgPath;
33
34 void SetTemporaryPath(const String& path)
35 {
36         strTempPath = paths::AddTrailingSlash(paths::GetLongPath(path));
37         paths::CreateIfNeeded(strTempPath);
38 }
39
40 /** 
41  * @brief Get folder for temporary files.
42  * This function returns system temp folder.
43  * @return Temp path, or empty string if error happened.
44  * @note Temp path is cached after first call.
45  * @todo Should we return `nullptr` for error case?
46  */
47 String GetTemporaryPath()
48 {
49         if (strTempPath.empty())
50         {
51                 strTempPath = GetSystemTempPath();
52                 if (strTempPath.empty())
53                         return strTempPath;
54
55                 paths::CreateIfNeeded(strTempPath);
56         }
57         return strTempPath;
58 }
59
60 /**
61  * @brief Get filename for temporary file.
62  * @param [in] lpPathName Temporary file folder.
63  * @param [in] lpPrefixString Prefix to use for filename.
64  * @param [out] pnerr Error code if error happened.
65  * @return Full path for temporary file or empty string if error happened.
66  */
67 String GetTemporaryFileName(const String& lpPathName, const String& lpPrefixString, int * pnerr /*= nullptr*/)
68 {
69         TCHAR buffer[MAX_PATH] = {0};
70         if (lpPathName.length() > MAX_PATH-14)
71                 return _T(""); // failure
72         int rtn = ::GetTempFileName(lpPathName.c_str(), lpPrefixString.c_str(), 0, buffer);
73         if (rtn == 0)
74         {
75                 paths::CreateIfNeeded(lpPathName);
76                 rtn = ::GetTempFileName(lpPathName.c_str(), lpPrefixString.c_str(), 0, buffer);
77                 if (rtn == 0)
78                 {
79                         int err = GetLastError();
80                         if (pnerr != nullptr)
81                                 *pnerr = err;
82                         return _T("");
83                 }
84         }
85         return buffer;
86 }
87
88 String GetTempChildPath()
89 {
90         String path;
91         do
92         {
93                 path = paths::ConcatPath(GetTemporaryPath(), strutils::format(_T("%08x"), rand()));
94         } while (paths::IsDirectory(path) || !paths::CreateIfNeeded(path));
95         return path;
96 }
97
98 void SetProgPath(const String& path)
99 {
100         strProgPath = paths::AddTrailingSlash(path);
101 }
102
103 String GetProgPath()
104 {
105         if (strProgPath.empty())
106         {
107                 TCHAR temp[MAX_PATH] = {0};
108                 GetModuleFileName(nullptr, temp, MAX_PATH);
109                 strProgPath = paths::GetPathOnly(temp);
110         }
111         return strProgPath;
112 }
113
114 /**
115  * @brief Get Windows directory.
116  * @return Windows directory.
117  */
118 String GetWindowsDirectory()
119 {
120         TCHAR path[MAX_PATH];
121         path[0] = _T('\0');
122         ::GetWindowsDirectory(path, MAX_PATH);
123         return path;
124 }
125
126 /**
127  * @brief Return User's My Documents Folder.
128  * This function returns full path to User's My Documents -folder.
129  * @return Full path to My Documents -folder.
130  */
131 String GetMyDocuments()
132 {
133         TCHAR path[MAX_PATH];
134         path[0] = _T('\0');
135         SHGetFolderPath(nullptr, CSIDL_PERSONAL, nullptr, 0, path);
136         return path;
137 }
138
139 /**
140  * @brief Return unique string for the instance.
141  * This function formats an unique string for WinMerge instance. The string
142  * is quaranteed to be unique for instance asking it.
143  * @param [in] name Additional name used as part of the string.
144  * @return Unique string for the instance.
145  */
146 String GetPerInstanceString(const String& name)
147 {
148         std::basic_stringstream<TCHAR> stream;
149         stream << name << Process::id();
150         return stream.str();
151 }
152
153 /**
154  * @brief Get system temporary directory.
155  * @return System temporary director.
156  */
157 String GetSystemTempPath()
158 {
159         try
160         {
161                 return ucr::toTString(Path::temp());
162         }
163         catch (...)
164         {
165                 return _T("");
166         }
167 }
168
169 static bool launchProgram(const String& sCmd, WORD wShowWindow)
170 {
171         STARTUPINFO stInfo = { sizeof(STARTUPINFO) };
172         stInfo.dwFlags = STARTF_USESHOWWINDOW;
173         stInfo.wShowWindow = wShowWindow;
174         PROCESS_INFORMATION processInfo;
175         bool retVal = !!CreateProcess(nullptr, (LPTSTR)sCmd.c_str(),
176                 nullptr, nullptr, FALSE, CREATE_DEFAULT_ERROR_MODE, nullptr, nullptr,
177                 &stInfo, &processInfo);
178         if (!retVal)
179                 return false;
180         CloseHandle(processInfo.hThread);
181         CloseHandle(processInfo.hProcess);
182         return true;
183 }
184
185 String ExpandEnvironmentVariables(const String& text)
186 {
187         TCHAR buf[512];
188         buf[0] = 0;
189         const unsigned size = sizeof(buf) / sizeof(buf[0]);
190         const unsigned expandedSize = ::ExpandEnvironmentStrings(text.c_str(), buf, size);
191         if (expandedSize <= size)
192                 return buf;
193         std::vector<TCHAR> newbuf(expandedSize);
194         ::ExpandEnvironmentStrings(text.c_str(), newbuf.data(), expandedSize);
195         return newbuf.data();
196 }
197
198 /**
199  * @brief Load registry keys from .reg file if existing .reg file
200  */
201 bool LoadRegistryFromFile(const String& sRegFilePath)
202 {
203         if (paths::DoesPathExist(sRegFilePath) != paths::IS_EXISTING_FILE)
204                 return false;
205         return launchProgram(_T("reg.exe import \"") + sRegFilePath + _T("\""), SW_HIDE);
206 }
207
208 /** 
209  * @brief Save registry keys to .reg file if existing .reg file
210  */
211 bool SaveRegistryToFile(const String& sRegFilePath, const String& sRegDir)
212 {
213         if (paths::DoesPathExist(sRegFilePath) != paths::IS_EXISTING_FILE)
214                 return false;
215         DeleteFile(sRegFilePath.c_str());
216         return launchProgram(_T("reg.exe export HKCU\\") + sRegDir + _T(" \"") + sRegFilePath + _T("\""), SW_HIDE);
217 }
218
219 }