基于windowsphone7的控制ppt播放

时间:2022-03-14 16:28:38

最近突然想起了一个学长的一个利用手机控制ppt播放的一个创意,并想将其在windows phone7上实现一下。

经过几天的努力已经可以控制ppt的播放,暂停,上一张,下一张了,并且电脑会将当前ppt的截图发送到手机端这里。

在代码的编写过程中,参考了IT黄老邪Windows Phone开发(46):与Socket有个约会进行服务端与wp客户端的socket通讯的编写,并加入了键盘消息模拟,服务端截屏,图片发送,与客户端的图片接受。

代码如下:

WP客户端

1、新建Windows Phone应用程序项目。(我这里的名称是叫PhoneApp2)

2、打开MainPage.xaml文件,输入以下代码。

<phone:PhoneApplicationPage
x:Class="PhoneApp2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="" d:DesignHeight=""
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True"> <!--LayoutRoot 是包含所有页面内容的根网格-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions> <!--TitlePanel 包含应用程序的名称和页标题-->
<StackPanel x:Name="TitlePanel" Grid.Row="" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="我的应用程序" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="PPT播放" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel> <!--ContentPanel - 在此处放置其他内容-->
<Grid x:Name="ContentPanel" Grid.Row="" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="" VerticalAlignment="Center" Text="服务器IP:" />
<TextBox Name="txtServerIP" Grid.Column="" Text="" />
<Button Grid.Column="" Content="连接" Click="onConnect"/>
</Grid> <Button Content="播放" Click="onPlay" Width="" Margin="54,0,248,463" Grid.Row="" />
<Button Content="下一张" Click="onPlayNext" Margin="0,78,21,358" Grid.Row="" HorizontalAlignment="Right" Width="" />
<Button Content="上一张" Click="onPlayBack" Margin="6,78,248,358" Grid.Row="" />
<Button Content="暂停" Click="onPause" Width="" Margin="237,0,75,463" Grid.Row="" />
<TextBlock Name="txtbInfo" Margin="6,475,0,6" Grid.Row="" />
<Image Grid.Row="" Height="" HorizontalAlignment="Left" Margin="12,170,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="" Tap="image1_Tap" />
</Grid>
</Grid> <!--演示 ApplicationBar 用法的示例代码-->
<!--<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="按钮 1"/>
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="按钮 2"/>
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem Text="菜单项 1"/>
<shell:ApplicationBarMenuItem Text="菜单项 2"/>
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>--> </phone:PhoneApplicationPage>

