您的位置:首页 > 运维架构

发布使用Windows Media Format 9 Series SDK 开发的程序

2009-04-19 00:05 344 查看

再分发 Windows Media 组件

转载摘要本文说明了将 Microsoft® Windows Media® runtime 组件包括在您的应用程序安装中的过程和要求。将按以下顺序讨论下列 Windows Media 技术:
Windows Media Format 9 Series SDK runtime (wmfdist.exe)
Windows Media Encoder 9 Series (WMEncoder.exe)
Windows Media Player 9 Series(MPSetup.exe、MPSetupXP.exe、wmppia.dll)
Windows Media Codecs (WM9Codecs.exe)
Primary Interop Assemblies
Windows Media Services 9 Series(wmstypelib.exe、wmspia.exe)
本页内容



再分发和许可 Windows Media 组件



再分发 Windows Media Format 9 Series 软件



再分发 Windows Media Encoder 9 Series 软件



再分发 Windows Media Player 9 Series 软件



Windows Media 编码解码器再分发



关于主 Interop 程序集



Windows Media Services 9 Series 软件
 

再分发和许可 Windows Media 组件

您可以仔细查阅 Microsoft 网站 Windows Media 许可
网页上的 Windows Media® 许可指南。有关其他的许可信息,请参阅 MSDN 网站上的 Redistributing and Licensing Windows Media Components

再分发 Windows Media Format 9 Series 软件


Windows Media 软件包括在某个应用程序安装中的过程称为再分发。Windows Media Format SDK 9 Series
包括了一个安装程序包 (wmfdist.exe),该程序包可以包括在您的应用程序安装中。安装 Windows Media Format SDK
时,此分发程序包会复制到 SDK 安装位置根目录下的 /Redist 文件夹中。下面几节将介绍将 Windows Media Format runtime 组件包括在您的应用程序安装中的过程和信息。创建再分发安装
1.调用再分发程序包之前,请首先让您的安装例程安装您的应用程序文件,并进行所需的设置。
2.安装 WMFDist.exe。您可以使用 /Q:A 标志执行安静的无人参与安装,并在应用程序(例如:WMFDist.exe /Q:A )安装期间不显示再分发安装的用户界面。然后您的例程必须检测结束时是否需要重新启动重新启动。

WMFdist.exe 命令行参数

将 WMFDist.exe 作为应用程序的一部分进行安装时,管理员或开发人员可以通过使用下列命令,来控制安装 UI 显示和重新启动重新启动行为:
WMFdist.exe /Q:A

此命令指定无人参与安装,并且不出现任何 UI 或警告。
下一节中的代码示例说明了如何在程序包运行结束之后确定成功还是失败,以及是否需要重新启动。

检测 WMFDist.exe 的安装状态

下面的代码可用于 Windows Media Format SDK runtime 再分发或 Windows Media Player 再分发程序包。安装状态将作为 HRESULT
存储在下列位置:
HKCU, Software/Microsoft/MediaPlayer/Setup, REG_SZ, value InstallResult

HRESULT
值可用于确定安装是否成功以及是否需要重新启动。下面的 C++ 示例代码可包含在一个调用安装应用程序中。此代码会根据组件再分发程序包中 Windows Media 安装写入的 HRESULT
值,将 fSuccess
和 fRebootNeeded
变量设置为合适的 true 或 false。 1
#include 
<
windows.h
> 2#include 
<
stdio.h
> 3  4//
 If NS_S_REBOOT_REQUIRED is undefined, use 0xD2AF9. 5#ifndef NS_S_REBOOT_REQUIRED 6#define
 NS_S_REBOOT_REQUIRED       0xd2af9 7#endif 8  9int
 main( 
void
 )10{11    HKEY hKey 
=
 NULL;12    BOOL fSuccess 
=
 FALSE;13    BOOL fRebootNeeded 
=
 FALSE;14 15if
( ERROR_SUCCESS 
==
 RegOpenKeyExA( 16                         HKEY_CURRENT_USER, 17                         
"
Software//Microsoft//MediaPlayer//Setup
"
, 18                         
0
, KEY_QUERY_VALUE, 
&
hKey ))19    {20        
char
 szResult[
64
];21        DWORD dwResult 
=
 
sizeof
( szResult );22 23if
( ERROR_SUCCESS 
==
 RegQueryValueExA( 24                         hKey, 
"
InstallResult
"
, NULL, NULL, 25                         (LPBYTE)szResult, 
&
dwResult ) )26        {27            sscanf( szResult, 
"
%x
"

&
dwResult );28            fSuccess 
=
 SUCCEEDED( dwResult );29            fRebootNeeded 
=
 ( NS_S_REBOOT_REQUIRED 
==
 dwResult );30        }31 32        RegCloseKey( hKey );33    }34 35    
if
( fSuccess )36    {37        printf( 
"
Setup Succeeded
"
 );38        
if
( fRebootNeeded )39            printf( 
"
A restart IS required
/n
"
 );40        
else41            printf( 
"
A restart IS NOT required
/n
"
 );42    }43    
else44    {45        printf( 
"
Setup Failed
"
 );46        
if
( fRebootNeeded )47            printf( 
"
A restart IS required
/n
"
 );48        
else49            printf( 
"
A restart IS NOT required
/n
"
 );50    }51 52    
return
 
0
;53}54


