Browse Source

WinRT: Various fix for downloading

Lou Yihua 6 years ago
parent
commit
785bbe18e6

+ 4 - 0
main.h

@@ -53,9 +53,13 @@
 #include "midi.h"
 #include "aviplay.h"
 
+PAL_C_LINKAGE_BEGIN
+
 VOID
 PAL_Shutdown(
    int exit_code
 );
 
+PAL_C_LINKAGE_END
+
 #endif

+ 7 - 7
util.c

@@ -578,12 +578,12 @@ UTIL_GetFullPathName(
 	const char *subpath
 )
 {
-	if (!buffer || !basepath || !subpath || buflen == 0) return NULL;
+	if (!buffer || !(basepath || subpath) || buflen == 0) return NULL;
 
-	int baselen = strlen(basepath), sublen = strlen(subpath);
-	if (sublen == 0) return NULL;
+	int baselen = basepath ? strlen(basepath) : 0, sublen = subpath ? strlen(subpath) : 0;
+	if (baselen + sublen == 0) return NULL;
 
-	char *_base = strdup(basepath), *_sub = strdup(subpath);
+	char *_base = basepath ? strdup(basepath) : NULL, *_sub = subpath ? strdup(subpath) : NULL;
 	const char *result = NULL;
 
 	if (access(UTIL_CombinePath(INTERNAL_BUFFER_SIZE_ARGS, 2, _base, _sub), 0) == 0)
@@ -592,7 +592,7 @@ UTIL_GetFullPathName(
 	}
 
 #if !defined(PAL_FILESYSTEM_IGNORE_CASE) || !PAL_FILESYSTEM_IGNORE_CASE
-	if (result == NULL)
+	if (result == NULL && _sub != NULL)
 	{
 		size_t pos = strspn(_sub, PAL_PATH_SEPARATORS);
 
@@ -606,7 +606,7 @@ UTIL_GetFullPathName(
 			// try to find the matching file in the directory.
 			//
 			struct dirent **list;
-			int n = scandir(_base, &list, 0, alphasort);
+			int n = scandir(_base ? _base : ".", &list, 0, alphasort);
 			while (n-- > 0)
 			{
 				if (!result && strcasecmp(list[n]->d_name, start) == 0)
@@ -735,7 +735,7 @@ UTIL_CheckResourceFiles(
 
 	for (int i = 0; i < sizeof(msg_files[0]) / sizeof(msg_files[0][0]); i++)
 	{
-		if (!UTIL_GetFullPathName(INTERNAL_BUFFER_SIZE_ARGS, path, msg_files[i][msgidx]))
+		if (!UTIL_GetFullPathName(INTERNAL_BUFFER_SIZE_ARGS, msgidx ? path : NULL, msg_files[i][msgidx]))
 		{
 			retval |= (PALFILE)(1 << ((i + 1) * msgidx + 13));
 		}

+ 8 - 0
winrt/SDLPal.Common/DownloadDialog.xaml

@@ -15,6 +15,14 @@
 
     <StackPanel Orientation="Vertical">
         <WebView x:Name="DownloadPage" NavigationStarting="OnNavigateStart" DOMContentLoaded="OnDOMContentLoaded" ScrollViewer.HorizontalScrollMode="Auto" ScrollViewer.VerticalScrollMode="Auto" />
+        <Grid x:Name="gridURL" HorizontalAlignment="Stretch">
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition />
+                <ColumnDefinition Width="Auto" />
+            </Grid.ColumnDefinitions>
+            <TextBox x:Name="tbURL" Grid.Column="0" HorizontalAlignment="Stretch" />
+            <Button x:Name="btnGoTo" Grid.Column="1" Content="->" Click="OnClick" />
+        </Grid>
         <ProgressBar x:Name="pbDownload" HorizontalAlignment="Stretch" Height="12" Margin="0,8,0,4" />
         <TextBlock x:Name="tbProgress" HorizontalAlignment="Right" Height="20" Margin="0,4,0,0" Text="0 / 0" />
     </StackPanel>

+ 200 - 185
winrt/SDLPal.Common/DownloadDialog.xaml.cpp

@@ -78,6 +78,192 @@ Platform::String^ SDLPal::DownloadDialog::FormatProgress()
 	return ref new Platform::String(buf);
 }
 
+void SDLPal::DownloadDialog::DoDownload(Platform::String^ url)
+{
+	DownloadPage->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
+	gridURL->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
+	pbDownload->Visibility = Windows::UI::Xaml::Visibility::Visible;
+	tbProgress->Visibility = Windows::UI::Xaml::Visibility::Visible;
+	this->MaxHeight -= DownloadPage->ActualHeight + gridURL->ActualHeight - 48;
+	this->PrimaryButtonText = m_resLdr->GetString("ButtonBack");
+	this->Title = m_title;
+	this->UpdateLayout();
+
+	concurrency::create_task([this, url]() {
+		Exception^ ex = nullptr;
+		auto client = ref new HttpClient();
+		try
+		{
+			concurrency::create_task(client->GetAsync(ref new Uri(url), HttpCompletionOption::ResponseHeadersRead)).then(
+				[this](HttpResponseMessage^ response)->IAsyncOperationWithProgress<IInputStream^, uint64_t>^ {
+				response->EnsureSuccessStatusCode();
+
+				bool determinate = response->Content->Headers->HasKey("Content-Length");
+				if (determinate)
+				{
+					m_totalBytes = wcstoull(response->Content->Headers->Lookup("Content-Length")->Data(), nullptr, 10);
+				}
+				this->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, determinate]() {
+					pbDownload->Maximum = (double)m_totalBytes;
+					pbDownload->IsIndeterminate = !determinate;
+				}));
+				return response->Content->ReadAsInputStreamAsync();
+			}).then([this, client](IInputStream^ input) {
+				auto buffer = ref new Buffer(_buffer_size);
+				uint64_t bytes = 0;
+				HANDLE hEvent = CreateEventEx(nullptr, nullptr, 0, EVENT_ALL_ACCESS);
+				for (bool looping = true; looping; )
+				{
+					concurrency::create_task(input->ReadAsync(buffer, _buffer_size, InputStreamOptions::None)).then(
+						[this, &bytes, &looping](IBuffer^ result)->IAsyncOperationWithProgress<uint32_t, uint32_t>^ {
+						looping = (result->Length == _buffer_size) && !m_Closable;
+						bytes += result->Length;
+						this->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, bytes]() {
+							pbDownload->Value = (double)bytes;
+							tbProgress->Text = FormatProgress();
+							UpdateLayout();
+						}));
+						return m_stream->WriteAsync(result);
+					}).then([this](uint32_t)->IAsyncOperation<bool>^ {
+						return m_stream->FlushAsync();
+					}).wait();
+				}
+				delete buffer;
+				delete client;
+				delete input;
+
+				this->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, bytes]() {
+					this->Title = m_resLdr->GetString("Extracting");
+					pbDownload->Value = 0.0;
+					UpdateLayout();
+				}));
+
+				m_stream->Seek(0);
+
+				Microsoft::WRL::ComPtr<IStream> strm;
+				HRESULT hr;
+				if (FAILED(hr = CreateStreamOverRandomAccessStream(m_stream, IID_PPV_ARGS(&strm)))) throw ref new Platform::Exception(hr);
+
+				zlib_filefunc_def funcs = {
+					/* open  */ [](voidpf opaque, const char* filename, int mode)->voidpf { return new zip_file((IStream*)opaque); },
+					/* read  */ [](voidpf opaque, voidpf stream, void* buf, uLong size)->uLong {
+					auto zip = (zip_file*)stream;
+					return SUCCEEDED(zip->hr = zip->stream->Read(buf, size, &zip->cbBytes)) ? zip->cbBytes : 0;
+				},
+					/* write */ [](voidpf opaque, voidpf stream, const void* buf, uLong size)->uLong {
+					auto zip = (zip_file*)stream;
+					return SUCCEEDED(zip->hr = zip->stream->Write(buf, size, &zip->cbBytes)) ? zip->cbBytes : 0;
+				},
+					/* tell  */ [](voidpf opaque, voidpf stream)->long {
+					auto zip = (zip_file*)stream;
+					LARGE_INTEGER liPos = { 0 };
+					ULARGE_INTEGER uliPos;
+					return SUCCEEDED(zip->hr = zip->stream->Seek(liPos, STREAM_SEEK_CUR, &uliPos)) ? uliPos.LowPart : UNZ_ERRNO;
+				},
+					/* seek  */ [](voidpf opaque, voidpf stream, uLong offset, int origin)->long {
+					auto zip = (zip_file*)stream;
+					LARGE_INTEGER liPos = { offset };
+					ULARGE_INTEGER uliPos;
+					return SUCCEEDED(zip->hr = zip->stream->Seek(liPos, origin, &uliPos)) ? 0 : UNZ_ERRNO;
+				},
+					/* close */ [](voidpf opaque, voidpf stream)->int { delete (zip_file*)stream; return 0; },
+					/* error */ [](voidpf opaque, voidpf stream)->int { return reinterpret_cast<zip_file*>(stream)->hr; },
+					strm.Get()
+				};
+				unz_global_info ugi;
+				char szFilename[65536];
+				uLong filenum = 0;
+				bool success = true;
+
+				auto uzf = unzOpen2("", &funcs);
+				unzGetGlobalInfo(uzf, &ugi);
+				this->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, ugi]() { pbDownload->Maximum = ugi.number_entry; UpdateLayout(); }));
+				for (auto ret = unzGoToFirstFile(uzf); ret == UNZ_OK; ret = unzGoToNextFile(uzf))
+				{
+					unz_file_info ufi;
+					if (UNZ_OK == unzGetCurrentFileInfo(uzf, &ufi, szFilename, sizeof(szFilename), nullptr, 0, nullptr, 0) &&
+						UNZ_OK == unzOpenCurrentFile(uzf))
+					{
+						std::auto_ptr<uint8_t> buf(new uint8_t[ufi.uncompressed_size]);
+						auto len = unzReadCurrentFile(uzf, buf.get(), ufi.uncompressed_size);
+						unzCloseCurrentFile(uzf);
+						if (len != ufi.uncompressed_size)
+						{
+							success = false;
+							break;
+						}
+
+						auto local = m_folder;
+						uLong prev = 0;
+						for (uLong i = 0; i < ufi.size_filename; i++)
+						{
+							if (szFilename[i] != '/') continue;
+							try
+							{
+								concurrency::create_task(local->GetFolderAsync(ConvertString(szFilename + prev, i - prev))).then([&local](StorageFolder^ sub) { local = sub; }).wait();
+							}
+							catch (Exception^ e)
+							{
+								concurrency::create_task(local->CreateFolderAsync(ConvertString(szFilename + prev, i - prev))).then([&local](StorageFolder^ sub) { local = sub; }).wait();
+							}
+							prev = i + 1;
+						}
+						if (prev < ufi.size_filename)
+						{
+							IRandomAccessStream^ stm = nullptr;
+							StorageFile^ file = nullptr;
+							auto filename = ConvertString(szFilename + prev, ufi.size_filename - prev);
+							concurrency::create_task(local->CreateFileAsync(filename, CreationCollisionOption::ReplaceExisting)).then([&](StorageFile^ f)->IAsyncOperation<IRandomAccessStream^>^ {
+								return (file = f)->OpenAsync(Windows::Storage::FileAccessMode::ReadWrite);
+							}).then([&](IRandomAccessStream^ s)->IAsyncOperationWithProgress<uint32_t, uint32_t>^ {
+								return (stm = s)->WriteAsync(NativeBuffer::GetIBuffer(buf.get(), ufi.uncompressed_size));
+							}).then([&](uint32_t size)->IAsyncOperation<bool>^ {
+								if (size < ufi.uncompressed_size) throw ref new Exception(E_FAIL);
+								return stm->FlushAsync();
+							}).wait();
+							delete stm;
+							delete file;
+						}
+					}
+					else
+					{
+						success = false;
+						break;
+					}
+					filenum++;
+					this->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, filenum, &ugi]() {
+						wchar_t buf[64];
+						swprintf_s(buf, L"%lu/%lu", filenum, ugi.number_entry);
+						pbDownload->Value = (double)filenum;
+						tbProgress->Text = ref new Platform::String(buf);
+						UpdateLayout();
+					}));
+				}
+				unzClose(uzf);
+
+				if (!success) throw ref new Exception(E_FAIL);
+			}).wait();
+		}
+		catch (Exception^ e)
+		{
+			ex = e;
+		}
+
+		this->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, ex]() {
+			Platform::String^ string;
+			if (m_Closable)
+				string = m_resLdr->GetString("MBDownloadCanceled");
+			else if (ex)
+				string = String::Concat(m_resLdr->GetString("MBDownloadError"), ex->Message);
+			else
+				string = m_resLdr->GetString("MBDownloadOK");
+			(ref new MessageDialog(string, m_resLdr->GetString("MBDownloadTitle")))->ShowAsync();
+			m_Closable = true;
+			Hide();
+		}));
+	});
+}
+
 void SDLPal::DownloadDialog::OnPrimaryButtonClick(Windows::UI::Xaml::Controls::ContentDialog^ sender, Windows::UI::Xaml::Controls::ContentDialogButtonClickEventArgs^ args)
 {
 	m_Closable = true;
@@ -93,7 +279,7 @@ void SDLPal::DownloadDialog::OnClosing(Windows::UI::Xaml::Controls::ContentDialo
 void SDLPal::DownloadDialog::OnOpened(Windows::UI::Xaml::Controls::ContentDialog^ sender, Windows::UI::Xaml::Controls::ContentDialogOpenedEventArgs^ args)
 {
 	DownloadPage->Width = m_width - 48;
-	DownloadPage->Height = m_height - 128;
+	DownloadPage->Height = m_height - 128 - gridURL->ActualHeight;
 	UpdateLayout();
 	DownloadPage->Navigate(ref new Uri(_url));
 }
@@ -106,187 +292,7 @@ void SDLPal::DownloadDialog::OnNavigateStart(Windows::UI::Xaml::Controls::WebVie
 
 	if (url->Length() >= _countof(_postfix) - 1 && _wcsicmp(url->Data() + url->Length() - (_countof(_postfix) - 1), _postfix) == 0)
 	{
-		DownloadPage->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
-		pbDownload->Visibility = Windows::UI::Xaml::Visibility::Visible;
-		tbProgress->Visibility = Windows::UI::Xaml::Visibility::Visible;
-		this->MaxHeight -= DownloadPage->ActualHeight - 48;
-		this->PrimaryButtonText = m_resLdr->GetString("ButtonBack");
-		this->Title = m_title;
-		this->UpdateLayout();
-		
-		concurrency::create_task([this, url]() {
-			Exception^ ex = nullptr;
-			auto client = ref new HttpClient();
-			try
-			{
-				concurrency::create_task(client->GetAsync(ref new Uri(url), HttpCompletionOption::ResponseHeadersRead)).then(
-					[this](HttpResponseMessage^ response)->IAsyncOperationWithProgress<IInputStream^, uint64_t>^ {
-					response->EnsureSuccessStatusCode();
-
-					bool determinate = response->Content->Headers->HasKey("Content-Length");
-					if (determinate)
-					{
-						m_totalBytes = wcstoull(response->Content->Headers->Lookup("Content-Length")->Data(), nullptr, 10);
-					}
-					this->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, determinate]() {
-						pbDownload->Maximum = (double)m_totalBytes;
-						pbDownload->IsIndeterminate = !determinate;
-					}));
-					return response->Content->ReadAsInputStreamAsync();
-				}).then([this, client](IInputStream^ input) {
-					auto buffer = ref new Buffer(_buffer_size);
-					uint64_t bytes = 0;
-					HANDLE hEvent = CreateEventEx(nullptr, nullptr, 0, EVENT_ALL_ACCESS);
-					for (bool looping = true; looping; )
-					{
-						concurrency::create_task(input->ReadAsync(buffer, _buffer_size, InputStreamOptions::None)).then(
-							[this, &bytes, &looping](IBuffer^ result)->IAsyncOperationWithProgress<uint32_t, uint32_t>^ {
-							looping = (result->Length == _buffer_size) && !m_Closable;
-							bytes += result->Length;
-							this->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, bytes]() {
-								pbDownload->Value = (double)bytes;
-								tbProgress->Text = FormatProgress();
-								UpdateLayout();
-							}));
-							return m_stream->WriteAsync(result);
-						}).then([this](uint32_t)->IAsyncOperation<bool>^ {
-							return m_stream->FlushAsync();
-						}).wait();
-					}
-					delete buffer;
-					delete client;
-					delete input;
-
-					this->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, bytes]() {
-						this->Title = m_resLdr->GetString("Extracting");
-						pbDownload->Value = 0.0;
-						UpdateLayout();
-					}));
-
-					m_stream->Seek(0);
-
-					Microsoft::WRL::ComPtr<IStream> strm;
-					HRESULT hr;
-					if (FAILED(hr = CreateStreamOverRandomAccessStream(m_stream, IID_PPV_ARGS(&strm)))) throw ref new Platform::Exception(hr);
-
-					zlib_filefunc_def funcs = {
-						/* open  */ [](voidpf opaque, const char* filename, int mode)->voidpf { return new zip_file((IStream*)opaque); },
-						/* read  */ [](voidpf opaque, voidpf stream, void* buf, uLong size)->uLong {
-						auto zip = (zip_file*)stream;
-						return SUCCEEDED(zip->hr = zip->stream->Read(buf, size, &zip->cbBytes)) ? zip->cbBytes : 0;
-					},
-						/* write */ [](voidpf opaque, voidpf stream, const void* buf, uLong size)->uLong {
-						auto zip = (zip_file*)stream;
-						return SUCCEEDED(zip->hr = zip->stream->Write(buf, size, &zip->cbBytes)) ? zip->cbBytes : 0;
-					},
-						/* tell  */ [](voidpf opaque, voidpf stream)->long {
-						auto zip = (zip_file*)stream;
-						LARGE_INTEGER liPos = { 0 };
-						ULARGE_INTEGER uliPos;
-						return SUCCEEDED(zip->hr = zip->stream->Seek(liPos, STREAM_SEEK_CUR, &uliPos)) ? uliPos.LowPart : UNZ_ERRNO;
-					},
-						/* seek  */ [](voidpf opaque, voidpf stream, uLong offset, int origin)->long {
-						auto zip = (zip_file*)stream;
-						LARGE_INTEGER liPos = { offset };
-						ULARGE_INTEGER uliPos;
-						return SUCCEEDED(zip->hr = zip->stream->Seek(liPos, origin, &uliPos)) ? 0 : UNZ_ERRNO;
-					},
-						/* close */ [](voidpf opaque, voidpf stream)->int { delete (zip_file*)stream; return 0; },
-						/* error */ [](voidpf opaque, voidpf stream)->int { return reinterpret_cast<zip_file*>(stream)->hr; },
-						strm.Get()
-					};
-					unz_global_info ugi;
-					char szFilename[65536];
-					uLong filenum = 0;
-					bool success = true;
-
-					auto uzf = unzOpen2("", &funcs);
-					unzGetGlobalInfo(uzf, &ugi);
-					this->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, ugi]() { pbDownload->Maximum = ugi.number_entry; UpdateLayout(); }));
-					for (auto ret = unzGoToFirstFile(uzf); ret == UNZ_OK; ret = unzGoToNextFile(uzf))
-					{
-						unz_file_info ufi;
-						if (UNZ_OK == unzGetCurrentFileInfo(uzf, &ufi, szFilename, sizeof(szFilename), nullptr, 0, nullptr, 0) &&
-							UNZ_OK == unzOpenCurrentFile(uzf))
-						{
-							std::auto_ptr<uint8_t> buf(new uint8_t[ufi.uncompressed_size]);
-							auto len = unzReadCurrentFile(uzf, buf.get(), ufi.uncompressed_size);
-							unzCloseCurrentFile(uzf);
-							if (len != ufi.uncompressed_size)
-							{
-								success = false;
-								break;
-							}
-
-							auto local = m_folder;
-							uLong prev = 0;
-							for (uLong i = 0; i < ufi.size_filename; i++)
-							{
-								if (szFilename[i] != '/') continue;
-								try
-								{
-									concurrency::create_task(local->GetFolderAsync(ConvertString(szFilename + prev, i - prev))).then([&local](StorageFolder^ sub) { local = sub; }).wait();
-								}
-								catch (Exception^ e)
-								{
-									concurrency::create_task(local->CreateFolderAsync(ConvertString(szFilename + prev, i - prev))).then([&local](StorageFolder^ sub) { local = sub; }).wait();
-								}
-								prev = i + 1;
-							}
-							if (prev < ufi.size_filename)
-							{
-								IRandomAccessStream^ stm = nullptr;
-								StorageFile^ file = nullptr;
-								auto filename = ConvertString(szFilename + prev, ufi.size_filename - prev);
-								concurrency::create_task(local->CreateFileAsync(filename, CreationCollisionOption::ReplaceExisting)).then([&](StorageFile^ f)->IAsyncOperation<IRandomAccessStream^>^ {
-									return (file = f)->OpenAsync(Windows::Storage::FileAccessMode::ReadWrite);
-								}).then([&](IRandomAccessStream^ s)->IAsyncOperationWithProgress<uint32_t, uint32_t>^ {
-									return (stm = s)->WriteAsync(NativeBuffer::GetIBuffer(buf.get(), ufi.uncompressed_size));
-								}).then([&](uint32_t size)->IAsyncOperation<bool>^ {
-									if (size < ufi.uncompressed_size) throw ref new Exception(E_FAIL);
-									return stm->FlushAsync();
-								}).wait();
-								delete stm;
-								delete file;
-							}
-						}
-						else
-						{
-							success = false;
-							break;
-						}
-						filenum++;
-						this->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, filenum, &ugi]() {
-							wchar_t buf[64];
-							swprintf_s(buf, L"%lu/%lu", filenum, ugi.number_entry);
-							pbDownload->Value = (double)filenum;
-							tbProgress->Text = ref new Platform::String(buf);
-							UpdateLayout();
-						}));
-					}
-					unzClose(uzf);
-
-					if (!success) throw ref new Exception(E_FAIL);
-				}).wait();
-			}
-			catch (Exception^ e)
-			{
-				ex = e; 
-			}
-
-			this->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, ex]() {
-				Platform::String^ string;
-				if (m_Closable)
-					string = m_resLdr->GetString("MBDownloadCanceled");
-				else if (ex)
-					string = String::Concat(m_resLdr->GetString("MBDownloadError"), ex->Message);
-				else
-					string = m_resLdr->GetString("MBDownloadOK");
-				(ref new MessageDialog(string, m_resLdr->GetString("MBDownloadTitle")))->ShowAsync();
-				m_Closable = true;
-				Hide();
-			}));
-		});
+		DoDownload(url);
 	}
 }
 