3、打开MainPage.xaml.cs,输入以下代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.IO;
using System.Windows.Media.Imaging; namespace PhoneApp2
{
public partial class MainPage : PhoneApplicationPage
{
Socket mySocket = null;
ManualResetEvent MyEvent = null;
Byte[] imgbyte = new Byte[];
// 构造函数
public MainPage()
{
InitializeComponent();
} protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e); if (mySocket == null)
{
mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
mySocket.ReceiveBufferSize = ; }
if (MyEvent == null)
{
MyEvent = new ManualResetEvent(false);
}
} protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
try
{
if (mySocket != null)
{
mySocket.Shutdown(SocketShutdown.Both);
mySocket.Close();
}
base.OnNavigatedFrom(e);
}
catch
{
base.OnNavigatedFrom(e);
}
} private void onConnect(object sender, RoutedEventArgs e)
{
if (mySocket != null)
{
SocketAsyncEventArgs connArg = new SocketAsyncEventArgs();
if(this.txtServerIP.Text=="")
{
txtbInfo.Text="请输入正确的ip";
return;
}
// 要连接的远程服务器
connArg.RemoteEndPoint = new DnsEndPoint(this.txtServerIP.Text, ); // 操作完成后的回调
connArg.Completed += (sendObj, arg) =>
{
if (arg.SocketError == SocketError.Success) //连接成功
{
Dispatcher.BeginInvoke(() => txtbInfo.Text = "连接成功。"); imgbyte = arg.Buffer;
}
else
{
Dispatcher.BeginInvoke(() =>
{
txtbInfo.Text = "连接失败,错误:" + arg.SocketError.ToString();
});
}
// 向调用线程报告操作结束
MyEvent.Set();
};
// 重置线程等待事件
MyEvent.Reset();
txtbInfo.Text = "正在连接,请等候……";
// 开始异连接
mySocket.ConnectAsync(connArg);
// 等待连接完成
MyEvent.WaitOne();
}
}
Byte[] imgInfo;
private void onPlayNext(object sender, RoutedEventArgs e)
{
SendCommand("playNext");
receiveImg(); }
private void receiveImg()
{
try
{
imgInfo = ReceiveInfo();
MemoryStream ms = new MemoryStream(imgInfo);
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(ms);
WriteableBitmap writeableBitmap = new WriteableBitmap(bitmapImage); this.image1.Source = writeableBitmap;
}
catch
{
SendCommand("newimg");
}
}
private void onPlayBack(object sender, RoutedEventArgs e)
{
SendCommand("playBack");
receiveImg();
}
private void onPlay(object sender, RoutedEventArgs e)
{
SendCommand("play");
receiveImg();
} private void onPause(object sender, RoutedEventArgs e)
{
SendCommand("pause");
receiveImg();
}
int i = ;
byte[] received = new Byte[ *];
private byte[] ReceiveInfo()
{ if (mySocket != null && mySocket.Connected)
{
SocketAsyncEventArgs receiveArg = new SocketAsyncEventArgs(); byte[] buffer = new byte[];
receiveArg.SetBuffer(buffer, , buffer.Length);
receiveArg.Completed += new EventHandler<SocketAsyncEventArgs>(receiveArg_Completed);
MyEvent.Reset();
mySocket.ReceiveAsync(receiveArg);
MyEvent.WaitOne();
}
return received; } void receiveArg_Completed(object sender, SocketAsyncEventArgs mArg)
{ if (mArg.SocketError == SocketError.Success)
{
if (i < )
{
Buffer.BlockCopy(mArg.Buffer,,received,i * , ); i++;
ReceiveInfo();
}
MyEvent.Set();
mArg.Dispose();
} } private void SendCommand(string txt)
{
i = ;
if (mySocket != null && mySocket.Connected)
{
SocketAsyncEventArgs sendArg = new SocketAsyncEventArgs(); byte[] buffer = System.Text.Encoding.UTF8.GetBytes(txt);
sendArg.SetBuffer(buffer, , buffer.Length);
// 发送完成后的回调
sendArg.Completed += (objSender, mArg) =>
{
// 如果操作成功
if (mArg.SocketError == SocketError.Success)
{
Dispatcher.BeginInvoke(() => txtbInfo.Text = "发送成功。"); } else
{
Dispatcher.BeginInvoke(() =>
{
this.txtbInfo.Text = "发送失败,错误:" + mArg.SocketError.ToString(); });
}
// 报告异步操作结束
MyEvent.Set();
};
// 重置信号
MyEvent.Reset();
txtbInfo.Text = "正在发送,请等候……";
// 异步发送
mySocket.SendAsync(sendArg);
// 等待操作完成
MyEvent.WaitOne();
}
} private void image1_Tap(object sender, GestureEventArgs e)
{
SendCommand("newimg");
receiveImg();
}
}
}

第一部分 服务器端

1、新建WPF应用程序项目。(我这里的名称是叫做WpfApplication4)

2、打开MainWindow.xaml文件,输入以下XAML代码。

<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="服务器端" Height="" Width="">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> <TextBlock Name="txtDisplay2" Grid.Row="" Margin="240,0,12,0" />
<TextBlock Name="txtDisplay" Grid.Row="" Margin="0,0,261,0" />
<TextBlock Height="" TextWrapping="Wrap" HorizontalAlignment="Left" Margin="88,60,0,0" Name="textBlock1" VerticalAlignment="Top" FontSize="" Width="" >
打开客户端,输入服务器ip后,将程序最小化,打开需要的ppt。
</TextBlock>
</Grid>
</Window>