果要将再分发程序包包括在您的应用程序中,则当您在安装例程中调用该再分发程序包时,可以使用 /Q:A 标志。这样会抑制用户界面 (UI)
的显示。因为 WMFdist.exe
程序包的设计意图就是为了用于软件再分发,所以该程序包会抑制自动重新启动,不会通过用户界面返回或通知用户重新启动情况。请确保使用返回注册表的信息来
执行下列操作:
确定在运行 WMFdist.exe 之后计算机是否需要重新启动。
处理需要重新启动的情况,以及需要重新启动时与最终用户的通信。
下面的示例代码可在您的安装例程中用来以安静模式运行再分发程序包,并在计算机必须重新启动时通知您的安装例程。  1
/**/
/////////////////////////////////////////////////////////////////////
//  2
//  3//
 MUST ADD:  4//  5//
 You must add "shlwapi.lib" to your project settings (link)  6//  7/**/
/////////////////////////////////////////////////////////////////////
//  8  9#include 
<
windows.h
> 10#include 
<
shlwapi.h
> 11#include 
<
TCHAR.H
> 12#include 
<
iostream
> 13using
 std::cout; 14using
 std::endl; 15 16#define
 MAX_TIMEOUT_MS 30 * 60 * 1000 17#define
 TIME_INCREMENT 250 18 19//
 Prototypes 20BOOL GoInstallWMRedist( BOOL ); 21BOOL SystemNeedsReboot( 
void
 ); 22 23void
 main( 
void
 ) 24{ 25    GoInstallWMRedist( TRUE ); 26 27    cout 
<<
 
"
Setup is complete
"
; 28 29    
if
( SystemNeedsReboot() ) 30    { 31        
//
 Write some code here to ensure that your application will  32        
//
 restart the computer, and delay dll registrations and so on  33        
//
 until after the restart, where possible. For example,  34        
//
 set a global flag for use by the application. 35        cout 
<<
  
"
A restart IS required
"
 
<<
 endl; 36    } 37    
else 38        cout 
<<
  
"
A restart IS NOT required
"
 
<<
 endl; 39     40} 41 42/**/
/////////////////////////////////////////////////////////////////////
// 43
//
  44//
 Usage: 45// 46//
 Takes one parameter (BOOL) 47// 48//
 If you want to wait for completion, pass TRUE, 49//
 else pass FALSE. 50// 51/**/
/////////////////////////////////////////////////////////////////////
// 52
BOOL GoInstallWMRedist( BOOL fWaitForCompletion ) 53/**/
/////////////////////////////////////////////////////////////////////
// 54{ 55    STARTUPINFO StartUpInfo; 56    PROCESS_INFORMATION ProcessInfo; 57 58    StartUpInfo.cb 
=
 
sizeof
( StartUpInfo ); 59    StartUpInfo.lpReserved 
=
 NULL; 60    StartUpInfo.dwFlags 
=
 
0
; 61    StartUpInfo.cbReserved2 
=
 
0
; 62    StartUpInfo.lpReserved2 
=
 NULL;  63    StartUpInfo.lpDesktop 
=
 NULL; 64    StartUpInfo.lpTitle 
=
 NULL; 65    StartUpInfo.dwX 
=
 
