Get method name from Image RVA - windows

I want to export stack trace data from an ETL file (Event Tracing for Windows) into a more readable format.
CPU profiling data is only useful with method names, but when on the recording machine no symbol server access exists it would be useful to record just the amount of data to later load the method names into the tool as an extra post processing step.
The input would be e.g. dll with a RVA (Relative Virtual Address) like
kernel32.dll+0xdddd
After storing this data I want to get the full method name out of this. As far as I have read the symbol server lookup uses just the tuple
Pdb Guid
Pdb Age
Pdb Name
In theory I should be able to retrieve a method name with a helper method with this signature:
string GetMethod(string dll, long RVA, Guid pdbGuid, int pdbAge, string pdbName)
The normal approach to lookup methods is to use Dbghelp.dll. To be able to use I need to call SymInitialize but all of these APIs expect a process handle.
BOOL IMAGEAPI SymInitializeW(
[in] HANDLE hProcess,
[in, optional] PCWSTR UserSearchPath,
[in] BOOL fInvadeProcess
);
Has anyone experience with getting the method name from an Image RVA address when the input is not a live process or a memory dump file? Or would I need to use another library (e.g. msdia140.dll)?

PerfView has full support for this already.
https://github.com/microsoft/perfview/blob/main/src/TraceEvent/Symbols/NativeSymbolModule.cs
/// <summary>
/// This overload of SourceLocationForRva like the one that takes only an RVA will return a source location
/// if it can. However this version has additional support for NGEN images. In the case of NGEN images
/// for .NET V4.6.1 or later), the NGEN images can't convert all the way back to a source location, but they
/// can convert the RVA back to IL artifacts (ilAssemblyName, methodMetadataToken, iloffset). THese can then
/// be used to look up the source line using the IL PDB.
///
/// Thus if the return value from this is null, check to see if the ilAssemblyName is non-null, and if not
/// you can look up the source location using that information.
/// </summary>
public SourceLocation SourceLocationForRva(uint rva, out string ilAssemblyName, out uint methodMetadataToken, out int ilOffset)
{
This is exactly what I need and it uses msdia140.dll. It looks like the "normal" dbghelp.dll is not the best fit for this task.

Related

How to force Explorer use modern file operation dialog with Shell Namespace Extension

In my understanding currently there are two ways to copy virtual files from a Shell Namespace Extension with the Explorer so that Copy GUI will be shown to the user:
Via IDataObject interface:
Reading a file is done via IDataObject::GetData that should support CFSTR_FILEDESCRIPTORW, CFSTR_FILECONTENTS and CFSTR_SHELLIDLIST clipboard formats at very minimum. Requesting CFSTR_FILECONTENTS from IDataObject::GetData should create an IStream that is used to access the data. UI is enabled via setting FD_PROGRESSUI flag when CFSTR_FILEDESCRIPTORW is requested.
Via ITransferSource interface:
Reading a file is done via ITransferSource::OpenItem requesting for IShellItemResources. Then IShellItemResources should report {4F74D1CF-680C-4EA3-8020-4BDA6792DA3C} resource as supported (GUID indicating that there is an IStream for the item). Finally an IStream is requested via parent ShellFolder::BindToObject for accessing the data. UI is handled by the Explorer itself, it is always shown.
My problem is: these two mechanisms are working just fine separately (as you can see from the screenshots). But once I enable both IDataObject from IShellFolder::GetUIObjectOf and ITransferSource from IShellFolder::CreateViewObject - the approach via IDataObject is always used leading to the old copy GUI (as on the first screenshot). I see from the trace logs that ITransferSource is requested several times, but no actions are performed, it just gets Released and destroyed right away.
So how may I force Explorer to show fancy copy GUI when copying from my Shell Namespace Extension?
A minimal reproducible example may be found here: https://github.com/BilyakA/SO_73938149
While working on Minimal Reproducible example I somehow managed to make it work as expected with both IDataObject and ITranfserSource interfaces enabled. It happened after:
unregistred x64 build SNE example (regsvr32 /u)
registred x32 build SNE example (it was not working in x64 explorer, root was not opening)
unregistred x32
registred x64 again.
Somehow new copy UI was shown to me when copying the files.
But I was not able to reproduce this result constantly after I have unregistred x64 SNE, restarted explorer and registered SNE x64 again.
What I have tried:
Registred both x32 and x64 SNE - still old GUI
Removed Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Cached value with my NSE GUID and restarted Explorer afterwards. Still old GUI.
I suspect there is some kind of cache (other than Registry) that keeps track if NSE supports ITransferSource. And since I have developed and tested without ITransferSource at the beginning - it is cached that my NSE does not support it even that I have added it later. And somehow registering 32bit reset that cache value.
The current code is doing something like this when asked for an IDataObject:
HRESULT CFolderViewImplFolder::GetUIObjectOf(HWND hwnd, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT rgfReserved, void **ppv)
{
....
if (riid == IID_IDataObject)
{
CDataObject* dataObject = new (std::nothrow) CDataObject(this, cidl, apidl);
return ::SHCreateDataObject(m_pidl, cidl, apidl, dataObject, riid, ppv);
}
...
}
SHCreateDataObject already creates already a full-blown IDataObject with everything needed from the (optional) input PIDL(s), including all Shell formats for items in the Shell namespace (CFSTR_SHELLIDLIST, etc.).
Passing an inner object 1) will probably conflict with what the Shell does and 2) requires a good implementation (I've not checked it).
So you can just replace it like this:
HRESULT CFolderViewImplFolder::GetUIObjectOf(HWND hwnd, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT rgfReserved, void **ppv)
{
....
if (riid == IID_IDataObject)
{
return ::SHCreateDataObject(m_pidl, cidl, apidl, NULL, riid, ppv);
}
...
}
In fact, the IDataObject provided by the Shell is complete (supports SetData method, etc.) so you should never need to implement it yourself, it's more complex than it seems. You can reuse it as a general purpose IDataObject (you can pass nulls and 0 for the 4 first arguments).
PS: the Shell also provides the "reverse" method: SHCreateShellItemArrayFromDataObject that gets a list of Shell items from an IDataObject (if the data object contains the expected clipboard formats).
For those who need to use inner IDataObject within SHCreateDataObject for additional format:
Inner IDataObject should support CFSTR_SHELLIDLIST clipboard format in GetData() as well as report this format in EnumFormatEtc(). Supporting SetData() with CFSTR_SHELLIDLIST format is really useful here since DefDataObject sets inner data object with already fully constructed CIDA and you may just store a copy of it.
Once inner data object will report CFSTR_SHELLIDLIST in EnumFormatEtc() and return valid CIDA in GetData() - modern Copy UI will be used since it relies only on PIDL of the items.

Nullable parameter in C++/CLI not appearing in XML documentation for C#

Here is an example of the problem. This is the implementation of a static method Add defined within a class foo.
/// <summary>
/// Adds two or three numbers together.
/// </summary>
/// <param name="x">First number</param>
/// <param name="y">Second number</param>
/// <param name="z">Third number - optional - defaults to 0 if set to null.</param>
System::Double foo::Add(
System::Double x,
System::Double y,
System::Nullable<System::Double> z)
{
System::Double output = x + y;
if (z.HasValue)
output = output + z.Value;
return output;
}
I have used /doc when compiling this code fragment using C++ with the /clr option.
Subsequently xdcmake is used to produce an XML file.
The XML file looks OK - the automatic description of the parameters looks like this:
Add(System.Double,System.Double,System.Nullable`1{System.Double})
followed by the summary and param tags defined in the code above.
However when I use the resulting .NET assembly within C# (Visual Studio 2010) I don't see any documentation for this function in the Object Browser (the entire function has no documentation, not just the nullable parameter z).
For functions without nullable inputs there is no problem and I see the list of parameters and summary in the Object Browser as I would have hoped.
Any ideas about what I need to do to fix this?
I managed to solve the problem today. From looking at the C# manual via http://www.microsoft.com/en-us/download/confirmation.aspx?id=7029 I saw that xdcmake was generating the wrong XML for nullable parameters. The `1 was not required.
The XML entry for the Add function with a nullable parameter should be:
Add(System.Double,System.Double,System.Nullable{System.Double})
instead. Quote from the manual (from section A.3.1 of the C# language specification version 5.0):
Arguments that refer to constructed generic types are encoded using
the generic type, followed by “{“, followed by a comma-separated list
of type arguments, followed by “}”.

How to get the IPreviewHandler for a file extension?

How do i get the shell IPreviewHandler for a particular file extension?
Background
Windows allows developers to create a preview handler for their custom file types:
Preview handlers are called when an item is selected to show a lightweight, rich, read-only preview of the file's contents in the view's reading pane. This is done without launching the file's associated application.
A preview handler is a hosted application. Hosts include the Windows Explorer in Windows Vista or Microsoft Outlook 2007.
I want to leverage the existing IPreviewHandler infrasturcture to get a thumbnail for a file.
In A Stream
The problem is that my files are not housed in the shell namespace (i.e. they are not sitting on the hard drive). They are sitting in memory, accessable through an IStream. This means i cannot use the legacy IExtractImage interface; as it does not support loading a file from a Stream.
Fortunately, this is why the modern IPreviewHandler supports (recommends, and prefers) loading data from a Stream, and recommends against loading previews from a file:
This method is preferred to Initialize due to its ability to use streams that are not accessible through a Win32 path, such as the contents of a compressed file with a .zip file name extension.
So how do i get it?
There is no documentation on the correct way to get ahold of the IPreviewHandler associated with a particular extension. But if i take the directions of how to register an IPreviewHandler, and read the contract from the other side:
HKEY_CLASSES_ROOT
.xyz
(Default) = xyzfile
HKEY_CLASSES_ROOT
xyzfile
shellex
{8895b1c6-b41f-4c1c-a562-0d564250836f} //IPreviewHandler subkey
(Default) = [clsid of the IPreviewHandler]
I should be able to follow the same route, given that i know the extension. Lets follow that with a real world example, a .jpg file:
Notice that the file has a preview. Notice i included the second screenshot only to reinforce the idea that the preview doesn't come from a file sitting on the hard drive.
Lets get spellunking!
First is the fact that it's a .jpg file:
HKEY_CLASSES_ROOT
.jpg
(Default) = ACDC_JPG
HKEY_CLASSES_ROOT
ACDC_JPG
ShellEx
{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}
ContextMenuHandlers
Wait, there is no {8895b1c6-b41f-4c1c-a562-0d564250836f} subkey for a previewhandler. That must mean that we cannot get a thumbnail for .jpg files.
reducto an absurdum
The Real Question
The careful reader will realize that the actual question i'm asking is:
How do i get the preview of an image contained only in a stream?
And while that is a useful question, and the real issue i'm having, having an answer on how to use IPreviewHandler is also a useful question.
So feel free to answer either; or both!
Bonus Reading
MSDN: Preview Handlers and Shell Preview Host
MSDN: How to Register a Preview Handler
MSDN: IInitializeWithStream::Initialize method
IPreviewHandler throws uncatchable exception
Outlook IPreviewHandler for Delphi
#hvd had the right answer.
File types have a ShellEx key, with {guid} subkeys. Each {guid} key represents a particular InterfaceID.
There are a number of standard shell interfaces that can be associated with a file type:
{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1} IExtractImage
{953BB1EE-93B4-11d1-98A3-00C04FB687DA} IExtractImage2
{e357fccd-a995-4576-b01f-234630154e96} IThumbnailProvider
{8895b1c6-b41f-4c1c-a562-0d564250836f} IPreviewHandler
Unsupported spelunking of undocumented registry keys
If i want to find, for example, the clsid of the IPreviewHandler associated with a .jpg file, i would look in:
HKEY_CLASSES_ROOT/.jpg/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
But that's not the only place i could look. I can also look in:
HKEY_CLASSES_ROOT/.jpg
(default) = jpgfile
HKEY_CLASSES_ROOT/jpgfile/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
But that's not the only place i could look. I can also look in:
HKEY_CLASSES_ROOT/SystemFileAssociations/.jpg/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
But that's not the only place i could look. I can also look in:
HKEY_CLASSES_ROOT/SystemFileAssociations/jpegfile/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
But that's not the only place i could look. If i think the file is an image, i can also look in:
HKEY_CLASSES_ROOT/SystemFileAssociations/image/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
How did i find these locations? Did i only follow documented and supported locations? No, i spied on Explorer using Process Monitor as it went hunting for an IThumbnailProvider.
Don't use undocumented spellunking
So now i want to use a standard shell interface for a file-type myself. This means that i have to crawl the locations. But why crawl these locations in an undocumented, unsupported way. Why incur the wrath from the guy from high atop the thing? Use AssocQueryString:
Guid GetShellClsidForFileType(String fileExtension, Guid interfaceID)
{
//E.g.:
// String fileExtension = ".jpg"
// Guid interfaceID = "{8895b1c6-b41f-4c1c-a562-0d564250836f}"; //IExtractImage
//The interface we're after - in string form
String szInterfaceID := GuidToString(interfaceID);
//Buffer to receive the clsid string
DWORD bufferSize := 1024; //more than enough to hold a 38-character clsid
String buffer;
SetLength(buffer, bufferSize);
HRESULT hr := AssocQueryString(
ASSOCF_INIT_DEFAULTTOSTAR,
ASSOCSTR_SHELLEXTENSION, //for finding shell extensions
fileExtension, //e.g. ".txt"
szInterfaceID, //e.g. "{8895b1c6-b41f-4c1c-a562-0d564250836f}"
buffer, //will receive the clsid string
#bufferSize);
if (hr <> S_OK)
return Guid.Empty;
Guid clsid;
HRESULT hr = CLSIDFromString(buffer, out clsid);
if (hr <> NOERROR)
return Guid.Empty;
return clsid;
}
And so to get the clsid of IPreviewHandler for .xps files:
Guid clsid = GetShellClsidForFileType(".xps", IPreviewHandler);
How to get IPreviewHandler for a file extension?
With all the above, we can now answer the question:
IPreviewHandler GetPreviewHandlerForFileType(String extension)
{
//Extension: the file type to return IPreviewHandler for (e.g. ".xps")
Guid previewHandlerClassID = GetShellClsidForFileType(extension, IPreviewHandler);
//Create the COM object
IUnknown unk = CreateComObject(previewHandlerClassID);
//Return the actual IPreviewHanler interface (not IUnknown)
return (IPreviewhandler)unk;
}

Copy embedded structure to clipboard and retrieve it in win32

I am trying to implement clipboard operation (cut/copy/paste) on my win32 window. This window has a bunch of gdi objects drawn over it, and the window can have child controls inserted in it as well.
I have searched allot on the win32 clipboard API, and every where they have explained how to handle a single type of data, e.g. we can write text onto clipboard by specifying the appropriate clipboard format and etc.
What I need is to place ALL the data on the clipboard that will be used to reconstruct the original window after the paste operation. I do not want to use COM as suggested by msdn for embedded data structures.
Can this be carried out using the basic clipboard API? Can anybody point me in the right direction and what steps do I need to take to bring this about? I am a newbie in win32 and don't know allot about what I am doing.
Use RegisterClipboardFormat() to register a custom clipboard format ID. Then serialize your data as needed, using whatever serialization format is meaningful for your data, and store it on the clipboard using SetClipboardData(). At a later time, you can use GetCliipboardData() to retrieve your data and de-serialize it as needed.
Update: For example:
struct sMyData
{
int Value1;
int Value2;
float Value3;
float Value4;
};
UINT uMyDataFmtID = RegisterClipboardFormat(TEXT("MyData"));
...
HANDLE hMyData = GlobalAlloc(GHND, sizeof(sMyData));
sMyData *pMyData = (sMyData*) GlobalLock(hMyData);
// fill in pMyData as needed...
GlobalUnlock(hMyData);
SetClipboardData(uMyDataFmtID, hMyData);
...
HANDLE hMyData = GetClipboardData(uMyDataFmtID);
sMyData *pMyData = (sMyData*) GlobalLock(hMyData);
// use pMyData as needed...
GlobalUnlock(hMyData);

Can anyone help me out to load values in string table vc++ mfc programatically

Can anyone help me to load values in a STRINGTABLE in vc++ programmatically? I'm using the MFC.
You can load strings directly from a string table using the LoadString method, I use it all the time.
http://msdn.microsoft.com/en-us/library/ms647486(v=vs.85).aspx
CStringW myString;
myString.LoadString(RESOURCE_ID); //where RESOURCE_ID is the Stringtable
//entry ID
*EDIT: Thanks for the input this makes the answer much better!!
You can have a custom resource where you would put a text file. At runtime, read that text file as resource.
void GetResourceAsString(int nResourceID, CStringA &strResourceString)
{
HRSRC hResource = FindResource(NULL, MAKEINTRESOURCE(nResourceID), L"DATA");
HGLOBAL hResHandle = LoadResource(NULL, hResource);
// Resource is ANSII
const char* lpData = static_cast<char*> ( LockResource(hResHandle) );
strResourceString.SetString(lpData, SizeofResource(NULL, hResource));
FreeResource(hResource);
}
Where DATA would be your custom resource type, and nResource would be resource-id under DATA resource type. Of course, you can choose another other name rather than "DATA".
Normally you define for each string a constant that gets included in your program as well as in the resource-file. The string resource is then placed in the .rsrc-section of your executable and strings can be retrieved with LoadString() by naming the defined constant for that string.
Maybe you instead want to iterate through all the string-resources of your executable at run-time? You can do that by reading your process-memory at the appropriate entry in the PE-struct. You can find the string-table entry in the PE-struct if you tahttp://msdn.microsoft.com/en-us/windows/hardware/gg463119.aspx under "Resource Directory Table" or have a look into the winapi include-files which define the PE-structs.
It's hard to know what you're really asking for, but I'm going to try an answer. This assumes you're asking how to put the strings into resources, rather than how to read an existing resource.
The .rc file containing the resources can contain #include directives. All you have to do is write out a text file containing the strings you want to include, along with the STRINGTABLE, BEGIN, and END directives along with the ID of each string. You should also create a .h file that defines each of the IDs and include that in the .rc too.

Resources