3.MainWindow.xaml.cs的代码如下。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Forms;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Animation;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging; namespace WpfApplication4
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{ Socket Server;
Byte[] imgInfo=new Byte[*];
public MainWindow()
{
InitializeComponent();
InitialTray(); // 从资源中把Key为std的Storyboard读出来 // 声明用于监听连接请求的Socket
Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// string strHostName = Dns.GetHostName(); //得到本机的主机名
IPHostEntry ipEntry = Dns.GetHostEntry(strHostName);
////取得本机IP
IPAddress strAddr = ipEntry.AddressList[];//.ToString();
txtDisplay2.Text = "服务器IP:" + strAddr.ToString();//假设本地主机为单网卡
//
IPEndPoint local = new IPEndPoint(IPAddress.Any, ); //监听所有网络接口上的地址
Server.Bind(local);// 绑定本地终结点
Server.Listen();// 侦听连接请求
// 开始异步接受传入的连接请求
Server.BeginAccept(new AsyncCallback(this.AcceptSocketCallback), Server);
}
private System.Windows.Forms.NotifyIcon notifyIcon = null; private void InitialTray()
{ //设置托盘的各个属性
notifyIcon = new System.Windows.Forms.NotifyIcon();
notifyIcon.BalloonTipText = "程序开始运行";
notifyIcon.Text = "ppt服务端";
notifyIcon.Icon = new System.Drawing.Icon("Downloads.ico");
notifyIcon.Visible = true;
notifyIcon.ShowBalloonTip();
notifyIcon.MouseClick += new System.Windows.Forms.MouseEventHandler(notifyIcon_MouseClick); //退出菜单项
System.Windows.Forms.MenuItem exit = new System.Windows.Forms.MenuItem("exit");
exit.Click += new EventHandler(exit_Click); //关联托盘控件
System.Windows.Forms.MenuItem[] childen = new System.Windows.Forms.MenuItem[] { exit };
notifyIcon.ContextMenu = new System.Windows.Forms.ContextMenu(childen); //窗体状态改变时候触发
this.StateChanged += new EventHandler(SysTray_StateChanged);
}
///
/// 窗体状态改变时候触发
///
/// /// private void SysTray_StateChanged(object sender, EventArgs e)
{
if (this.WindowState == WindowState.Minimized)
{
this.Visibility = Visibility.Hidden;
}
} ///
/// 退出选项
///
/// /// private void exit_Click(object sender, EventArgs e)
{
if (System.Windows.MessageBox.Show("确定要关闭吗?",
"退出",
MessageBoxButton.YesNo,
MessageBoxImage.Question,
MessageBoxResult.No) == MessageBoxResult.Yes)
{
notifyIcon.Dispose();
System.Windows.Application.Current.Shutdown();
}
} ///
/// 鼠标单击
///
/// /// private void notifyIcon_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
if (this.Visibility == Visibility.Visible)
{
this.Visibility = Visibility.Hidden; }
else
{
this.Visibility = Visibility.Visible; this.Activate();
}
}
} //
/// <summary>
/// 接受传入的Socket的回调
/// </summary>
private void AcceptSocketCallback(IAsyncResult ia)
{
Socket _socket = ia.AsyncState as Socket;
Socket accptSocket = _socket.EndAccept(ia);
try
{
IPEndPoint remote = (IPEndPoint)accptSocket.RemoteEndPoint;
// 显示客户端的IP
Dispatcher.BeginInvoke(new Action<string>(this.SetIPForText), remote.Address.ToString());
StateObject so = new StateObject();
so.theSocket = accptSocket;
// 开始异步接收消息
accptSocket.BeginReceive(so.Buffer, , so.Buffer.Length, SocketFlags.None, new AsyncCallback(this.ReceiveCallback), so);
}
catch
{ }
// 继续接受连接请求
_socket.BeginAccept(new AsyncCallback(this.AcceptSocketCallback), _socket);
}
/// <summary>
/// 接收消息的回调
/// </summary>
private void ReceiveCallback(IAsyncResult ia)
{
StateObject _so = ia.AsyncState as StateObject;
Socket _socket = _so.theSocket;
try
{
int n = _socket.EndReceive(ia);//n就是接收到的字节数
string msg = Encoding.UTF8.GetString(_so.Buffer, , n); // 判断客户端发送了啥命令
switch (msg)
{
case "playNext": System.Windows.Forms.SendKeys.SendWait("{Right}");
SendCommand(_socket, CatchScreen());
break;
case "playBack": System.Windows.Forms.SendKeys.SendWait("{Left}");
SendCommand(_socket, CatchScreen());
break;
case "pause": System.Windows.Forms.SendKeys.SendWait("{B}");
SendCommand(_socket, CatchScreen());
break;
case "play": System.Windows.Forms.SendKeys.SendWait("{F5}");
SendCommand(_socket, CatchScreen());
break;
case "newimg":
SendCommand(_socket, CatchScreen());
break;
default:
break;
}
}
catch
{
}
_so = new StateObject();
_so.theSocket = _socket;
// 继续接收消息
_socket.BeginReceive(_so.Buffer,
,
_so.Buffer.Length,
SocketFlags.None,
new AsyncCallback(this.ReceiveCallback),
_so);
} private void SendCommand(Socket handler,byte[] imginfo)
{ try
{
handler.BeginSend(imginfo, , imginfo.Length, , new AsyncCallback(SendCallBack), handler);
}
catch
{
} }
private void SendCallBack(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
int bytesSend = handler.EndSend(ar);
if (bytesSend > )
{
Console.WriteLine("Succeed");
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
} }
private byte[] CatchScreen()
{
Screen scr = Screen.PrimaryScreen;
System.Drawing.Rectangle rc = scr.Bounds;
int iWidth = rc.Width;
int iHeight = rc.Height;
//创建一个和屏幕一样大的Bitmap
System.Drawing.Image myImage = new Bitmap(iWidth, iHeight); //从一个继承自Image类的对象中创建Graphics对象
Graphics g = Graphics.FromImage(myImage); g.CopyFromScreen(new System.Drawing.Point(, ), new System.Drawing.Point(, ), new System.Drawing.Size(iWidth, iHeight));
return ImgToByt(myImage.GetThumbnailImage(iWidth / , iHeight/, new System.Drawing.Image.GetThumbnailImageAbort(CallBack), IntPtr.Zero));
}
private static bool CallBack()
{
return false; } public byte[] ImgToByt(System.Drawing.Image img)
{
MemoryStream ms = new MemoryStream();
byte[] imagedata = new Byte[ * ];// null;
byte[] imagedata2 = null;
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
imagedata2 = ms.GetBuffer();
Buffer.BlockCopy(imagedata2, , imagedata, , imagedata2.Length);
return imagedata;
}
/// <summary>
/// 字节流转换成图片
/// </summary>
/// <param name="byt">要转换的字节流</param>
/// <returns>转换得到的Image对象</returns>
public System.Drawing.Image BytToImg(byte[] byt)
{
MemoryStream ms = new MemoryStream(byt);
System.Drawing.Image img = System.Drawing.Image.FromStream(ms);
return img;
}
/// <summary>
/// 显示客户端的IP
/// </summary>
private void SetIPForText(string ip)
{
this.txtDisplay.Text = "客户端IP:" + ip;
} } /// <summary>
/// 用于异步Socket操作传递的状态对象
/// </summary>
public class StateObject
{
private const int BUFFER_SIZE = ; public byte[] Buffer { get; set; } public Socket theSocket { get; set; } /// <summary>
/// 构造函数
/// </summary>
public StateObject()
{
this.Buffer = new byte[BUFFER_SIZE];
}
}
}