0
; 66    StartUpInfo.dwY 
=
 
0
; 67    StartUpInfo.dwXSize 
=
 
0
; 68    StartUpInfo.dwYSize 
=
 
0
; 69    StartUpInfo.dwXCountChars 
=
 
0
; 70    StartUpInfo.dwYCountChars 
=
 
0
; 71    StartUpInfo.dwFillAttribute 
=
 
0
; 72    StartUpInfo.dwFlags 
=
 
0
; 73    StartUpInfo.wShowWindow 
=
 
0
; 74    StartUpInfo.hStdInput 
=
 NULL; 75    StartUpInfo.hStdOutput 
=
 NULL; 76    StartUpInfo.hStdError 
=
 NULL; 77 78    
//
 Run the installer with the Quiet for All and Reboot:Never  79    
//
 flags. The installation should be silent, and the setup routine   80    
//
 will be notified whether the computer must be restarted. 81 82    
if

!
CreateProcess( _T(
"
c://temp//WMFDist.exe
"
),  83            _T(
"
c://temp//WMFDist.exe /Q:A
"
), NULL, NULL, FALSE,  84            
0
, NULL, NULL, 
&
StartUpInfo, 
&
ProcessInfo ) ) 85    { 86        DWORD myError 
=
 GetLastError(); 87        
return
( FALSE ); 88    } 89 90    CloseHandle( ProcessInfo.hThread ); 91 92    
if
( fWaitForCompletion ) 93    { 94        DWORD dwTimePassed 
=
 
0
; 95        
while
( TRUE ) 96        { 97            
if
( WAIT_TIMEOUT 
!=
 WaitForMultipleObjects(  98                  
1

&
ProcessInfo.hProcess, FALSE, TIME_INCREMENT ) ) 99                
break
;100101            
if
( dwTimePassed 
>
 MAX_TIMEOUT_MS )102            {103                TerminateProcess( ProcessInfo.hProcess, E_FAIL );104                
break
;105            }106            dwTimePassed 
+=
 TIME_INCREMENT;107        }108    }109    CloseHandle( ProcessInfo.hProcess);110111    
return
( TRUE );112}113114/**/
/////////////////////////////////////////////////////////////////////
//115
//116//
  Used to determine whether the system should be restarted
117//118/**/
/////////////////////////////////////////////////////////////////////
//119
BOOL SystemNeedsReboot( 
void
 )120/**/
/////////////////////////////////////////////////////////////////////
//121{122    BOOL fNeedExists 
=
 FALSE;123    OSVERSIONINFO osvi;124125    osvi.dwOSVersionInfoSize 
=
 
sizeof
( OSVERSIONINFO );126    GetVersionEx( 
&
osvi );127128    
if
( VER_PLATFORM_WIN32_NT 
!=
 osvi.dwPlatformId )129    {130        TCHAR szIniPath[MAX_PATH];131132        GetWindowsDirectory(szIniPath, 133                            
sizeof
(szIniPath)
/
sizeof
(TCHAR));134        PathAddBackslash( szIniPath );135        _tcscat( szIniPath, _T(
"
wininit.ini
"
) );136137        
if

0xFFFFFFFF
 
!=
 GetFileAttributes( szIniPath ) )138        {139            HFILE hFile;140141            
if
( (hFile 
=
 142                   _lopen(szIniPath,OF_READ
|
OF_SHARE_DENY_NONE))
!=
 143                                                      HFILE_ERROR )144            {145                fNeedExists 
=
 ( 
0
 
!=
 _llseek(hFile, 
0L
, FILE_END) );146                _lclose(hFile);147            }148        }149    }150    
else151    {152        HKEY hKey 
=
 NULL;153154        
if
( ERROR_SUCCESS 
==
 RegOpenKeyEx( HKEY_LOCAL_MACHINE, 155            _T(
"
System//CurrentControlSet//Control//Session Manager
"
), 156             
0
, KEY_READ, 
&
hKey ) )157        {158            
if
( ERROR_SUCCESS 
==
 RegQueryValueEx( hKey, 159                     _T(
"
PendingFileRenameOperations
"
), 160                      NULL, NULL, NULL, NULL))161            {162                fNeedExists 
=
 TRUE;163            }164165            RegCloseKey( hKey );166        }167    }168169    
return
( fNeedExists );170}