@@ -306,8 +312,8 @@ void SDLPal::DownloadDialog::OnDOMContentLoaded(Windows::UI::Xaml::Controls::Web
 				elems[i].target = '';
 				elems[i].focus();
 				var r = elems[i].getBoundingClientRect();
-				var y = (r.top + r.bottom - window.innerHeight) / 2 + window.scrollY;
-				var x = (r.left + r.right - window.innerWidth) / 2 + window.scrollX;
+				var y = (r.top + r.bottom - window.innerHeight) / 2 + window.pageYOffset;
+				var x = (r.left + r.right - window.innerWidth) / 2 + window.pageXOffset;
 				window.scroll(x, y);
 			}
 			else
@@ -325,6 +331,15 @@ void SDLPal::DownloadDialog::OnSizeChanged(Platform::Object^ sender, Windows::UI
 	if (DownloadPage->Visibility == Windows::UI::Xaml::Visibility::Visible)
 	{
 		DownloadPage->Width = e->NewSize.Width - 48;
-		DownloadPage->Height = e->NewSize.Height - 128;
+		DownloadPage->Height = e->NewSize.Height - 128 - gridURL->ActualHeight;
+	}
+}
+
+
+void SDLPal::DownloadDialog::OnClick(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
+{
+	if (tbURL->Text->Length() > 0)
+	{
+		DoDownload(tbURL->Text);
 	}
 }

+ 2 - 0
winrt/SDLPal.Common/DownloadDialog.xaml.h

@@ -25,6 +25,7 @@ namespace SDLPal
 		bool m_Closable, m_InitialPhase;
 
 		Platform::String^ FormatProgress();
+		void DoDownload(Platform::String^ url);
 
 		void OnPrimaryButtonClick(Windows::UI::Xaml::Controls::ContentDialog^ sender, Windows::UI::Xaml::Controls::ContentDialogButtonClickEventArgs^ args);
 		void OnClosing(Windows::UI::Xaml::Controls::ContentDialog^ sender, Windows::UI::Xaml::Controls::ContentDialogClosingEventArgs^ args);
@@ -32,5 +33,6 @@ namespace SDLPal
 		void OnNavigateStart(Windows::UI::Xaml::Controls::WebView^ sender, Windows::UI::Xaml::Controls::WebViewNavigationStartingEventArgs^ args);
 		void OnDOMContentLoaded(Windows::UI::Xaml::Controls::WebView^ sender, Windows::UI::Xaml::Controls::WebViewDOMContentLoadedEventArgs^ args);
 		void OnSizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e);
