How to change the language property of a dll/exe on Windows - windows

How do you change the language property of a Windows DLL or EXE? The property I am talking about can be seen if you right-click on a DLL and go "Properties" > "Details". Something from the command line would be preferred.
Background...
I am trying to get rid of a warning when building a Windows installation package using WiX. The warning is:
LGHT1076: ICE60: The file somedll.dll
is not a Font, and its version is not
a companion file reference. It should
have a language specified in the
Language column.
If you add a DefaultLanguage attribute for the file within the WiX project file, this changes to:
LGHT1101: The DefaultLanguage '0' was
used for file 'somedll.dll' which has
no language. Specifying a language
that is different from the actual file
may result in unexpected versioning
behavior during a repair or while
patching. Either specify a value for
DefaultLanguage or put the language in
the version information resource to
eliminate this warning.
I'm really not sure what the first solution they suggest means ... didn't I just "specify a value for DefaultLanguage?" So I'm trying the second solution, which I'm guessing is the language property of the file? I am building somedll.dll from source, so if it is something that has to be done when building, I might be able to do that.

A file's language is an attribute of its versioninfo resource. WiX reads it to autopopulate the language (and version) columns in the .msi File table.

Since I had access to the source, I was able to change the version resource file to include the language in this case. The specific library was Qt, the fix can be seen in QTBUG-16583.
Still not sure how one would do it without access to source.

Related

Visual c++ programatically get file version number within the file itself

I know I can call GetFileVersionInfo() windows API to retrieve file version information.
Is there an easier way to determine the version information, from within the program itself?
For example, suppose I am writing codes for Foo.dll, and inside Foo.dll, I want to support a version function, say GetFooVersion(), which reports the version number of Foo.dll.
If I have to use GetFileVersionInfo(), then I need to search which Foo.dll in the path that is been linked (dynamically), and apply GetFileVersionInfo(). It's tedious and error-prone.
The target visual studio version is VS2012.
There is no GetFileVersionInfoByHandle nor GetFileVersionInfoFromModule unfortunately.
You can use FindResource etc. on your own module but you then have to parse the version info yourself because GetFileVersionInfo does not always retrieve the raw resource data (it can translate to/from Unicode etc.).
Another option is to put version #defines in a .h file that your function and your resource.rc can use so you only have to update a single file when the version changes.

$(shell some-command) equivalent for Visual Studio project macros?

