OSDN Git Service

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