//----------------------------------------------------------------------------- // File: DPlayConnect_JoinForm.cs // // Desc: Application class for the DirectPlay samples framework. // // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- using System; using System.Collections; using System.Windows.Forms; using System.Threading; using System.Timers; using Microsoft.DirectX; using Microsoft.DirectX.DirectPlay; /// /// This form will search for existing running samples and allow you to join them or will /// allow you to create your own session as a host /// public class CreateJoinForm : System.Windows.Forms.Form { private System.Windows.Forms.Button btnJoin; private System.Windows.Forms.Label label1; private System.Windows.Forms.Button btnCreate; private System.Windows.Forms.ListBox lstSession; private System.Windows.Forms.Button btnCancel; private System.Windows.Forms.Button btnSearch; private const int EnumExpireThreshold = 2000; private bool amJoining = false; /// /// Hold our information of hosts we found /// private struct FindHostsResponseInformation { public int LastFoundTime; public ApplicationDescription ApplicationDesc; public int RoundTripLatencyMs; public Address sender; public Address device; public override string ToString() { if (ApplicationDesc.MaxPlayers > 0) return ApplicationDesc.SessionName + " (" + ApplicationDesc.CurrentPlayers + "/" + ApplicationDesc.MaxPlayers + ") (" + RoundTripLatencyMs + "ms)"; else return ApplicationDesc.SessionName + " (" + ApplicationDesc.CurrentPlayers + ") (" + RoundTripLatencyMs + "ms)"; } }; private Peer peer; private ConnectWizard connectionWizard; private Address deviceAddress; private Address hostAddress = null; private bool isSearching = false; private int findHostHandle = 0; private CreateSessionForm createSessionForm = null; private ResultCode resultCode; private ArrayList foundHosts = new ArrayList(); private bool isConnected = false; private ManualResetEvent connectEvent = null; private System.Timers.Timer updateListTimer = null; private System.Timers.Timer connectTimer = null; /// /// Constructor /// public CreateJoinForm(Peer peerObject, Address addressObject, ConnectWizard connectionWizard) { // // Required for Windows Form Designer support // InitializeComponent(); peer = peerObject; this.connectionWizard = connectionWizard; this.Text = connectionWizard.SampleName + " - " + this.Text; deviceAddress = addressObject; //Set up the event handlers peer.FindHostResponse += new FindHostResponseEventHandler(FindHostResponseMessage); peer.ConnectComplete += new ConnectCompleteEventHandler(ConnectResult); peer.AsyncOperationComplete += new AsyncOperationCompleteEventHandler(CancelAsync); //Set up our timer updateListTimer = new System.Timers.Timer(300); // A 300 ms interval updateListTimer.Elapsed += new System.Timers.ElapsedEventHandler(this.UpdateTimer); updateListTimer.SynchronizingObject = this; updateListTimer.Start(); //Set up our connect timer connectTimer = new System.Timers.Timer(100); // A 100ms interval connectTimer.Elapsed += new System.Timers.ElapsedEventHandler(this.ConnectTimer); connectTimer.SynchronizingObject = this; // Set up our connect event connectEvent = new ManualResetEvent(false); } /// /// An asynchronous operation was cancelled /// private void CancelAsync(object sender, AsyncOperationCompleteEventArgs e) { if (e.Message.AsyncOperationHandle == findHostHandle) { findHostHandle = 0; btnSearch.Text = "Start Search"; isSearching = false; btnCreate.Enabled = true; btnSearch.Enabled = true; } } /// /// A host was found and responded to our query /// private void FindHostResponseMessage(object sender, FindHostResponseEventArgs dpMessage) { // Now we need to add this to our list of available sessions SessionAdd(dpMessage.Message); } /// /// Add this session to our list /// /// private void SessionAdd(FindHostsResponseMessage dpMessage) { FindHostsResponseInformation dpInfo = new FindHostsResponseInformation(); dpInfo.ApplicationDesc = dpMessage.ApplicationDescription; dpInfo.device = dpMessage.AddressDevice; dpInfo.sender = dpMessage.AddressSender; dpInfo.RoundTripLatencyMs = dpMessage.RoundTripLatencyMs; dpInfo.LastFoundTime = Environment.TickCount; // Let's check the items first and see if this one already exists bool isFound = false; lock (foundHosts) { for (int i = 0; i < lstSession.Items.Count; i++) { if (dpInfo.ApplicationDesc.GuidInstance == ((FindHostsResponseInformation)lstSession.Items[i]).ApplicationDesc.GuidInstance) { foundHosts[i] = dpInfo; lstSession.Items[i] = dpInfo; isFound = true; } } if (!isFound) { lstSession.Items.Add(dpInfo); foundHosts.Add(dpInfo); } } } /// /// Clean up any resources being used. /// protected override void Dispose(bool Disposing) { base.Dispose(Disposing); if (isSearching) { if (findHostHandle != 0) peer.CancelAsyncOperation(findHostHandle); isSearching = !isSearching; } if (connectTimer != null) connectTimer.Dispose(); if (updateListTimer != null) updateListTimer.Dispose(); } #region Windows Form Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.btnSearch = new System.Windows.Forms.Button(); this.btnCancel = new System.Windows.Forms.Button(); this.lstSession = new System.Windows.Forms.ListBox(); this.btnCreate = new System.Windows.Forms.Button(); this.label1 = new System.Windows.Forms.Label(); this.btnJoin = new System.Windows.Forms.Button(); this.SuspendLayout(); // // btnSearch // this.btnSearch.Location = new System.Drawing.Point(319, 7); this.btnSearch.Name = "btnSearch"; this.btnSearch.Size = new System.Drawing.Size(86, 27); this.btnSearch.TabIndex = 2; this.btnSearch.Text = "Start Search"; this.btnSearch.Click += new System.EventHandler(this.btnSearch_Click); // // btnCancel // this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.btnCancel.Location = new System.Drawing.Point(333, 227); this.btnCancel.Name = "btnCancel"; this.btnCancel.Size = new System.Drawing.Size(74, 27); this.btnCancel.TabIndex = 3; this.btnCancel.Text = "Cancel"; // // lstSession // this.lstSession.Location = new System.Drawing.Point(5, 37); this.lstSession.Name = "lstSession"; this.lstSession.Size = new System.Drawing.Size(400, 186); this.lstSession.TabIndex = 1; this.lstSession.DoubleClick += new System.EventHandler(this.btnJoin_Click); this.lstSession.SelectedValueChanged += new System.EventHandler(this.SelectedChange); // // btnCreate // this.btnCreate.DialogResult = System.Windows.Forms.DialogResult.Yes; this.btnCreate.Location = new System.Drawing.Point(84, 227); this.btnCreate.Name = "btnCreate"; this.btnCreate.Size = new System.Drawing.Size(74, 27); this.btnCreate.TabIndex = 2; this.btnCreate.Text = "Create"; this.btnCreate.Click += new System.EventHandler(this.btnCreate_Click); // // label1 // this.label1.Location = new System.Drawing.Point(5, 13); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(312, 16); this.label1.TabIndex = 0; this.label1.Text = "Select session to join, or click Create to start a new session."; // // btnJoin // this.btnJoin.Enabled = false; this.btnJoin.Location = new System.Drawing.Point(7, 227); this.btnJoin.Name = "btnJoin"; this.btnJoin.Size = new System.Drawing.Size(74, 27); this.btnJoin.TabIndex = 2; this.btnJoin.Text = "Join"; this.btnJoin.Click += new System.EventHandler(this.btnJoin_Click); // // CreateJoinForm // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.CancelButton = this.btnCancel; this.ClientSize = new System.Drawing.Size(411, 264); this.ControlBox = false; this.Controls.Add(this.btnCreate); this.Controls.Add(this.btnJoin); this.Controls.Add(this.btnSearch); this.Controls.Add(this.btnCancel); this.Controls.Add(this.lstSession); this.Controls.Add(this.label1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; this.MaximizeBox = false; this.MinimizeBox = false; this.Name = "CreateJoinForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Join or create a session"; this.ResumeLayout(false); } #endregion /// /// The selected session was changed. /// private void SelectedChange(object sender, System.EventArgs e) { if (amJoining) return; // Do nothing if we are already joining a session btnJoin.Enabled = (lstSession.SelectedItem != null); } /// /// We either want to start or stop searching /// private void btnSearch_Click(object sender, System.EventArgs e) { if (!isSearching) { if( hostAddress != null ) hostAddress.Dispose(); hostAddress = new Address(); hostAddress.ServiceProvider = deviceAddress.ServiceProvider; // See if we should prompt the user for the remote address if (ConnectWizard.ProviderRequiresPort(hostAddress.ServiceProvider)) { AddressForm addressDialog = new AddressForm(connectionWizard.DefaultPort); addressDialog.ShowDialog(this); // If the user cancelled the address form, abort the search if (addressDialog.DialogResult != DialogResult.OK) return; // If a port was specified, add the component if (addressDialog.Hostname != "") hostAddress.AddComponent(Address.KeyHostname, addressDialog.Hostname); // If a hostname was specified, add the component if (addressDialog.Port > 0) hostAddress.AddComponent(Address.KeyPort, addressDialog.Port); } //Time to enum our hosts ApplicationDescription desc = new ApplicationDescription(); desc.GuidApplication = connectionWizard.ApplicationGuid; // If the user was not already asked for address information, DirectPlay // should prompt with native UI FindHostsFlags flags = 0; if (!ConnectWizard.ProviderRequiresPort(deviceAddress.ServiceProvider)) flags = FindHostsFlags.OkToQueryForAddressing; peer.FindHosts(desc,hostAddress,deviceAddress,null,Timeout.Infinite,0,Timeout.Infinite, flags, out findHostHandle); isSearching = true; btnCreate.Enabled = false; btnSearch.Text = "Stop Search"; } else { btnSearch.Text = "Stopping..."; btnSearch.Enabled = false; if (findHostHandle != 0) peer.CancelAsyncOperation(findHostHandle); } } /// /// A form was disposed /// /// /// public void FormDisposed(object sender, EventArgs e) { if (sender == createSessionForm) createSessionForm = null; } /// /// We should create a new session. Display a dialog allowing the user to set /// certain options /// private void btnCreate_Click(object sender, System.EventArgs e) { this.DialogResult = DialogResult.None; ((Button)sender).DialogResult = DialogResult.None; if (createSessionForm == null) { createSessionForm = new CreateSessionForm(peer,deviceAddress,connectionWizard); createSessionForm.Disposed += new System.EventHandler(this.FormDisposed); } if (createSessionForm.ShowDialog(this) != DialogResult.Cancel) { ((Button)sender).DialogResult = DialogResult.Yes; this.DialogResult = DialogResult.Yes; } } /// /// Determine if we need to expire any of our currently listed servers /// private void UpdateTimer(object sender, System.Timers.ElapsedEventArgs e) { lock (foundHosts) { for (int i = 0; i< foundHosts.Count; i++) { // First check to see if this session has expired if (Environment.TickCount - ((FindHostsResponseInformation)foundHosts[i]).LastFoundTime > EnumExpireThreshold) { foundHosts.RemoveAt(i); break; } } for (int i = 0; i< lstSession.Items.Count; i++) { // First check to see if this session has expired if (Environment.TickCount - ((FindHostsResponseInformation)lstSession.Items[i]).LastFoundTime > EnumExpireThreshold) { lstSession.Items.RemoveAt(i); break; } } } } /// /// Wait for a connect to complete /// private void ConnectTimer(object sender, System.Timers.ElapsedEventArgs e) { if (connectEvent.WaitOne(0,false)) // Wait for the Connect event to be fired { if (isConnected) // Are we connected? { // Get rid of the timer if (updateListTimer != null) updateListTimer.Stop(); if (connectTimer != null) connectTimer.Stop(); this.DialogResult = DialogResult.OK; this.Close(); return; } else { MessageBox.Show(this,"Failed to connect. The error code was: \n" + resultCode.ToString() ,"Failed to connect",MessageBoxButtons.OK,MessageBoxIcon.Information); // Restart our timer updateListTimer.Start(); } } } /// /// Fired when a connect complete message is received from DirectPlay. Fire /// our event to notify the sample we've connected /// private void ConnectResult(object sender, ConnectCompleteEventArgs e) { if (e.Message.ResultCode == 0) { isConnected = true; } else isConnected = false; resultCode = e.Message.ResultCode; // Notify the timer that we've connected. connectEvent.Set(); } /// /// Join an existing session /// private void btnJoin_Click(object sender, System.EventArgs e) { FindHostsResponseInformation dpInfo; if (lstSession.SelectedItem == null) { MessageBox.Show(this,"Please select a session before clicking join.","No session",MessageBoxButtons.OK,MessageBoxIcon.Information); return; } // Turn off all buttons btnCreate.Enabled = false; btnCancel.Enabled = false; btnJoin.Enabled = false; btnSearch.Enabled = false; amJoining = true; // Stop our secondary timer updateListTimer.Stop(); dpInfo = ((FindHostsResponseInformation)lstSession.SelectedItem); connectionWizard.SetUserInfo(); peer.Connect(dpInfo.ApplicationDesc,dpInfo.sender, dpInfo.device,null,ConnectFlags.OkToQueryForAddressing); // Now start our 'Connect' timer connectTimer.Start(); } }