OSDN Git Service

Add option to change default host settings.
[ffftp/ffftp.git] / updater.c
1 // updater.c\r
2 // Copyright (C) 2014 Suguru Kawamoto\r
3 // ソフトウェア自動更新\r
4 // コードの再利用のため表記はwchar_t型だが実体はchar型でUTF-8\r
5 \r
6 #include <tchar.h>\r
7 #include <ws2tcpip.h>\r
8 #include <windows.h>\r
9 #include <mmsystem.h>\r
10 typedef SOCKADDR_STORAGE_XP SOCKADDR_STORAGE;\r
11 typedef SOCKADDR_STORAGE *PSOCKADDR_STORAGE, FAR *LPSOCKADDR_STORAGE;\r
12 #include <winhttp.h>\r
13 \r
14 #include "updater.h"\r
15 #include "socketwrapper.h"\r
16 #include "protectprocess.h"\r
17 #include "mbswrapper.h"\r
18 #include "apiemulator.h"\r
19 \r
20 typedef struct\r
21 {\r
22         BYTE Signature[64];\r
23         BYTE ListHash[64];\r
24 } UPDATE_HASH;\r
25 \r
26 #define UPDATE_LIST_FILE_FLAG_DIRECTORY 0x00000001\r
27 \r
28 typedef struct\r
29 {\r
30         DWORD Flags;\r
31         CHAR SrcPath[128];\r
32         BYTE SrcHash[64];\r
33         CHAR DstPath[128];\r
34         FILETIME Timestamp;\r
35 } UPDATE_LIST_FILE;\r
36 \r
37 typedef struct\r
38 {\r
39         DWORD Version;\r
40         CHAR VersionString[32];\r
41         CHAR Description[1024];\r
42         DWORD FileCount;\r
43         UPDATE_LIST_FILE File[1];\r
44 } UPDATE_LIST;\r
45 \r
46 BOOL ReadFileViaHTTPW(void* pOut, DWORD Length, DWORD* pLength, LPCWSTR UserAgent, LPCWSTR ServerName, LPCWSTR ObjectName)\r
47 {\r
48         BOOL bResult;\r
49         HINTERNET hSession;\r
50         HINTERNET hConnect;\r
51         HINTERNET hRequest;\r
52         bResult = FALSE;\r
53         if(hSession = WinHttpOpen(UserAgent, WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0))\r
54         {\r
55                 if(hConnect = WinHttpConnect(hSession, ServerName, INTERNET_DEFAULT_HTTP_PORT, 0))\r
56                 {\r
57                         if(hRequest = WinHttpOpenRequest(hConnect, L"GET", ObjectName, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0))\r
58                         {\r
59                                 if(WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0))\r
60                                 {\r
61                                         if(WinHttpReceiveResponse(hRequest, NULL))\r
62                                         {\r
63                                                 if(WinHttpQueryDataAvailable(hRequest, pLength))\r
64                                                 {\r
65                                                         if(*pLength <= Length)\r
66                                                         {\r
67                                                                 if(WinHttpReadData(hRequest, pOut, Length, pLength))\r
68                                                                         bResult = TRUE;\r
69                                                         }\r
70                                                 }\r
71                                         }\r
72                                 }\r
73                                 WinHttpCloseHandle(hRequest);\r
74                         }\r
75                         WinHttpCloseHandle(hConnect);\r
76                 }\r
77                 WinHttpCloseHandle(hSession);\r
78         }\r
79         return bResult;\r
80 }\r
81 \r
82 BOOL ReadFileViaHTTP(void* pOut, DWORD Length, DWORD* pLength, LPCSTR UserAgent, LPCSTR ServerName, LPCSTR ObjectName)\r
83 {\r
84         BOOL r;\r
85         wchar_t* pw0;\r
86         wchar_t* pw1;\r
87         wchar_t* pw2;\r
88         pw0 = DuplicateMtoW(UserAgent, -1);\r
89         pw1 = DuplicateMtoW(ServerName, -1);\r
90         pw2 = DuplicateMtoW(ObjectName, -1);\r
91         r = ReadFileViaHTTPW(pOut, Length, pLength, pw0, pw1, pw2);\r
92         FreeDuplicatedString(pw0);\r
93         FreeDuplicatedString(pw1);\r
94         FreeDuplicatedString(pw2);\r
95         return r;\r
96 }\r
97 \r
98 BOOL SaveMemoryToFileWithTimestamp(LPCTSTR FileName, void* pData, DWORD Size, FILETIME* pTimestamp)\r
99 {\r
100         BOOL bResult;\r
101         HANDLE hFile;\r
102         bResult = FALSE;\r
103         if((hFile = CreateFile(FileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)\r
104         {\r
105                 if(WriteFile(hFile, pData, Size, &Size, NULL))\r
106                 {\r
107                         if(pTimestamp)\r
108                         {\r
109                                 if(SetFileTime(hFile, NULL, NULL, pTimestamp))\r
110                                         bResult = TRUE;\r
111                         }\r
112                         else\r
113                                 bResult = TRUE;\r
114                 }\r
115                 CloseHandle(hFile);\r
116         }\r
117         return bResult;\r
118 }\r
119 \r
120 BOOL LoadMemoryFromFileWithTimestamp(LPCTSTR FileName, void* pData, DWORD Size, DWORD* pReadSize, FILETIME* pTimestamp)\r
121 {\r
122         BOOL bResult;\r
123         HANDLE hFile;\r
124         LARGE_INTEGER li;\r
125         bResult = FALSE;\r
126         if((hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)\r
127         {\r
128                 if(GetFileSizeEx(hFile, &li))\r
129                 {\r
130                         if(li.QuadPart <= (LONGLONG)Size)\r
131                         {\r
132                                 if(ReadFile(hFile, pData, Size, pReadSize, NULL))\r
133                                 {\r
134                                         if(*pReadSize == li.LowPart)\r
135                                         {\r
136                                                 if(pTimestamp)\r
137                                                 {\r
138                                                         if(GetFileTime(hFile, NULL, NULL, pTimestamp))\r
139                                                                 bResult = TRUE;\r
140                                                 }\r
141                                                 else\r
142                                                         bResult = TRUE;\r
143                                         }\r
144                                 }\r
145                         }\r
146                         CloseHandle(hFile);\r
147                 }\r
148         }\r
149         return bResult;\r
150 }\r
151 \r
152 BOOL CopyAllFilesInDirectory(LPCTSTR From, LPCTSTR To)\r
153 {\r
154         BOOL bResult;\r
155         TCHAR* pFrom;\r
156         TCHAR* pTo;\r
157         SHFILEOPSTRUCT fop;\r
158         bResult = FALSE;\r
159         if(pFrom = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(From) + _tcslen(_T("\\*")) + 2)))\r
160         {\r
161                 _tcscpy(pFrom, From);\r
162                 _tcsncpy(pFrom + _tcslen(pFrom), _T("\\*"), _tcslen(_T("\\*")) + 2);\r
163                 if(pTo = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(To) + 2)))\r
164                 {\r
165                         _tcsncpy(pTo, To, _tcslen(To) + 2);\r
166                         memset(&fop, 0, sizeof(SHFILEOPSTRUCT));\r
167                         fop.wFunc = FO_COPY;\r
168                         fop.pFrom = pFrom;\r
169                         fop.pTo = pTo;\r
170                         fop.fFlags = FOF_NO_UI;\r
171                         if(SHFileOperation(&fop) == 0)\r
172                                 bResult = TRUE;\r
173                         free(pTo);\r
174                 }\r
175                 free(pFrom);\r
176         }\r
177         return bResult;\r
178 }\r
179 \r
180 BOOL DeleteDirectoryAndContents(LPCTSTR Path)\r
181 {\r
182         BOOL bResult;\r
183         TCHAR* pFrom;\r
184         SHFILEOPSTRUCT fop;\r
185         bResult = FALSE;\r
186         if(pFrom = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(Path) + 2)))\r
187         {\r
188                 _tcsncpy(pFrom, Path, _tcslen(Path) + 2);\r
189                 memset(&fop, 0, sizeof(SHFILEOPSTRUCT));\r
190                 fop.wFunc = FO_DELETE;\r
191                 fop.pFrom = pFrom;\r
192                 fop.fFlags = FOF_NO_UI;\r
193                 if(SHFileOperation(&fop) == 0)\r
194                         bResult = TRUE;\r
195                 free(pFrom);\r
196         }\r
197         return bResult;\r
198 }\r
199 \r
200 DWORD ListUpdateFile(UPDATE_LIST* pList, DWORD MaxCount, LPCTSTR ServerPath, LPCTSTR ReferenceDir, LPCTSTR Path)\r
201 {\r
202         DWORD Result;\r
203         TCHAR Temp1[MAX_PATH];\r
204         TCHAR Temp2[MAX_PATH];\r
205         TCHAR Temp3[MAX_PATH];\r
206         HANDLE hFind;\r
207         WIN32_FIND_DATA Find;\r
208         void* pBuf;\r
209         DWORD Length;\r
210         FILETIME Time;\r
211         BYTE Hash[64];\r
212         Result = 0;\r
213         if(!Path)\r
214                 Path = _T("");\r
215         if(_tcslen(ReferenceDir) + _tcslen(Path) + _tcslen(_T("\\*")) < MAX_PATH)\r
216         {\r
217                 _tcscpy(Temp1, ReferenceDir);\r
218                 _tcscat(Temp1, Path);\r
219                 _tcscat(Temp1, _T("\\*"));\r
220                 if((hFind = FindFirstFile(Temp1, &Find)) != INVALID_HANDLE_VALUE)\r
221                 {\r
222                         do\r
223                         {\r
224                                 if(_tcscmp(Find.cFileName, _T(".")) != 0 && _tcscmp(Find.cFileName, _T("..")) != 0)\r
225                                 {\r
226                                         if(_tcslen(ServerPath) + _tcslen(_T("/")) + _tcslen(Find.cFileName) < 128 && _tcslen(Path) + _tcslen(_T("\\")) + _tcslen(Find.cFileName) < 128)\r
227                                         {\r
228                                                 _tcscpy(Temp1, ServerPath);\r
229                                                 _tcscat(Temp1, _T("/"));\r
230                                                 _tcscat(Temp1, Find.cFileName);\r
231                                                 _tcscpy(Temp2, Path);\r
232                                                 _tcscat(Temp2, _T("\\"));\r
233                                                 _tcscat(Temp2, Find.cFileName);\r
234                                                 if(_tcslen(ReferenceDir) + _tcslen(Temp2) < MAX_PATH)\r
235                                                 {\r
236                                                         _tcscpy(Temp3, ReferenceDir);\r
237                                                         _tcscat(Temp3, Temp2);\r
238                                                         if((Find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))\r
239                                                         {\r
240                                                                 if(!(Find.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))\r
241                                                                 {\r
242                                                                         if(pList)\r
243                                                                         {\r
244                                                                                 memset(&pList->File[pList->FileCount], 0, sizeof(UPDATE_LIST_FILE));\r
245                                                                                 pList->File[pList->FileCount].Flags = UPDATE_LIST_FILE_FLAG_DIRECTORY;\r
246                                                                                 _tcscpy(pList->File[pList->FileCount].DstPath, Temp2);\r
247                                                                                 pList->FileCount++;\r
248                                                                         }\r
249                                                                         Result++;\r
250                                                                         if(Result >= MaxCount)\r
251                                                                                 break;\r
252                                                                         Result += ListUpdateFile(pList, MaxCount, Temp1, ReferenceDir, Temp2);\r
253                                                                 }\r
254                                                         }\r
255                                                         else\r
256                                                         {\r
257                                                                 if(pList)\r
258                                                                 {\r
259                                                                         if(pBuf = malloc(16777216))\r
260                                                                         {\r
261                                                                                 if(LoadMemoryFromFileWithTimestamp(Temp3, pBuf, 16777216, &Length, &Time))\r
262                                                                                 {\r
263                                                                                         if(GetHashSHA512(pBuf, Length, &Hash))\r
264                                                                                         {\r
265                                                                                                 memset(&pList->File[pList->FileCount], 0, sizeof(UPDATE_LIST_FILE));\r
266                                                                                                 _tcscpy(pList->File[pList->FileCount].SrcPath, Temp1);\r
267                                                                                                 memcpy(&pList->File[pList->FileCount].SrcHash, &Hash, 64);\r
268                                                                                                 _tcscpy(pList->File[pList->FileCount].DstPath, Temp2);\r
269                                                                                                 pList->File[pList->FileCount].Timestamp = Time;\r
270                                                                                                 pList->FileCount++;\r
271                                                                                         }\r
272                                                                                 }\r
273                                                                                 free(pBuf);\r
274                                                                         }\r
275                                                                 }\r
276                                                                 Result++;\r
277                                                                 if(Result >= MaxCount)\r
278                                                                         break;\r
279                                                         }\r
280                                                 }\r
281                                         }\r
282                                 }\r
283                         }\r
284                         while(FindNextFile(hFind, &Find));\r
285                         FindClose(hFind);\r
286                 }\r
287         }\r
288         return Result;\r
289 }\r
290 \r
291 // FFFTPの更新情報を作成\r
292 BOOL BuildUpdates(LPCTSTR PrivateKeyFile, LPCTSTR Password, LPCTSTR ServerPath, LPCTSTR HashFile, LPCTSTR ListFile, DWORD Version, LPCTSTR VersionString, LPCTSTR Description)\r
293 {\r
294         BOOL bResult;\r
295         char PrivateKey[4096];\r
296         DWORD Length;\r
297         TCHAR Name[MAX_PATH];\r
298         TCHAR* p;\r
299         UPDATE_LIST* pList;\r
300         UPDATE_HASH Hash;\r
301         BYTE Buf[1024];\r
302         bResult = FALSE;\r
303         memset(PrivateKey, 0, sizeof(PrivateKey));\r
304         if(LoadMemoryFromFileWithTimestamp(PrivateKeyFile, &PrivateKey, sizeof(PrivateKey) - sizeof(char), &Length, NULL))\r
305         {\r
306                 if(GetModuleFileName(NULL, Name, MAX_PATH) > 0)\r
307                 {\r
308                         if(p = _tcsrchr(Name, _T('\\')))\r
309                                 *p = _T('\0');\r
310                         if(pList = (UPDATE_LIST*)malloc(1048576))\r
311                         {\r
312                                 memset(pList, 0, 1048576);\r
313                                 pList->Version = Version;\r
314                                 _tcscpy(pList->VersionString, VersionString);\r
315                                 _tcscpy(pList->Description, Description);\r
316                                 ListUpdateFile(pList, (1048576 - sizeof(UPDATE_LIST)) / sizeof(UPDATE_LIST_FILE) + 1, ServerPath, Name, NULL);\r
317                                 Length = (pList->FileCount - 1) * sizeof(UPDATE_LIST_FILE) + sizeof(UPDATE_LIST);\r
318                                 if(SaveMemoryToFileWithTimestamp(ListFile, pList, Length, NULL))\r
319                                 {\r
320                                         memcpy(&Hash.Signature, UPDATE_SIGNATURE, 64);\r
321                                         if(GetHashSHA512(pList, Length, &Hash.ListHash))\r
322                                         {\r
323                                                 if(EncryptSignature(PrivateKey, Password, &Hash, sizeof(UPDATE_HASH), &Buf, sizeof(Buf), &Length))\r
324                                                 {\r
325                                                         if(SaveMemoryToFileWithTimestamp(HashFile, &Buf, Length, NULL))\r
326                                                                 bResult = TRUE;\r
327                                                 }\r
328                                         }\r
329                                 }\r
330                                 free(pList);\r
331                         }\r
332                 }\r
333         }\r
334         return bResult;\r
335 }\r
336 \r
337 // FFFTPの更新情報を確認\r
338 BOOL CheckForUpdates(BOOL bDownload, LPCTSTR DownloadDir, DWORD* pVersion, LPTSTR pVersionString, LPTSTR pDescription)\r
339 {\r
340         BOOL bResult;\r
341         DWORD Length;\r
342         BYTE Buf1[1024];\r
343         BYTE Buf2[1024];\r
344         void* pBuf;\r
345         UPDATE_HASH UpdateHash;\r
346         BYTE Hash[64];\r
347         UPDATE_LIST* pUpdateList;\r
348         bResult = FALSE;\r
349         if(ReadFileViaHTTP(&Buf1, sizeof(Buf1), &Length, HTTP_USER_AGENT, UPDATE_SERVER, UPDATE_HASH_PATH))\r
350         {\r
351                 if(DecryptSignature(UPDATE_RSA_PUBLIC_KEY, NULL, &Buf1, Length, &Buf2, sizeof(Buf2), &Length))\r
352                 {\r
353                         if(Length == sizeof(UPDATE_HASH))\r
354                         {\r
355                                 memcpy(&UpdateHash, &Buf2, sizeof(UPDATE_HASH));\r
356                                 if(memcmp(&UpdateHash.Signature, UPDATE_SIGNATURE, 64) == 0)\r
357                                 {\r
358                                         if(pBuf = malloc(1048576))\r
359                                         {\r
360                                                 if(ReadFileViaHTTP(pBuf, 1048576, &Length, HTTP_USER_AGENT, UPDATE_SERVER, UPDATE_LIST_PATH))\r
361                                                 {\r
362                                                         if(GetHashSHA512(pBuf, Length, &Hash))\r
363                                                         {\r
364                                                                 if(memcmp(&Hash, &UpdateHash.ListHash, 64) == 0)\r
365                                                                 {\r
366                                                                         if(Length >= sizeof(UPDATE_LIST))\r
367                                                                         {\r
368                                                                                 bResult = TRUE;\r
369                                                                                 pUpdateList = (UPDATE_LIST*)pBuf;\r
370                                                                                 if(pUpdateList->Version > *pVersion)\r
371                                                                                 {\r
372                                                                                         *pVersion = pUpdateList->Version;\r
373                                                                                         _tcscpy(pVersionString, pUpdateList->VersionString);\r
374                                                                                         _tcscpy(pDescription, pUpdateList->Description);\r
375                                                                                 }\r
376                                                                                 if(bDownload)\r
377                                                                                         bResult = PrepareUpdates(pBuf, Length, DownloadDir);\r
378                                                                         }\r
379                                                                 }\r
380                                                         }\r
381                                                 }\r
382                                                 free(pBuf);\r
383                                         }\r
384                                 }\r
385                         }\r
386                 }\r
387         }\r
388         return bResult;\r
389 }\r
390 \r
391 // 更新するファイルをダウンロード\r
392 BOOL PrepareUpdates(void* pList, DWORD ListLength, LPCTSTR DownloadDir)\r
393 {\r
394         BOOL bResult;\r
395         UPDATE_LIST* pUpdateList;\r
396         void* pBuf;\r
397         DWORD i;\r
398         BOOL b;\r
399         DWORD Length;\r
400         BYTE Hash[64];\r
401         TCHAR Path[MAX_PATH];\r
402         bResult = FALSE;\r
403         if(ListLength >= sizeof(UPDATE_LIST))\r
404         {\r
405                 pUpdateList = (UPDATE_LIST*)pList;\r
406                 if((pUpdateList->FileCount - 1) * sizeof(UPDATE_LIST_FILE) + sizeof(UPDATE_LIST) >= ListLength)\r
407                 {\r
408                         bResult = TRUE;\r
409                         DeleteDirectoryAndContents(DownloadDir);\r
410                         CreateDirectory(DownloadDir, NULL);\r
411                         if(pBuf = malloc(16777216))\r
412                         {\r
413                                 for(i = 0; i < pUpdateList->FileCount; i++)\r
414                                 {\r
415                                         b = FALSE;\r
416                                         if(pUpdateList->File[i].Flags & UPDATE_LIST_FILE_FLAG_DIRECTORY)\r
417                                         {\r
418                                                 _tcscpy(Path, DownloadDir);\r
419                                                 _tcscat(Path, pUpdateList->File[i].DstPath);\r
420                                                 if(CreateDirectory(Path, NULL))\r
421                                                         b = TRUE;\r
422                                         }\r
423                                         if(strlen(pUpdateList->File[i].SrcPath) > 0)\r
424                                         {\r
425                                                 if(ReadFileViaHTTP(pBuf, 16777216, &Length, HTTP_USER_AGENT, UPDATE_SERVER, pUpdateList->File[i].SrcPath))\r
426                                                 {\r
427                                                         if(GetHashSHA512(pBuf, Length, &Hash))\r
428                                                         {\r
429                                                                 if(memcmp(&Hash, &pUpdateList->File[i].SrcHash, 64) == 0)\r
430                                                                 {\r
431                                                                         _tcscpy(Path, DownloadDir);\r
432                                                                         _tcscat(Path, pUpdateList->File[i].DstPath);\r
433                                                                         if(SaveMemoryToFileWithTimestamp(Path, pBuf, Length, &pUpdateList->File[i].Timestamp))\r
434                                                                                 b = TRUE;\r
435                                                                 }\r
436                                                         }\r
437                                                 }\r
438                                         }\r
439                                         if(!b)\r
440                                         {\r
441                                                 bResult = FALSE;\r
442                                                 break;\r
443                                         }\r
444                                 }\r
445                                 free(pBuf);\r
446                         }\r
447                 }\r
448         }\r
449         return bResult;\r
450 }\r
451 \r
452 // FFFTPを更新\r
453 BOOL ApplyUpdates(LPCTSTR DestinationDir, LPCTSTR BackupDirName)\r
454 {\r
455         BOOL bResult;\r
456         TCHAR Source[MAX_PATH];\r
457         TCHAR Backup[MAX_PATH];\r
458         TCHAR DestinationBackup[MAX_PATH];\r
459         TCHAR* p;\r
460         bResult = FALSE;\r
461         if(GetModuleFileName(NULL, Source, MAX_PATH) > 0)\r
462         {\r
463                 if(p = _tcsrchr(Source, _T('\\')))\r
464                         *p = _T('\0');\r
465                 _tcscpy(Backup, Source);\r
466                 _tcscat(Backup, _T("\\"));\r
467                 _tcscat(Backup, BackupDirName);\r
468                 DeleteDirectoryAndContents(Backup);\r
469                 if(CreateDirectory(Backup, NULL))\r
470                 {\r
471                         if(CopyAllFilesInDirectory(DestinationDir, Backup))\r
472                         {\r
473                                 _tcscpy(DestinationBackup, DestinationDir);\r
474                                 _tcscat(DestinationBackup, _T("\\"));\r
475                                 _tcscat(DestinationBackup, BackupDirName);\r
476                                 if(CopyAllFilesInDirectory(Source, DestinationDir))\r
477                                 {\r
478                                         DeleteDirectoryAndContents(DestinationBackup);\r
479                                         bResult = TRUE;\r
480                                 }\r
481                                 else\r
482                                 {\r
483                                         DeleteDirectoryAndContents(DestinationBackup);\r
484                                         CopyAllFilesInDirectory(Backup, DestinationDir);\r
485                                 }\r
486                         }\r
487                 }\r
488         }\r
489         return bResult;\r
490 }\r
491 \r
492 // 更新するファイルをダウンロード\r
493 BOOL CleanupUpdates(LPCTSTR DownloadDir)\r
494 {\r
495         BOOL bResult;\r
496         bResult = FALSE;\r
497         if(DeleteDirectoryAndContents(DownloadDir))\r
498                 bResult = TRUE;\r
499         return bResult;\r
500 }\r
501 \r
502 // 更新用のプロセスを起動\r
503 BOOL StartUpdateProcess(LPCTSTR DownloadDir, LPCTSTR CommandLine)\r
504 {\r
505         BOOL bResult;\r
506         TCHAR Name[MAX_PATH];\r
507         TCHAR* p;\r
508         TCHAR Path[MAX_PATH];\r
509         bResult = FALSE;\r
510         if(GetModuleFileName(NULL, Name, MAX_PATH) > 0)\r
511         {\r
512                 if(p = _tcsrchr(Name, _T('\\')))\r
513                         p++;\r
514                 else\r
515                         p = Name;\r
516                 _tcscpy(Path, DownloadDir);\r
517                 _tcscat(Path, _T("\\"));\r
518                 _tcscat(Path, p);\r
519                 if(ShellExecute(NULL, _T("open"), Path, CommandLine, NULL, SW_SHOW) > (HINSTANCE)32)\r
520                         bResult = TRUE;\r
521         }\r
522         return bResult;\r
523 }\r
524 \r
525 // 更新用のプロセスを管理者権限で起動\r
526 // Windows XP以前など起動できない場合は現在のプロセスで処理を続行\r
527 BOOL RestartUpdateProcessAsAdministrator(LPCTSTR CommandLine, LPCTSTR Keyword)\r
528 {\r
529         BOOL bResult;\r
530         TCHAR* NewCommandLine;\r
531         TCHAR Path[MAX_PATH];\r
532         SHELLEXECUTEINFO Info;\r
533         bResult = FALSE;\r
534         if(_tcslen(CommandLine) < _tcslen(Keyword) || _tcscmp(CommandLine + _tcslen(CommandLine) - _tcslen(Keyword), Keyword) != 0)\r
535         {\r
536                 if(NewCommandLine = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(CommandLine) + _tcslen(Keyword) + 1)))\r
537                 {\r
538                         _tcscpy(NewCommandLine, CommandLine);\r
539                         _tcscat(NewCommandLine, Keyword);\r
540                         if(GetModuleFileName(NULL, Path, MAX_PATH) > 0)\r
541                         {\r
542                                 memset(&Info, 0, sizeof(SHELLEXECUTEINFO));\r
543                                 Info.cbSize = sizeof(SHELLEXECUTEINFO);\r
544                                 Info.fMask = SEE_MASK_NOCLOSEPROCESS;\r
545                                 if(IsUserAnAdmin())\r
546                                         Info.lpVerb = _T("open");\r
547                                 else\r
548                                         Info.lpVerb = _T("runas");\r
549                                 Info.lpFile = Path;\r
550                                 Info.lpParameters = NewCommandLine;\r
551                                 Info.nShow = SW_SHOW;\r
552                                 if(ShellExecuteEx(&Info))\r
553                                 {\r
554                                         WaitForSingleObject(Info.hProcess, INFINITE);\r
555                                         CloseHandle(Info.hProcess);\r
556                                         bResult = TRUE;\r
557                                 }\r
558                         }\r
559                         free(NewCommandLine);\r
560                 }\r
561         }\r
562         return bResult;\r
563 }\r
564 \r