Google Drive Integration

This commit is contained in:
Souryo 2016-05-22 14:43:07 -04:00
parent a9fa9b9ba7
commit 545962cfa7
32 changed files with 986 additions and 56 deletions

View file

@ -58,6 +58,30 @@ namespace Mesen.GUI.Config
}
}
public static string SaveFolder
{
get
{
string movieFolder = Path.Combine(ConfigManager.HomeFolder, "Saves");
if(!Directory.Exists(movieFolder)) {
Directory.CreateDirectory(movieFolder);
}
return movieFolder;
}
}
public static string SaveStateFolder
{
get
{
string movieFolder = Path.Combine(ConfigManager.HomeFolder, "SaveStates");
if(!Directory.Exists(movieFolder)) {
Directory.CreateDirectory(movieFolder);
}
return movieFolder;
}
}
public static string DownloadFolder
{
get

View file

@ -36,6 +36,9 @@ namespace Mesen.GUI.Config
public bool UseAlternativeMmc3Irq = false;
public bool CloudSaveIntegration = false;
public DateTime CloudLastSync = DateTime.MinValue;
public PreferenceInfo()
{
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -35,6 +35,8 @@
<Message ID="UpgradeSuccess">Upgrade completed successfully.</Message>
<Message ID="UpdaterNotFound">The update process could not be started due to missing files.</Message>
<Message ID="Net45NotFound">The Microsoft .NET Framework 4.5 could not be found. Please download and install the latest version of the .NET Framework from Microsoft's website and try again.</Message>
<Message ID="GoogleDriveIntegrationError">Mesen could not connect to your Google Drive account - please try again.</Message>
</Messages>
<Enums>
<Enum ID="ControllerType">

View file

@ -197,6 +197,15 @@
<Control ID="chkRemoveSpriteLimit">Éliminer la limite de sprites (Réduit le clignotement dans certains jeux)</Control>
<Control ID="chkFdsAutoLoadDisk">Insérer le côté A du disque 1 lors du chargement d'un jeu de FDS</Control>
<Control ID="chkFdsFastForwardOnLoad">Augmenter la vitesse d'émulation pendant le chargement des jeux FDS</Control>
<Control ID="tpgCloudSave">Sauvegarde en ligne</Control>
<Control ID="lblGoogleDriveIntegration">Mesen peut utiliser Google Drive pour mettre vos sauvegardes dans votre compte Google Drive. Lorsque l'intégration est activée, toutes les données de sauvegarde de vos jeux (fichiers .sav et sauvegardes rapides) sont facilement accessibles à partir de n'importe quel ordinateur.</Control>
<Control ID="lblIntegrationOK">L'intégration avec Google Drive est active.</Control>
<Control ID="btnDisableIntegration">Désactiver l'intégration Google Drive</Control>
<Control ID="btnEnableIntegration">Activer l'intégration Google Drive</Control>
<Control ID="lblLastSync">Dernière synchronisation : </Control>
<Control ID="btnResync">Resynchroniser</Control>
<Control ID="btnOK">OK</Control>
<Control ID="btnCancel">Annuler</Control>
</Form>
@ -297,8 +306,9 @@
<Message ID="UpdateDownloadFailed">Le téléchargement a échoué - le fichier semble être corrompu. Veuillez visiter le site de Mesen pour télécharger manuellement la version la plus récente.</Message>
<Message ID="UpgradeSuccess">La mise-à-jour s'est faite avec succès.</Message>
<Message ID="UpdaterNotFound">Le processus de mise-à-jour ne peut être démarré puisque certains fichiers sont manquants.</Message>
<Message ID="Net45NotFound">Le .NET Framework 4.5 de Microsoft n'a pas été trouvé. Veuillez télécharger la plus récente version du .NET Framework à partir du site de Microsoft et essayer à nouveau.</Message>
<Message ID="GoogleDriveIntegrationError">Mesen n'a pas été en mesure de se connecter à votre compte Google Drive, veuillez essayer à nouveau.</Message>
</Messages>
<Enums>
<Enum ID="ControllerType">

View file

@ -197,6 +197,15 @@
<Control ID="chkRemoveSpriteLimit">スプライトの制限を解除 (点滅を軽減する)</Control>
<Control ID="chkFdsAutoLoadDisk">ファミコンディスクシステムのゲームをロードする時に自動的にディスクのA面を入れる</Control>
<Control ID="chkFdsFastForwardOnLoad">ファミコンディスクシステムのゲームをディスクからロードする時に自動的に最高速度にする</Control>
<Control ID="tpgCloudSave">クラウドバックアップ</Control>
<Control ID="lblGoogleDriveIntegration">MesenはGoogle Driveを利用することでクラウドバックアップが出来ます。 Google Drive同期を有効にすれば、ゲームのセーブデータはGoogle Driveにバックアップされ、どんなパソコンからのアクセスが可能になります。</Control>
<Control ID="lblIntegrationOK">Google Drive同期は有効です。</Control>
<Control ID="btnDisableIntegration">Google Drive同期を無効にする</Control>
<Control ID="btnEnableIntegration">Google Drive同期を有効にする</Control>
<Control ID="btnResync">同期</Control>
<Control ID="lblLastSync">最終同期: </Control>
<Control ID="btnOK">OK</Control>
<Control ID="btnCancel">キャンセル</Control>
</Form>
@ -290,8 +299,9 @@
<Message ID="UpdateDownloadFailed">ダウンロードは失敗しました。 Mesenのサイトに行って、新しいバージョンをダウンロードしてください。</Message>
<Message ID="UpdaterNotFound">必要不可欠なファイルがないため、アップデートは出来なかった。</Message>
<Message ID="UpgradeSuccess">アップデートは完了しました。</Message>
<Message ID="Net45NotFound">Microsoft .NET Framework 4.5はインストールされていないため、Mesenは起動できません。Microsoft .NET Frameworkの最新版をMicrosoftのサイトからダウンロードして、インストールしてください。</Message>
<Message ID="GoogleDriveIntegrationError">MesenはGoogle Driveにアクセス出来ませんでした。</Message>
</Messages>
<Enums>
<Enum ID="ControllerType">

View file

@ -27,6 +27,8 @@
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(frmPreferences));
this.tlpMain = new System.Windows.Forms.TableLayoutPanel();
this.chkSingleInstance = new System.Windows.Forms.CheckBox();
this.chkAutomaticallyCheckForUpdates = new System.Windows.Forms.CheckBox();
@ -42,6 +44,20 @@
this.cboDisplayLanguage = new System.Windows.Forms.ComboBox();
this.tabMain = new System.Windows.Forms.TabControl();
this.tpgGeneral = new System.Windows.Forms.TabPage();
this.tpgCloudSave = new System.Windows.Forms.TabPage();
this.tlpCloudSaves = new System.Windows.Forms.TableLayoutPanel();
this.tlpCloudSaveDesc = new System.Windows.Forms.TableLayoutPanel();
this.lblGoogleDriveIntegration = new System.Windows.Forms.Label();
this.btnEnableIntegration = new System.Windows.Forms.Button();
this.tlpCloudSaveEnabled = new System.Windows.Forms.TableLayoutPanel();
this.btnDisableIntegration = new System.Windows.Forms.Button();
this.flowLayoutPanel3 = new System.Windows.Forms.FlowLayoutPanel();
this.picOK = new System.Windows.Forms.PictureBox();
this.lblIntegrationOK = new System.Windows.Forms.Label();
this.flowLayoutPanel4 = new System.Windows.Forms.FlowLayoutPanel();
this.lblLastSync = new System.Windows.Forms.Label();
this.lblLastSyncDateTime = new System.Windows.Forms.Label();
this.btnResync = new System.Windows.Forms.Button();
this.tpgFileAssociations = new System.Windows.Forms.TabPage();
this.grpFileAssociations = new System.Windows.Forms.GroupBox();
this.tlpFileFormat = new System.Windows.Forms.TableLayoutPanel();
@ -56,10 +72,18 @@
this.chkRemoveSpriteLimit = new System.Windows.Forms.CheckBox();
this.chkFdsAutoLoadDisk = new System.Windows.Forms.CheckBox();
this.chkFdsFastForwardOnLoad = new System.Windows.Forms.CheckBox();
this.tmrSyncDateTime = new System.Windows.Forms.Timer(this.components);
this.tlpMain.SuspendLayout();
this.flowLayoutPanel2.SuspendLayout();
this.tabMain.SuspendLayout();
this.tpgGeneral.SuspendLayout();
this.tpgCloudSave.SuspendLayout();
this.tlpCloudSaves.SuspendLayout();
this.tlpCloudSaveDesc.SuspendLayout();
this.tlpCloudSaveEnabled.SuspendLayout();
this.flowLayoutPanel3.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picOK)).BeginInit();
this.flowLayoutPanel4.SuspendLayout();
this.tpgFileAssociations.SuspendLayout();
this.grpFileAssociations.SuspendLayout();
this.tlpFileFormat.SuspendLayout();
@ -69,7 +93,7 @@
//
// baseConfigPanel
//
this.baseConfigPanel.Location = new System.Drawing.Point(0, 270);
this.baseConfigPanel.Location = new System.Drawing.Point(0, 255);
this.baseConfigPanel.Size = new System.Drawing.Size(458, 29);
//
// tlpMain
@ -100,7 +124,7 @@
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.Size = new System.Drawing.Size(444, 238);
this.tlpMain.Size = new System.Drawing.Size(444, 223);
this.tlpMain.TabIndex = 1;
//
// chkSingleInstance
@ -188,7 +212,7 @@
// btnOpenMesenFolder
//
this.btnOpenMesenFolder.AutoSize = true;
this.btnOpenMesenFolder.Location = new System.Drawing.Point(3, 212);
this.btnOpenMesenFolder.Location = new System.Drawing.Point(3, 197);
this.btnOpenMesenFolder.Name = "btnOpenMesenFolder";
this.btnOpenMesenFolder.Size = new System.Drawing.Size(117, 23);
this.btnOpenMesenFolder.TabIndex = 16;
@ -228,13 +252,14 @@
// tabMain
//
this.tabMain.Controls.Add(this.tpgGeneral);
this.tabMain.Controls.Add(this.tpgCloudSave);
this.tabMain.Controls.Add(this.tpgFileAssociations);
this.tabMain.Controls.Add(this.tpgAdvanced);
this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabMain.Location = new System.Drawing.Point(0, 0);
this.tabMain.Name = "tabMain";
this.tabMain.SelectedIndex = 0;
this.tabMain.Size = new System.Drawing.Size(458, 270);
this.tabMain.Size = new System.Drawing.Size(458, 255);
this.tabMain.TabIndex = 2;
//
// tpgGeneral
@ -243,18 +268,186 @@
this.tpgGeneral.Location = new System.Drawing.Point(4, 22);
this.tpgGeneral.Name = "tpgGeneral";
this.tpgGeneral.Padding = new System.Windows.Forms.Padding(3);
this.tpgGeneral.Size = new System.Drawing.Size(450, 244);
this.tpgGeneral.Size = new System.Drawing.Size(450, 229);
this.tpgGeneral.TabIndex = 0;
this.tpgGeneral.Text = "General";
this.tpgGeneral.UseVisualStyleBackColor = true;
//
// tpgCloudSave
//
this.tpgCloudSave.Controls.Add(this.tlpCloudSaves);
this.tpgCloudSave.Location = new System.Drawing.Point(4, 22);
this.tpgCloudSave.Name = "tpgCloudSave";
this.tpgCloudSave.Padding = new System.Windows.Forms.Padding(3);
this.tpgCloudSave.Size = new System.Drawing.Size(450, 229);
this.tpgCloudSave.TabIndex = 3;
this.tpgCloudSave.Text = "Cloud Saves";
this.tpgCloudSave.UseVisualStyleBackColor = true;
//
// tlpCloudSaves
//
this.tlpCloudSaves.ColumnCount = 1;
this.tlpCloudSaves.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpCloudSaves.Controls.Add(this.tlpCloudSaveDesc, 0, 0);
this.tlpCloudSaves.Controls.Add(this.tlpCloudSaveEnabled, 0, 1);
this.tlpCloudSaves.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpCloudSaves.Location = new System.Drawing.Point(3, 3);
this.tlpCloudSaves.Name = "tlpCloudSaves";
this.tlpCloudSaves.RowCount = 2;
this.tlpCloudSaves.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpCloudSaves.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpCloudSaves.Size = new System.Drawing.Size(444, 223);
this.tlpCloudSaves.TabIndex = 0;
//
// tlpCloudSaveDesc
//
this.tlpCloudSaveDesc.ColumnCount = 1;
this.tlpCloudSaveDesc.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpCloudSaveDesc.Controls.Add(this.lblGoogleDriveIntegration, 0, 0);
this.tlpCloudSaveDesc.Controls.Add(this.btnEnableIntegration, 0, 1);
this.tlpCloudSaveDesc.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpCloudSaveDesc.Location = new System.Drawing.Point(0, 0);
this.tlpCloudSaveDesc.Margin = new System.Windows.Forms.Padding(0);
this.tlpCloudSaveDesc.Name = "tlpCloudSaveDesc";
this.tlpCloudSaveDesc.RowCount = 2;
this.tlpCloudSaveDesc.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpCloudSaveDesc.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpCloudSaveDesc.Size = new System.Drawing.Size(444, 100);
this.tlpCloudSaveDesc.TabIndex = 0;
//
// lblGoogleDriveIntegration
//
this.lblGoogleDriveIntegration.AutoSize = true;
this.lblGoogleDriveIntegration.Location = new System.Drawing.Point(3, 0);
this.lblGoogleDriveIntegration.Name = "lblGoogleDriveIntegration";
this.lblGoogleDriveIntegration.Size = new System.Drawing.Size(436, 52);
this.lblGoogleDriveIntegration.TabIndex = 0;
this.lblGoogleDriveIntegration.Text = resources.GetString("lblGoogleDriveIntegration.Text");
this.lblGoogleDriveIntegration.UseWaitCursor = true;
//
// btnEnableIntegration
//
this.btnEnableIntegration.Location = new System.Drawing.Point(3, 55);
this.btnEnableIntegration.Name = "btnEnableIntegration";
this.btnEnableIntegration.Size = new System.Drawing.Size(172, 23);
this.btnEnableIntegration.TabIndex = 1;
this.btnEnableIntegration.Text = "Enable Google Drive Integration";
this.btnEnableIntegration.UseVisualStyleBackColor = true;
this.btnEnableIntegration.Click += new System.EventHandler(this.btnEnableIntegration_Click);
//
// tlpCloudSaveEnabled
//
this.tlpCloudSaveEnabled.ColumnCount = 1;
this.tlpCloudSaveEnabled.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpCloudSaveEnabled.Controls.Add(this.btnDisableIntegration, 0, 2);
this.tlpCloudSaveEnabled.Controls.Add(this.flowLayoutPanel3, 0, 0);
this.tlpCloudSaveEnabled.Controls.Add(this.flowLayoutPanel4, 0, 1);
this.tlpCloudSaveEnabled.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpCloudSaveEnabled.Location = new System.Drawing.Point(0, 100);
this.tlpCloudSaveEnabled.Margin = new System.Windows.Forms.Padding(0);
this.tlpCloudSaveEnabled.Name = "tlpCloudSaveEnabled";
this.tlpCloudSaveEnabled.RowCount = 4;
this.tlpCloudSaveEnabled.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpCloudSaveEnabled.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpCloudSaveEnabled.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpCloudSaveEnabled.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tlpCloudSaveEnabled.Size = new System.Drawing.Size(444, 123);
this.tlpCloudSaveEnabled.TabIndex = 1;
//
// btnDisableIntegration
//
this.btnDisableIntegration.Location = new System.Drawing.Point(3, 53);
this.btnDisableIntegration.Name = "btnDisableIntegration";
this.btnDisableIntegration.Size = new System.Drawing.Size(172, 23);
this.btnDisableIntegration.TabIndex = 2;
this.btnDisableIntegration.Text = "Disable Google Drive Integration";
this.btnDisableIntegration.UseVisualStyleBackColor = true;
this.btnDisableIntegration.Click += new System.EventHandler(this.btnDisableIntegration_Click);
//
// flowLayoutPanel3
//
this.flowLayoutPanel3.Controls.Add(this.picOK);
this.flowLayoutPanel3.Controls.Add(this.lblIntegrationOK);
this.flowLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutPanel3.Location = new System.Drawing.Point(0, 0);
this.flowLayoutPanel3.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel3.Name = "flowLayoutPanel3";
this.flowLayoutPanel3.Size = new System.Drawing.Size(444, 22);
this.flowLayoutPanel3.TabIndex = 1;
//
// picOK
//
this.picOK.Image = global::Mesen.GUI.Properties.Resources.Accept;
this.picOK.Location = new System.Drawing.Point(3, 3);
this.picOK.Name = "picOK";
this.picOK.Size = new System.Drawing.Size(16, 16);
this.picOK.TabIndex = 0;
this.picOK.TabStop = false;
//
// lblIntegrationOK
//
this.lblIntegrationOK.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblIntegrationOK.AutoSize = true;
this.lblIntegrationOK.Location = new System.Drawing.Point(25, 4);
this.lblIntegrationOK.Name = "lblIntegrationOK";
this.lblIntegrationOK.Size = new System.Drawing.Size(166, 13);
this.lblIntegrationOK.TabIndex = 1;
this.lblIntegrationOK.Text = "Google Drive integration is active.";
//
// flowLayoutPanel4
//
this.flowLayoutPanel4.Controls.Add(this.lblLastSync);
this.flowLayoutPanel4.Controls.Add(this.lblLastSyncDateTime);
this.flowLayoutPanel4.Controls.Add(this.btnResync);
this.flowLayoutPanel4.Location = new System.Drawing.Point(0, 22);
this.flowLayoutPanel4.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel4.Name = "flowLayoutPanel4";
this.flowLayoutPanel4.Size = new System.Drawing.Size(444, 28);
this.flowLayoutPanel4.TabIndex = 3;
//
// lblLastSync
//
this.lblLastSync.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblLastSync.AutoSize = true;
this.lblLastSync.Location = new System.Drawing.Point(3, 9);
this.lblLastSync.Name = "lblLastSync";
this.lblLastSync.Size = new System.Drawing.Size(57, 13);
this.lblLastSync.TabIndex = 0;
this.lblLastSync.Text = "Last Sync:";
//
// lblLastSyncDateTime
//
this.lblLastSyncDateTime.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblLastSyncDateTime.AutoSize = true;
this.lblLastSyncDateTime.Location = new System.Drawing.Point(66, 9);
this.lblLastSyncDateTime.Name = "lblLastSyncDateTime";
this.lblLastSyncDateTime.Size = new System.Drawing.Size(114, 13);
this.lblLastSyncDateTime.TabIndex = 1;
this.lblLastSyncDateTime.Text = "9999/01/01 12:00 PM";
//
// btnResync
//
this.btnResync.AutoSize = true;
this.btnResync.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnResync.Image = global::Mesen.GUI.Properties.Resources.Reset;
this.btnResync.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnResync.Location = new System.Drawing.Point(186, 3);
this.btnResync.MinimumSize = new System.Drawing.Size(0, 25);
this.btnResync.Name = "btnResync";
this.btnResync.Size = new System.Drawing.Size(69, 25);
this.btnResync.TabIndex = 4;
this.btnResync.Text = "Resync";
this.btnResync.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
this.btnResync.UseVisualStyleBackColor = true;
this.btnResync.Click += new System.EventHandler(this.btnResync_Click);
//
// tpgFileAssociations
//
this.tpgFileAssociations.Controls.Add(this.grpFileAssociations);
this.tpgFileAssociations.Location = new System.Drawing.Point(4, 22);
this.tpgFileAssociations.Name = "tpgFileAssociations";
this.tpgFileAssociations.Padding = new System.Windows.Forms.Padding(3);
this.tpgFileAssociations.Size = new System.Drawing.Size(450, 244);
this.tpgFileAssociations.Size = new System.Drawing.Size(450, 229);
this.tpgFileAssociations.TabIndex = 2;
this.tpgFileAssociations.Text = "File Associations";
this.tpgFileAssociations.UseVisualStyleBackColor = true;
@ -265,7 +458,7 @@
this.grpFileAssociations.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpFileAssociations.Location = new System.Drawing.Point(3, 3);
this.grpFileAssociations.Name = "grpFileAssociations";
this.grpFileAssociations.Size = new System.Drawing.Size(444, 238);
this.grpFileAssociations.Size = new System.Drawing.Size(444, 223);
this.grpFileAssociations.TabIndex = 12;
this.grpFileAssociations.TabStop = false;
this.grpFileAssociations.Text = "File Associations";
@ -287,7 +480,7 @@
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tlpFileFormat.Size = new System.Drawing.Size(438, 219);
this.tlpFileFormat.Size = new System.Drawing.Size(438, 204);
this.tlpFileFormat.TabIndex = 0;
//
// chkNesFormat
@ -337,7 +530,7 @@
this.tpgAdvanced.Location = new System.Drawing.Point(4, 22);
this.tpgAdvanced.Name = "tpgAdvanced";
this.tpgAdvanced.Padding = new System.Windows.Forms.Padding(3);
this.tpgAdvanced.Size = new System.Drawing.Size(450, 244);
this.tpgAdvanced.Size = new System.Drawing.Size(450, 229);
this.tpgAdvanced.TabIndex = 1;
this.tpgAdvanced.Text = "Advanced";
this.tpgAdvanced.UseVisualStyleBackColor = true;
@ -361,7 +554,7 @@
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(444, 238);
this.tableLayoutPanel1.Size = new System.Drawing.Size(444, 223);
this.tableLayoutPanel1.TabIndex = 0;
//
// chkUseAlternativeMmc3Irq
@ -414,15 +607,21 @@
this.chkFdsFastForwardOnLoad.Text = "Automatically fast forward FDS games when disk or BIOS is loading";
this.chkFdsFastForwardOnLoad.UseVisualStyleBackColor = true;
//
// tmrSyncDateTime
//
this.tmrSyncDateTime.Enabled = true;
this.tmrSyncDateTime.Tick += new System.EventHandler(this.tmrSyncDateTime_Tick);
//
// frmPreferences
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(458, 299);
this.ClientSize = new System.Drawing.Size(458, 284);
this.Controls.Add(this.tabMain);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.MinimumSize = new System.Drawing.Size(474, 322);
this.Name = "frmPreferences";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Preferences";
@ -434,6 +633,16 @@
this.flowLayoutPanel2.PerformLayout();
this.tabMain.ResumeLayout(false);
this.tpgGeneral.ResumeLayout(false);
this.tpgCloudSave.ResumeLayout(false);
this.tlpCloudSaves.ResumeLayout(false);
this.tlpCloudSaveDesc.ResumeLayout(false);
this.tlpCloudSaveDesc.PerformLayout();
this.tlpCloudSaveEnabled.ResumeLayout(false);
this.flowLayoutPanel3.ResumeLayout(false);
this.flowLayoutPanel3.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picOK)).EndInit();
this.flowLayoutPanel4.ResumeLayout(false);
this.flowLayoutPanel4.PerformLayout();
this.tpgFileAssociations.ResumeLayout(false);
this.grpFileAssociations.ResumeLayout(false);
this.tlpFileFormat.ResumeLayout(false);
@ -476,5 +685,20 @@
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2;
private System.Windows.Forms.Label lblDisplayLanguage;
private System.Windows.Forms.ComboBox cboDisplayLanguage;
private System.Windows.Forms.TabPage tpgCloudSave;
private System.Windows.Forms.TableLayoutPanel tlpCloudSaves;
private System.Windows.Forms.TableLayoutPanel tlpCloudSaveDesc;
private System.Windows.Forms.Label lblGoogleDriveIntegration;
private System.Windows.Forms.Button btnEnableIntegration;
private System.Windows.Forms.TableLayoutPanel tlpCloudSaveEnabled;
private System.Windows.Forms.Button btnDisableIntegration;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel3;
private System.Windows.Forms.PictureBox picOK;
private System.Windows.Forms.Label lblIntegrationOK;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel4;
private System.Windows.Forms.Label lblLastSync;
private System.Windows.Forms.Label lblLastSyncDateTime;
private System.Windows.Forms.Timer tmrSyncDateTime;
private System.Windows.Forms.Button btnResync;
}
}