再分发 Windows Media Encoder 9 Series 软件


您分发基于 Windows Media Encoder SDK 的应用程序时,必须通过在安装中再分发 Windows Media
Encoder,或者要求您的用户自行安装 Windows Media Encoder,将 Windows Media Encoder
软件也包括在内。如果您要再分发 Windows Media Encoder,则必须在安装中包括并运行 WMEncoder.exe 安装文件。Microsoft 网站的下载中心
中提供有此文件。如果您希望最终用户自行安装 Windows Media Encoder,则可以引导这些用户访问此网站。默认情况下,Windows Media Encoder 安装在 C:/Program Files/Windows Media Components/Encoder 目录中。WMEncoder.exe
命令行参数下面几项内容显示了 WMEncoder.exe 常用的命令行参数。对于不带
UI
的无人参与安装:
wmencoder.exe /Q:A

对于带有进度条的无人参与安装:
wmencoder.exe /Q

检测
Windows Media Encoder 9 Series您可以通过搜索注册表的方式,确定所安装的 Windows Media Encoder 的版本:
HKLM, Software/Microsoft/Windows Media/Encoder, "Version"

在该编码器项下面,如果设置了 Version 字符串值,则可以放心地使用该字符串值作为所安装的 Windows Media Encoder 的版本。您可以使用下列注册表项来确定 Windows Media Encoder 安装目录的位置:
HKLM, Software/Microsoft/Windows Media/Encoder, "InstallDir"


再分发 Windows Media Player 9 Series 软件

在应用程序中检测 Windows Media Player

您可以通过搜索注册表的方式,确定所安装的 Windows Media Player 的版本。
HKEY_LOCAL_MACHINE/Software/Microsoft/Active Setup/Installed Components

对于 Windows Media Player 6.4,请查看该项:
"{22d6f312-b0f6-11d0-94ab-0080c74c7e95}"

对于 Windows Media Player 7、Windows Media Player for Windows® XP 或 Windows Media Player 9 Series,请查看该项:
"{6BF52A52-394A-11d3-B153-00C04F79FAA6}"

在上述任一项下面,如果 IsInstalled
DWORD
值设置为 0x1,则可以放心地使用“Version”字符串值作为所安装的 Windows Media Player 的版本。MPSetup.exe

MPSetupXP.exe
命令行参数下面是几个常用的命令行参数。对于不带
UI
、不需要重新启动或没有重新启动提示的无人参与安装:
mpsetup.exe /q:A /c:"setup_wm.exe /Q:A /R:N /P:#e"

这是一个标准的命令行,通常应该用于执行无人参与安装。防止媒体库移植:
mpsetup.exe /q:A /R:N /c:"setup_wm.exe /NoMigrate /P:#e"

对安装程序包进行缓存,用于以后的
Windows
升级移植:
mpsetup.exe /q:A /R:N /c:"setup_wm.exe /P:#e"

/P:#e
指定,在 Windows Media Player 安装过程中应该对 Windows Media Player
安装程序包进行缓存。在处理操作系统将来升级的所有命令行中,通常应该使用此参数。不应在命令行中包括 /P:#e
的唯一一种情况为,您知道目标系统永远不会升级为更高版本的操作系统。例如,如果您正在 Windows 2000 上安装 Windows
Media Player 9 Series,并且该计算机在将来的某一天可能会升级为 Windows XP,则必须在命令行中使用
/P:#e。如果不使用此参数,则在 Windows XP 安装之后,Windows Media Player 9 Series 文件会被
Windows Media Player for Windows XP 的文件所覆盖。对于安静模式:
/Q

此参数用于不带 UI 的无人参与安装。取消重新启动提示:
/R:N

此参数表示永远不需要重新启动,也不出现提示。如果您忽略此命令,则无论是否已经安装该软件,播放器都会在安装结束时提示用户重新启动计算机。创建嵌套的系统还原点:
/NestedRestore

如果您的应用程序创建的系统还原点会将 Windows Media Player 还原点嵌套在应用程序还原点中,请使用此参数。不允许创建系统还原点
/DisallowSystemRestore


