当前位置: 代码迷 >> .NET相关 >> 【WP8.1开发】用手机来控制电脑的多媒体播发
  详细解决方案

【WP8.1开发】用手机来控制电脑的多媒体播发

热度:161   发布时间:2016-04-24 02:59:11.0
【WP8.1开发】用手机来控制电脑的多媒体播放

为了用电脑看电影时方便控制,我就突发其想,做一个手机app来通过无线网络远程调节电脑上的音量。后来进行尝试成功后,我就想,光是调音量似乎单调了些,就把播放/暂停,上一首,下一首,等多媒体控制功能也加上,这样好玩一点。

下面向大家简单介绍一下原理,整个解决方案的源代码我会共享给大家,以作参考。

 

先说服务器,因为控制命令比较简单,我直接用一个WPF应用程序来完成,这样方便运行,用socket来通信比较麻烦,我就用WCF来做服务,使用WebServiceHoset,让WP手机客户端用HTTP-POST的方式来调用。

这个相信大家都会,还有一个核心,就是如何控制系统的多媒体功能? 其实大家应该发现在你的笔记本键盘上,有一排功能按钮,可以通过按这些键来调整音量,控制播放、上一首歌曲等,还有各种功能开关,比如打开/关闭无线功能等。

也就是说,只要代码能够模拟发出这些按键就可以实现控制了,这就要用到Win32 API中的SendInput函数。在最初尝试时,我将SendInput函数导进托管代码中,但调用没有反应,不知道是不是我Import不对。

后来,我干脆用C++来写一个dll,把各个控制操作都用独立的导出函数来包装,再把自己写的dll中的导出函数在托管项目中DllImport。

自己编写的dll的头文件如下:

#pragma once#include "stdafx.h"/* 增大音量 */extern "C" __declspec(dllexport) void volume_up();/* 减小音量 */extern "C" __declspec(dllexport) void volume_down();/* 静音/恢复 */extern "C" __declspec(dllexport) void volume_mute();/* 下一首 */extern "C" __declspec(dllexport) void media_next_track();/* 上一首 */extern "C" __declspec(dllexport) void media_prev_track();/* 播放/暂停 */extern "C" __declspec(dllexport) void media_play_pause();/* 停止 */extern "C" __declspec(dllexport) void media_stop();void send_input_core(WORD vkey);

__declspec(dllexport)注明的函数为导出函数,即可以在其他代码中使用,而最后的send_input_core函数只供dll内部使用,就不再导出了。

注意要加上extern "C",让函数以C语言的规范进行导出,由于C语言不支持函数重载,在编译时编译器不会改变函数的名字,所以加上extern "C"让托管代码在Dll Import时可以直接使用函数的原名,这样就不需要编写复杂的模块定义文件来重命名符号了,这种方法写dll是最方便的。

下面在cpp文件中实现send_input_core函数:

void send_input_core(WORD vkey) {    INPUT input;    input.type = INPUT_KEYBOARD;    input.ki.dwFlags = NULL;    input.ki.wVk = vkey;    SendInput(1, &input, sizeof(INPUT));}

用vkey参数来接收要模拟的按键,这样就不用重复写SendInput的调用代码了,其余的函数可以直接调用该函数,然后传递按键值就可以了。

void volume_up() {    send_input_core(VK_VOLUME_UP);}void volume_down(){    send_input_core(VK_VOLUME_DOWN);}void volume_mute() {    send_input_core(VK_VOLUME_MUTE);}void media_next_track(){    send_input_core(VK_MEDIA_NEXT_TRACK);}void media_prev_track() {    send_input_core(VK_MEDIA_PREV_TRACK);}void media_play_pause() {    send_input_core(VK_MEDIA_PLAY_PAUSE);}void media_stop(){    send_input_core(VK_MEDIA_STOP);}

 

完成dll后,就导入到C#托管代码中:

namespace DllAPIs{    using System;    using System.Runtime.InteropServices;    public sealed class MediaControlAPIs    {        // dll文件的名字        const string DLL_NAME = "mediactrllib.dll";        #region 从dll导入的API        [DllImport(DLL_NAME)]        extern static void volume_up();        [DllImport(DLL_NAME)]        extern static void volume_down();        [DllImport(DLL_NAME)]        extern static void volume_mute();        [DllImport(DLL_NAME)]        extern static void media_next_track();        [DllImport(DLL_NAME)]        extern static void media_prev_track();        [DllImport(DLL_NAME)]        extern static void media_play_pause();        [DllImport(DLL_NAME)]        extern static void media_stop();        #endregion        #region 公共方法        /// <summary>        /// 增大音量        /// </summary>        public static void VolumeUp()        {            volume_up();        }        /// <summary>        /// 减小音量        /// </summary>        public static void VolumeDown()        {            volume_down();        }        /// <summary>        /// 静音/恢复        /// </summary>        public static void VolumeMute()        {            volume_mute();        }        /// <summary>        /// 下一曲目        /// </summary>        public static void MediaNextTrack()        {            media_next_track();        }        /// <summary>        /// 上一曲目        /// </summary>        public static void MediaPrevTrack()        {            media_prev_track();        }        /// <summary>        /// 播放/暂停        /// </summary>        public static void MediaPlayPause()        {            media_play_pause();        }        /// <summary>        /// 停止播放        /// </summary>        public static void MediaStop()        {            media_stop();        }        #endregion    }}

我想,这样导入要比直接导入Win32 API要简便得多。

接着,完成WCF服务。

    [ServiceContract]    public interface IService    {        [OperationContract]        [WebInvoke(UriTemplate = "invoke?action={act}")]        void Invoke(string act);    }    public class WcfService : IService    {        public void Invoke(string act)        {            switch (act)            {                case "vu": //增大音量                    DllAPIs.MediaControlAPIs.VolumeUp();                    break;                case "vd": //减小音量                    DllAPIs.MediaControlAPIs.VolumeDown();                    break;                case "vm": //静音/恢复                    DllAPIs.MediaControlAPIs.VolumeMute();                    break;                case "mn": //下一首                    DllAPIs.MediaControlAPIs.MediaNextTrack();                    break;                case "mp": //上一首                    DllAPIs.MediaControlAPIs.MediaPrevTrack();                    break;                case "mpp": //播放/暂停                    DllAPIs.MediaControlAPIs.MediaPlayPause();                    break;                case "ms": //停止                    DllAPIs.MediaControlAPIs.MediaStop();                    break;            }        }    }


其他代码就不介绍了,大家看源码吧。

最后是实现手机客户端,其实就是用HTTP-POST向刚才的WCF服务发数据即可。

        private async Task PostActionAsync(string action)        {            string postUri = string.Format("http://{0}:{1}/invoke?action={2}", HostName, Port, action);            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(postUri);            request.Method = "POST";            var rep = await request.GetResponseAsync();        }

 

最后看看结果:

 

 

源代码下载:http://files.cnblogs.com/tcjiaan/RemoteMediaControlSlsn.zip

 

8楼大黑兔
mark
7楼cwxfriend
呵呵,有特色,赞一个!
6楼时间都去哪了
最好提供一份安装包下载,这样大家就不用编译了
5楼王洪旭
mark
4楼土豆哥哥
学以致用,这种人我最佩服,顶你了
3楼小槽君
赞,非常实用
2楼透明的水
学习了www.599xs.com
1楼jello chen
上回也做了一个,记得还请教了您wcf host的问题
  相关解决方案