说明:这个程序是从命令行执行的,解析命令行传入的参数信息,执行远程桌面连接。只描述实现过程,不讨论实现原理。
1. 打开VS 2005,新建一个“MFC智能设备应用程序”项目
2. 在应用程序类型处选择“单文档”;取消“文档/视图结构支持”;选择“在共享库中使用MFC”
3. 在高级功能处选上“ActiveX控件”和“Windows套接字”
4. 项目新建完成后,从项目源文件中排除"ChildView.h"和“ChildView.cpp”
5. 打开"MainFrm.h",删除这两个成员变量
protected: // 控件条嵌入成员
//CCommandBar m_wndCommandBar;
//CChildView m_wndView;
6. 修改以下三个函数函数,注释掉无用的代码
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
#if 0
// 创建一个视图以占用框架的工作区
if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
{
TRACE0("未能创建视图窗口\n");
return -1;
}
if (!m_wndCommandBar.Create(this) ||
!m_wndCommandBar.InsertMenuBar(IDR_MAINFRAME) ||
!m_wndCommandBar.AddAdornments(dwAdornmentFlags))
{
TRACE0("未能创建 CommandBar\n");
return -1; // 未能创建
}
m_wndCommandBar.SetBarStyle(m_wndCommandBar.GetBarStyle() | CBRS_SIZE_FIXED);
#endif
return 0;
}
void CMainFrame::OnSetFocus(CWnd* /*pOldWnd*/)
{
// 将焦点前移到视图窗口
#if 0
m_wndView.SetFocus();
#endif
}
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
// 让视图第一次尝试该命令
#if 0
if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
#endif
// 否则,执行默认处理
return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
注意:“return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);”这行代码不能删除,否则无法接收控件事件。
此时项目应该可以编译运行了。我们继续。
7. 代开 “stdafx.h”文件,在“#include <afxdisp.h>” 这行下面添加以下代码
#include <mstsax.h>
#include <urlmon.h>
#include <shlobj.h>
#include <winnetwk.h>
8. 打开"MainFrm.h"文件,在CMainFrame类中添加以下定义
public:
IMsRdpClient *m_pMsTsc;
IMsRdpClientNonScriptable3 *pns;
IMsRdpClientSecuredSettings *pss;
IMsRdpClientAdvancedSettings *padv;
CWnd m_wndMsTsc;
void RegisterMstscax();
void UnRegisterMstscax();
void OnConnecting();
void OnDisconnected(long discReason);
void OnEnterFullScreenMode();
void OnLeaveFullScreenMode();
void OnLoginComplete();
void OnConnected();
void OnRequestGoFullScreen();
void OnRequestLeaveFullScreen();
void OnLogonError(long lError);
void ShowTaskBar(BOOL show);
int MstscConnect(void);
9. 修改CMainFrame类中的 “// 生成的消息映射函数” 注释下面的代码为
// 生成的消息映射函数
protected:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSetFocus(CWnd *pOldWnd);
afx_msg void OnSize(UINT nType,int x,int y);
DECLARE_MESSAGE_MAP()
DECLARE_EVENTSINK_MAP()
添加了“OnSize”消息处理函数声明和“DECLARE_EVENTSINK_MAP() ”控件消息映射
10. 修改MainFrm.cpp,在消息映射宏里添加“ON_WM_SIZE()”
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_CREATE()
ON_WM_SETFOCUS()
ON_WM_SIZE()
END_MESSAGE_MAP()
11. 在MainFrm.cpp中增加控件事件映射宏
BEGIN_EVENTSINK_MAP(CMainFrame, CFrameWnd)
ON_EVENT(CMainFrame, AFX_IDW_PANE_FIRST, 1, CMainFrame::OnConnecting, VTS_NONE)
ON_EVENT(CMainFrame, AFX_IDW_PANE_FIRST, 4, CMainFrame::OnDisconnected, VTS_I4)
ON_EVENT(CMainFrame, AFX_IDW_PANE_FIRST, 5, CMainFrame::OnEnterFullScreenMode, VTS_NONE)
ON_EVENT(CMainFrame, AFX_IDW_PANE_FIRST, 6, CMainFrame::OnLeaveFullScreenMode, VTS_NONE)
ON_EVENT(CMainFrame, AFX_IDW_PANE_FIRST, 3, CMainFrame::OnLoginComplete, VTS_NONE)
ON_EVENT(CMainFrame, AFX_IDW_PANE_FIRST, 2, CMainFrame::OnConnected, VTS_NONE)
ON_EVENT(CMainFrame, AFX_IDW_PANE_FIRST, 8, CMainFrame::OnRequestGoFullScreen, VTS_NONE)
ON_EVENT(CMainFrame, AFX_IDW_PANE_FIRST, 9, CMainFrame::OnRequestLeaveFullScreen, VTS_NONE)
ON_EVENT(CMainFrame, AFX_IDW_PANE_FIRST, 22, CMainFrame::OnLogonError, VTS_I4)
END_EVENTSINK_MAP()
12. 在CMainFrame构造函数中初始化m_pMsTsc为NULL
CMainFrame::CMainFrame()
{
// TODO: 在此添加成员初始化代码
m_pMsTsc = NULL;
}
13. 在CMainFrame析构函数中释放资源,显示任务栏
CMainFrame::~CMainFrame()
{
ShowTaskBar(TRUE);
if(NULL != m_pMsTsc)
{
m_pMsTsc->Disconnect();
m_pMsTsc->Release();
}
m_pMsTsc = NULL;
}
14. 实现远程桌面控件事件处理函数
void CMainFrame::OnConnecting()
{
}
void CMainFrame::OnEnterFullScreenMode()
{
ShowTaskBar(FALSE);
}
void CMainFrame::OnLeaveFullScreenMode()
{
ShowTaskBar(TRUE);
}
void CMainFrame::OnRequestGoFullScreen()
{
}
void CMainFrame::OnRequestLeaveFullScreen()
{
}
void CMainFrame::OnLoginComplete()
{
LONG style;
style = GetWindowLong(GetSafeHwnd(),GWL_STYLE);
style |= WS_MAXIMIZEBOX;
style |= WS_MINIMIZEBOX;
SetWindowLong(GetSafeHwnd(),GWL_STYLE,style);
m_pMsTsc->put_FullScreen(TRUE);
ShowTaskBar(FALSE);
}
void CMainFrame::OnConnected()
{
}
void CMainFrame::OnLogonError(long lError)
{
}
void CMainFrame::OnDisconnected(long discReason)
{
ShowTaskBar(TRUE);
DestroyWindow();
if(NULL != m_pMsTsc)
{
m_pMsTsc->Disconnect();
m_pMsTsc->Release();
}
m_pMsTsc = NULL;
}
15. 实现OnSize函数
void CMainFrame::OnSize(UINT nType,int cx,int cy)
{
int IsSet=0;
if(nType==SIZE_MAXIMIZED)
{
m_pMsTsc->put_FullScreen(TRUE);
}
else
{
if(GetSystemMetrics(SM_CXSCREEN)<cx)
{
cx = GetSystemMetrics(SM_CXSCREEN);
IsSet = 1;
}
if(GetSystemMetrics(SM_CYSCREEN)<cy)
{
cy = GetSystemMetrics(SM_CYSCREEN);
IsSet = 1;
}
if(IsSet)
{
SetWindowPos(NULL,0,0,cx,cy,0);
}
if(m_pMsTsc != NULL)
{
m_wndMsTsc.SetWindowPos(NULL,0,0,cx,cy,0);
}
}
}
16. 实现控件注册、反注册和控件函数
void CMainFrame::UnRegisterMstscax()
{ //装载ActiveX控件
LPCTSTR pszDllName= TEXT("\\windows\\mstscax.dll");
HINSTANCE hLib = LoadLibrary( pszDllName );
if (hLib == NULL)
{
//AfxMessageBox( _T( "不能载入Dll文件!" ) );
return;
}
//获取反注册函数 DllUnregisterServer 地址
FARPROC lpDllEntryPoint;
lpDllEntryPoint = GetProcAddress (hLib,_T( "DllUnregisterServer" ));
//调用注册函数 DllUnregisterServer
if( lpDllEntryPoint != NULL )
{
if( FAILED((*lpDllEntryPoint)()) )
{
//AfxMessageBox( _T( "调用 DllUnregisterServer 失败!" ) );
FreeLibrary( hLib );
return;
}
}
//MessageBox(TEXT("调用DllRegisterServer成功!"),TEXT("结果"),MB_OK);
}
void CMainFrame::RegisterMstscax()
{
//ActiveX控件的路径及文件名
LPCTSTR pszDllName= TEXT("\\windows\\mstscax.dll");
//装载ActiveX控件
HINSTANCE hLib = LoadLibrary(pszDllName);
if (hLib == NULL)
{
MessageBox(TEXT("不能载入Dll文件!"),TEXT("结果"),MB_OK);
return;
}
//获取注册函数DllRegisterServer地址
FARPROC lpDllEntryPoint;
lpDllEntryPoint = GetProcAddress (hLib,TEXT( "DllRegisterServer"));
//调用注册函数DllRegisterServer
if(lpDllEntryPoint!=NULL)
{
if(FAILED((*lpDllEntryPoint)()))
{
MessageBox(TEXT("调用Dll Entry失败!"), TEXT("结果"),MB_OK);
FreeLibrary(hLib);
return;
}
//MessageBox(TEXT("注册成功"),TEXT("结果"),MB_OK);
}
else
{
MessageBox(TEXT("调用DllRegisterServer失败!"),TEXT("结果"),MB_OK);
}
}
void CMainFrame::ShowTaskBar(BOOL show)
{
CWnd *pwndTaskBar;
pwndTaskBar = FindWindow(TEXT("HHTaskBar"),NULL);
if(show)
{
pwndTaskBar->ShowWindow(SW_NORMAL);
}
else
{
pwndTaskBar->ShowWindow(SW_HIDE);
}
pwndTaskBar->UpdateWindow();
}
#define COMMAND_HELP \
TEXT("\
-host <host>\r\n\
-port <rdp port>\r\n\
-user <user name>\r\n\
-password <password>\r\n\
-domain <domain>\r\n\
-color <8/15/16>\r\n\
-mode <m/w/l>\r\n\
-audio\r\n\
-comport\r\n\
-printer\r\n\
-regmstsc\r\n\
")
int CMainFrame::MstscConnect(void)
{
CLSID CLSID_MsRdpClient5={0x4eb2f086,0xc818,0x447e,0xb3,0x2c,0xc5,0x1c,0xe2,0xb3,0x0d,0x31};
IID IID_IMsRdpClient5={0x4eb5335b,0x6429,0x477d,0xb9,0x22,0xe0,0x6a,0x28,0xec,0xd8,0xbf};
IID IID_IMsRdpClientNonScriptable3={0xb3378d90,0x0728,0x45c7,0x8e,0xd7,0xb6,0x15,0x9f,0xb9,0x22,0x19};
TCHAR szServer[64]; // -host
TCHAR szPort[6]={0,0,0,0,0,0}; // -port
TCHAR szUserName[128]; // -user
TCHAR szPassword[128]; // -password
TCHAR szDomain[128]; // -domain
TCHAR szColor[3]={0,0,0};// -color
TCHAR szMode[2]={0,0}; // -mode
int color=16;
int port=3389;
int audio=1; // -audio 0,local,1 remote
int comport=0; // -comport
int printer=0; // -printer
int mode=0x00; // LAN
memset(szServer,0,sizeof(szServer));
memset(szUserName,0,sizeof(szUserName));
memset(szPassword,0,sizeof(szPassword));
memset(szDomain,0,sizeof(szDomain));
LPWSTR Para,p,q=NULL;
Para = GetCommandLine();
if(wcslen(Para) < 2)
{
MessageBox(COMMAND_HELP,TEXT("参数信息"),MB_OK);
EndModalLoop(IDOK);
return FALSE;
}
p = Para;
while(*p)
{
if(iswspace(*p))
{
p++;
continue;
}
if(q != NULL)
{
while(*p && !iswspace(*p))
{
*q++ = *p++;
}
q = NULL;
continue;
}
if(0 == wcsncmp(p,TEXT("-host"),5))
{
q = szServer;
p+=5;
}
else if(0 == wcsncmp(p,TEXT("-port"),5))
{
q = szPort;
p+=5;
}
else if(0 == wcsncmp(p,TEXT("-user"),5))
{
q = szUserName;
p+=5;
}
else if(0 == wcsncmp(p,TEXT("-password"),9))
{
q = szPassword;
p+=9;
}
else if(0 == wcsncmp(p,TEXT("-domain"),7))
{
q = szDomain;
p+=7;
}
else if(0 == wcsncmp(p,TEXT("-mode"),5))
{
q = szMode;
p+=5;
}
else if(0 == wcsncmp(p,TEXT("-color"),6))
{
q = szColor;
p+=6;
}
else if(0 == wcsncmp(p,TEXT("-audio"),6))
{
audio = 0;
p+=6;
}
else if(0 == wcsncmp(p,TEXT("-comport"),8))
{
comport = 1;
p+=8;
}
else if(0 == wcsncmp(p,TEXT("-printer"),8))
{
printer = 1;
p+=8;
}
else if(0 == wcsncmp(p,TEXT("-regmstsc"),9))
{
RegisterMstscax();
p+=9;
}
else
{
while(*p && !iswspace(*p))
{
p++;
}
}
}
if(0 == wcsncmp(szColor,TEXT("8"),1))
{
color = 8;
}
else if(0 == wcsncmp(szColor,TEXT("15"),2))
{
color = 15;
}
port = _wtoi(szPort);
if((port <= 0) || (port > 65535))
{
port = 3389;
}
if(0 == wcsncmp(szMode,TEXT("m"),1))
{
mode = 0x1 + 0x2 + 0x4 + 0x8;
}
else if(0 == wcsncmp(szMode,TEXT("w"),1))
{
mode = 0x2 + 0x4;
}
RECT rectClient;
GetWindowRect(&rectClient);
///创建控件
if (!m_wndMsTsc.CreateControl(CLSID_MsRdpClient5, NULL, WS_VISIBLE, rectClient,this, AFX_IDW_PANE_FIRST))
{
DestroyWindow();
return FALSE;
}
///得到指针
LPUNKNOWN lpUnk = m_wndMsTsc.GetControlUnknown();
HRESULT hr = lpUnk->QueryInterface(IID_IMsRdpClient5, (void**) &m_pMsTsc);
if (!SUCCEEDED(hr))
{
m_pMsTsc = NULL;
m_wndMsTsc.DestroyWindow();
DestroyWindow();
return FALSE;
}
lpUnk->QueryInterface(IID_IMsRdpClientNonScriptable3, (void**) &pns);
m_pMsTsc->get_SecuredSettings2(&pss);
m_pMsTsc->get_AdvancedSettings2(&padv);
m_pMsTsc->put_Server(szServer);
padv->put_RDPPort(port);
m_pMsTsc->put_UserName(szUserName);
pns->put_ClearTextPassword(szPassword);
m_pMsTsc->put_Domain(szDomain);
padv->put_RedirectPrinters(printer);
padv->put_RedirectPorts(comport);
m_pMsTsc->put_ColorDepth(color);
pss->put_AudioRedirectionMode(audio);
//padv->put_PerformanceFlags(mode);
padv->put_BitmapPersistence(1);
padv->put_Compress(1);
m_pMsTsc->put_DesktopWidth(GetSystemMetrics(SM_CXSCREEN));
m_pMsTsc->put_DesktopHeight(GetSystemMetrics(SM_CYSCREEN));
m_pMsTsc->put_FullScreen(FALSE);
//padv->put_ContainerHandledFullScreen(TRUE);
m_pMsTsc->Connect();
return 0;
}
17. 在App的InitInstance函数中隐藏主窗口并执行控件连接
// 唯一的一个窗口已初始化,因此显示它并对其进行更新
//pFrame->ShowWindow(SW_SHOWMAXIMIZED);
//pFrame->UpdateWindow();
pFrame->MstscConnect();
return TRUE;
到此代码基本准备完成,编译后放到WinCE6.0上应该可以执行远程桌面连接。在某些系统上需要先注册一下Mstscax控件,在命令参数中加入-regmstsc即可,反注册函数没有使用,一般情况下没有这必要。
Good Luck!