1 // SoftEther VPN Source Code - Developer Edition Master Branch
2 // Cedar Communication Module
3 
4 
5 // Win32Com.c
6 // Win32 COM module call
7 
8 #ifdef OS_WIN32
9 
10 #include "Win32Com.h"
11 
12 extern "C"
13 {
14 #include "Mayaqua/FileIO.h"
15 #include "Mayaqua/Internat.h"
16 #include "Mayaqua/Mayaqua.h"
17 #include "Mayaqua/Memory.h"
18 #include "Mayaqua/Str.h"
19 }
20 
21 #include <devguid.h>
22 #include <MsHtmHst.h>
23 #include <natupnp.h>
24 #include <netcfgn.h>
25 #include <SetupAPI.h>
26 #include <ShlObj.h>
27 
28 // Add a UPnP port
Win32UPnPAddPort(UINT outside_port,UINT inside_port,bool udp,char * local_ip,wchar_t * description,bool remove_before_add)29 bool Win32UPnPAddPort(UINT outside_port, UINT inside_port, bool udp, char *local_ip, wchar_t *description, bool remove_before_add)
30 {
31 	bool ret = false;
32 	HRESULT hr;
33 	IUPnPNAT *nat = NULL;
34 	wchar_t ip_str[MAX_SIZE];
35 	BSTR bstr_ip, bstr_description, bstr_protocol;
36 	const wchar_t *protocol_str = (udp ? L"UDP" : L"TCP");
37 	// Validate arguments
38 	if (outside_port == 0 || outside_port >= 65536 || inside_port == 0 || inside_port >= 65536 ||
39 		IsEmptyStr(local_ip) || UniIsEmptyStr(description))
40 	{
41 		return false;
42 	}
43 
44 	StrToUni(ip_str, sizeof(ip_str), local_ip);
45 	bstr_ip = SysAllocString(ip_str);
46 	bstr_description = SysAllocString(description);
47 	bstr_protocol = SysAllocString(protocol_str);
48 
49 	hr = CoCreateInstance(CLSID_UPnPNAT, NULL, CLSCTX_INPROC_SERVER, IID_IUPnPNAT, (void **)&nat);
50 
51 	if (SUCCEEDED(hr))
52 	{
53 		if (nat != NULL)
54 		{
55 			IStaticPortMappingCollection *collection = NULL;
56 			hr = nat->get_StaticPortMappingCollection(&collection);
57 
58 			if (SUCCEEDED(hr))
59 			{
60 				if (collection != NULL)
61 				{
62 					IStaticPortMapping *mapping = NULL;
63 
64 					if (remove_before_add)
65 					{
66 						hr = collection->Remove((long)outside_port, bstr_protocol);
67 					}
68 
69 					hr = collection->Add((long)outside_port, bstr_protocol, (long)inside_port,
70 						bstr_ip, VARIANT_TRUE, bstr_description, &mapping);
71 
72 					if (SUCCEEDED(hr))
73 					{
74 						ret = true;
75 
76 						if (mapping != NULL)
77 						{
78 							mapping->Release();
79 						}
80 					}
81 
82 					collection->Release();
83 				}
84 				else
85 				{
86 					WHERE;
87 				}
88 			}
89 			else
90 			{
91 				WHERE;
92 			}
93 
94 			nat->Release();
95 		}
96 		else
97 		{
98 			WHERE;
99 		}
100 	}
101 	else
102 	{
103 		WHERE;
104 	}
105 
106 	SysFreeString(bstr_ip);
107 	SysFreeString(bstr_description);
108 	SysFreeString(bstr_protocol);
109 
110 	return ret;
111 }
112 
113 // Install the NDIS protocol driver
UninstallNdisProtocolDriver(wchar_t * id,UINT lock_timeout)114 bool UninstallNdisProtocolDriver(wchar_t *id, UINT lock_timeout)
115 {
116 	bool ret = false;
117 	HRESULT hr;
118 	INetCfg *pNetCfg;
119 	// Validate arguments
120 	if (id == NULL)
121 	{
122 		return false;
123 	}
124 
125 	hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (void **)&pNetCfg);
126 
127 	if (SUCCEEDED(hr))
128 	{
129 		INetCfgLock *pLock;
130 
131 		hr = pNetCfg->QueryInterface(IID_INetCfgLock, (PVOID*)&pLock);
132 
133 		if (SUCCEEDED(hr))
134 		{
135 			LPWSTR locked_by;
136 
137 			hr = pLock->AcquireWriteLock(lock_timeout, L"SoftEther VPN", &locked_by);
138 
139 			if (SUCCEEDED(hr))
140 			{
141 				hr = pNetCfg->Initialize(NULL);
142 
143 				if (SUCCEEDED(hr))
144 				{
145 					INetCfgComponent *pncc = NULL;
146 
147 					hr = pNetCfg->FindComponent(id, &pncc);
148 
149 					if (pncc == NULL || hr == S_FALSE)
150 					{
151 						hr = E_FAIL;
152 					}
153 
154 					if (SUCCEEDED(hr))
155 					{
156 						INetCfgClass *pncClass;
157 
158 						hr = pNetCfg->QueryNetCfgClass(&GUID_DEVCLASS_NETTRANS, IID_INetCfgClass, (void **)&pncClass);
159 						if (SUCCEEDED(hr))
160 						{
161 							INetCfgClassSetup *pncClassSetup;
162 
163 							hr = pncClass->QueryInterface(IID_INetCfgClassSetup, (void **)&pncClassSetup);
164 							if (SUCCEEDED(hr))
165 							{
166 								OBO_TOKEN obo;
167 								wchar_t *c = NULL;
168 
169 								Zero(&obo, sizeof(obo));
170 
171 								obo.Type = OBO_USER;
172 
173 								hr = pncClassSetup->DeInstall(pncc, &obo, &c);
174 
175 								if (SUCCEEDED(hr))
176 								{
177 									hr = pNetCfg->Apply();
178 
179 									if (SUCCEEDED(hr))
180 									{
181 										ret = true;
182 									}
183 									else
184 									{
185 										WHERE;
186 										Debug("0x%x\n", hr);
187 									}
188 								}
189 								else
190 								{
191 									WHERE;
192 									Debug("0x%x\n", hr);
193 								}
194 
195 								pncClassSetup->Release();
196 							}
197 							else
198 							{
199 								WHERE;
200 							}
201 
202 							pncClass->Release();
203 						}
204 						else
205 						{
206 							WHERE;
207 						}
208 
209 						pncc->Release();
210 					}
211 					else
212 					{
213 						WHERE;
214 					}
215 				}
216 				else
217 				{
218 					WHERE;
219 				}
220 
221 				pLock->ReleaseWriteLock();
222 			}
223 			else
224 			{
225 				WHERE;
226 			}
227 
228 			pLock->Release();
229 		}
230 
231 		pNetCfg->Release();
232 	}
233 	else
234 	{
235 		WHERE;
236 	}
237 
238 	return ret;
239 }
240 
241 // Install the NDIS protocol driver
InstallNdisProtocolDriver(wchar_t * inf_path,wchar_t * id,UINT lock_timeout)242 bool InstallNdisProtocolDriver(wchar_t *inf_path, wchar_t *id, UINT lock_timeout)
243 {
244 	bool ret = false;
245 	HRESULT hr;
246 	INetCfg *pNetCfg;
247 	HINSTANCE hSetupApiDll = NULL;
248 	BOOL (WINAPI *_SetupCopyOEMInfW)(PCWSTR, PCWSTR, DWORD, DWORD, PWSTR, DWORD, PDWORD, PWSTR *) = NULL;
249 	BOOL (WINAPI *_SetupUninstallOEMInfW)(PCWSTR, DWORD, PVOID) = NULL;
250 	// Validate arguments
251 	if (inf_path == NULL || id == NULL)
252 	{
253 		return false;
254 	}
255 
256 	hSetupApiDll = LoadLibraryA("setupapi.dll");
257 	if (hSetupApiDll == NULL)
258 	{
259 		WHERE;
260 		goto LABEL_CLEANUP;
261 	}
262 
263 	_SetupCopyOEMInfW =
264 		(BOOL (__stdcall *)(PCWSTR,PCWSTR,DWORD,DWORD,PWSTR,DWORD,PDWORD,PWSTR *))
265 		GetProcAddress(hSetupApiDll, "SetupCopyOEMInfW");
266 
267 	_SetupUninstallOEMInfW =
268 		(BOOL (__stdcall *)(PCWSTR,DWORD,PVOID))
269 		GetProcAddress(hSetupApiDll, "SetupUninstallOEMInfW");
270 
271 	if (_SetupCopyOEMInfW == NULL || _SetupUninstallOEMInfW == NULL)
272 	{
273 		WHERE;
274 		goto LABEL_CLEANUP;
275 	}
276 
277 	hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (void **)&pNetCfg);
278 
279 	if (SUCCEEDED(hr))
280 	{
281 		INetCfgLock *pLock;
282 
283 		hr = pNetCfg->QueryInterface(IID_INetCfgLock, (PVOID*)&pLock);
284 
285 		if (SUCCEEDED(hr))
286 		{
287 			LPWSTR locked_by;
288 
289 			hr = pLock->AcquireWriteLock(lock_timeout, L"SoftEther VPN", &locked_by);
290 
291 			if (SUCCEEDED(hr))
292 			{
293 				hr = pNetCfg->Initialize(NULL);
294 
295 				if (SUCCEEDED(hr))
296 				{
297 					wchar_t inf_dir[MAX_PATH];
298 
299 					GetDirNameFromFilePathW(inf_dir, sizeof(inf_dir), inf_path);
300 
301 					if (_SetupCopyOEMInfW(inf_path, inf_dir, SPOST_PATH, 0, NULL, 0, NULL, 0))
302 					{
303 						INetCfgClassSetup *pSetup;
304 
305 						hr = pNetCfg->QueryNetCfgClass(&GUID_DEVCLASS_NETTRANS, IID_INetCfgClassSetup, (void **)&pSetup);
306 
307 						if (SUCCEEDED(hr))
308 						{
309 							OBO_TOKEN token;
310 							INetCfgComponent *pComponent;
311 
312 							Zero(&token, sizeof(token));
313 
314 							token.Type = OBO_USER;
315 
316 							hr = pSetup->Install(id, &token, 0, 0, NULL, NULL, &pComponent);
317 
318 							if (SUCCEEDED(hr))
319 							{
320 								pNetCfg->Apply();
321 
322 								ret = true;
323 							}
324 							else
325 							{
326 								WHERE;
327 								Debug("0x%x\n", hr);
328 							}
329 
330 							pSetup->Release();
331 						}
332 						else
333 						{
334 							WHERE;
335 						}
336 
337 						if (ret == false)
338 						{
339 							wchar_t dst_inf_name[MAX_PATH];
340 							DWORD dst_inf_name_size = MAX_PATH;
341 
342 							if (_SetupCopyOEMInfW(inf_path, inf_dir, SPOST_PATH, SP_COPY_REPLACEONLY,
343 								dst_inf_name, dst_inf_name_size, &dst_inf_name_size, NULL) == false &&
344 								GetLastError() == ERROR_FILE_EXISTS)
345 							{
346 								_SetupUninstallOEMInfW(dst_inf_name, 0, NULL);
347 							}
348 						}
349 					}
350 					else
351 					{
352 						WHERE;
353 					}
354 				}
355 				else
356 				{
357 					WHERE;
358 				}
359 
360 				pLock->ReleaseWriteLock();
361 			}
362 			else
363 			{
364 				WHERE;
365 			}
366 
367 			pLock->Release();
368 		}
369 
370 		pNetCfg->Release();
371 	}
372 	else
373 	{
374 		WHERE;
375 	}
376 
377 LABEL_CLEANUP:
378 
379 	if (hSetupApiDll != NULL)
380 	{
381 		FreeLibrary(hSetupApiDll);
382 	}
383 
384 	return ret;
385 }
386 
387 typedef struct FOLDER_DLG_INNER_DATA
388 {
389 	wchar_t *default_dir;
390 } FOLDER_DLG_INNER_DATA;
391 
FolderDlgInnerCallbackA(HWND hWnd,UINT msg,LPARAM lParam,LPARAM lData)392 int CALLBACK FolderDlgInnerCallbackA(HWND hWnd, UINT msg, LPARAM lParam, LPARAM lData)
393 {
394 	FOLDER_DLG_INNER_DATA *data = (FOLDER_DLG_INNER_DATA *)lData;
395 	LPITEMIDLIST pidl;
396 
397 	switch (msg)
398 	{
399 	case BFFM_INITIALIZED:
400 		if (data->default_dir != NULL)
401 		{
402 			char *default_dir_a = CopyUniToStr(data->default_dir);
403 
404 			SendMessage(hWnd, BFFM_SETSELECTIONA, true, (LPARAM)default_dir_a);
405 
406 			Free(default_dir_a);
407 		}
408 		break;
409 
410 	case BFFM_SELCHANGED:
411 		pidl = (LPITEMIDLIST)lParam;
412 
413 		if (pidl)
414 		{
415 			char tmp[MAX_PATH];
416 
417 			Zero(tmp, sizeof(tmp));
418 			if (SHGetPathFromIDListA(pidl, tmp))
419 			{
420 				SendMessage(hWnd, BFFM_ENABLEOK, 0, 1);
421 			}
422 			else
423 			{
424 				SendMessage(hWnd, BFFM_ENABLEOK, 0, 0);
425 			}
426 		}
427 		break;
428 	}
429 
430 	return 0;
431 }
432 
FolderDlgInnerA(HWND hWnd,wchar_t * title,char * default_dir)433 char *FolderDlgInnerA(HWND hWnd, wchar_t *title, char *default_dir)
434 {
435 	BROWSEINFOA info;
436 	char display_name[MAX_PATH];
437 	FOLDER_DLG_INNER_DATA data;
438 	LPMALLOC pMalloc;
439 	char *ret = NULL;
440 	char *title_a;
441 	if (UniIsEmptyStr(title))
442 	{
443 		title = NULL;
444 	}
445 	if (IsEmptyStr(default_dir))
446 	{
447 		default_dir = NULL;
448 	}
449 
450 	Zero(&data, sizeof(data));
451 	data.default_dir = CopyStrToUni(default_dir);
452 
453 	Zero(display_name, sizeof(display_name));
454 	Zero(&info, sizeof(info));
455 	info.hwndOwner = hWnd;
456 	info.pidlRoot = NULL;
457 	info.pszDisplayName = display_name;
458 	title_a = CopyUniToStr(title);
459 	info.lpszTitle = title_a;
460 	info.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS | BIF_VALIDATE | BIF_SHAREABLE;
461 	info.lpfn = FolderDlgInnerCallbackA;
462 	info.lParam = (LPARAM)&data;
463 
464 	if (SUCCEEDED(SHGetMalloc(&pMalloc)))
465 	{
466 		LPITEMIDLIST pidl;
467 
468 		pidl = SHBrowseForFolderA(&info);
469 
470 		if (pidl)
471 		{
472 			char tmp[MAX_PATH];
473 
474 			if (SHGetPathFromIDListA(pidl, tmp))
475 			{
476 				ret = CopyStr(tmp);
477 			}
478 
479 			pMalloc->Free(pidl);
480 		}
481 
482 		pMalloc->Release();
483 	}
484 
485 	Free(data.default_dir);
486 	Free(title_a);
487 
488 	return ret;
489 }
490 
FolderDlgInnerCallbackW(HWND hWnd,UINT msg,LPARAM lParam,LPARAM lData)491 int CALLBACK FolderDlgInnerCallbackW(HWND hWnd, UINT msg, LPARAM lParam, LPARAM lData)
492 {
493 	FOLDER_DLG_INNER_DATA *data = (FOLDER_DLG_INNER_DATA *)lData;
494 	LPITEMIDLIST pidl;
495 
496 	switch (msg)
497 	{
498 	case BFFM_INITIALIZED:
499 		if (data->default_dir != NULL)
500 		{
501 			SendMessage(hWnd, BFFM_SETSELECTIONW, true, (LPARAM)data->default_dir);
502 		}
503 		break;
504 
505 	case BFFM_SELCHANGED:
506 		pidl = (LPITEMIDLIST)lParam;
507 
508 		if (pidl)
509 		{
510 			wchar_t tmp[MAX_PATH];
511 
512 			Zero(tmp, sizeof(tmp));
513 			if (SHGetPathFromIDListW(pidl, tmp))
514 			{
515 				SendMessage(hWnd, BFFM_ENABLEOK, 0, 1);
516 			}
517 			else
518 			{
519 				SendMessage(hWnd, BFFM_ENABLEOK, 0, 0);
520 			}
521 		}
522 		break;
523 	}
524 
525 	return 0;
526 }
527 
FolderDlgInnerW(HWND hWnd,wchar_t * title,wchar_t * default_dir)528 wchar_t *FolderDlgInnerW(HWND hWnd, wchar_t *title, wchar_t *default_dir)
529 {
530 	BROWSEINFOW info;
531 	wchar_t display_name[MAX_PATH];
532 	FOLDER_DLG_INNER_DATA data;
533 	LPMALLOC pMalloc;
534 	wchar_t *ret = NULL;
535 	if (UniIsEmptyStr(title))
536 	{
537 		title = NULL;
538 	}
539 	if (UniIsEmptyStr(default_dir))
540 	{
541 		default_dir = NULL;
542 	}
543 
544 	Zero(&data, sizeof(data));
545 	data.default_dir = default_dir;
546 
547 	Zero(display_name, sizeof(display_name));
548 	Zero(&info, sizeof(info));
549 	info.hwndOwner = hWnd;
550 	info.pidlRoot = NULL;
551 	info.pszDisplayName = display_name;
552 	info.lpszTitle = title;
553 	info.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS | BIF_VALIDATE | BIF_SHAREABLE;
554 	info.lpfn = FolderDlgInnerCallbackW;
555 	info.lParam = (LPARAM)&data;
556 
557 	if (SUCCEEDED(SHGetMalloc(&pMalloc)))
558 	{
559 		LPITEMIDLIST pidl;
560 
561 		pidl = SHBrowseForFolderW(&info);
562 
563 		if (pidl)
564 		{
565 			wchar_t tmp[MAX_PATH];
566 
567 			if (SHGetPathFromIDListW(pidl, tmp))
568 			{
569 				ret = CopyUniStr(tmp);
570 			}
571 
572 			pMalloc->Free(pidl);
573 		}
574 
575 		pMalloc->Release();
576 	}
577 
578 	return ret;
579 }
580 
581 
582 class CModule
583 {
584 public:
CModule()585     CModule()
586     {
587         m_hInstLib = NULL;
588     }
CModule(HINSTANCE hInstLib)589     CModule( HINSTANCE hInstLib )
590     {
591         m_hInstLib = NULL;
592         this->Attach( hInstLib );
593     }
CModule(LPCTSTR pszModuleName)594     CModule( LPCTSTR pszModuleName )
595     {
596         m_hInstLib = NULL;
597         this->LoadLibrary( pszModuleName );
598     }
~CModule()599     virtual ~CModule()
600     {
601         this->FreeLibrary();
602     }
603 
604 public:
Attach(HINSTANCE hInstLib)605     BOOL Attach( HINSTANCE hInstLib )
606     {
607         this->FreeLibrary();
608         m_hInstLib = hInstLib;
609 
610         return TRUE;
611     }
Detach()612     BOOL Detach()
613     {
614         m_hInstLib = NULL;
615 
616         return TRUE;
617     }
618 
619 public:
GetHandle()620     HMODULE GetHandle()
621     {
622         return m_hInstLib;
623     }
624     // Load the DLL
LoadLibrary(LPCTSTR pszModuleName)625     HINSTANCE LoadLibrary( LPCTSTR pszModuleName )
626     {
627         this->FreeLibrary();
628         m_hInstLib = ::LoadLibrary( pszModuleName );
629 
630         return m_hInstLib;
631     }
632     // Release the DLL
FreeLibrary()633     BOOL FreeLibrary()
634     {
635         if (m_hInstLib == NULL)
636         {
637             return FALSE;
638         }
639 
640         BOOL bResult = ::FreeLibrary( m_hInstLib );
641         m_hInstLib = NULL;
642 
643         return bResult;
644     }
645     // Get the address of the function
GetProcAddress(LPCTSTR pszProcName)646     FARPROC GetProcAddress( LPCTSTR pszProcName )
647     {
648         if (m_hInstLib == NULL)
649         {
650             return NULL;
651         }
652 
653         return ::GetProcAddress(m_hInstLib, pszProcName);
654     }
655     // Get a handle to the information block of resource with the specified name and the type
FindResource(LPCTSTR lpName,LPCTSTR lpType)656     HRSRC FindResource(LPCTSTR lpName, LPCTSTR lpType)
657     {
658         if (m_hInstLib == NULL)
659         {
660             return NULL;
661         }
662 
663         return ::FindResource(m_hInstLib, lpName, lpType);
664     }
665     // Load the specified resource
LoadResource(HRSRC hResInfo)666     HGLOBAL LoadResource(HRSRC hResInfo)
667     {
668         if (m_hInstLib == NULL)
669         {
670             return NULL;
671         }
672 
673         return ::LoadResource(m_hInstLib, hResInfo);
674     }
675 
676 protected:
677     HINSTANCE m_hInstLib;
678 };
679 
680 
681 
_ShowHTMLDialog(HWND hwndParent,IMoniker * pMk,VARIANT * pvarArgIn=NULL,WCHAR * pchOptions=NULL,VARIANT * pvarArgOut=NULL)682 static HRESULT _ShowHTMLDialog(
683     HWND hwndParent,
684     IMoniker* pMk,
685     VARIANT* pvarArgIn = NULL,
686     WCHAR* pchOptions = NULL,
687     VARIANT* pvarArgOut = NULL)
688 {
689     HRESULT hr = S_OK;
690 
691     try
692     {
693         CModule Module("MSHTML.DLL");
694         if (Module.GetHandle() == NULL)
695         {
696             return E_FAIL;
697         }
698 
699         SHOWHTMLDIALOGFN* fnShowHTMLDialog =
700             (SHOWHTMLDIALOGFN*)Module.GetProcAddress("ShowHTMLDialog");
701         if (fnShowHTMLDialog == NULL)
702         {
703             return E_FAIL;
704         }
705 
706         hr = (*fnShowHTMLDialog)(hwndParent, pMk, pvarArgIn, pchOptions, pvarArgOut);
707         if (FAILED(hr))
708         {
709             return hr;
710         }
711     }
712     catch (...)
713     {
714         return E_FAIL;
715     }
716 
717     return hr;
718 }
719 
ShowHTMLDialogFromURL(HWND hwndParent,wchar_t * szURL,VARIANT * pvarArgIn,WCHAR * pchOptions,VARIANT * pvarArgOut)720 HRESULT ShowHTMLDialogFromURL(HWND hwndParent,wchar_t *szURL,VARIANT* pvarArgIn,WCHAR* pchOptions,VARIANT* pvarArgOut)
721 {
722     HRESULT hr = S_OK;
723 
724     try
725     {
726         IMoniker *spMoniker;
727         hr = ::CreateURLMoniker(NULL, szURL, &spMoniker);
728         if (FAILED(hr))
729         {
730             return hr;
731         }
732 
733         hr = ::_ShowHTMLDialog(hwndParent, spMoniker, pvarArgIn, pchOptions, pvarArgOut);
734         if (FAILED(hr))
735         {
736             return hr;
737         }
738     }
739     catch (...)
740     {
741         return E_FAIL;
742     }
743 
744     return hr;
745 }
746 
747 // Create a shortcut
CreateLinkInnerA(char * filename,char * target,char * workdir,char * args,char * comment,char * icon,UINT icon_index)748 bool CreateLinkInnerA(char *filename, char *target, char *workdir, char *args,
749 				     char *comment, char *icon, UINT icon_index)
750 {
751 	HRESULT r;
752 	wchar_t tmp[MAX_SIZE];
753 	IShellLinkA* pShellLink;
754 	IPersistFile* pPersistFile;
755 
756 	r = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkA, (void **)&pShellLink);
757 	if (FAILED(r))
758 	{
759 		return false;
760 	}
761 
762 	r = pShellLink->QueryInterface(IID_IPersistFile,(void **)&pPersistFile);
763 	if (FAILED(r))
764 	{
765 		pShellLink->Release();
766 		return false;
767 	}
768 
769 	r = pShellLink->SetPath(target);
770 	if (FAILED(r))
771 	{
772 		pShellLink->Release();
773 		pPersistFile->Release();
774 		return false;
775 	}
776 
777 	if (workdir != NULL)
778 	{
779 		r = pShellLink->SetWorkingDirectory(workdir);
780 		if (FAILED(r))
781 		{
782 			pShellLink->Release();
783 			pPersistFile->Release();
784 			return false;
785 		}
786 	}
787 
788 	if (args != NULL)
789 	{
790 		r = pShellLink->SetArguments(args);
791 		if (FAILED(r))
792 		{
793 			pShellLink->Release();
794 			pPersistFile->Release();
795 			return false;
796 		}
797 	}
798 
799 	if (comment != NULL)
800 	{
801 		r = pShellLink->SetDescription(comment);
802 		if (FAILED(r))
803 		{
804 			pShellLink->Release();
805 			pPersistFile->Release();
806 			return false;
807 		}
808 	}
809 
810 	if (icon != NULL)
811 	{
812 		r = pShellLink->SetIconLocation(icon, icon_index);
813 		if (FAILED(r))
814 		{
815 			pShellLink->Release();
816 			pPersistFile->Release();
817 			return false;
818 		}
819 	}
820 
821 	StrToUni(tmp, sizeof(tmp), filename);
822 	r = pPersistFile->Save(tmp, true);
823 	if (FAILED(r))
824 	{
825 		pShellLink->Release();
826 		pPersistFile->Release();
827 		return false;
828 	}
829 
830 	pShellLink->Release();
831 	pPersistFile->Release();
832 	return true;
833 }
CreateLinkInner(wchar_t * filename,wchar_t * target,wchar_t * workdir,wchar_t * args,wchar_t * comment,wchar_t * icon,UINT icon_index)834 bool CreateLinkInner(wchar_t *filename, wchar_t *target, wchar_t *workdir, wchar_t *args,
835 				     wchar_t *comment, wchar_t *icon, UINT icon_index)
836 {
837 	HRESULT r;
838 	IShellLinkW* pShellLink;
839 	IPersistFile* pPersistFile;
840 
841 	r = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (void **)&pShellLink);
842 	if (FAILED(r))
843 	{
844 		return false;
845 	}
846 
847 	r = pShellLink->QueryInterface(IID_IPersistFile,(void **)&pPersistFile);
848 	if (FAILED(r))
849 	{
850 		pShellLink->Release();
851 		return false;
852 	}
853 
854 	r = pShellLink->SetPath(target);
855 	if (FAILED(r))
856 	{
857 		pShellLink->Release();
858 		pPersistFile->Release();
859 		return false;
860 	}
861 
862 	if (workdir != NULL)
863 	{
864 		r = pShellLink->SetWorkingDirectory(workdir);
865 		if (FAILED(r))
866 		{
867 			pShellLink->Release();
868 			pPersistFile->Release();
869 			return false;
870 		}
871 	}
872 
873 	if (comment != NULL)
874 	{
875 		r = pShellLink->SetDescription(comment);
876 		if (FAILED(r))
877 		{
878 			pShellLink->Release();
879 			pPersistFile->Release();
880 			return false;
881 		}
882 	}
883 
884 	if (args != NULL)
885 	{
886 		r = pShellLink->SetArguments(args);
887 		if (FAILED(r))
888 		{
889 			pShellLink->Release();
890 			pPersistFile->Release();
891 			return false;
892 		}
893 	}
894 
895 	if (icon != NULL)
896 	{
897 		r = pShellLink->SetIconLocation(icon, icon_index);
898 		if (FAILED(r))
899 		{
900 			pShellLink->Release();
901 			pPersistFile->Release();
902 			return false;
903 		}
904 	}
905 
906 	r = pPersistFile->Save(filename, true);
907 	if (FAILED(r))
908 	{
909 		pShellLink->Release();
910 		pPersistFile->Release();
911 		return false;
912 	}
913 
914 	pShellLink->Release();
915 	pPersistFile->Release();
916 	return true;
917 }
918 
919 extern "C"
920 {
921 
922 // Show the folder selection dialog
FolderDlgW(HWND hWnd,wchar_t * title,wchar_t * default_dir)923 wchar_t *FolderDlgW(HWND hWnd, wchar_t *title, wchar_t *default_dir)
924 {
925 	return FolderDlgInnerW(hWnd, title, default_dir);
926 }
FolderDlgA(HWND hWnd,wchar_t * title,char * default_dir)927 char *FolderDlgA(HWND hWnd, wchar_t *title, char *default_dir)
928 {
929 	return FolderDlgInnerA(hWnd, title, default_dir);
930 }
931 
932 // Create a shortcut
CreateLink(wchar_t * filename,wchar_t * target,wchar_t * workdir,wchar_t * args,wchar_t * comment,wchar_t * icon,UINT icon_index)933 bool CreateLink(wchar_t *filename, wchar_t *target, wchar_t *workdir, wchar_t *args,
934 				wchar_t *comment, wchar_t *icon, UINT icon_index)
935 {
936 	if (filename == NULL || target == NULL)
937 	{
938 		return false;
939 	}
940 
941 	return CreateLinkInner(filename, target, workdir, args, comment, icon, icon_index);
942 }
943 
944 // Show the HTML
ShowHtml(HWND hWnd,char * url,wchar_t * option)945 void ShowHtml(HWND hWnd, char *url, wchar_t *option)
946 {
947 	wchar_t tmp[MAX_SIZE];
948 	// Validate arguments
949 	if (url == NULL || option == NULL)
950 	{
951 		return;
952 	}
953 
954 	StrToUni(tmp, sizeof(tmp), url);
955 
956 	ShowHTMLDialogFromURL(hWnd, tmp, NULL, option, NULL);
957 }
958 
959 }
960 
961 #endif
962