With Makefiles I'm used to being able to write things like:
includedir=$(shell pg_config --includedir)/server
to run an external program, pg_config, with argument(s) --includedir, and include the result in a variable or as part of a variable. So if pg_config --includedir output /usr/include to stdout, the value of includedir would become:
includedir=/usr/include/server
Is there any way to do the equivalent with a Visual Studio project? Run a command, get the result, and substitute it into a property?
I find myself having to edit properties pages all over the place - changing the include directories and library directories for both the x86 and x64 configurations of a project whenever I want to build an extension against a different PostgreSQL version. It is intensely frustrating.
I want to be able to put something like this into Configuration Properties -> C/C++ -> General -> Additional Include Directories:
%(shell pg_config --includedir)
or even better:
%(shell %(PG_CONFIG) --includedir)
where %(PG_CONFIG)'s location is defined in a single place for each platform in the project.
So I'm looking for at least user-defined macros, and preferably the ability to invoke a command line tool and replace the macro with the resulting standard output.
(Preferably in a way that doesn't involve delving into semi-documented UI elements that move and get renamed in every VS version, and that appear and disappear from the various Express editions).
This has been possible in Makefiles for 20 years, there must be a way to do it in VS, right? Or do "Real Windows Developers" generate their VS projects with scripts and build them using MSBuild?
I've looked at some similar questions without finding much of use, e.g.:
Visual Studio - Where to define custom path macros?
In particular, I'm aware of property sheets (View -> Other Windows -> Property Manager), but they don't seem to provide a way to set a value in just one place, they're still per-configuration and per-architecture, so if you have four configurations and two architectures it gets awkward. Unlike with the normal project property editor you can't even apply a change across a group of architectures/configurations, either.
I could use a VS extension, but they require installation into the user's VS, can be version-specific, and seem like a very big hammer for a small problem.
I find myself having to edit properties pages all over the place
That bugged me to no end as well. Property sheets to the rescue! When setting up a major solution in VS10, for example, I had every project pull in a settings.props that contained the common settings, made in only one place. Then go through all the generated or imported projects and kill any explicit value (even if blank) for everything possible. That way things will inherit from property sheets. Select "all configurations" and on each properly use the drop-down to "inherit from...".
I have property sheets for each special library too, just defining the proper #define, include paths, lib paths, etc. Projects that use that particular external lib simply use that property sheet. Users are told, in the worst case, to “edit the XML to change the path to where you have Boost”.
As for setting such a properly to a dynamic determined value, you can do that too. There are property functions you can use.
It sounds like you're going down the same path as I did.
More notes: “prop sheets are per configuration/platform”: If you include a prop sheet at the top-level node for the project itself (not the Debug|Win32, etc. child nodes) it will include it into all current configurations at once. If you edit the properly page, you can choose Multiple or All configurations on the Property dialog box, just as with the usual project use of the Property dialog.
“Custom user macros are well hidden” A property page shows up for that when in a property sheet you created, but not when opening property dialog on a proj file as in the normal File View. The macro will be set in one place (the prop page) and usable as a $(name) in all projects that include it, and even in other property pages that come later in the evaluation sequence.
Let me know how it goes. You should be able to do everything you asked.
—John
In addition to #jdlugosz's answer:
It looks like the traditional way to do this with Visual Studio, before the advent of property functions, was to write a new MSBuild Task. The task can potentially do things like modify a property sheet.
MSBuild supports "inline tasks" where the task code is in the MSBuild project file, rather than a separate assembly, so it might not be neccessary to create a new subproject just for the task.
There are a bunch of built-in tasks, like Exec and CreateProperty that may be useful.
The docs say that:
[The Exec task] is useful when a specific MSBuild task for the job that you want to perform is not available. However, the Exec task, unlike a more specific task, cannot gather output from the tool or command that it runs.
... but that seems to be outdated/wrong so you don't need horrible workarounds.
So, prior to .NET 4.5 I'd probably have to write a custom task for this simple job, because there's no way to feed the command stdout/stderr into the CreateProperty task or have Exec create a property directly. But in 4.5 it looks like I can do it directly. At least in VS Express support for tasks etc is very limited so you'll probably land up editing the XML.

File Versioning Rules When Neither Components Has a Key File

According to URLs I referenced, I understand that the Windows Installer uses key files to compare the version, date, and language of components and determine whether to update the component on target machine.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa368599%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/aa371221%28v=vs.85%29.aspx
I also understand that default versining rules consist of 4 different cases as listed below.
Both Files Have a Version
Neither File Has a Version
Neither File Has a Version with File Hash Check
One File Has a Version
What I don't understand is that how does the installer determine whether the component needs to be updated if neither components has a key file?
And what's going to happen if neither components has a key file, but a file on the target computer indicates that its Modified date is later than the Create date? In this case, even when both products have a version, are they going to be considered as having Non-versioned files because no key file is set to components? How does the installer determine whether to install?
Any answers would be really appreciated,
Every component from the installer must have a key member, this is imposed by Windows Installer to build a valid MSI package. Also, Microsoft strongly recommends that you create independent components for each DLL, EXE, OCX and hlp/help file. This will allow the file versioning rules to be correctly applied.

How to share VB project with another programmer overcoming the vbp "reference" issue?

I have this old VB6 project that is composed of a few DLLs, OCXs, and GUIs.
There is a GUI component that includes this in it's VBP file:
Type=Exe
Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\Windows\SysWOW64\stdole2.tlb#OLE Automation
Object={EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}#1.1#0; ieframe.dll
Object={3050F1C5-98B5-11CF-BB82-00AA00BDCE0B}#4.0#0; mshtml.tlb
Reference=*\G{64E54C86-D847-48F7-9AE5-D6C9B8E6A3A2}#3.0#0#..\..\bin\Crypt.dll#Crypt
Reference=*\G{B3E7F95C-B6D9-458E-B4D4-5272759B139A}#4.0#0#..\..\bin\SpeechMike.dll#SpeechMike_DLL
Object={831FDD16-0C5C-11D2-A9FC-0000F8754DA1}#2.1#0; MSCOMCTL.OCX
Object={AB4F6C60-4898-11D2-9692-204C4F4F5020}#29.0#0; Ccrpsld.ocx
Object={48E59290-9880-11CF-9754-00AA00C00908}#1.0#0; msinet.ocx
Object={9C526969-AA6E-4D61-BAFA-117FD20C2B38}#3.0#0; SpeechMike.ocx
The Reference settings are a pain since they always change from one machine to the other. I mean, the GUID '9C526969-AA6E-4D61-BAFA-117FD20C2B38', for the last one as an example, will be something on my system, but something else on somebody else's machine.
For now, to make it work, I erase References to Crypt.dll and SpeechMike.dll. Also Object SpeechMike.ocx. Otherwise, Visual studio looks for something that does not exists. Then in "project > references" I check both Crypt and SpeechMike and the Reference goes back to the VBP with the proper GUID and version. Finally, in 'project > components' I add the OCX and I'm good to go.
Am I wrong about that? How can I share the project with some else without going through hoops and loops to start the project?
I'm using MS Visual Basic 6 (part of VS 6 enterprise).
This sounds like "failure to maintain binary compatibility." Normally you only do this to yourself, but of course it can be a bigger headache if multiple people are compiling your libraries from the source Project files.
When you create ActiveX EXEs, DLLs and OCXs you need to create a "base" version where type and class ID values (GUIDs) get assigned. The documentation even suggests that you do this leaving the procedures empty: just a comment line or something so the IDE does not remove the empty declarations.
You don't have to use an "empty" base reference library, it can be one with full code in it.
Once you have compiled this baseline library, you'd exit and save your Project. Then rename this "empty" library as something else and from there keep it along with your Project source files.
After this you re-open the Project and go into Project Properties and on the Component tab change the Compatibility setting to Binary Compatibility and in the box there enter the full path and name of your compiled baseline library. Save the Project. Now you can add code and compile the "real" library to be used by other programs.
When you distribute these libraries (DLLs, OCXs) to somebody else in source code form so that they can compile them you must provide this renamed compiled baseline library along with the source code files, VBP file, resource files, etc.
From there your GUIDs will be stable until you make a change to something that breaks binary compatibility (changing a method's argument list, etc.).
There is more detail on this in the online Help (MSDN Library). See:
Using Visual Basic|Component Tools Guide|Creating ActiveX Components|Debugging, Testing, and Deploying Components|Version Compatibility in ActiveX Components

What does 'VersionCompatible32="1"' mean within a VBP file?

I have a VB6 project, when I came to check in changes to the VB6 project file I noticed that the Visual Studio 6 IDE had automatically inserted the following line:
VersionCompatible32="1"
What does this mean?
As an aside: Is there a good resource to help me make sense of the VBP file?
The VersionCompatible32 value in the VBP file seems to be part of the binary compatibility settings of an ActiveX project, maybe the typelib it needs to be compatible with (there can be several in a library).
When my project is set to no, or just project compatibility, this value is removed.
Note that the compatibility setting itself is stored in the CompatibleMode value.
First of all, I don't think it is a good idea to edit the VBP file manually. As far as I know, VersionCompatible32 is a hint about the VB(A) version that was used to save this file, probably for newer versions to recognize changes in the file format.

Resources