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

Visual Studio 的原生浏览器插件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (3投票s)

2010 年 4 月 26 日

Ms-PL

3分钟阅读

viewsIcon

36851

downloadIcon

310

Visual Studio 2005/2008 插件,用于浏览本机库导出的方法

Native_Browser_Addin_for_Visual_Studio

引言

使用 .NET 程序集,现在可以更容易地获取有关类和成员的所有信息。 您可以简单地使用反射,您将获得所有元数据,即使它是 privateinternalpublic。 但是您是否尝试获取本机库的内容,例如“advapi32.dll”或“user32.dll”。 当然,最好的方法是永远不要使用 pInvoke,因为您的应用程序将不符合 CLS 标准。 但是,在某些情况下,您必须这样做。

背景

几年前,我用 Delphi 6 开发了一个应用程序,它向我显示了本机 (Win32) 库的导出方法头。 但是,自从我开始使用 Visual Studio .NET 进行开发以来,该应用程序不再有用,因为我不喜欢在开发时在多个应用程序之间切换。

旧的 Delphi 代码

以下 Delphi 代码片段是要转换为 C# 的代码的一部分。 该代码托管在 COM 库中,因为我想将其与其他语言一起使用。 COM 库至今仍然运行良好(除了有时无法使用 Windows 7 获取方法的总数),但将来我不想在我的 .NET 应用程序中使用 COM 互操作。

// This is the Delphi code
function ListDLLExports(const FileName: string): TStringList;
type
  TDWordArray = array [0..$FFFFF] of DWORD;
var
imageinfo: LoadedImage;
  pExportDirectory: PImageExportDirectory;
  dirsize: Cardinal;
  pDummy: PImageSectionHeader;
  i: Cardinal;
  pNameRVAs: ^TDWordArray;
  Name: string;
begin
  {$Warnings Off}
  Result := TStringList.Create;
  if MapAndLoad(PAnsiChar(FileName), nil, @imageinfo, True, True) then begin
    try
      pExportDirectory := ImageDirectoryEntryToData
	(imageinfo.MappedAddress, False, IMAGE_DIRECTORY_ENTRY_EXPORT, dirsize);
      if (pExportDirectory <> nil) then begin
        pNameRVAs := ImageRvaToVa(imageinfo.FileHeader, 
	imageinfo.MappedAddress, DWORD(pExportDirectory^.AddressOfNames), pDummy);
        for i := 0 to pExportDirectory^.NumberOfNames - 1 do begin
          Name := PChar(ImageRvaToVa(imageinfo.FileHeader, 
		imageinfo.MappedAddress, pNameRVAs^[i], pDummy));
          Result.Add(Name);
        end;
      end;
    finally
      UnMapAndLoad(@imageinfo);
    end;
  end;
  {$Warnings ON}
end;

C# 代码

好吧,我很抱歉,但在我修复了 Managed C++ 中的代码后,我删除了所有用 C# 编写的代码,但几年前我在 CodeProject 上发布了一篇文章。 所以如果您有兴趣,请查看这个链接

正如您从上面的发布时间戳中看到的那样,我尝试了很长时间将 Delphi 代码片段迁移到 C#,但最终我没有得到任何结果。 首先,有很多代码需要 pInvoke 和使用封送处理属性,但最终它没有奏效。 这非常令人沮丧,但最终我决定尝试 Managed C++。

如果您混合使用本机和托管 C++,我会惊讶于在 C++ 中 pInvoke 是多么容易。 您不必 pInvoke 任何东西,因为您可以在 C++ 中访问所有 Win32 库,另一方面,您还可以创建一个 .NET 程序集并在其他 .NET 程序集中像往常一样使用它。

混合代码(C++ 和 Managed C++)

#pragma once

using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Collections::Generic;
using namespace System::Reflection;

namespace System{namespace Runtime{namespace InteropServices{namespace PlatformInvoke 
{
public ref class NativeImage
{
public:
static List<String^>^ OpenImage(String ^imageName, String ^dllPath)
{
List<String^>^ methodNames = gcnew List<String^>();
LOADED_IMAGE* pLoadedImage = new LOADED_IMAGE();
char* pImageName = (char*)Marshal::StringToHGlobalAnsi(imageName).ToPointer();
char* pDllPath = (char*)Marshal::StringToHGlobalAnsi(dllPath).ToPointer();

try
{
if (MapAndLoad(pImageName, pDllPath, pLoadedImage, TRUE, TRUE))
{
ULONG pSize;
PIMAGE_EXPORT_DIRECTORY pImageExportDirectory = 
	(PIMAGE_EXPORT_DIRECTORY)ImageDirectoryEntryToData
	(pLoadedImage->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &pSize);
PIMAGE_SECTION_HEADER *pImageSectionHeader = new PIMAGE_SECTION_HEADER();

if (pImageExportDirectory != NULL)
{
PULONG pImageImportDescriptor = (PULONG)ImageRvaToVa
	(pLoadedImage->FileHeader, pLoadedImage->MappedAddress, 
	pImageExportDirectory->AddressOfNames, pImageSectionHeader);

for (ULONG i = 0; i < pImageExportDirectory->NumberOfNames; i++)
{

PVOID pVoid = ImageRvaToVa(pLoadedImage->FileHeader, 
	pLoadedImage->MappedAddress, pImageImportDescriptor[i] , pImageSectionHeader);
methodNames->Add(gcnew String((PSTR)pVoid));
}
}

UnMapAndLoad(pLoadedImage);
}

return methodNames;
}
catch (Exception ^exception)
{
System::Diagnostics::Debug::WriteLine(exception->Message);

return gcnew List<String^>();
}
finally
{
Marshal::FreeHGlobal(IntPtr(pImageName));
Marshal::FreeHGlobal(IntPtr(pDllPath));
}
}
};
}}}}

安装插件

首先,下载 ZIP 文件,保存并将其解压缩到临时文件夹中。 该文件夹包含一个 * .vsi * 文件,您可以通过双击执行它。 如果一切正常,Visual Studio 安装程序助手应该会弹出。 请按照向导操作,直到安装 AddIn。

成功安装后,打开 Visual Studio 2005/2008/2010,然后单击 MainMenu>View>Object browser (Native)。 应该打开一个名为“本机对象浏览器”的新 ToolWindow。 在 ToolWindow 中,单击工具栏上的“打开”按钮,然后选择一个本机库,例如“C:\Windows\System32\User32.dll”。

现在您可以看到本机库的所有导出方法。 如果在右侧列表视图中选择一个导出的方法,请按 F1 获取其在线帮助。 您也可以单击动态帮助窗口中提供的链接之一。

关注点

通常,我使用 C# 开发我的应用程序,但是这个项目教会了我 C# 并不总是最简单的方法。 我曾尝试使用 C# 开发几个月的主要功能(枚举方法头),但最后我在大约 1 天内使用 C++ 和 Managed C++ 的混合修复了它。 好吧,最后我认为,这对我来说是一个很大的好处,将来我会首先使用 Managed C++。

一些链接

源代码和安装程序也可以在 www.codeplex.comhttp://nativebrowser.codeplex.com/ 上找到。

© . All rights reserved.