View file

@ -8,6 +8,7 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Config;
using Mesen.GUI.GoogleDriveIntegration;
namespace Mesen.GUI.Forms.Config
{
@ -40,6 +41,8 @@ namespace Mesen.GUI.Forms.Config
AddBinding("AllowBackgroundInput", chkAllowBackgroundInput);
AddBinding("PauseOnMovieEnd", chkPauseOnMovieEnd);
UpdateCloudDisplay();
}
protected override void OnFormClosed(FormClosedEventArgs e)
@ -60,5 +63,64 @@ namespace Mesen.GUI.Forms.Config
{
System.Diagnostics.Process.Start(ConfigManager.HomeFolder);
}
private void UpdateCloudDisplay()
{
if(!this.IsDisposed) {
if(this.InvokeRequired) {
this.BeginInvoke((MethodInvoker)(() => this.UpdateCloudDisplay()));
} else {
this.tlpCloudSaveDesc.Visible = !ConfigManager.Config.PreferenceInfo.CloudSaveIntegration;
this.tlpCloudSaveEnabled.Visible = ConfigManager.Config.PreferenceInfo.CloudSaveIntegration;
}
}
}
private void TryEnableSync(bool retry = true)
{
if(CloudSyncHelper.EnableSync()) {
if(!CloudSyncHelper.Sync()) {
if(retry) {
TryEnableSync(false);
} else {
MesenMsgBox.Show("GoogleDriveIntegrationError", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
} else {
UpdateCloudDisplay();
}
} else {
MesenMsgBox.Show("GoogleDriveIntegrationError", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void btnEnableIntegration_Click(object sender, EventArgs e)
{
Task.Run(() => TryEnableSync());
}
private void btnDisableIntegration_Click(object sender, EventArgs e)
{
Task.Run(() => {
CloudSyncHelper.DisableSync();
UpdateCloudDisplay();
});
}
private void tmrSyncDateTime_Tick(object sender, EventArgs e)
{
btnDisableIntegration.Enabled = !CloudSyncHelper.Syncing;
btnResync.Enabled = btnDisableIntegration.Enabled;
if(ConfigManager.Config.PreferenceInfo.CloudLastSync != DateTime.MinValue) {
lblLastSyncDateTime.Text = ConfigManager.Config.PreferenceInfo.CloudLastSync.ToLongDateString() + " " + ConfigManager.Config.PreferenceInfo.CloudLastSync.ToLongTimeString();
} else {
lblLastSyncDateTime.Text = "";
}
}
private void btnResync_Click(object sender, EventArgs e)
{
Task.Run(() => CloudSyncHelper.Sync());
}
}
}

View file

@ -120,4 +120,10 @@
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<data name="lblGoogleDriveIntegration.Text" xml:space="preserve">
<value>Mesen can integrate with Google Drive to keep your save data in the cloud. When Google Drive integration is enabled, your save data is easily accessible from any computer and is synced between computers. Additionally, save data stored on Google Drive can be restored in the event it is erased from your computer.</value>
</data>
<metadata name="tmrSyncDateTime.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>110, 17</value>
</metadata>
</root>

View file

@ -14,7 +14,11 @@ namespace Mesen.GUI.Forms
string resourceText = ResourceHelper.GetMessage(text, args);
if(resourceText.StartsWith("[[")) {
return MessageBox.Show(string.Format("Critical error (" + text + ") {0}", args), "Mesen", buttons, icon);
if(args != null && args.Length > 0) {
return MessageBox.Show(string.Format("Critical error (" + text + ") {0}", args), "Mesen", buttons, icon);
} else {
return MessageBox.Show(string.Format("Critical error (" + text + ")"), "Mesen", buttons, icon);
}
} else {
return MessageBox.Show(ResourceHelper.GetMessage(text, args), "Mesen", buttons, icon);
}

View file

@ -18,19 +18,7 @@ namespace Mesen.GUI.Forms
if(disposing && (components != null)) {
components.Dispose();
}
if(_notifListener != null) {
_notifListener.Dispose();
_notifListener = null;
}
if(_debugger != null) {
_debugger.Close();
}
ConfigManager.Config.VideoInfo.VideoScale = _regularScale;
ConfigManager.ApplyChanges();
StopEmu();
InteropEmu.Release();
base.Dispose(disposing);
}

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
@ -15,6 +16,7 @@ using Mesen.GUI.Debugger;
using Mesen.GUI.Forms.Cheats;
using Mesen.GUI.Forms.Config;
using Mesen.GUI.Forms.NetPlay;
using Mesen.GUI.GoogleDriveIntegration;
namespace Mesen.GUI.Forms
{
@ -73,6 +75,10 @@ namespace Mesen.GUI.Forms
UpdateViewerSize();
if(ConfigManager.Config.PreferenceInfo.CloudSaveIntegration) {
Task.Run(() => CloudSyncHelper.Sync());
}
if(_romToLoad != null) {
LoadFile(this._romToLoad);
}
@ -89,6 +95,30 @@ namespace Mesen.GUI.Forms
PerformUpgrade();
}
protected override void OnClosing(CancelEventArgs e)
{
if(_notifListener != null) {
_notifListener.Dispose();
_notifListener = null;
}
if(_debugger != null) {
_debugger.Close();
}
ConfigManager.Config.VideoInfo.VideoScale = _regularScale;
ConfigManager.ApplyChanges();
StopEmu();
if(ConfigManager.Config.PreferenceInfo.CloudSaveIntegration) {
CloudSyncHelper.Sync();
}
InteropEmu.Release();
base.OnClosing(e);
}
void PerformUpgrade()
{
if(new Version(ConfigManager.Config.MesenVersion) < new Version(InteropEmu.GetMesenVersion())) {

View file

@ -147,6 +147,46 @@
<SignManifests>false</SignManifests>
</PropertyGroup>
<ItemGroup>
<Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Dependencies\BouncyCastle.Crypto.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Google.Apis, Version=1.13.0.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Dependencies\Google.Apis.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Google.Apis.Auth, Version=1.13.0.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Dependencies\Google.Apis.Auth.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Google.Apis.Auth.PlatformServices, Version=1.13.0.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Dependencies\Google.Apis.Auth.PlatformServices.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Google.Apis.Core, Version=1.13.0.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Dependencies\Google.Apis.Core.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Google.Apis.Drive.v3, Version=1.13.0.483, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Dependencies\Google.Apis.Drive.v3.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Google.Apis.PlatformServices, Version=1.13.0.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Dependencies\Google.Apis.PlatformServices.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Dependencies\Newtonsoft.Json.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO.Compression" />
@ -160,6 +200,11 @@
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="UIAutomationClient" />
<Reference Include="Zlib.Portable, Version=1.11.0.0, Culture=neutral, PublicKeyToken=431cba815f6a8b5b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Dependencies\Zlib.Portable.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Config\PreferenceInfo.cs" />
@ -425,6 +470,9 @@
<DependentUpon>frmServerConfig.cs</DependentUpon>
</Compile>
<Compile Include="Forms\ResourceHelper.cs" />
<Compile Include="GoogleDriveIntegration\CloudSyncHelper.cs" />
<Compile Include="GoogleDriveIntegration\GoogleDriveAccessor.cs" />
<Compile Include="GoogleDriveIntegration\MesenCodeReceiver.cs" />
<Compile Include="InteropEmu.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@ -520,6 +568,7 @@
</EmbeddedResource>
<EmbeddedResource Include="Forms\Config\frmPreferences.resx">
<DependentUpon>frmPreferences.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Config\frmVideoConfig.resx">
<DependentUpon>frmVideoConfig.cs</DependentUpon>
@ -567,12 +616,6 @@
<None Include="Dependencies\Font.64.spritefont">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Dependencies\MSVCx64.zip">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Dependencies\MSVCx86.zip">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
@ -584,9 +627,33 @@
</Compile>
</ItemGroup>
<ItemGroup>
<Content Include="Dependencies\BouncyCastle.Crypto.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Dependencies\Google.Apis.Auth.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Dependencies\Google.Apis.Auth.PlatformServices.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Dependencies\Google.Apis.Core.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Dependencies\Google.Apis.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Dependencies\Google.Apis.Drive.v3.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Dependencies\Google.Apis.PlatformServices.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Dependencies\LICENSE.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Dependencies\Newtonsoft.Json.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Dependencies\resources.en.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<SubType>Designer</SubType>
@ -603,7 +670,11 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<SubType>Designer</SubType>
</Content>
<Content Include="Dependencies\Zlib.Portable.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Icon.ico" />
<None Include="Resources\accept.png" />
<Content Include="Resources\coins.png" />
<None Include="Resources\DipSwitches.png" />
<None Include="Resources\MesenIcon.png" />
@ -647,21 +718,13 @@ if "x64" == "$(PlatformName)" copy "C:\Program Files (x86)\Microsoft Visual Stud
if "PGO Optimize" == "$(ConfigurationName)" (
copy "$(SolutionDir)bin\x86\PGO Profile\WinMesen.dll" "Dependencies\WinMesen.x86.dll"
copy "$(SolutionDir)bin\x86\PGO Profile\BlipBuffer.dll" "Dependencies\BlipBuffer.x86.dll"
copy "$(SolutionDir)bin\x86\PGO Profile\NesNtsc.dll" "Dependencies\NesNtsc.x86.dll"
copy "$(SolutionDir)bin\x64\PGO Profile\WinMesen.dll" "Dependencies\WinMesen.x64.dll"
copy "$(SolutionDir)bin\x64\PGO Profile\BlipBuffer.dll" "Dependencies\BlipBuffer.x64.dll"
copy "$(SolutionDir)bin\x64\PGO Profile\NesNtsc.dll" "Dependencies\NesNtsc.x64.dll"
)
if NOT "PGO Optimize" == "$(ConfigurationName)" (
copy "$(SolutionDir)bin\x86\$(ConfigurationName)\WinMesen.dll" "Dependencies\WinMesen.x86.dll"
copy "$(SolutionDir)bin\x86\$(ConfigurationName)\BlipBuffer.dll" "Dependencies\BlipBuffer.x86.dll"
copy "$(SolutionDir)bin\x86\$(ConfigurationName)\NesNtsc.dll" "Dependencies\NesNtsc.x86.dll"
copy "$(SolutionDir)bin\x64\$(ConfigurationName)\WinMesen.dll" "Dependencies\WinMesen.x64.dll"
copy "$(SolutionDir)bin\x64\$(ConfigurationName)\BlipBuffer.dll" "Dependencies\BlipBuffer.x64.dll"
copy "$(SolutionDir)bin\x64\$(ConfigurationName)\NesNtsc.dll" "Dependencies\NesNtsc.x64.dll"
)
copy "MesenUpdater.exe" "Dependencies\MesenUpdater.exe"
call DependencyPacker.exe

View file

@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Mesen.GUI.Config;
namespace Mesen.GUI.GoogleDriveIntegration
{
public class CloudSyncHelper
{
private static object _lock = new object();
private static GoogleDriveAccessor _accessor;
public static bool Syncing
{
get
{
bool lockTaken = false;
System.Threading.Monitor.TryEnter(_lock, ref lockTaken);
if(lockTaken) {
System.Threading.Monitor.Exit(_lock);
}
return !lockTaken;
}
}
public static bool Sync()
{
if(!System.Threading.Monitor.TryEnter(_lock)) {
//Already syncing, return when on-going sync is done
lock(_lock) {
return true;
}
} else {
try {
InteropEmu.DisplayMessage("Google Drive", "Synchronization started.");
using(_accessor = new GoogleDriveAccessor()) {
if(!CloudSyncHelper.DownloadData()) {
InteropEmu.DisplayMessage("Google Drive", "Synchronization failed.");
ConfigManager.Config.PreferenceInfo.CloudLastSync = DateTime.Now;
ConfigManager.ApplyChanges();
return false;
}
CloudSyncHelper.UploadData();
InteropEmu.DisplayMessage("Google Drive", "Synchronization completed.");
ConfigManager.Config.PreferenceInfo.CloudLastSync = DateTime.Now;
ConfigManager.ApplyChanges();
return true;
}
} finally {
System.Threading.Monitor.Exit(_lock);
}
}
}
public static bool EnableSync()
{
using(_accessor = new GoogleDriveAccessor()) {
bool result = _accessor.AcquireToken();
if(result) {
ConfigManager.RejectChanges();
ConfigManager.Config.PreferenceInfo.CloudSaveIntegration = true;
ConfigManager.ApplyChanges();
}
return result;
}
}
public static void DisableSync()
{
using(_accessor = new GoogleDriveAccessor()) {
_accessor.RevokeToken();
}
ConfigManager.RejectChanges();
ConfigManager.Config.PreferenceInfo.CloudSaveIntegration = false;
ConfigManager.ApplyChanges();
}
private static bool UploadData()
{
using(MemoryStream stream = CloudSyncHelper.GetDataStream()) {
var gdAccessor = new GoogleDriveAccessor();
return _accessor.UploadFile(stream, "MesenData.zip");
}
}
private static bool DownloadData()
{
using(MemoryStream stream = new MemoryStream()) {
bool result = _accessor.DownloadFile(stream, "MesenData.zip");
if(result) {
stream.Position = 0;
string homeFolder = ConfigManager.HomeFolder;
//Make sure the folders exist
string saveFolder = ConfigManager.SaveFolder;
string saveStateFolder = ConfigManager.SaveStateFolder;
using(ZipArchive archive = new ZipArchive(stream)) {
foreach(ZipArchiveEntry entry in archive.Entries) {
if(!string.IsNullOrWhiteSpace(entry.Name)) {
string[] fileAndFolder = entry.FullName.Split('/');
string fileName = Path.Combine(homeFolder, fileAndFolder[0], fileAndFolder[1]);
if(!File.Exists(fileName) || File.GetLastWriteTime(fileName) < entry.LastWriteTime.ToLocalTime()) {
//File on server is more recent, or doesn't exist on local computer, extract it
entry.ExtractToFile(fileName, true);
}
}
}
}
} else if(_accessor.Revoked) {
ConfigManager.Config.PreferenceInfo.CloudSaveIntegration = false;
ConfigManager.ApplyChanges();
}
return result;
}
}
private static MemoryStream GetDataStream()
{
MemoryStream outputStream = new MemoryStream();
using(ZipArchive archive = new ZipArchive(outputStream, ZipArchiveMode.Create, true)) {
archive.CreateEntry("Saves/");
foreach(string filename in System.IO.Directory.EnumerateFiles(ConfigManager.SaveFolder, "*.sav", System.IO.SearchOption.AllDirectories)) {
archive.CreateEntryFromFile(filename, "Saves/" + System.IO.Path.GetFileName(filename));
}
archive.CreateEntry("SaveStates/");
foreach(string filename in System.IO.Directory.EnumerateFiles(ConfigManager.SaveStateFolder, "*.mst", System.IO.SearchOption.AllDirectories)) {
archive.CreateEntryFromFile(filename, "SaveStates/" + System.IO.Path.GetFileName(filename));
}
}
return outputStream;
}
}
}

View file

@ -0,0 +1,203 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Responses;
using Google.Apis.Download;
using Google.Apis.Drive.v3;
using Google.Apis.Drive.v3.Data;
using Google.Apis.Services;
using Google.Apis.Upload;
namespace Mesen.GUI.GoogleDriveIntegration
{
public class GoogleDriveAccessor : IDisposable
{
private const string _contentType = @"application/zip";
private readonly string[] _scopes = new[] { DriveService.Scope.DriveAppdata };
private File _driveFile = null;
private UserCredential _credentials = null;
private DriveService _service = null;
private bool _connected = false;
private bool _revoked = false;
public bool Revoked { get { return _revoked; } }
public bool UploadFile(System.IO.MemoryStream fileStream, string filename)
{
fileStream.Position = 0;
try {
this.Connect().GetAwaiter().GetResult();
if(_connected) {
this.UploadFileAsync(fileStream, filename).GetAwaiter().GetResult();
}
} catch(TokenResponseException ex) {
_revoked = true;
_connected = false;
_credentials = null;
_service = null;
} catch {
_connected = false;
_credentials = null;
_service = null;
}
return _connected;
}
public bool DownloadFile(System.IO.MemoryStream fileStream, string filename)
{
try {
this.Connect().GetAwaiter().GetResult();
if(_connected) {
this.DownloadFileAsync(fileStream, filename).GetAwaiter().GetResult();
}
} catch(TokenResponseException ex) {
_revoked = true;
_connected = false;
_credentials = null;
_service = null;
} catch {
_connected = false;
_credentials = null;
_service = null;
}
return _connected;
}
public bool AcquireToken()
{
this.Connect().GetAwaiter().GetResult();
return _connected;
}
public void RevokeToken()
{
Task.Run(async () => {
try {
_credentials = await this.GetCredentials().ConfigureAwait(false);
await _credentials.RevokeTokenAsync(CancellationToken.None).ConfigureAwait(false);
} catch {
}
_service = null;
_credentials = null;
}).Wait();
}
private async Task Connect()
{
if(_service == null) {
try {
_credentials = await this.GetCredentials().ConfigureAwait(false);
_service = new DriveService(new BaseClientService.Initializer() {
HttpClientInitializer = _credentials,
ApplicationName = "Mesen",
});
_connected = true;
} catch(AggregateException ex) {
foreach(Exception innerException in ex.InnerExceptions) {
if(innerException is TokenResponseException) {
_connected = false;
_revoked = true;
}
}
_connected = false;
_credentials = null;
_service = null;
} catch {
_connected = false;
_credentials = null;
_service = null;
}
}
}
private async Task<UserCredential> GetCredentials()
{
var clientSecrets = new ClientSecrets { ClientId = "478233037635-nf90q052c32suhm0l8r9fkkk34k7hkl5.apps.googleusercontent.com", ClientSecret = "zGatV81vs5kKuhHq3fZuw4lc" };
GoogleWebAuthorizationBroker.Folder = System.IO.Path.Combine(Config.ConfigManager.HomeFolder, "GoogleDrive");
return await GoogleWebAuthorizationBroker.AuthorizeAsync(clientSecrets, _scopes, Environment.UserName, CancellationToken.None, codeReceiver: new MesenCodeReceiver()).ConfigureAwait(false);
}
private File GetFileMatchingName(string filename)
{
var listService = _service.Files.List();
listService.Spaces = "appDataFolder";
foreach(File file in listService.Execute().Files) {
if(file.Name == filename) {
return file;
}
}
return null;
}
private Task<IUploadProgress> UploadFileAsync(System.IO.MemoryStream fileStream, string filename)
{
File driveFile = this.GetFileMatchingName(filename);
Task<IUploadProgress> task;
if(driveFile == null) {
//File does not exist, create it
var insert = _service.Files.Create(new File { Name = "MesenData.zip", Parents = new List<string>() { "appDataFolder" } }, fileStream, _contentType);
insert.ChunkSize = FilesResource.CreateMediaUpload.MinimumChunkSize * 2;
insert.ResponseReceived += Upload_ResponseReceived;
task = insert.UploadAsync();
} else {
//File exists, update it
var update = _service.Files.Update(null, driveFile.Id, fileStream, _contentType);
update.ResponseReceived += Upload_ResponseReceived;
task = update.UploadAsync();
}
task.ContinueWith(t => {
// NotOnRanToCompletion - this code will be called if the upload fails
Console.WriteLine("Upload Failed. " + t.Exception);
}, TaskContinuationOptions.NotOnRanToCompletion);
task.ContinueWith(t => {
fileStream.Dispose();
});
return task;
}
private async Task DownloadFileAsync(System.IO.MemoryStream outStream, string filename)
{
File driveFile = this.GetFileMatchingName(filename);
if(driveFile != null) {
var request = _service.Files.Get(driveFile.Id);
var progress = await request.DownloadAsync(outStream).ConfigureAwait(false);
if(progress.Status == DownloadStatus.Completed) {
_driveFile = driveFile;
} else {
_driveFile = null;
}
}
}
private async Task DeleteFile(File file)
{
await _service.Files.Delete(file.Id).ExecuteAsync().ConfigureAwait(false);
}
void Upload_ResponseReceived(File file)
{
_driveFile = file;
}
void IDisposable.Dispose()
{
if(_service != null) {
_service.Dispose();
}
}
}
}

View file

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Requests;
using Google.Apis.Auth.OAuth2.Responses;
namespace Mesen.GUI.GoogleDriveIntegration
{
public class MesenCodeReceiver : LocalServerCodeReceiver, ICodeReceiver
{
private const string baseResponse =
@"<html>
<head>
<title>Mesen - Authentication Successful</title>
<style>
html, body {
font-family: Calibri;
height:100%;
background-color: #EEE;
}
img {
margin: 10px;
vertical-align: middle;
}
div {
background-color: #FFF;
position: relative;
top: 50px;
margin:auto;
width:600px;
height:154px;
border:1px solid #999;
text-align:center;
}
span {
vertical-align: middle;
}
</style>
</head>";
private const string successResponse = baseResponse +
@"<body>
<div>
<img src='http://www.mesen.ca/Images/MesenIcon.png'/><span>Mesen - Authentication Successful</span><br/>
Mesen will now save battery files and save states in your Google Drive account.<br/>
<br/>
Please close this window.
</div>
</body>
</html>";
private const string failureResponse = baseResponse +
@"<body>
<div>
<img src='http://www.mesen.ca/Images/MesenIcon.png'/><span>Mesen - Authentication <span style='color:red'>Failed</span></span><br/>
Mesen was unable to integrate with your Google Drive account - please close this window and try again.<br/>
</div>
</body>
</html>";
async Task<AuthorizationCodeResponseUrl> ICodeReceiver.ReceiveCodeAsync(AuthorizationCodeRequestUrl url, CancellationToken taskCancellationToken)
{
var authorizationUrl = url.Build().ToString();
using(var listener = new HttpListener()) {
listener.Prefixes.Add(RedirectUri);
try {
listener.Start();
Process.Start(authorizationUrl);
// Wait to get the authorization code response.
var context = await listener.GetContextAsync().ConfigureAwait(false);
NameValueCollection coll = context.Request.QueryString;
// Write a "close" response.
Thread.Sleep(200);
// Create a new response URL with a dictionary that contains all the response query parameters.
var codeResponse = new AuthorizationCodeResponseUrl(coll.AllKeys.ToDictionary(k => k, k => coll[k]));
using(var writer = new System.IO.StreamWriter(context.Response.OutputStream)) {
writer.WriteLine(string.IsNullOrWhiteSpace(codeResponse.Error) ? successResponse : failureResponse);
writer.Flush();
}
context.Response.OutputStream.Close();
return codeResponse;
} finally {
listener.Close();
}
}
}
}
}

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Threading;
@ -29,6 +30,26 @@ namespace Mesen.GUI
MesenMsgBox.Show("UnexpectedError", MessageBoxButtons.OK, MessageBoxIcon.Error, e.ExceptionObject.ToString());
}
[DebuggerNonUserCode]
private static Assembly LoadAssemblies(object sender, ResolveEventArgs e)
{
//Allow assemblies to be loaded from subfolders in the home folder (used for Google Drive API dlls)
string assemblyFile = e.Name.Contains(',') ? e.Name.Substring(0, e.Name.IndexOf(',')) : e.Name;
assemblyFile += ".dll";
string absoluteFolder = new FileInfo((new System.Uri(Assembly.GetExecutingAssembly().CodeBase)).LocalPath).Directory.FullName;
string targetPath = Path.Combine(ConfigManager.HomeFolder, "GoogleDrive", assemblyFile);
try {
if(File.Exists(targetPath)) {
return Assembly.LoadFile(targetPath);
}
} catch(Exception) {
return null;
}
return null;
}
/// <summary>
/// The main entry point for the application.
/// </summary>
@ -37,6 +58,7 @@ namespace Mesen.GUI
private static void Main(string[] args)
{
try {
AppDomain.CurrentDomain.AssemblyResolve += LoadAssemblies;
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += Application_ThreadException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

View file

@ -60,6 +60,16 @@ namespace Mesen.GUI.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Accept {
get {
object obj = ResourceManager.GetObject("Accept", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View file

@ -199,4 +199,7 @@
<data name="DipSwitches" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\DipSwitches.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Accept" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\accept.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View file

@ -52,29 +52,46 @@ namespace Mesen.GUI
return null;
}
private static void CleanupOldFiles()
{
try {
if(Directory.Exists(Path.Combine(ConfigManager.HomeFolder, "Resources"))) {
Directory.Delete(Path.Combine(ConfigManager.HomeFolder, "Resources"), true);
}
if(Directory.Exists(Path.Combine(ConfigManager.HomeFolder, "WinMesen"))) {
Directory.Delete(Path.Combine(ConfigManager.HomeFolder, "WinMesen"), true);
}
if(File.Exists(Path.Combine(ConfigManager.HomeFolder, "NesNtsc.dll"))) {
File.Delete(Path.Combine(ConfigManager.HomeFolder, "NesNtsc.dll"));
}
if(File.Exists(Path.Combine(ConfigManager.HomeFolder, "BlipBuffer.dll"))) {
File.Delete(Path.Combine(ConfigManager.HomeFolder, "BlipBuffer.dll"));
}
} catch { }
}
public static void ExtractResources()
{
CleanupOldFiles();
Directory.CreateDirectory(Path.Combine(ConfigManager.HomeFolder, "Resources"));
Directory.CreateDirectory(Path.Combine(ConfigManager.HomeFolder, "WinMesen"));
Directory.CreateDirectory(Path.Combine(ConfigManager.HomeFolder, "GoogleDrive"));
ZipArchive zip = new ZipArchive(Assembly.GetExecutingAssembly().GetManifestResourceStream("Mesen.GUI.Dependencies.Dependencies.zip"));
//Extract all needed files
string suffix = IntPtr.Size == 4 ? ".x86" : ".x64";
foreach(ZipArchiveEntry entry in zip.Entries) {
if(entry.Name == "MSVCx64.zip" && IntPtr.Size == 8 || entry.Name == "MSVCx86.zip" && IntPtr.Size == 4) {
using(Stream stream = entry.Open()) {
ZipArchive msvcZip = new ZipArchive(stream);
foreach(ZipArchiveEntry msvcEntry in msvcZip.Entries) {
ExtractFile(msvcEntry, Path.Combine(ConfigManager.HomeFolder, "WinMesen", msvcEntry.Name));
}
}
} else if(entry.Name.Contains(suffix)) {
string outputFilename = Path.Combine(ConfigManager.HomeFolder, "WinMesen", entry.Name.Replace(suffix, ""));
if(entry.Name.Contains(suffix)) {
string outputFilename = Path.Combine(ConfigManager.HomeFolder, entry.Name.Replace(suffix, ""));
ExtractFile(entry, outputFilename);
} else if(entry.Name == "MesenUpdater.exe") {
string outputFilename = Path.Combine(ConfigManager.HomeFolder, entry.Name.Replace(suffix, ""));
ExtractFile(entry, outputFilename);
} else if(entry.Name.StartsWith("Google.Apis") || entry.Name == "BouncyCastle.Crypto.dll" || entry.Name == "Zlib.Portable.dll" || entry.Name == "Newtonsoft.Json.dll") {
string outputFilename = Path.Combine(ConfigManager.HomeFolder, "GoogleDrive", entry.Name.Replace(suffix, ""));
ExtractFile(entry, outputFilename);
} else if(entry.Name == "Font.24.spritefont" || entry.Name == "Font.64.spritefont" || entry.Name == "LICENSE.txt") {
string outputFilename = Path.Combine(ConfigManager.HomeFolder, "Resources", entry.Name.Replace(suffix, ""));
ExtractFile(entry, outputFilename);

Binary file not shown.

After

Width:  |  Height:  |  Size: 643 B

View file

@ -17,11 +17,8 @@ namespace Mesen.GUI
public static bool TestDll()
{
try {
Directory.SetCurrentDirectory(Path.Combine(ConfigManager.HomeFolder, "WinMesen"));
return InteropEmu.TestDll();
} catch {
} finally {
Directory.SetCurrentDirectory(Path.Combine(ConfigManager.HomeFolder));
}
if(!File.Exists("WinMesen.dll")) {

View file

@ -382,6 +382,8 @@ namespace NES
}
_pDeviceContext->Unmap(_pTexture[0], 0);
_needFlip = true;
_frameLock.Release();
_frameChanged = true;
@ -390,9 +392,12 @@ namespace NES
void Renderer::DrawNESScreen()
{
//Swap buffers - emulator always writes to texture 0, screen always draws texture 1 (allows us to release a lock earlier while avoiding crashes)
ID3D11Texture2D *texture = _pTexture[0];
_pTexture[0] = _pTexture[1];
_pTexture[1] = texture;
if(_needFlip) {
ID3D11Texture2D *texture = _pTexture[0];
_pTexture[0] = _pTexture[1];
_pTexture[1] = texture;
_needFlip = false;
}
ID3D11ShaderResourceView *nesOutputBuffer = GetShaderResourceView(_pTexture[1]);

View file

@ -29,6 +29,7 @@ namespace NES {
ID3D11SamplerState* _samplerState = nullptr;
atomic<bool> _needFlip = false;
ID3D11Texture2D* _pTexture[2] = { nullptr,nullptr };
ID3D11Texture2D* _overlayTexture = nullptr;