+		void OnClick(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
 	};
 }

+ 4 - 4
winrt/SDLPal.Common/MainPage.xaml

@@ -24,7 +24,7 @@
                         <ColumnDefinition/>
                         <ColumnDefinition Width="Auto"/>
                     </Grid.ColumnDefinitions>
-                    <TextBox x:Name="tbGamePath" x:Uid="GamePath" Grid.Column="0" TextWrapping="Wrap" VerticalAlignment="Top" Header="游戏资源文件夹" IsReadOnly="True" PlaceholderText="未选择游戏资源文件夹"/>
+                    <TextBox x:Name="tbGamePath" x:Uid="GamePath" Grid.Column="0" TextWrapping="Wrap" VerticalAlignment="Top" Header="游戏资源文件夹" IsReadOnly="True" PlaceholderText="未选择游戏资源文件夹" />
                     <Button x:Name="btnBrowseGame" x:Uid="ButtonBrowse" Grid.Column="1" Content="浏览" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Click="btnBrowseFolder_Click" />
                 </Grid>
                 <Button x:Name="btnDownloadGame" x:Uid="ButtonDownload" Content="下载正版游戏资源" HorizontalAlignment="Center" Click="btnDownloadGame_Click" IsEnabled="False" />
@@ -34,7 +34,7 @@
                         <ColumnDefinition/>
                         <ColumnDefinition Width="Auto"/>
                     </Grid.ColumnDefinitions>