标志会禁止系统还原点的创建。大多数情况下,对于一般的软件再分发方案都不应该使用此标志。只有当您可以代表最终用户作出明确选择, 不支持
Windows Media Player 9 Series
文件回滚到该播放器的更早版本时,才应该使用此标志。此标志只应在公司部署或者原始设备制造商 (OEM) 安装方案中使用。注意
命令行参数区分大小写。
取消重新启动提示时,必须检查 InstallResult 注册表项,并处理调用安装应用程序中的重新启动通知。
Windows
Media Player 9 Series 还会安装 Windows Media Format runtime,因此无需将 Media
Player 9 Series 分发程序包和 Windows Media Format Runtime
分发程序包同时包括在一个软件再分发程序包中。例如,如果您在安装中包括了 MPSetup.exe 或 MPSetupXP.exe,则无需包括
WMFdist.exe。
检测
MPSetup.exe

MPSetupXP.exe
的安装状态下面的代码可用于 Windows Media Player 再分发程序包。安装状态作为 HRESULT
存储在下列位置:
HKCU, Software/Microsoft/MediaPlayer/Setup, REG_SZ, value InstallResult

HRESULT
值可用于确定安装是否成功以及是否需要重新启动。下面的 C++ 示例代码可包含在一个调用安装应用程序中。此代码会根据组件再分发程序包中 Windows Media 安装写入的 HRESULT
值,将 fSucess
和 fRebootNeeded
变量设置为合适的 true 或 false。 1
#include 
<
windows.h
> 2#include 
<
stdio.h
> 3  4//
 If NS_S_REBOOT_REQUIRED is undefined, use 0xD2AF9. 5#ifndef NS_S_REBOOT_REQUIRED 6#define
 NS_S_REBOOT_REQUIRED       0xd2af9 7#endif 8  9int
 main( 
void
 )10{11    HKEY hKey 
=
 NULL;12    BOOL fSuccess 
=
 FALSE;13    BOOL fRebootNeeded 
=
 FALSE;14 15if
( ERROR_SUCCESS 
==
 RegOpenKeyExA( 16                         HKEY_CURRENT_USER, 17                         
"
Software//Microsoft//MediaPlayer//Setup
"
, 18                         
0
, KEY_QUERY_VALUE, 
&
hKey ))19    {20        
char
 szResult[
64
];21        DWORD dwResult 
=
 
sizeof
( szResult );22 23if
( ERROR_SUCCESS 
==
 RegQueryValueExA( 24                         hKey, 
"
InstallResult
"
, NULL, NULL, 25                         (LPBYTE)szResult, 
&
dwResult ) )26        {27            sscanf( szResult, 
"
%x
"

&
dwResult );28            fSuccess 
=
 SUCCEEDED( dwResult );29            fRebootNeeded 
=
 ( NS_S_REBOOT_REQUIRED 
==
 dwResult );30        }31 32        RegCloseKey( hKey );33    }34 35    
if
( fSuccess )36    {37        printf( 
"
Setup Succeeded
"
 );38        
if
( fRebootNeeded )39            printf( 
"
A restart IS required
/n
"
 );40        
else41            printf( 
"
A restart IS NOT required
/n
"
 );42    }43    
else44    {45        printf( 
"
Setup Failed
"
 );46        
if
( fRebootNeeded )47            printf( 
"
A restart IS required
/n
"
 );48        
else49            printf( 
"
A restart IS NOT required
/n
"
 );50    }51 52    
return
 
0
;53}

 

Windows Media 编码解码器再分发


可以更新 Windows Media Player 7 或 Windows Media Player for Windows
XP,以使得这些软件不必依赖 Internet 代码自动下载机制即可支持 Windows Media 9 Series
编码解码器。有一个用于此目的的编码解码器再分发程序包,名为 WM9Codecs.exe,该程序包可用于公司和软件部署。要在应用程序再分发安装中使用这个程序包更新编码解码器,请使用下面的命令行将 WM9Codecs.exe 包括在内,并运行该程序包。
WM9Codecsxe /Q:A

这样会启动不带 UI 的无人参与安装。注意
您必须使用 Windows Media Format runtime 再分发部分中说明的注册表信息,来检查安装成功状态,并确定系统是否需要重新启动来完成安装。
如果在再分发安装中包括了 Windows Media Player 9 Series 或 Windows Media Format runtime 分发程序包,则无需包括 Windows Media Codecs 安装程序包。

 

关于主 Interop 程序集

