When localizing applications in Windows, you provide your application:
C:\Program Files\Contoso\Grobber.exe
and you supply various dll (with a .mui extension) in child folders that contain localized resources:
C:\Program Files\Contoso\Grobber.exe
C:\Program Files\Contoso\en-US\Grobber.exe.mui
C:\Program Files\Contoso\en-CA\Grobber.exe.mui
C:\Program Files\Contoso\fr-CAca\Grobber.exe.mui
C:\Program Files\Contoso\fr-FR\Grobber.exe.mui
C:\Program Files\Contoso\es-US\Grobber.exe.mui
C:\Program Files\Contoso\fr-DE\Grobber.exe.mui
And according to Microsoft, and their documentation for localizing an application, if you are running on Windows Vista or later, you are supposed to be able to call LoadLibrary, and Windows will transparently select the appropriate file out of the appropriate folder based on the current locale of the system:
// 1. Basic application obtains access to the proper resource container
// for standard Win32 resource loading this is normally a PE module - use LoadLibraryEx
// LoadLibraryEx is the preferred alternative for resource modules as used below because it
// provides increased security and performance over that of LoadLibrary
HMODULE resContainer = LoadLibraryExW(HELLO_MODULE_CONTRIVED_FILE_PATH,NULL,LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE);
if(!resContainer)
{
swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to load the resource container module, last error = %d.",GetLastError());
MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR);
return 1; // exit
}
Except when i run it, it simply loads my base executable, rather than:
C:\Program Files\Contoso\en-US\Grobber.exe.mui
My pseudo-code:
HMODULE resContainer = LoadLibraryExW("C:\Program Files\Contoso\Grobber.exe", NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE);
int n = LoadStringW(resContainer, SInternalRequestsMUI, buffer, bufferLen);
MessageBox(0, "TestApp", buffer, MB_OK);
returns the unlocalized string - the one in the Language Neutral (LN) file.
Note: I don't understand how Windows can be expected to psychically know that i want it to load some other library, rather than the one i specified, but that's what the documentation says.
So what am i missing? It's supposed to be loading a different file, found in a language-COUNTRY folder, based on the OS's current language. Why is it not loading one?
Setting a custom language
Microsoft also notes that your Windows Vista or newer app can override the system default language, and instead specify another language to load into your application by calling SetThreadPreferredUILanguages:
MUI: Application-Specific Settings Sample (Windows Vista)
// the following line of code is supported on Windows Vista and forward
if(!SetThreadPreferredUILanguages(MUI_LANGUAGE_NAME,userLanguagesMultiString,&langCount) || langCount == 0)
{
swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to set the user defined, last error = %d.",GetLastError());
MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR);
return 1; // exit
}
They also note that pre-Vista the system would not perform this automatic searching for you, and instead you had to call an alternative to LoadLibrary called LoadMUILibrary that would do the searching work:
MUI: Application-Specific Settings Sample (Pre-Windows Vista)
resContainer = LoadMUILibraryW(HELLO_MODULE_CONTRIVED_FILE_PATH,MUI_LANGUAGE_NAME,0);
Those are interesting tidbits. But since i'm not using Windows XP or earlier, they don't really matter. And i only care about the default system language - not overriding it.
LoadLibraryExW is not loading the language-specific MUI version of the
application
it and not must do this. and can not - because LoadLibraryExW not take Language ID as parameter.
and you note it by self
I don't understand how Windows can be expected to psychically know that i want it to load some other library, rather than the one i
specified, but that's what the documentation says.
the MUI dll is loaded during call to FindResourceEx/LoadString - example of call graph:
also we can do this direct by call api from ntdll
EXTERN_C
NTSYSAPI
NTSTATUS
NTAPI
LdrLoadAlternateResourceModuleEx (
_In_ HMODULE hModule,
_In_ LANGID LangId,
_Out_ HMODULE* pAltResourceDllHandle,
_Out_ PSIZE_T ViewSize);
MSDN says:
Association of files uses a checksum reflected in resource configuration data contained in all associated files. The resource loader uses the checksum to verify that the files hold the same version of the required resources. It also validates the language in the language-specific file with its folder name. The loader does not load a resource file if the appropriate association is not established.
This means you have to pass the correct switches to the resource compiler or use the MUIRCT tool from the SDK to please the MUI part of the loader.
If you look at the system files shipped with Windows in a resource editor you will see a magic MUI resource with undocumented contents...
Did your LN File in the Grobber.exe configure correctly?
According to LN File which is referred as *.dll in the document, you need to associate an LN file with its language-specific files. And then when Loading Language Resources, Many resource loading functions have been modified to load resources from language-specific resource files automatically, treating resources as if they are contained in the LN file.
Related
I am working on a UWP application that calls a function from a DLL. It supplies the function with the application installation path so that I can go ahead and write some data to it.
I imported the DLL using LoadPackagedLibrary as described in How to: Use Existing C++ Code in a Universal Windows Platform App.
I retrieved the path using Windows::Storage::StorageFolder^ installedLocation = Windows::ApplicationModel::Package::Current->InstalledLocation;.
However, when I try to open the file and get a handle to it using fopen, I get a NULL pointer. I retrieved the error code using GetLastError() and it returned ERROR_ACCESS_DENINED error.
What could be the reason for this? Am I missing something? Do I need to declare additional capabilities to ensure that the DLL can access files in the application's installation path?
Writing to the UWP app's installation folder is restricted by design. This is to ensure the integrity of the app installation and to enable seamless, incremental automatic updates for the application package.
If you want to write data you will need to write it to the app's appdata location, not the install location.
fopen() relies on CreateFile to do the actual work. CreateFile only knows how to handle filesystem ACLs, not capability-based UWP permissions, and so it always fails with ACCESS_DENIED for anything other than your AppData directories (for read/write access) or your install location (for read-only access).
There is a work-around using CreateFileFromApp but it won't work for fopen() unless you're willing to statically-link the CRT, which has its cons. For example, you don't get the benefit of automatic security patches and you might not be able to distribute through the Microsoft Store.
I am writting application in fasm and have problem with determinating Windows version 8.1 and upper. Functions GetVersionEx and Version Helper give me Windows 8. As MSDN says, I must target my application via changing manifest file in Visual Studio, but I'm not using VS, so what should I do?
Any programming environment that allows you to link resources into the compiled executable can be used to create a manifest resource. All you have to do is write a suitable .manifest file for your app that contains the desired XML values, and then link that file's content directly into your application's resources, making sure the resource type is 24 and the resource ID is 1, 2, or 3 (see this page for details about when to use which ID). You are not required to use VisualStudio for this.
If, for some reason, you cannot link the manifest directly into your app's resources, you can alternatively save the XML into a file named <myappname>.exe.manifest (where <myappname> is the actual name of your EXE file) and put it in the same folder as your app. This is not the preferred approach to manifestation, but it does work.
That being said, there are alternative APIs you can use instead of GetVersion/Ex() or VerifyVersionInfo()-based helpers to get the correct OS version without dealing with manifestation at all. Namely, RtlGetVersion(), NetServerGetInfo(), and NetWkstaGetInfo() can be used instead (and all of them have been tested as working in Windows 8.1 and 10).
The manifest file is XML file embedded as Win32 resource. It can also be external file with the name your.exe.manifest. Search for examples in internet for sample contents.
I have an ActiveX component in XE2 that connects to a database to handle transaction processing, and it includes a check of its version against that of the database to determine if they are compatible.
Unlike C#, where the AssemblyVersion attribute can be obtained at runtime using the Application.ProductVersion property, Delphi XE2 has no such built-in property for getting the version information included in the project options, with the preferred method being to use GetFileVersionInfo, passing in the full path to the program, or in this case the OCX.
Originally the OCX was always installed to the Windows System path but we have changed our installation process so that the OCX is installed to the same folder as the executable that uses it, which is a location determined by the user.
What I need is a consistent method that I can use from within the OCX code to obtain the installation folder from the registry across the multitude of Windows environments. I assume it would have something to do with the GUID's defined in the _TLB.pas file.
You don't need to query the Registry at all. The OCX can retreive its own filename by passing Delphi's global HInstance variable as the module handle to the Win32 API GetModuleFileName() function, then it can pass that filename to GetFileVersionInfo().
Although, a better way for the OCX to access its own version, without resorting to GetFileVersionInfo(), is to use Find/Load/LockResource() to access its own version resource directly, then no filename is needed at all. You can copy the version resource data into a temp buffer and pass that to VerQueryValue() to retrieve the resource's VS_FIXEDFILEINFO structure (retrieving anything else from the resource gets a bit trickier because GetFileVersionInfo() prepares certain lookup data that VerQueryValue() then uses).
You certainly don't need to use the registry here. Not least because there could potentially be multiple versions of the DLL on the machine, because you are installing to the executable directory of any program that uses the DLL.
You could certainly read the version resource as Remy describes. But another alternative would be to include a constant in your program that encodes the database version compatibility.
const
DatabaseVersion = 1;
Check this constant against the value read from the database and fail if not compatible.
To me this makes a little more sense as it separates the version of the DLL from the version of the database. The two are not necessarily linked. You could, and probably do, update the DLL without changing the database structure.
We create a DLL for other applications to load and use some of the functionality in the application. The DLL has dependency on the the actual path where it is loaded from.
<product_home>/bin/<DLL is here>
|
|----/configdir/configfile
|----/lib/<java jarfiles>
It needs the product_home location to read config files and load jar files etc
My windows application proloads a special DLL. I need to find actual path to a loaded DLL with in the process and use it to set a "HOME" variable. This will be used in rest of the processing. Using an externally set environment variable some time fails when there are multiple versions of dll present on the machine. To me it looks like DLL can figure out its own "product_home" as long it can get the actual loaded location.
The DLL This article Get Your DLL's Path/Name provides one such way- (yet to try it successfully. The generated exe crashes). Is this the correct approach?
Either I don't understand your need, or the link you mention is not what you need. If I understand you correctly, you'd like to get the full path of a certain DLL loaded by the process. So, say that DLL is "kernel32.dll", you'd like to get "c:\windows\system32\kernel32.dll". Please correct me if I'm wrong.
If that's what you want, the easiest way to do that would be:
HMODULE hModule = GetModuleHandle(_T("kernel32.dll"));
TCHAR dllPath[_MAX_PATH];
GetModuleFileName(hModule, dllPath, _MAX_PATH);
Failures checks omitted for brevity - read more about GetModuleHandle and GetModuleFileName.
all. I would like to know if there is a good way to read out values in a compiled resource (*.res) file. I am familiar with reading resources from an executable, and I'm wondering if there is a similar way to read out resources from a resource file. Thanks in advance!
The windows functionality for dealing with res files deals with them almost exclusively as embedded resources. Typically an application will ship with localized resources contained in resource only dlls. LoadLibraryEx takes flags like LOAD_LIBRARY_AS_DATAFILE that are used to prevent the Dlls DllMain being called.
The most help you're going to get from Microsoft wrt loading res files directly is this MSDN Page
If manipulation of resources is what you want BeginUpdateResource UpdateResource, EndUpdateResource is an API you can use to inject (or modify) a version resource in an existing dll.