4.新建一个叫做KeyboardToolkit.cs的类,用于模拟键盘消息,代码如下。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.ComponentModel; namespace WpfApplication4
{
class KeyboardToolkit
{
internal static class NativeMethods
{
#region User32
// Various Win32 constants
internal const int KeyeventfKeyup = 0x0002;
internal const int KeyeventfScancode = 0x0008;
internal const int InputKeyboard = ; // Various Win32 data structures
[StructLayout(LayoutKind.Sequential)]
internal struct INPUT
{
internal int type;
internal INPUTUNION union;
}; [StructLayout(LayoutKind.Explicit)]
internal struct INPUTUNION
{
[FieldOffset()]
internal MOUSEINPUT mouseInput;
[FieldOffset()]
internal KEYBDINPUT keyboardInput;
}; [StructLayout(LayoutKind.Sequential)]
internal struct MOUSEINPUT
{
internal int dx;
internal int dy;
internal int mouseData;
internal int dwFlags;
internal int time;
internal IntPtr dwExtraInfo;
}; [StructLayout(LayoutKind.Sequential)]
internal struct KEYBDINPUT
{
internal short wVk;
internal short wScan;
internal int dwFlags;
internal int time;
internal IntPtr dwExtraInfo;
}; // Importing various Win32 APIs that we need for input
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
internal static extern int GetSystemMetrics(int nIndex); [DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern int MapVirtualKey(int nVirtKey, int nMapType); [DllImport("user32.dll", SetLastError = true)]
internal static extern int SendInput(int nInputs, ref INPUT mi, int cbSize); [DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern short VkKeyScan(char ch); #endregion User32
} public static class Keyboard
{
/// <summary>
/// Presses down a key.
/// </summary>
/// <param name="key">The key to press.</param>
public static void Press(Key key)
{
SendKeyboardInput(key, true);
} /// <summary>
/// Releases a key.
/// </summary>
/// <param name="key">The key to release.</param>
public static void Release(Key key)
{
SendKeyboardInput(key, false);
} /// <summary>
/// Resets the system keyboard to a clean state.
/// </summary>
public static void Reset()
{
foreach (Key key in Enum.GetValues(typeof(Key)))
{
if (key != Key.None && (System.Windows.Input.Keyboard.GetKeyStates(key) & KeyStates.Down) > )
{
Release(key);
}
}
} /// <summary>
/// Performs a press-and-release operation for the specified key, which is effectively equivallent to typing.
/// </summary>
/// <param name="key">The key to press.</param>
public static void Type(Key key)
{
Press(key);
System.Threading.Thread.Sleep();
Release(key);
} [PermissionSet(SecurityAction.Assert, Name = "FullTrust")]
private static void SendKeyboardInput(Key key, bool press)
{
PermissionSet permissions = new PermissionSet(PermissionState.Unrestricted);
permissions.Demand(); NativeMethods.INPUT ki = new NativeMethods.INPUT();
ki.type = NativeMethods.InputKeyboard;
ki.union.keyboardInput.wVk = (short)KeyInterop.VirtualKeyFromKey(key);
ki.union.keyboardInput.wScan = (short)NativeMethods.MapVirtualKey(ki.union.keyboardInput.wVk, ); int dwFlags = ; if (ki.union.keyboardInput.wScan > )
{
dwFlags |= NativeMethods.KeyeventfScancode;
} if (!press)
{
dwFlags |= NativeMethods.KeyeventfKeyup;
} ki.union.keyboardInput.dwFlags = dwFlags; ki.union.keyboardInput.time = ;
ki.union.keyboardInput.dwExtraInfo = new IntPtr(); if (NativeMethods.SendInput(, ref ki, Marshal.SizeOf(ki)) == )
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
} }
}
}

先打开服务端

基于windowsphone7的控制ppt播放

在手机客户端,输入服务器端的IP地址,点击连接,连接成功后就可以进行操作了

基于windowsphone7的控制ppt播放

基于windowsphone7的控制ppt播放