-                    <TextBox x:Name="tbMsgFile" x:Uid="MessageFile" Grid.Column="0" TextWrapping="Wrap" VerticalAlignment="Top" PlaceholderText="无自定义语言文件" IsReadOnly="True"/>
+                    <TextBox x:Name="tbMsgFile" x:Uid="MessageFile" Grid.Column="0" TextWrapping="Wrap" VerticalAlignment="Top" PlaceholderText="无自定义语言文件" IsReadOnly="True" />
                     <Button x:Name="btnBrowseMsgFile" x:Uid="ButtonBrowse" Grid.Column="1" Content="浏览" HorizontalAlignment="Right" Click="btnBrowseFileOpen_Click" />
                 </Grid>
                 <CheckBox x:Name="cbUseFontFile" x:Uid="UseFontFile" Content="自定义字体文件" Checked="cbUseFile_CheckChanged" Unchecked="cbUseFile_CheckChanged" />
@@ -43,7 +43,7 @@
                         <ColumnDefinition/>
                         <ColumnDefinition Width="Auto"/>
                     </Grid.ColumnDefinitions>
-                    <TextBox x:Name="tbFontFile" x:Uid="FontFile" Grid.Column="0" TextWrapping="Wrap" VerticalAlignment="Top" PlaceholderText="无自定义字体文件" IsReadOnly="True"/>
+                    <TextBox x:Name="tbFontFile" x:Uid="FontFile" Grid.Column="0" TextWrapping="Wrap" VerticalAlignment="Top" PlaceholderText="无自定义字体文件" IsReadOnly="True" />
                     <Button x:Name="btnBrowseFontFile" x:Uid="ButtonBrowse" Grid.Column="1" Content="浏览" HorizontalAlignment="Right" Click="btnBrowseFileOpen_Click" />
                 </Grid>
                 <ToggleSwitch x:Name="tsTouchOverlay" x:Uid="TouchOverlay" Header="启用触屏辅助" OffContent="否" OnContent="是" />
@@ -100,7 +100,7 @@
                         <ColumnDefinition/>
                         <ColumnDefinition Width="Auto"/>
                     </Grid.ColumnDefinitions>
-                    <TextBox x:Name="tbLogFile" x:Uid="LogFile" Grid.Column="0" TextWrapping="Wrap" VerticalAlignment="Top" PlaceholderText="无日志文件" IsReadOnly="True"/>
+                    <TextBox x:Name="tbLogFile" x:Uid="LogFile" Grid.Column="0" TextWrapping="Wrap" VerticalAlignment="Top" PlaceholderText="无日志文件" IsReadOnly="True" />
                     <Button x:Name="btnBrowseLogFile" x:Uid="ButtonBrowse" Grid.Column="1" Content="浏览" HorizontalAlignment="Right" Click="btnBrowseFileSave_Click" />
                 </Grid>
                 <Grid VerticalAlignment="Top">

+ 72 - 62
winrt/SDLPal.Common/MainPage.xaml.cpp

@@ -16,8 +16,11 @@
 using namespace SDLPal;
 
 using namespace Platform;
+using namespace Platform::Collections;
 using namespace Windows::Foundation;
 using namespace Windows::Foundation::Collections;
+using namespace Windows::Storage;
+using namespace Windows::Storage::AccessCache;
 using namespace Windows::UI::Core;
 using namespace Windows::UI::Popups;
 using namespace Windows::UI::Xaml;
@@ -28,10 +31,6 @@ using namespace Windows::UI::Xaml::Input;
 using namespace Windows::UI::Xaml::Media;
 using namespace Windows::UI::Xaml::Navigation;
 
-static Platform::String^ msg_file_exts[] = { ".msg" };
-static Platform::String^ font_file_exts[] = { ".bdf" };
-static Platform::String^ log_file_exts[] = { ".log" };
-
 MainPage^ MainPage::Current = nullptr;
 
 MainPage::MainPage()
@@ -41,13 +40,13 @@ MainPage::MainPage()
 
 	Current = this;
 
-	m_controls = ref new Platform::Collections::Map<Platform::String^, ButtonAttribute^>();
-	m_controls->Insert(btnBrowseMsgFile->Name, ref new ButtonAttribute(tbMsgFile, ref new Platform::Array<Platform::String^>(msg_file_exts, sizeof(msg_file_exts) / sizeof(msg_file_exts[0]))));
-	m_controls->Insert(btnBrowseFontFile->Name, ref new ButtonAttribute(tbFontFile, ref new Platform::Array<Platform::String^>(font_file_exts, sizeof(font_file_exts) / sizeof(font_file_exts[0]))));
-	m_controls->Insert(btnBrowseLogFile->Name, ref new ButtonAttribute(tbLogFile, ref new Platform::Array<Platform::String^>(log_file_exts, sizeof(log_file_exts) / sizeof(log_file_exts[0]))));
-	m_controls->Insert(cbUseMsgFile->Name, ref new ButtonAttribute(gridMsgFile, nullptr));
-	m_controls->Insert(cbUseFontFile->Name, ref new ButtonAttribute(gridFontFile, nullptr));
-	m_controls->Insert(cbUseLogFile->Name, ref new ButtonAttribute(gridLogFile, nullptr));
+	m_controls = ref new Map<String^, FrameworkElement^>();
+	m_controls->Insert(btnBrowseMsgFile->Name, tbMsgFile);
+	m_controls->Insert(btnBrowseFontFile->Name, tbFontFile);
+	m_controls->Insert(btnBrowseLogFile->Name, tbLogFile);
+	m_controls->Insert(cbUseMsgFile->Name, gridMsgFile);
+	m_controls->Insert(cbUseFontFile->Name, gridFontFile);
+	m_controls->Insert(cbUseLogFile->Name, gridLogFile);
 
 	m_acl[PALCFG_GAMEPATH] = ref new AccessListEntry(tbGamePath, nullptr, ConvertString(PAL_ConfigName(PALCFG_GAMEPATH)));
 	m_acl[PALCFG_SAVEPATH] = ref new AccessListEntry(tbGamePath, nullptr, ConvertString(PAL_ConfigName(PALCFG_SAVEPATH)));
