Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Obtain filename of COM DLL at runtime - DAX


This question is answered.


Permlink Replies: 4 - Last Post: Jun 9, 2014 7:02 PM Last Post By: Remy Lebeau (Te...
Matt McNabb

Posts: 21
Registered: 6/9/11
Obtain filename of COM DLL at runtime - DAX  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 3, 2013 6:33 PM
In my ATL COM server project I called the function:
GetModuleFilename( _Module.GetModuleInstance(), filename, sizeof filename)

However, with DAX, _Module does not exist (it was a TComModule, which no longer exists either).

I am the passing this filename to the Windows API function GetFileVersionInfo.

(I was also using _Module.GetResourceInstance() to retrieve compiled-in resources at runtime).

What is the DAX equivalent of _Module?

Currently using C++Builder XE Update 1.
Steven Haworth

Posts: 1
Registered: 3/26/00
Re: Obtain filename of COM DLL at runtime - DAX
Correct
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 3, 2013 9:16 PM   in response to: Matt McNabb in response to: Matt McNabb
Not sure on _Module.GetResourceInstance() but I usually just store the HINSTANCE passed to DllEntryPoint in a global and use that for GetModuleFileName when I need it.
Matt McNabb

Posts: 21
Registered: 6/9/11
Re: Obtain filename of COM DLL at runtime - DAX  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jun 9, 2014 5:58 PM   in response to: Steven Haworth in response to: Steven Haworth
Steven Haworth wrote:
Not sure on _Module.GetResourceInstance() but I usually just store the HINSTANCE passed to DllEntryPoint in a global and use that for GetModuleFileName when I need it.

Smart idea. For the filename I ended up doing:

std::wstring read_hinstance_filename(HINSTANCE hinst)
{
wchar_t filename[MAX_PATH] = { 0 };
GetModuleFileNameW( hinst, filename, dimof(filename) );
return filename;
}

which has the bonus that you can either call it with the handle from DllEntryPoint to
get the path to your DLL, or you can call it with NULL to get the path to the executable
that loaded your DLL. (Also you can use this function in an executable to get the name of the executable).

Regarding the version info. Following Remy's suggestion that it is inefficient for a DLL
or an executable to call GetFileVersionInfo on its own filename:

// g_inst is global variable saved from DLL entry point file
// again we can use NULL here to get version info for the executable that invoked us
HINSTANCE hinst = g_inst;
HRSRC h_res = FindResource(hinst, MAKEINTRESOURCE(1), RT_VERSION);
HGLOBAL h_dat = LoadResource(hinst, h_res);
DWORD dwSize = SizeofResource(hinst, h_res);
void *p_res = LockResource(h_dat);

Now you can pass `p_res` and `dwSize` to some code which expects to use the value
returned by `GetFileVersionInfo`.

Although this appeared to work, I found another page on stackoverflow which suggested
that you are not supposed to call VerQueryValue on the buffer returned by LockResource
as it might write the buffer, so I actually now copy this buffer and pass the copy to the
code for reading it.

Edited by: Matt McNabb on Jun 9, 2014 7:00 PM - clarified the paragraph "Regarding the version info."
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Obtain filename of COM DLL at runtime - DAX
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jun 9, 2014 6:27 PM   in response to: Matt McNabb in response to: Matt McNabb
Matt wrote:

Regarding the version info. Following Remy's suggestion that it is
inefficient to call GetFileVersionInfo on a DLL

That is not what I said.

not sure if that is just DLL or if it applies to executables also

It applies to any executable. GetFileVersionInfo*() opens its own handle
to the specified file on the filesystem - even if it is accessing the same
file that created the calling process. That is what makes it an inefficient
API for an executable to access its own own version resource, which is already
present in the calling process's memory.

Now you can pass `p_res` and `dwSize` to some code which expects to
use the value returned by `GetFileVersionInfo`.

If you take the resource pointer returned by LockResource() and pass it as-is
to VerQueryValue(), you will CRASH it (I've done it before). The memory
block returned by LockResource() is read-only, but VerQueryValue() requires
the memory blocked to be writable instead. GetFileVersionInfo*() guarantees
that, since you have to allocate the memory block that it fills. VerQueryValue()
also expects certain data inside of the memory block to be fixed up by GetFileVersionInfo*()
- something LockResource() does not do - so if you did pass the raw resource
block to VerQueryValue(), the only data it could safely extract without runing
into problems is the VS_FIXEDFILEINFO structure and none of the localized
data.

If you want to use LockResource() with VerQueryValue(), you need to make
a copy of the resource data first, eg:

HRSRC h_res = FindResource(hinst, MAKEINTRESOURCE(1), RT_VERSION);
HGLOBAL h_dat = LoadResource(hinst, h_res);
DWORD dwSize = SizeofResource(hinst, h_res);
void *p_res = LockResource(h_dat);
 
BYTE *p_res_copy = new BYTE[dwSize];
memcpy(p_res, p_res_copy, dwSize);
 
// Now you can pass `p_res_copy` and `dwSize` to some code which
// expects to use the value returned by `GetFileVersionInfo`.
 
delete[] p_res_copy;


Although this appeared to work, I found another page on stackoverflow
which suggested that you are not supposed to call VerQueryValue on
the buffer returned by LockResource as it might write the buffer, so I
actually now copy this buffer and pass the copy to the code for reading it.

That is correct.

--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Obtain filename of COM DLL at runtime - DAX
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 3, 2013 11:15 PM   in response to: Matt McNabb in response to: Matt McNabb
Matt wrote:

I am the passing this filename to the Windows API function
GetFileVersionInfo.

It is not efficient to have a DLL call that API on itself. It causes the
API to load a second copy of the file in memory just to access its resources
- which are already in memory in the calling instance. You can alternatively
use FindResource(), LoadResource(), and LockResource() (or a TResourceStream)
to access the DLL's version resource directly.

What is the DAX equivalent of _Module?

There isn't one.

--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02