使
用 Microsoft Windows .NET 框架嵌入 Windows Media Player 控件的过程需要使用 Windows
Media Player 主 interop 程序集 (PIA)。PIA 是一个独特的框架程序集,其中包含了 COM
组件所实现的各种类型的类型定义(作为元数据)。只有类型库的发布者才能生成真正的 PIA,该 PIA 将成为用于与基础 COM
类型进行交互的正式类型定义的单元。有关详细信息,请参阅 MSDN 网站上的 主 Interop 程序集 (PIA)

与您的应用程序一起再分发主 Interop 程序集


Interop 程序集 (PIA) 是做为 Microsoft Windows .NET
框架应用程序的一部分再分发给最终用户的。包含一个或多个 PIA 的应用程序的部署与任何基于 .NET
的应用程序一样,不需要在用户计算机上注册每个相关的 COM 类型库。按照定义,PIA
总是由它们的发布者进行签名,以确保唯一性。按照它们所描述类型的唯一官方定义,您可以希望一些常用的 PIA
安装在全局程序集缓存中,即使将这同一个程序集部署到应用程序目录中也可如此。当全局程序集与本地程序集具有相同的供应商签名时,公共语言运行库总是会将
您的应用程序指向该全局程序集缓存中的
PIA。在这种情况下,您的应用程序不会受到保护,会受供应商发起的版本更改的影响。最佳方法是始终安装供应商提供的最新版本。然而,当您的应用程序需要
上述保护时,则可以通过使用类型库导入程序 (Tlbimp.exe)(而不是 PIA)来生成自己的 interop 程序集。

注册用于应用程序开发的主 Interop 程序集

您必须使用程序集注册工具 (RegAsm.exe) 和全局程序集缓存实用程序 (GacUtil.exe) 来注册和安装 Windows Media Player PIA。要注册 PIA,请在命令提示符下,键入:
regasm assemblyname

在此命令中,assemblyname
为要注册的程序集的文件名。下面的示例会注册 wmppia.dll PIA。
regasm C:/WMSDK/WMPSDK9/redist/wmppia.dll

Regasm.exe 在与原始类型库相同的注册表项下面添加一个用于该 PIA 的注册表项。注册了该 PIA 之后,使用全局程序集缓存实用程序将其安装到全局程序集缓存 (GAC) 中。要将 PIA 安装到 GAC 中,请在命令提示符下,键入:
Gacutil /i assemblyname

在此命令中,assemblyname
为要安装的程序集的文件名。下面的示例会在 GAC 中安装 Windows Media Player PIA。
Gacutil /i C:/WMSDK/WMPSDK9/redist/wmppia.dll


您应该在计算机中搜索 RegAsm.exe 和 Gacutil.exe。通常这两个程序位于 %windir%/Microsoft.NET/Framework/v1.0.xxxx
中(其中 xxxx
为您正在使用的 Windows .NET 框架的版本的内部版本号)或者您在其中安装开发环境的 /FrameworkSDK/Bin 文件夹中。包
含 Windows Media Player SDK 完整安装所包含的 C# 示例应用程序的文件夹还包含了一个名为 regpiagac.vbs
的脚本文件。此实用程序可使得注册 PIA 并将其添加到 GAC
中的过程变得十分简单。双击该文件并在出现提示时提供正确的路径,即可完成该过程。如果您使用默认安装路径安装了 Windows Media
Player SDK 和 Visual Studio
.NET,则只需更改驱动器盘符。如果没有使用默认路径安装这些产品,则可能会发生非预期的结果。 

Windows Media Services 9 Series 软件

Windows Media Services 9 Series 包含了下面两个可再分发的组件,这两个组件可在与 Windows Media Services 交互的软件应用程序开发中使用。
WMSServerTypeLib.dll
microsoft.windowsmediaservices.dll

两个文件可从 Microsoft Platform SDK 通过 Windows Media Services 9 Series
组件安装选项获得。安装 Microsoft Platform SDK 会同时授予开发人员再分发这两个文件的权利。这两个文件位于
Microsoft Windows Platform SDK 安装根文件夹下的 /include 目录中。默认情况下,该文件夹为
C:/Program Files/Microsoft SDK/include。默认情况下,许可条款位于 Microsoft
SDK/License 文件夹中。转到原英文内页面
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息