启动 VNC Shell 扩展






4.36/5 (11投票s)
从网络邻居启动 VNC
引言

我们使用 RealVNC 来远程控制我们网络中的 PC,VNC 是一个很棒的产品,但是如果不记住计算机名称,在网络邻居中找到计算机,然后将计算机名称复制到 VNC 连接屏幕中可能会很繁琐,所以我开发了这个 Shell 扩展。
什么是 VNC?
来自 RealVNC 网站
“VNC 代表虚拟网络计算。它是一种远程控制软件,允许您使用另一台计算机上的简单程序(“查看器”)查看一台计算机(“服务器”)并与之交互,无论该计算机在 Internet 上的任何位置。这两台计算机甚至不必是同一类型,例如,您可以使用 VNC 查看您在家庭 Windows PC 上的办公室 Linux 机器。VNC 是免费且公开提供的,并在行业、学术界和个人中得到广泛的积极使用。”
可以在这里下载 RealVNC。
创建扩展
首先,我要感谢 Michael Dunn 他的所有伟大努力,特别是他的教程:《编写 Shell 扩展的完整白痴指南 - 第一部分》。我将它用作我的扩展的起点。
我按照他的步骤创建了他的扩展演示,然后更改了他的初始化接口代码来处理网络资源,而不是文件名。
CFSTR_NETRESOURCES
当传输网络资源(例如域或服务器)时,使用此格式标识符。数据是一个 STGMEDIUM
结构,其中包含一个全局内存对象。该结构的 hGlobal
成员指向一个 NRESARRAY
结构。该结构的 nr
成员指示一个 NETRESOURCE
结构,该结构的 lpRemoteName
成员包含一个以 null 结尾的字符串,用于标识网络资源。
我们必须使用 RegisterClipboardFormat
API 函数,提供 CFSTR_NETRESOURCES
作为参数,才能获得 shell 注册的剪贴板格式的网络资源。然后,我们可以从 NRESARRAY
结构的 nr
成员中的第一个 NETRESOURCE
结构中提取所选项目的名称。
我们检查资源的类型,因为我们只对服务器感兴趣。dwDisplayType 成员包含资源的类型。
if(pNtary->nr[0].dwDisplayType == RESOURCEDISPLAYTYPE_SERVER)
NETRESOURCE
结构中的字符串成员包含偏移量而不是地址!
因此,我们通过将结构转换为 char
指针来获取第一个选定的名称,然后将偏移量添加到指针,然后将其转换为 WCHAR
指针。
WCHAR* pwchRemoteName = (WCHAR*)((char*)pNtary + int(pNtary->nr[0].lpRemoteName));
我们从返回的名称的开头删除 \\
,并将其存储在 m_szPCName
成员变量中以供以后使用。
STDMETHODIMP CVNCShell::Initialize(LPCITEMIDLIST pIDFolder, IDataObject *pDataObj, HKEY hRegKey) { HRESULT hr; if (pDataObj) { STGMEDIUM medium; FORMATETC fe; fe.cfFormat = RegisterClipboardFormat(CFSTR_NETRESOURCES); fe.ptd = NULL; fe.dwAspect = DVASPECT_CONTENT; fe.lindex = -1; fe.tymed = TYMED_HGLOBAL; hr = pDataObj->GetData(&fe, &medium); if(SUCCEEDED(hr)) { LPVOID lpv = GlobalLock(medium.hGlobal); if (lpv) { LPNRESARRAY pNtary = (NRESARRAY*)lpv; m_bShowMenuItem = false; if(pNtary->nr[0].dwDisplayType == RESOURCEDISPLAYTYPE_SERVER) { m_bShowMenuItem = true; // The string members in the structure // contain offsets instead of addresses! WCHAR* pwchRemoteName = (WCHAR*)((char*)pNtary + int(pNtary->nr[0].lpRemoteName)); // Copy name, minus \\ at begining of name, to local variable lstrcpynW (m_szPCName, pwchRemoteName + 2, lstrlenW(pwchRemoteName) * sizeof(TCHAR)); } GlobalUnlock(medium.hGlobal); } else hr = E_UNEXPECTED; ReleaseStgMedium(&medium); } } return hr; }
我还更改了他的 InvokeCommand
接口,以替换显示 MessageBox
的代码,该代码执行 VNC 程序,这假设 VNC 程序安装在提供的固定路径中,在我们的例子中,它始终安装在那里,我们传递包含我们之前存储的 PC 名称的 m_szPCName
成员变量。
ShellExecute (pCmdInfo->hwnd, _T("open"), _T("C:\\Program Files\\RealVNC\\vncviewer.exe"), m_szPCName, NULL, SW_SHOWNORMAL); return S_OK;
注册 shell 扩展
Shell 在 HKEY_CLASSES_ROOT
下定义了其他对象,这些对象可以像文件类型一样进行扩展。
我们唯一感兴趣的是 Network\Type\2 子键
HKEY_CLASSES_ROOT\Network\Type\2\ShellEx\ContextMenuHandlers\VNCShellExt
来自 MSDN
“对于 Network\Type\#,"#" 是十进制的网络提供程序类型代码。网络提供程序类型代码是网络类型的高位字。网络类型的列表在 Winnetwk.h 头文件中给出 (WNNC_NET_* 值)。”
所以我将注册表资源从文本文件更改为这个
NoRemove Network
{
NoRemove Type
{
NoRemove 2
{
NoRemove ShellEx
{
NoRemove ContextMenuHandlers
{
ForceRemove VNCShellExt = s '{B9442EFE-9815-4046-B6FF-4F3606291D8E}'
}
}
}
}
}
就这些了,这是我第一次尝试写文章,而且我编程 C++ 的时间很短,请多多包涵 :)
参考文献
- Michael Dunn 的教程:编写 Shell 扩展的完整白痴指南 - 第一部分 & 第二部分
- MSDN:创建 Shell 扩展处理程序,Shell 剪贴板格式