【WP8.1開發】用手機來控制電腦的多媒體播放

爲了用電腦看電影時方便控制,我就突發其想,作一個手機app來經過無線網絡遠程調節電腦上的音量。後來進行嘗試成功後,我就想,光是調音量彷佛單調了些,就把播放/暫停,上一首,下一首,等多媒體控制功能也加上,這樣好玩一點。服務器

下面向你們簡單介紹一下原理,整個解決方案的源代碼我會共享給你們,以做參考。網絡

 

先說服務器,由於控制命令比較簡單,我直接用一個WPF應用程序來完成,這樣方便運行,用socket來通訊比較麻煩,我就用WCF來作服務,使用WebServiceHoset,讓WP手機客戶端用HTTP-POST的方式來調用。app

這個相信你們都會,還有一個核心,就是如何控制系統的多媒體功能? 其實你們應該發如今你的筆記本鍵盤上,有一排功能按鈕,能夠經過按這些鍵來調整音量,控制播放、上一首歌曲等,還有各類功能開關,好比打開/關閉無線功能等。socket

也就是說,只要代碼可以模擬發出這些按鍵就能夠實現控制了,這就要用到Win32 API中的SendInput函數。在最初嘗試時,我將SendInput函數導進託管代碼中,但調用沒有反應,不知道是否是我Import不對。async

後來,我乾脆用C++來寫一個dll,把各個控制操做都用獨立的導出函數來包裝,再把本身寫的dll中的導出函數在託管項目中DllImport。函數

本身編寫的dll的頭文件以下:post

#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內部使用,就再也不導出了。spa

注意要加上extern "C",讓函數以C語言的規範進行導出,因爲C語言不支持函數重載,在編譯時編譯器不會改變函數的名字,因此加上extern "C"讓託管代碼在Dll Import時能夠直接使用函數的原名,這樣就不須要編寫複雜的模塊定義文件來重命名符號了,這種方法寫dll是最方便的。code

下面在cpp文件中實現send_input_core函數:orm

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

相關文章
相關標籤/搜索