Click here to Skip to main content
15,867,756 members
Articles / Desktop Programming / Win32

Native Browser Addin for Visual Studio

Rate me:
Please Sign up or sign in to vote.
4.33/5 (3 votes)
2 May 2010Ms-PL3 min read 35.1K   290   24   8
Visual Studio 2005/2008 AddIn for browsing exported methods of native libraries
Native_Browser_Addin_for_Visual_Studio

Introduction

With .NET Assemblies, today it is much easier to get all information about the classes and members inside. You can simply use Reflection and you will get all Meta Data even if it is private, internal or public. But did you ever try to get the content of native libraries such as "advapi32.dll" or "user32.dll". Sure, the best way should be never to use pInvoke because your application will not be CLS compliant. However, in some circumstances, you have to.

Background

Some years ago, I developed an application in Delphi 6, showing me the exported method headers of native (Win32) libraries. However, that application was no longer useful since I started developing with Visual Studio .NET, because I don't like switching between several applications while developing.

The Old Delphi Code

The following Delphi snippet is part of the code that has to be converted into C#. The code was hosted inside a COM Library because I wanted to use it with other languages. The COM Library still works fine today (except, sometimes getting the whole number of methods with Windows 7), but I don't want to use COM Interop in my .NET applications in future.

C#
// 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;

The C# Code

Ok, I'm sorry but I deleted all the code written in C#, after I fixed it in Managed C++, but I did a posting on CodeProject some years ago. So if you are interested, please have a look at this link.

As you can see by the posting time stamp from above, I've tried a long time to migrate the Delphi snippet to C#, but finally I got no results. First of all, it was a lot of code to pInvoke and playing around with marshalling attributes, but finally it didn't work. It was very frustrating but finally I decided to give Managed C++ a chance.

I was very surprised at how easy it is to pInvoke in C++, if you mix native and managed C++. You do not have to pInvoke anything because you can access all Win32 libraries in C++ and on the other side you can also create a .NET Assembly and use it as usual in other .NET Assemblies.

The Hybrid Code (C++ and Managed C++)

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));
}
}
};
}}}}

Installing the AddIn

First of all, download the ZIP file, save and extract it into a temporary folder. The folder contains a .vsi file which you can execute with a double click. If everything is fine, the Visual Studio Installer Assistant should pop up. Please follow the wizard until the AddIn is installed.

After a successful installation, open Visual Studio 2005/2008/2010 and click on MainMenu>View>Object browser (Native). A new ToolWindow called "Native Object Browser should be opened. In the ToolWindow, click on the Open-Button on the Toolbar and select a native library, e.g. "C:\Windows\System32\User32.dll".

Now you can see all the exported methods of the native library. If you select one of the exported methods on the right list view, press F1 for its online help. You can also click on one of the provided links on the dynamic help window.

Points of Interest

Normally, I develop my applications in C#, but this project has taught me that C# is not always the easiest way. I have tried to develop the main functionality (enumerating method headers) for several months in C#, but last but not least I fixed it in about 1 day with a mix of C++ and Managed C++. Well finally I think, it was a great benefit for me, and in future I will use Managed C++ at first.

Some Links

The source code and the installer are also available at www.codeplex.com at http://nativebrowser.codeplex.com/.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Software Developer Goerlitz AG
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionVisual Studio 2008 and 2010 on x64 machine Pin
semicode198221-Mar-12 0:47
semicode198221-Mar-12 0:47 
GeneralC++/CLI Pin
TobiasP5-Sep-10 23:20
TobiasP5-Sep-10 23:20 
General"Correct verison of content installer component cannot be found" Pin
yurikus784-May-10 2:04
yurikus784-May-10 2:04 
GeneralRe: "Correct verison of content installer component cannot be found" Pin
Thomas van Veen4-May-10 4:58
Thomas van Veen4-May-10 4:58 
QuestionInstalled. Now what? Pin
Pete Also26-Apr-10 6:04
Pete Also26-Apr-10 6:04 
AnswerRe: Installed. Now what? [modified] Pin
Thomas van Veen26-Apr-10 10:41
Thomas van Veen26-Apr-10 10:41 
GeneralRe: Installed. Now what? Pin
Adrian Cole26-Apr-10 18:05
Adrian Cole26-Apr-10 18:05 
GeneralRe: Installed. Now what? Pin
Pete Also27-Apr-10 3:21
Pete Also27-Apr-10 3:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.