使用P/Invoke、C#与Windows Media Player互操作(一)

介绍 

这篇文章将示范:

  • 怎样使用P/Invoke 访问非托管代码。
  • 怎样使用Spy++将Windows消息载入日志,获取参数wParam,lParam的值。
  • 怎样用C#实现FindWindow( )方法和SendMessage( )方法。
  • 怎样和Windows Media Player互操作。

关于Win32 APIs

MSDN对Windows API的定义是这样的:

    Windows API(Application Programming Interface 应用程序接口)由函数,消息,数据结构,数据类型和对它们的描述组成,可以使用这些创建在Windows环境下运行的应用程序。API 中使用最多的部分是通过Windows(操作系统)调用API函数的代码,包括: 对Windows函数的必要的声明,用户自定义的类型(作为数据结构传递给Windows函数),还有常量的声明(作为传递给那些函数或者它们的返回值)。

简单的说,Windows APIs就是嵌入微软Windows操作系统的动态链接库。因为这些库中包含了数以千计的有用的函数,因此如果在我们的代码中使用Window APIs,将大大减少开发的时间和复杂度。但这样做也有不利之处:Window APIs没有使用托管代码,而且有许多不同于Visual Studio.NET中的数据类型。.NET框架已经为我们将一部分重要的Win32 APIs包装为托管代码,而剩下的那些则需要我们在平台调用服务(Platform Invocation Service,一下称为P/Invoke)中编写托管代码来调用了。

关于平台调用服务(Platform Invocation Services,P/Invoke)

P/Invoke是这样一种机制:通过它,托管代码可以调用DLL中实现的那些非托管函数。

当调用非托管函数时,P/Invoke必须知道动态链接库的名字和它所包含的函数(或者序号)。DllImport属性用来指定DLL的位置(包含某些外部方法的实现的DLL),而该属性的参数用来详细说明一些细节,比如EntryPointCharSet。获得更多关于DllImport属性的信息,请参考MSDN中的DllImportAttribute类。

 表1:Win32 API中常用的DLL

DLL描述

Kernel32.dll

包含一些关于内存管理和资源处理的底层函数                                 

GDI32.dll

包含设备输出的一些图形设备接口,比如管理绘图和字体的一些接口

User32.dll

包含Windows处理消息、计时、菜单、通信的函数

使用C# 调用Windows API的步骤

  1. 导入System.Runtime.InteropServices 名称空间
  2. DllImport定义函数
  3. 增加编码调用Win32 API

我们将通过下面的Win32类来说明怎样实现和User32.dll中的API函数有关系的FindWindow( )、SendMessage( )。

 

public   class  Win32
{
    
//当用户从菜单中选择一条命令,
    
//一个控件向它的父窗口发送通知消息,
    
//或者快捷键被按下时,
    
//将发送WM_COMMAND消息
    public const int WM_COMMAND = 0x111;

    
//  FindWindow 函数可找到一个类名、窗口名
    
//与指定字符串相匹配的最上层的窗口的句柄
    
// 该函数不搜索子窗口.
    
// 该函数的搜索过程中不区分大小写.
    [DllImport("User32.dll")]
    
public static extern int FindWindow(string strClassName, 
                                             
string strWindowName);

    
//  FindWindow 函数可找到一个类名、窗口名
    
//与指定字符串相匹配的最上层的窗口的句柄
    
// 该函数从制定的子窗口起依次搜索子窗口
    
// 该函数的搜索过程中不区分大小写.
    [DllImport("User32.dll")]
    
public static extern int FindWindowEx(int hwndParent, 
        
int hwndChildAfter, string strClassName, string strWindowName);


    
//  SendMessage 函数给一个或几个窗口发送特定的消息 
    
// 特定的窗口通过该函数调用程序段,直到处理消息后返回. 
    [DllImport("User32.dll")]
    
public static extern Int32 SendMessage(
        
int hWnd,               // 目标窗口句柄
        int Msg,                // 消息
        int wParam,             // 消息的前一个附加参数
        [MarshalAs(UnmanagedType.LPStr)] string lParam); 
                                
// 消息的第二个附加参数
    [DllImport(
"User32.dll")]
    
public static extern Int32 SendMessage(
        
int hWnd,               // 目标窗口的句柄
        int Msg,                // 消息
        int wParam,             // 消息的第一个附加参数
        int lParam);            // 消息的第二个附加参数
    
public Win32()
    
{

    }


    
~Win32()
    
{
    }

}

 

 Windows Media Player 的交互操作概念:

需要:

  • Microsoft Visual Studio .NET
  • Microsoft Spy++
  • Windows Media Player
  1. 打开Spy++。
  2. 打开Windows Media Player,拖动窗口使Media Player 和Spy++同时可见。
  3. 确保Windows Media Player 没有使用“自动隐藏菜单栏”属性。
  4. 在工作区中选择窗口“Windows Media Player”后按下Log Messages 按钮,或者按快捷键“Ctrl+M”。

接下来,在“Message Options”对话框中切换到Messages标签页,清除所有选中的消息,在显示消息的列表框中向下滚动,选中“WM_COMMAND”,然后单击OK确定。

接下来,在Windows Media Player的菜单“Play”下选择“Stop”命令,或者按快捷键“Ctrl+S”(确保Player先前处于播放状态),Spy++ 将会记录WM_COMMAND消息

 

< 00001 >  0023017A P WM_COMMAND wNotifyCode: 0  (sent from a menu) wID: 18809

 

Spy++的查看消息窗口将如下图所示。请注意,第一列显示了窗口的句柄,第二列显示了这条消息的编码,而剩下的部分则显示了消息的参数和返回值。

在这条消息上单击右键选择“属性”,就可以查看该消息的附加信息,比如wParamlParam的十六进制值

对于Windows Media Player中“Play”命令的消息,也可以通过重复以上步骤得到:

 

< 00002 >  0023017A P WM_COMMAND wNotifyCode: 0  (sent from a menu) wID: 18808

使用P/Invoke和Spy++,很容易扩展包括其他一些操作的功能,比如切换、重复、调整音量等,但作为示例,我们只实现 播放/暂停 和 停止。

 

private  System.Int32 iHandle;

private   void  btnStop_Click( object  sender, System.EventArgs e)
{
    Win32.SendMessage(iHandle, Win32.WM_COMMAND, 
0x000049790x00000000);
}


private   void  btnPlayPause_Click( object  sender, System.EventArgs e)
{
    Win32.SendMessage(iHandle, Win32.WM_COMMAND, 
0x000049780x00000000);
}


private   void  MainForm_Load( object  sender, System.EventArgs e)
{
    
// 获得窗口句柄
    iHandle = Win32.FindWindow("WMPlayerApp""Windows Media Player"); 
}

 结束语

我写这篇文章只是兴趣所在,尽管这不是什么新颖的想法,但我还是希望有人能发现它的用处。开始,我打算深入的研究Windows Media Player,通过FindWindowEx( )函数和ATL:SysListView32中的“Current Playlist”,在远程机器上使用WMI接口操作本机Windows Media Player的播放列表。如果谁有好的意见或者独特的想法,请联系我。

作者简介

Alexander Kent


Biography in progress ;o)
Occupation: Architect
Location: United States United States

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值