Retrieving product information from an unmanaged executing application in C#/.NET
Question
In C#, it is possible to retrieve assembly related information like product name, version etc using reflection:
string productName = Assembly.GetCallingAssembly().GetName().Name;
string versionString = Assembly.GetCallingAssembly().GetName().Version.ToString();
How do I do the equivalent if the executing assembly is written in unmanaged C++ (say)? Is it even possible? Assume that I have a .NET dll which is being invoked in unmanaged code via a COM interface.
edit:
To make things absolutely clear, this is my scenario:
- I have an executable written in unmanaged C++
- I have a dll written in C#/.NET
- The dll is invoked by the executable via a COM interface
- Within the .NET dll I want to be able to retrieve information like the product name and version of the calling executable.
Possible?
Solution
Walking the stack is not necessary to find out what process you are in. You simply make a single Win32 API call:
HMODULE hEXE = GetModuleHandle(NULL);
According to the documentation for this call:
If this parameter is NULL, GetModuleHandle returns a handle to the file used to create the calling process (.exe file).
You can turn this module handle into a filename with GetModuleFileName(), another standard Win32 API. File name in hand, you can then call GetFileVersionInfo() to retrieve the VS_VERSIONINFO structure for that file. The information you want is in there.
Now since you are in .NET you could use P/Invoke signatures for GetModuleHandle(), GetModuleFileName(). For GetFileVersionInfo() you can use System.Diagnostics.FileVersionInfo.
But actually the easiest way to do it is probably to stick with the System.Diagnostics namespace, everything you need is there. Call System.Diagnostics.Process.GetCurrentProcess() to return a Process object for the process you are running in. Then you can retrieve a ProcessModule from the MainModule property. ProcessModule has a property called FileVersionInfo. The information you want is there.
OTHER TIPS
you could use the following code in VB.Net to retrieve extended document properties:
Sub Main()
Dim arrHeaders(41)
Dim shell As New Shell32.Shell
Dim objFolder As Shell32.Folder
objFolder = shell.NameSpace("C:\tmp\")
For i = 0 To 40
arrHeaders(i) = objFolder.GetDetailsOf(objFolder.Items, i)
Next
For Each strFileName In objfolder.Items
For i = 0 To 40
Console.WriteLine(i & vbTab & arrHeaders(i) & ": " & objFolder.GetDetailsOf(strFileName, i))
Next
Next
End Sub
Add a COM reference to Microsoft Shell Controls and Automation to your project to compile.
The output of the above program will be a list of the meta data assigned to all files in C:\tmp such as
0 Name: dpvoice.dll
1 Size: 208 KB
2 Type: Application Extension
3 Date Modified: 14.04.2008 04:41
4 Date Created: 14.04.2008 04:41
5 Date Accessed: 01.12.2008 09:56
6 Attributes: A
7 Status: Online
8 Owner: Administrators
9 Author:
10 Title:
11 Subject:
12 Category:
13 Pages:
14 Comments:
15 Copyright:
16 Artist:
17 Album Title:
18 Year:
19 Track Number:
20 Genre:
21 Duration:
22 Bit Rate:
23 Protected:
24 Camera Model:
25 Date Picture Taken:
26 Dimensions:
27 :
28 :
29 Episode Name:
30 Program Description:
31 :
32 Audio sample size:
33 Audio sample rate:
34 Channels:
35 Company: Microsoft Corporation
36 Description: Microsoft DirectPlay Voice
37 File Version: 5.3.2600.5512
38 Product Name: Microsoftr Windowsr Operating System
39 Product Version: 5.03.2600.5512
40 Keywords:
Let's assume you're after an EXE/DLL's PE header data that @divo's calls return e.g. Company, Product etc... These btw. are derived from calling Win32 Version Info API's - details up on MSDN:
The next challenge you face is enumerating the callstack to discover your caller's module context. I've not tried - but if you examine your own callstack, I doubt you'll see the unmanaged caller's frames marshalled into there. Suspect it stops at transitional frame injected before switching into the CCW. Also since it's COM, conceivably the caller could call from out of process - your caller would be a proxy process.
If that fails - you'd need the debugging API's to unwind the external stack - that introduces other constraints:
- elevated security permissions required to traverse the stack
- potential performance impact unwinding the stack.
On a call-by-call basis either of these could make the debugger approach impractical.
Update
Some research indicates there are plenty of bugs and gotchas for reading the stack above the CCW transitional frame even in the debugger. e.g.
Mixed Unmanaged/Managed symbol resolution is pretty ugly - some thoughts here on how to do it... DaveBr's blog on debugging is pretty awesome too.
There is plenty of fodder on the steps taken marshalling calls between unmanaged/managed clients - e.g.