Click here to Skip to main content
Click here to Skip to main content

Native Browser Addin for Visual Studio

, 2 May 2010
Rate this:
Please Sign up or sign in to vote.
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.

// 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++)

#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)

Share

About the Author

Thomas van Veen
Software Developer Goerlitz AG
Germany Germany
No Biography provided

Comments and Discussions

 
QuestionVisual Studio 2008 and 2010 on x64 machine Pinmembersemicode198221-Mar-12 0:47 
GeneralC++/CLI PinmemberTobiasP5-Sep-10 23:20 
This is really an area where C++/CLI shines, working as the glue between pure native and pure managed code. It just works! Smile | :)
 
By the way, the language is called C++/CLI nowadays (since VS 2005). Managed C++ was the name of the language when it was conceptually the same, but used a completely different and much, much clumsier syntax that is now deprecated.
General"Correct verison of content installer component cannot be found" Pinmemberyurikus784-May-10 2:04 
GeneralRe: "Correct verison of content installer component cannot be found" PinmemberThomas van Veen4-May-10 4:58 
QuestionInstalled. Now what? PinmemberPete Also26-Apr-10 6:04 
AnswerRe: Installed. Now what? [modified] PinmemberThomas van Veen26-Apr-10 10:41 
GeneralRe: Installed. Now what? PinmemberAdrian Cole26-Apr-10 18:05 
GeneralRe: Installed. Now what? PinmemberPete Also27-Apr-10 3:21 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140827.1 | Last Updated 2 May 2010
Article Copyright 2010 by Thomas van Veen
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid