65.9K
CodeProject 正在变化。 阅读更多。
Home

启动 VNC Shell 扩展

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.36/5 (11投票s)

2003年11月25日

CPOL

3分钟阅读

viewsIcon

100841

downloadIcon

1091

从网络邻居启动 VNC

引言

Sample image

我们使用 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++ 的时间很短,请多多包涵 :)

参考文献

© . All rights reserved.