一:描述
本文描述了使用C#来制作一个ActiveX控件,暴露相应的属性、方法、事件等。
此例中主要是对RdpClient控件的二次封装,可以通过在IE中打开TestRDP.html进行测试:
实现效果图如下:
二:具体实现
基本的实现可以参考文章:
http://blog.youkuaiyun.com/veryhappy/article/details/1604406
其他具体的就不多描述了,看代码吧。
完整代码请于如下链接下载:
http://download.youkuaiyun.com/detail/tragicguy/5447715
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using MSTSCLib;
namespace PemRDPControl
{
[Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IObjectSafety
{
// methods
void GetInterfacceSafyOptions(
System.Int32 riid,
out System.Int32 pdwSupportedOptions,
out System.Int32 pdwEnabledOptions);
void SetInterfaceSafetyOptions(
System.Int32 riid,
System.Int32 dwOptionsSetMask,
System.Int32 dwEnabledOptions);
}
//the function for ie to call
[ComVisible(true)]
[Guid("89970EFC-0014-4A1C-BA19-A18332E7A0BB")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IPemRDPControl
{
[DispId(1)]
void SetControlSize(int width, int height);
[DispId(2)]
void Connect();
string Server
{
get;
set;
}
string UserName
{
get;
set;
}
string PassWord
{
get;
set;
}
string Domain
{
get;
set;
}
int RDPPort
{
get;
set;
}
bool ConnectToServerConsole
{
get;
set;
}
bool ConnectToAdministerServer
{
get;
set;
}
int DesktopWidth
{
get;
set;
}
int DesktopHeight
{
get;
set;
}
int Width
{
get;
set;
}
int Height
{
get;
set;
}
bool FullScreen
{
get;
set;
}
ExtendedDisconnectReasonCode ExtendedDisconnectReason
{
get;
}
}
//the events
[ComVisible(true)]
[Guid("60FB4E65-C928-4D2F-B52E-2993165D314D")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IPemRDPControlEvents
{
[DispId(21)]
void OnConnected();
[DispId(22)]
void OnConnecting();
[DispId(23)]
void OnDisconnected(int reasoncode);
}
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(IPemRDPControl))]
[ComSourceInterfaces(typeof(IPemRDPControlEvents))]
[ComVisible(true)]
[Guid("845FC80C-753A-4095-96D4-9BA2F6DE8E23")]
public partial class UserControl1 : UserControl, IObjectSafety, IPemRDPControl
{
public delegate void OnConnectedHandler();
public delegate void OnConnectingHandler();
public delegate void OnDisconnectedHandler(int reasoncode);
public event OnConnectedHandler OnConnected;
public event OnDisconnectedHandler OnDisconnected;
public event OnConnectingHandler OnConnecting;
#region Property
public string Server
{
get;
set;
}
public string UserName
{
get;
set;
}
public string PassWord
{
get;
set;
}
public string Domain
{
get;
set;
}
public int RDPPort
{
get;
set;
}
public bool ConnectToServerConsole
{
get;
set;
}
public bool ConnectToAdministerServer
{
get;
set;
}
public int DesktopWidth
{
get;
set;
}
public int DesktopHeight
{
get;
set;
}
public int Width
{
get;
set;
}
public int Height
{
get;
set;
}
public bool FullScreen
{
get;
set;
}
#endregion
public UserControl1()
{
InitializeComponent();
Server = "";
UserName = "";
PassWord = "";
ConnectToServerConsole = true;
ConnectToAdministerServer = true;
RDPPort = 3389;
Domain = "";
Width = Height = 0;
DesktopWidth = DesktopHeight = 0;
FullScreen = false;
}
public ExtendedDisconnectReasonCode ExtendedDisconnectReason
{
get { return (ExtendedDisconnectReasonCode)0; }
}
public void Connect()
{
((Control)this).Width = Width;
((Control)this).Height = Height;
axMstscObj.Width = Width;
axMstscObj.Height = Height;
axMstscObj.DesktopWidth = DesktopWidth;
axMstscObj.DesktopHeight = DesktopHeight;
// axMstscObj.ful.FullScreen = FullScreen;
axMstscObj.Domain = Domain;
axMstscObj.Server = Server;
axMstscObj.UserName = UserName;
IMsRdpClientAdvancedSettings7 iClientSetting = (IMsRdpClientAdvancedSettings7)axMstscObj.AdvancedSettings;
iClientSetting.RedirectDrives = false;
iClientSetting.RedirectPrinters = true;
iClientSetting.RedirectPorts = false;
iClientSetting.RedirectSmartCards = true;
iClientSetting.RDPPort = RDPPort;
iClientSetting.ClearTextPassword = PassWord;
iClientSetting.ConnectToServerConsole = ConnectToServerConsole;
iClientSetting.ConnectToAdministerServer = ConnectToAdministerServer;
axMstscObj.Connect();
}
private void axMstscObj_OnConnected(object sender, EventArgs e)
{
//fire event to ie
OnConnected();
}
private void axMstscObj_OnDisconnected(object sender, AxMSTSCLib.IMsTscAxEvents_OnDisconnectedEvent e)
{
//fire event to ie
OnDisconnected(e.discReason);
}
private void axMstscObj_OnConnecting(object sender, EventArgs e)
{
//fire event to ie
OnConnecting();
}
private void axMstscObj_OnLogonError(object sender, AxMSTSCLib.IMsTscAxEvents_OnLogonErrorEvent e)
{
}
#region IPemRDPControl 成员
public void SetControlSize(int width, int height)
{
axMstscObj.Width = width;
axMstscObj.Height = height;
}
#endregion
#region IObjectSafety 成员
public void GetInterfacceSafyOptions(Int32 riid, out Int32 pdwSupportedOptions, out Int32 pdwEnabledOptions)
{
pdwSupportedOptions = 1;
pdwEnabledOptions = 2;
}
public void SetInterfaceSafetyOptions(Int32 riid, Int32 dwOptionsSetMask, Int32 dwEnabledOptions)
{
}
#endregion
private void axMstscObj_OnAuthenticationWarningDismissed(object sender, EventArgs e)
{
}
private void axMstscObj_OnAuthenticationWarningDisplayed(object sender, EventArgs e)
{
}
}
}
网页调用代码如下【运行前请先注册控件】:
<html>
<head>
<title>Demo test</title>
<script language="javascript">
function TestConnect() {
try {
var obj = document.getElementById("MyActive");
obj.Server = "testserver";
obj.RDPPort = 3389;
obj.UserName = "root";
obj.PassWord = "testpwd";
obj.ConnectToServerConsole = true;
obj.ConnectToAdministerServer = true;
var screenHeight = 1920;
var screenWidth = 1080;
obj.Width = screenHeight;
obj.Height = screenWidth;
obj.DesktopWidth = screenHeight;
obj.DesktopHeight = screenWidth;
obj.Connect();
}
catch (e) {
alert(e.Message);
}
}
</script>
</head>
<body style=" margin-left:0; margin-right: 0; margin-top:0;margin-bottom:0" >
<script for="MyActive" event="OnConnected" language="javascript">
//alert("OnConnected");
</script>
<script for="MyActive" event="OnConnecting" language="javascript">
//alert("OnConnecting");
</script>
<script for="MyActive" event="OnDisConnected(reasoncode)" language="javascript">
alert("OnDisConnected:" + reasoncode);
//alert(document.getElementById("MyActive").ExtendedDisconnectReason);
</script>
<!--
<a href='javascript::' onclick='TestConnect();'>connect</a> <br />
<a href='javascript::' onclick='document.getElementById("MyActive").SetControlSize(300, 200);'>Set size</a><br />
<a href='javascript::' onclick='alert(document.getElementById("MyActive").ExtendedDisconnectReason);'>show externalerrorcode</a><br />
-->
<object id="MyActive" name="MyActive" classid="clsid:845FC80C-753A-4095-96D4-9BA2F6DE8E23" VIEWASTEXT ></object>
<script language="javascript">
function OpenActiveX()
{
try {
var obj = document.getElementById("MyActive");
if (obj != null) {
// obj.mWidth = 1030;
// obj.mHeight = 780;
TestConnect();
}
else
alert("Load failed.");
}
catch(Err)
{
alert(Err.description);
}
}
OpenActiveX();
</script>
</body>
</html>
三:后续建议
请关注上图中的 “RDPClient安全警告框.jpg”,在我封装的过程中,使用WINFORM封装控件,在部分机器上正常,而在WIN8等机器上则会出现:
同样,我封装的控件,在IE中也是加载不上来的,可以通过在JS中监控一个事件来验证:
OnAuthenticationWarningDisplayed, 此事件在警告框弹出前会触发。
后来对比了两种代码,发现正常的使用的是类AxMSTSCLib.AxMsTscAxNotSafeForScripting,而我不正常的使用的是AxMSTSCLib.AxMsRdpClient5,这导致了不同的行为。
【这一块没有深究,希望哪位熟悉的给解释一下两者的不同】
通过“RDPClient安全警告框.jpg”中的提示,搜索到国外较多的资料,里面有不少方法来设置解决,我这边试过一些,暂未发现有效的。
另外有一链接中提到使用不同的方式来加载控件,即可避开此错误。
其他参考链接:
以下是我查看过的几个链接:
http://blogs.msdn.com/b/rds/archive/2012/10/23/rdp-8-0-update-for-windows-7-sp1-released-to-web.aspx?PageIndex=2
http://social.technet.microsoft.com/Forums/en-US/w8itprosecurity/thread/1fd2f8d2-ef44-45a8-8561-7c805dfe9bb6
此文件中提到:
Problem solved for me - I used a different id for the control(MsTscAx.MsTscAx instead of MSRDP.MSRDP)
这个与我在处理控件封装中解决提示问题的方法一致,如果能应用到加载RDPClient控件的JS脚本中,相信问题也就解决了