@@ -55,6 +54,10 @@ MainPage::MainPage()
 	m_acl[PALCFG_FONTFILE] = ref new AccessListEntry(tbFontFile, cbUseFontFile, ConvertString(PAL_ConfigName(PALCFG_FONTFILE)));
 	m_acl[PALCFG_LOGFILE] = ref new AccessListEntry(tbLogFile, cbUseLogFile, ConvertString(PAL_ConfigName(PALCFG_LOGFILE)));
 
+	tbMsgFile->Tag = ConvertString(PAL_ConfigName(PALCFG_MESSAGEFILE));
+	tbFontFile->Tag = ConvertString(PAL_ConfigName(PALCFG_MESSAGEFILE));
+	tbLogFile->Tag = ConvertString(PAL_ConfigName(PALCFG_MESSAGEFILE));
+
 	tbGitRevision->Text = "  " PAL_GIT_REVISION;
 
 	LoadControlContents(false);
@@ -69,7 +72,7 @@ MainPage::MainPage()
 
 	try
 	{
-		delete AWait(Windows::Storage::ApplicationData::Current->LocalFolder->GetFileAsync("sdlpal.cfg"));
+		delete AWait(ApplicationData::Current->LocalFolder->GetFileAsync("sdlpal.cfg"), g_eventHandle);
 	}
 	catch (Exception^)
 	{
@@ -83,32 +86,42 @@ void SDLPal::MainPage::LoadControlContents(bool loadDefault)
 	{
 		auto item = i->second;
 		item->text->Text = "";
-		item->text->Tag = nullptr;
 		if (item->check)
 		{
 			item->check->IsChecked = false;
-			m_controls->Lookup(item->check->Name)->Object->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
+			m_controls->Lookup(item->check->Name)->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
 		}
 	}
 
+	// Clear MRU list
+	StorageApplicationPermissions::MostRecentlyUsedList->Clear();
+
 	if (!loadDefault)
 	{
 		// Always load folder/files from FutureAccessList
 		std::list<Platform::String^> invalid_tokens;
-		auto fal = Windows::Storage::AccessCache::StorageApplicationPermissions::FutureAccessList;
+		auto fal = StorageApplicationPermissions::FutureAccessList;
 		for each (auto entry in fal->Entries)
 		{
-			auto& ace = m_acl[PAL_ConfigIndex(ConvertString(entry.Token).c_str())];
-			ace->text->Tag = AWait(fal->GetItemAsync(entry.Token), g_eventHandle);
-			if (ace->text->Tag)
+			try
+			{
+				auto item = AWait(fal->GetItemAsync(entry.Token), g_eventHandle);
+				auto& ace = m_acl[PAL_ConfigIndex(ConvertString(entry.Token).c_str())];
 				ace->text->Text = entry.Metadata;
-			else
-				invalid_tokens.push_back(entry.Token);
-			if (ace->check)
+				if (ace->check)
+				{
+					auto grid = m_controls->Lookup(ace->check->Name);
+					ace->check->IsChecked = (item != nullptr);
+					grid->Visibility = ace->check->IsChecked->Value ? Windows::UI::Xaml::Visibility::Visible : Windows::UI::Xaml::Visibility::Collapsed;
+				}
+				else
+				{
+					ace->text->Tag = item;
+				}
+			}
+			catch (Exception ^)
 			{
-				auto grid = m_controls->Lookup(ace->check->Name)->Object;
-				ace->check->IsChecked = (ace->text->Tag != nullptr);
-				grid->Visibility = ace->check->IsChecked->Value ? Windows::UI::Xaml::Visibility::Visible : Windows::UI::Xaml::Visibility::Collapsed;
+				invalid_tokens.push_back(entry.Token);
 			}
 		}
 		for (auto i = invalid_tokens.begin(); i != invalid_tokens.end(); fal->Remove(*i++));
@@ -213,16 +226,25 @@ void SDLPal::MainPage::btnFinish_Click(Platform::Object^ sender, Windows::UI::Xa
 			return;
 		}
 
-		auto fal = Windows::Storage::AccessCache::StorageApplicationPermissions::FutureAccessList;
+		auto fal = StorageApplicationPermissions::FutureAccessList;
+		auto mru = StorageApplicationPermissions::MostRecentlyUsedList;
+		fal->Clear();
 		for (auto i = m_acl.begin(); i != m_acl.end(); i++)
 		{
-			auto item = i->second;
-			auto check = item->check ? item->check->IsChecked->Value : true;
-			if (check && item->text->Tag)
-				fal->AddOrReplace(item->token, safe_cast<Windows::Storage::IStorageItem^>(item->text->Tag), item->text->Text);
-			else if (fal->ContainsItem(item->token))
-				fal->Remove(item->token);
+			auto entry = i->second;
+			try
+			{
+				auto item = AWait(mru->GetItemAsync(entry->token), g_eventHandle);
+				if ((!entry->check || entry->check->IsChecked->Value) && item)
+				{
+					fal->AddOrReplace(entry->token, item, entry->text->Text);
+				}
+			}
+			catch (Exception ^)
+			{
+			}
 		}
+		mru->Clear();
 
 		SaveControlContents();
 		gConfig.fLaunchSetting = FALSE;
@@ -241,36 +263,37 @@ void SDLPal::MainPage::btnFinish_Click(Platform::Object^ sender, Windows::UI::Xa
 void SDLPal::MainPage::btnClearFile_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
 {
 	tbMsgFile->Text = "";
-	tbMsgFile->Tag = nullptr;
 }
 
-void SDLPal::MainPage::SetPath(Windows::Storage::StorageFolder^ folder)
+void SDLPal::MainPage::SetPath(StorageFolder^ folder)
 {
 	if (folder)
 	{
 		tbGamePath->Text = folder->Path;
 		tbGamePath->Tag = folder;
 		btnDownloadGame->IsEnabled = true;
+		StorageApplicationPermissions::MostRecentlyUsedList->AddOrReplace(m_acl[PALCFG_GAMEPATH]->token, folder, folder->Path);
+		StorageApplicationPermissions::MostRecentlyUsedList->AddOrReplace(m_acl[PALCFG_SAVEPATH]->token, folder, folder->Path);
 	}
 }
 
-void SDLPal::MainPage::SetFile(Windows::UI::Xaml::Controls::TextBox^ target, Windows::Storage::StorageFile^ file)
+void SDLPal::MainPage::SetFile(Windows::UI::Xaml::Controls::TextBox^ target, StorageFile^ file)
 {
 	if (target && file)
 	{
 		target->Text = file->Path;
-		target->Tag = file;
+		StorageApplicationPermissions::MostRecentlyUsedList->AddOrReplace(static_cast<String^>(target->Tag), file, file->Path);
 	}
 }
 
 void SDLPal::MainPage::btnBrowseFolder_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
 {
-	auto picker = ref new Windows::Storage::Pickers::FolderPicker();
+	auto picker = ref new Pickers::FolderPicker();
 	picker->FileTypeFilter->Append("*");
 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
 	picker->PickFolderAndContinue();
 #else
-	concurrency::create_task(picker->PickSingleFolderAsync()).then([this](Windows::Storage::StorageFolder^ folder) { SetPath(folder); });
+	concurrency::create_task(picker->PickSingleFolderAsync()).then([this](StorageFolder^ folder) { SetPath(folder); });
 #endif
 }
 
@@ -278,17 +301,13 @@ void SDLPal::MainPage::btnBrowseFileOpen_Click(Platform::Object^ sender, Windows
 {
 	auto button = static_cast<Windows::UI::Xaml::Controls::Button^>(sender);
 	auto target = m_controls->Lookup(button->Name);
-	auto picker = ref new Windows::Storage::Pickers::FileOpenPicker();
-	picker->FileTypeFilter->ReplaceAll(target->Filter);
+	auto picker = ref new Pickers::FileOpenPicker();
+	picker->FileTypeFilter->Append("*");
 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
 	picker->ContinuationData->Insert("Target", button->Name);
 	picker->PickSingleFileAndContinue();
 #else
-	concurrency::create_task(picker->PickSingleFileAsync()).then(
-		[this, target](Windows::Storage::StorageFile^ file) {
-			SetFile(static_cast<Windows::UI::Xaml::Controls::TextBox^>(target->Object), file);
-		}
-	);
+	concurrency::create_task(picker->PickSingleFileAsync()).then([this, target](StorageFile^ file) { SetFile(static_cast<TextBox^>(target), file); });
 #endif
 }
 
@@ -296,25 +315,20 @@ void SDLPal::MainPage::btnBrowseFileSave_Click(Platform::Object^ sender, Windows
 {
 	auto button = static_cast<Windows::UI::Xaml::Controls::Button^>(sender);
 	auto target = m_controls->Lookup(button->Name);
-	auto picker = ref new Windows::Storage::Pickers::FileSavePicker();
-	picker->FileTypeChoices->Insert(m_resLdr->GetString("LogFileType"), ref new Platform::Collections::Vector<Platform::String^>(target->Filter));
+	auto picker = ref new Pickers::FileSavePicker();
+	picker->FileTypeChoices->Insert(m_resLdr->GetString("LogFileType"), ref new Vector<String^>(1, ref new String(L".log")));
 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
 	picker->ContinuationData->Insert("Target", button->Name);
 	picker->PickSaveFileAndContinue();
 #else
-	concurrency::create_task(picker->PickSaveFileAsync()).then(
-		[this, target](Windows::Storage::StorageFile^ file) {
-		SetFile(static_cast<Windows::UI::Xaml::Controls::TextBox^>(target->Object), file);
-	}
-	);
+	concurrency::create_task(picker->PickSaveFileAsync()).then([this, target](StorageFile^ file) { SetFile(static_cast<TextBox^>(target), file); });
 #endif
 }
 
 void SDLPal::MainPage::cbUseFile_CheckChanged(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
 {
 	auto checker = static_cast<Windows::UI::Xaml::Controls::CheckBox^>(sender);
-	auto attr = m_controls->Lookup(checker->Name);
-	attr->Object->Visibility = checker->IsChecked->Value ? Windows::UI::Xaml::Visibility::Visible : Windows::UI::Xaml::Visibility::Collapsed;
+	m_controls->Lookup(checker->Name)->Visibility = checker->IsChecked->Value ? Windows::UI::Xaml::Visibility::Visible : Windows::UI::Xaml::Visibility::Collapsed;
 }
 
 void SDLPal::MainPage::Page_Loaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
@@ -328,10 +342,9 @@ void SDLPal::MainPage::Page_Loaded(Platform::Object^ sender, Windows::UI::Xaml::
 #endif
 }
 
-
 void SDLPal::MainPage::btnDownloadGame_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
 {
-	auto folder = dynamic_cast<Windows::Storage::StorageFolder^>(tbGamePath->Tag);
+	auto folder = dynamic_cast<StorageFolder^>(tbGamePath->Tag);
 	auto msgbox = ref new MessageDialog(m_resLdr->GetString("MBDownloadMessage"), m_resLdr->GetString("MBDownloadTitle"));
 	msgbox->Commands->Append(ref new UICommand(m_resLdr->GetString("MBButtonOK"), nullptr, 1));
 	msgbox->Commands->Append(ref new UICommand(m_resLdr->GetString("MBButtonCancel"), nullptr, nullptr));
@@ -361,26 +374,23 @@ void SDLPal::MainPage::btnDownloadGame_Click(Platform::Object^ sender, Windows::
 	}).then([this, folder](IUICommand^ command) {
 		if (command->Id != nullptr)
 		{
-			HANDLE hEvent = CreateEventEx(nullptr, nullptr, 0, EVENT_ALL_ACCESS);
 			try
 			{
-				auto file = AWait(folder->CreateFileAsync("pal98.zip", Windows::Storage::CreationCollisionOption::ReplaceExisting), hEvent);
-				auto stream = AWait(file->OpenAsync(Windows::Storage::FileAccessMode::ReadWrite), hEvent);
+				auto file = AWait(folder->CreateFileAsync("pal98.zip", CreationCollisionOption::ReplaceExisting), g_eventHandle);
+				auto stream = AWait(file->OpenAsync(FileAccessMode::ReadWrite), g_eventHandle);
 				concurrency::create_task(this->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, folder, file, stream]() {
 					m_dlg = ref new DownloadDialog(m_resLdr, folder, stream, ActualWidth, ActualHeight);
 				}))).then([this]()->IAsyncOperation<ContentDialogResult>^{
 					return m_dlg->ShowAsync();
-				}).then([this, file, stream, hEvent](ContentDialogResult result) {
+				}).then([this, file, stream](ContentDialogResult result) {
 					delete stream;
-					AWait(file->DeleteAsync(), hEvent);
+					AWait(file->DeleteAsync(), g_eventHandle);
 					delete file;
-					CloseHandle(hEvent);
 				});
 			}
 			catch (Exception^ e)
 			{
 				(ref new MessageDialog(String::Concat(m_resLdr->GetString("MBDownloadError"), e)))->ShowAsync();
-				CloseHandle(hEvent);
 			}
 		}
 	});

+ 1 - 13
winrt/SDLPal.Common/MainPage.xaml.h

@@ -16,18 +16,6 @@
 
 namespace SDLPal
 {
-	ref struct ButtonAttribute sealed
-	{
-		property Windows::UI::Xaml::FrameworkElement^ Object;
-		property Platform::Array<Platform::String^>^  Filter;
-
-		ButtonAttribute(Windows::UI::Xaml::FrameworkElement^ o, const Platform::Array<Platform::String^>^ f)
-		{
-			Object = o;
-			Filter = f;
-		}
-	};
-
 	ref struct AccessListEntry sealed
 	{
 		property Windows::UI::Xaml::Controls::TextBox^  text;
@@ -58,7 +46,7 @@ namespace SDLPal
 		void SaveControlContents();
 
 	private:
-		Platform::Collections::Map<Platform::String^, ButtonAttribute^>^ m_controls;
+		Platform::Collections::Map<Platform::String^, Windows::UI::Xaml::FrameworkElement^>^ m_controls;
 		Windows::ApplicationModel::Resources::ResourceLoader^ m_resLdr;
 		std::map<PALCFG_ITEM, AccessListEntry^> m_acl;
 		Windows::UI::Xaml::Controls::ContentDialog^ m_dlg;

+ 1 - 1
winrt/SDLPal.Common/SDLPal.cpp

@@ -17,7 +17,7 @@ int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
 	if (FAILED(Windows::Foundation::Initialize(RO_INIT_MULTITHREADED))) {
 		return 1;
 	}
-
+	
 	PAL_LoadConfig(TRUE);
 
 	bool last_crashed = false;

+ 3 - 3
winrt/SDLPal.Common/Strings/en/Resources.resw

@@ -229,8 +229,8 @@
     <value>Download aborted due to error: </value>
   </data>
   <data name="MBDownloadMessage" xml:space="preserve">
-    <value>You're going to be brought to the download page provided by baiyou100.com, from where you can download the game resource to the folder you've just chosen. The download link will be automatically centered so that anyone who don't understand Chinese can download it without trouble.
-Please note that this download page is not provided by this App's creator, so we can't guarantee the availablity of the donwload link.
+    <value>You're going to be brought to the download page, from where you can download the game resource to the folder you've just chosen. The download link will be automatically centered so that anyone who don't understand Chinese can download it without trouble.  You also have the opportunity to enter any direct download URL you know.
+Please note that this download page is not provided by this App's creator, so we can't guarantee the availablity of the donwload link or take responsibility for any consequences.
 Click 'ok' to continue or click 'cancel' to return.</value>
   </data>
   <data name="MBDownloadOK" xml:space="preserve">
@@ -251,7 +251,7 @@ You can use the main menu option inside the game to return to this page.</value>
   </data>
   <data name="MBStartupMessage" xml:space="preserve">
     <value>You need to choose the folder that contains game resource files before you can start the game, because such files are NOT bundled due to copyright restrictions.
-But fortunately, these files can be downloaded freely from baiyou100.com, the publisher's website.  You'll be brought to this website by clicking the 'download' button after you've chosen a folder to save the downloaded files.
+But fortunately, a licensed copy of such files can be downloaded freely from Internet.  You'll be brought to this website by clicking the 'download' button after you've chosen a folder to save the downloaded files.
 Once you've finished the setting process, you will be brought to the game directly at next launch.</value>
   </data>
   <data name="MBStartupTitle" xml:space="preserve">

+ 3 - 3
winrt/SDLPal.Common/Strings/zh-hans/Resources.resw

@@ -229,8 +229,8 @@
     <value>下载已被如下错误中止:</value>
   </data>
   <data name="MBDownloadMessage" xml:space="preserve">
-    <value>您即将进入由baiyou100.com提供的游戏资源文件下载页,您可从该页面下载免费的正版游戏资源文件并保存于您所选择的文件夹中。
-您应知晓,上述资源文件并非由本应用的开发方提供,故我们无法保证上述下载链接的可用性。
+    <value>您即将进入游戏发行商提供的游戏资源文件下载页,您可从该页面(或任何您输入的URL)下载免费的正版游戏资源文件并保存于您所选择的文件夹中。
+您应知晓,上述资源文件并非由本应用的开发方提供,故我们无法保证下载链接的可用性,也不对您的行为承担任何责任
 请点击“确定”按钮开始下载,或点击“取消”返回设置页面。</value>
   </data>
   <data name="MBDownloadOK" xml:space="preserve">
@@ -251,7 +251,7 @@
   </data>
   <data name="MBStartupMessage" xml:space="preserve">
     <value>由于受版权限制,游戏资源文件并未包含在本应用当中,您需要首先在设置页面中选择游戏资源所在文件夹后方可进入游戏。
-对于尚未拥有游戏资源者,目前可从baiyou100.com上下载免费的正版游戏资源,请在选择文件夹后点击“下载”按钮进入下载页面。
+对于尚未拥有游戏资源者,目前可从Internet上下载免费的正版游戏资源,请在选择文件夹后点击“下载”按钮进入下载页面。
 一旦您完成设置,在您下一次启动本应用时将直接开始游戏进程。</value>
   </data>
   <data name="MBStartupTitle" xml:space="preserve">

+ 3 - 3
winrt/SDLPal.Common/Strings/zh-hant/Resources.resw

@@ -229,8 +229,8 @@
     <value>下載已被如下錯誤中止:</value>
   </data>
   <data name="MBDownloadMessage" xml:space="preserve">
-    <value>您即將進入由baiyou100.com提供的遊戲資源檔下載頁,您可從該頁面下載免費的正版遊戲資源檔並保存於您所選擇的資料夾中。
-您應知曉,上述資源檔並非由本應用的開發方提供,故我們無法保證上述下載連結的可用性。
+    <value>您即將進入由遊戲發行商提供的遊戲資源檔下載頁,您可從該頁面(或任何您輸入的URL)下載免費的正版遊戲資源檔並保存於您所選擇的資料夾中。
+您應知曉,上述資源檔並非由本應用的開發方提供,故我們無法保證下載連結的可用性,也不對您的行為承擔任何責任
 請點擊「確定」按鈕開始下載,或點擊「取消」返回設置頁面。</value>
   </data>
   <data name="MBDownloadOK" xml:space="preserve">
@@ -251,7 +251,7 @@
   </data>
   <data name="MBStartupMessage" xml:space="preserve">
     <value>由於受智慧產權限制,遊戲資源檔並未包含在本應用當中,您需要首先在設置頁面中選擇遊戲資源所在資料夾後方可進入遊戲。
-對於尚未擁有遊戲資源者,目前可從baiyou100.com上下載免費的正版遊戲資源,請在選擇資料夾後點擊「下載」按鈕進入下載頁面。
+對於尚未擁有遊戲資源者,目前可從Internet上下載免費的正版遊戲資源,請在選擇資料夾後點擊「下載」按鈕進入下載頁面。
 一旦您完成設置,在您下一次啟動本應用時將直接開始遊戲進程。</value>
   </data>
   <data name="MBStartupTitle" xml:space="preserve">

+ 19 - 16
winrt/SDLPal.Common/WinRTIO.cpp

@@ -32,6 +32,9 @@
 #include "AsyncHelper.h"
 #include "StringHelper.h"
 
+using namespace Windows::Storage;
+using namespace Windows::Storage::Streams;
+
 #pragma comment(lib, "ShCore.lib")
 
 #define PAL_PATH_NAME	"SDLPAL"
@@ -53,7 +56,7 @@ struct WRT_FILE
 	bool binary;
 
 	WRT_FILE() : sig(&liZero), stream(nullptr), readable(false), writable(false), binary(false) { InitializeCriticalSectionEx(&cs, 4000, 0); }
-	WRT_FILE(Windows::Storage::Streams::IRandomAccessStream^ s, bool r, bool w, bool b)
+	WRT_FILE(IRandomAccessStream^ s, bool r, bool w, bool b)
 		: sig(&liZero), stream(nullptr), readable(r), writable(w), binary(b)
 	{
 		HRESULT hr;
@@ -64,8 +67,8 @@ struct WRT_FILE
 	~WRT_FILE() { if (stream) stream->Release(); DeleteCriticalSection(&cs); }
 };
 
-static std::map<std::string, Windows::Storage::StorageFile^> g_specialFiles;
-static std::map<std::string, Windows::Storage::StorageFolder^> g_specialFolders;
+static std::map<std::string, StorageFile^> g_specialFiles;
+static std::map<std::string, StorageFolder^> g_specialFolders;
 
 class CriticalSection
 {
@@ -120,8 +123,8 @@ static const std::string get_filename(const char* _Filename)
 	return ptr;
 }
 
-extern "C" std::map<std::string, Windows::Storage::StorageFile^>* get_special_files_map() { return &g_specialFiles; }
-extern "C" std::map<std::string, Windows::Storage::StorageFolder^>* get_special_folders_map() { return &g_specialFolders; }
+extern "C" std::map<std::string, StorageFile^>* get_special_files_map() { return &g_specialFiles; }
+extern "C" std::map<std::string, StorageFolder^>* get_special_folders_map() { return &g_specialFolders; }
 
 extern "C"
 errno_t WRT_fopen_s(WRT_FILE ** pFile, const char * _Filename, const char * _Mode)
@@ -156,14 +159,14 @@ errno_t WRT_fopen_s(WRT_FILE ** pFile, const char * _Filename, const char * _Mod
 		// If the file belongs to so-called 'special files' (i.e., specified in configuration file), then return its object directly
 		if (g_specialFiles.find(_Filename) != g_specialFiles.end())
 		{
-			*pFile = new WRT_FILE(AWait(g_specialFiles[_Filename]->OpenAsync(w ? Windows::Storage::FileAccessMode::ReadWrite : Windows::Storage::FileAccessMode::Read), eventHandle), r, w, b);
+			*pFile = new WRT_FILE(AWait(g_specialFiles[_Filename]->OpenAsync(w ? FileAccessMode::ReadWrite : FileAccessMode::Read), eventHandle), r, w, b);
 			return 0;
 		}
 
 		auto directory = get_directory(_Filename);
 		auto filename = get_filename(_Filename);
 
-		Windows::Storage::StorageFolder^ folder = nullptr;
+		StorageFolder^ folder = nullptr;
 
 		// If the file's folder belongs to so-called 'special folders' (i.e., specified in configuration file), then use the cache folder object
 		for (auto i = g_specialFolders.begin(); directory.length() > 0 && i != g_specialFolders.end(); i++)
@@ -190,23 +193,23 @@ errno_t WRT_fopen_s(WRT_FILE ** pFile, const char * _Filename, const char * _Mod
 		// The try get folder directly by its full path
 		if (!folder && directory.length())
 		{
-			folder = AWait(Windows::Storage::StorageFolder::GetFolderFromPathAsync(ConvertString(directory)), eventHandle);
+			folder = AWait(StorageFolder::GetFolderFromPathAsync(ConvertString(directory)), eventHandle);
 		}
 
 		// As a last sort, use app's local folder
 		if (!folder)
 		{
-			folder = Windows::Storage::ApplicationData::Current->LocalFolder;
+			folder = ApplicationData::Current->LocalFolder;
 		}
 
-		Windows::Storage::StorageFile^ file = nullptr;
+		StorageFile^ file = nullptr;
 		switch (*_Mode)
 		{
 		case 'a':
-			file = AWait(folder->CreateFileAsync(ConvertString(filename), Windows::Storage::CreationCollisionOption::OpenIfExists), eventHandle);
+			file = AWait(folder->CreateFileAsync(ConvertString(filename), CreationCollisionOption::OpenIfExists), eventHandle);
 			break;
 		case 'w':
-			file = AWait(folder->CreateFileAsync(ConvertString(filename), Windows::Storage::CreationCollisionOption::ReplaceExisting), eventHandle);
+			file = AWait(folder->CreateFileAsync(ConvertString(filename), CreationCollisionOption::ReplaceExisting), eventHandle);
 			break;
 		case 'r':
 			file = AWait(folder->GetFileAsync(ConvertString(filename)), eventHandle);
@@ -214,7 +217,7 @@ errno_t WRT_fopen_s(WRT_FILE ** pFile, const char * _Filename, const char * _Mod
 		}
 		if (file)
 		{
-			*pFile = new WRT_FILE(AWait(file->OpenAsync(w ? Windows::Storage::FileAccessMode::ReadWrite : Windows::Storage::FileAccessMode::Read), eventHandle), r, w, b);
+			*pFile = new WRT_FILE(AWait(file->OpenAsync(w ? FileAccessMode::ReadWrite : FileAccessMode::Read), eventHandle), r, w, b);
 		}
 	}
 	catch (Platform::AccessDeniedException^)
@@ -426,10 +429,10 @@ int WRT_access(const char * const _FileName, int _AccessMode)
 
 	try
 	{
-		auto file = AWait(Windows::Storage::StorageFile::GetFileFromPathAsync(ConvertString(_FileName)));
+		auto file = AWait(StorageFile::GetFileFromPathAsync(ConvertString(_FileName)));
 
-		if ((file->Attributes & Windows::Storage::FileAttributes::Directory) != Windows::Storage::FileAttributes::Directory &&
-			(file->Attributes & Windows::Storage::FileAttributes::ReadOnly) == Windows::Storage::FileAttributes::ReadOnly &&
+		if ((file->Attributes & FileAttributes::Directory) != FileAttributes::Directory &&
+			(file->Attributes & FileAttributes::ReadOnly) == FileAttributes::ReadOnly &&
 			(_AccessMode & 0x2) != 0)
 		{
 			throw ref new Platform::AccessDeniedException();

+ 35 - 26
winrt/SDLPal.Common/WinRTUtil.cpp

@@ -8,7 +8,8 @@
 #include <ppltasks.h>
 #include "../SDLPal.Common/AsyncHelper.h"
 #include "../SDLPal.Common/StringHelper.h"
-#include "../../main.h"
+#include "input.h"
+#include "main.h"
 
 #include "SDL.h"
 #include "SDL_endian.h"
@@ -126,13 +127,19 @@ static int SDLCALL WinRT_EventFilter(void *userdata, SDL_Event * event)
 	return 0;
 }
 
-static int input_event_filter(const SDL_Event *lpEvent, PALINPUTSTATE *state)
+static int input_event_filter(const SDL_Event *lpEvent, volatile PALINPUTSTATE *state)
 {
 	if (lpEvent->type == SDL_KEYDOWN &&
-		lpEvent->key.keysym.sym == SDLK_AC_BACK &&
-		!gpGlobals->fInMainGame)
+		lpEvent->key.keysym.sym == SDLK_AC_BACK)
 	{
-		PAL_Shutdown(0);
+		if (gpGlobals->fInMainGame)
+		{
+			state->dwKeyPress |= kKeyFlee;
+		}
+		else
+		{
+			PAL_Shutdown(0);
+		}
 	}
 	return 0;
 }
@@ -160,34 +167,36 @@ INT UTIL_Platform_Init(int argc, char* argv[])
 	auto fal = Windows::Storage::AccessCache::StorageApplicationPermissions::FutureAccessList;
 	for each (auto entry in fal->Entries)
 	{
-		Windows::Storage::IStorageItem^ item = nullptr;
-		try { item = AWait(fal->GetItemAsync(entry.Token), g_eventHandle); } catch (Exception^) {}
-		if (!item)
+		try
 		{
-			invalid_tokens.push_back(entry.Token);
-			continue;
+			auto item = AWait(fal->GetItemAsync(entry.Token), g_eventHandle);
+			if (dynamic_cast<Windows::Storage::StorageFolder^>(item) != nullptr)
+			{
+				auto localfolder = entry.Metadata;
+				if (localfolder->End()[-1] != L'\\') localfolder += "\\";
+				auto folder = ConvertString(localfolder);
+				folders[folder] = dynamic_cast<Windows::Storage::StorageFolder^>(item);
+				PAL_SetConfigItem(PAL_ConfigIndex(ConvertString(entry.Token).c_str()), ConfigValue{ folder.c_str() });
+				continue;
+			}
+
+			if (dynamic_cast<Windows::Storage::StorageFile^>(item) != nullptr)
+			{
+				auto file = ConvertString(entry.Metadata);
+				files[file] = dynamic_cast<Windows::Storage::StorageFile^>(item);
+				PAL_SetConfigItem(PAL_ConfigIndex(ConvertString(entry.Token).c_str()), ConfigValue{ file.c_str() });
+				continue;
+			}
 		}
-
-		if (dynamic_cast<Windows::Storage::StorageFolder^>(item) != nullptr)
+		catch (Exception^ e)
 		{
-			auto localfolder = entry.Metadata;
-			if (localfolder->End()[-1] != L'\\') localfolder += "\\";
-			auto folder = ConvertString(localfolder);
-			folders[folder] = dynamic_cast<Windows::Storage::StorageFolder^>(item);
-			PAL_SetConfigItem(PAL_ConfigIndex(ConvertString(entry.Token).c_str()), ConfigValue{ folder.c_str() });
-			continue;
-		}
-
-		if (dynamic_cast<Windows::Storage::StorageFile^>(item) != nullptr)
-		{
-			auto file = ConvertString(entry.Metadata);
-			files[file] = dynamic_cast<Windows::Storage::StorageFile^>(item);
-			PAL_SetConfigItem(PAL_ConfigIndex(ConvertString(entry.Token).c_str()), ConfigValue{ file.c_str() });
-			continue;
+			invalid_tokens.push_back(entry.Token);
 		}
 	}
 	for (auto i = invalid_tokens.begin(); i != invalid_tokens.end(); fal->Remove(*i++));
 
+	PAL_RegisterInputFilter(nullptr, input_event_filter, nullptr);
+
 	return 0;
 }