How to get .exe file version number from file path - c#-4.0

I am using .Net 3.5/4.0 with code in C#.
I am trying to get a version number of an exe file on my C: drive.
For example path is: c:\Program\demo.exe. If the version number of demo.exe is 1.0.
How can i use this path to grab version number?.

You can use FileVersionInfo.FileVersion to fetch this from a path.
var versionInfo = FileVersionInfo.GetVersionInfo(pathToExe);
string version = versionInfo.FileVersion; // Will typically return "1.0.0.0" in your case

Updated and modernized 2018 (e.g. string interpolation of C#6):
The accepted answer is partly not correct (ProductVersion is not typically returning three-part version) and a bit misleading:
Here is a more complete answer. To get the main text not too lengthy I splitted it in a short(er) summary which may be "enough" for a lot of people. You are not obliged to read the detailed second part, so please no tl;dr :-)
Short summary:
There are different versions (assembly version, file version, product version) of each file, but normally you will have them all equal to not get "version hell" already on file level (it will come early enough).
The file version (which is visible in Explorer and used in setups/installations) is, what I would name the most important to bother.
To achieve this, simply comment out fileversion in AssemblyInfo.cs file as below. This assures that the three possible different versions of one file are the same!
[assembly: AssemblyVersion("1.1.2.")]
//[assembly: AssemblyFileVersion("1.1.2.")]
E.g. for Semantic versioning you want to get only 3 version parts out of possible 4 :
Having an automatic build counting for every Visual Studio build is useful. But this build counting is not always useful to tell your customers, internal or external. So for mentioning the file version to windows, in title dialogs, I would advice to show only three parts v1.2.3 (and of course with semantic versioning):
using System.Diagnostics;
...
var versInfo= FileVersionInfo.GetVersionInfo(pathToVersionedFile);
string fileVersionFull = versInfo.FileVersion; // No difference here for versinfo.ProductVersion if recommendation in AssemblyInfo.cs is followed
string fileVersionSemantic = $"V{versInfo.FileMajorPart}.{versInfo.FileMinorPart}.{versInfo.FileBuildPart}";
string fileVersionFull2 = $"V{versInfo.FileMajorPart}.{versInfo.FileMinorPart}.{versInfo.FileBuildPart}.{versInfo.FilePrivatePart}";
FileVersionFull2 is just showing how to handle all 4 parts, except the "V" it contains the same as FileVersionFull .
Details:
First is a cheat sheet about how to get and set the three versions:
File version: [assembly: AssemblyFileVersion(..)] => System.Diagnostics.FileVersionInfo.FileVersion
Product version: [assembly: AssemblyInformationalVersion(..)] => System.Diagnostics.FileVersionInfo.ProductVersion
Assembly version: [assembly: AssemblyVersion(..)] => System.Reflection.Assembly.Version
Especially the defaulting may be confusing. Recommended SO link to understand details: FileVersionInfo and AssemblyInfo
EntryAssembly vs. ExecutingAssembly
For fully considering every case for getting the version of the running app, search elsewhere for more details, e.g. here:
Which is better for getting assembly location , GetAssembly().Location or GetExecutingAssembly().Location
Especially, there can be confusion, if EntryAssembly or ExecutingAssembly should be used. They both have advantages and caveats.
If you have the following code not in the same assembly as the .exe, e.g. in a helper assembly, things get more complicated. Usually you would use EntryAssembly then, to get the version of the .exe.
But: For unit tests in Visual Studio to test routines in a parallel .exe project, GetEntryAssembly() doesn´t work (my env: NUnit, VS2017). But GetExecutingAssembly() doesn´t crash at least, only during unit test you get the assembly version of the test project. Fine enough for me.There may be situations which are not as simple.
If wanted, you can omit the declaration as static making it really possible to get versions of several different assemblies in one program.
public static class AppInfo
{
public static string FullAssemblyName { get; }
..
static AppInfo()
{
Assembly thisAssembly = null;
try
{
thisAssembly = Assembly.GetEntryAssembly();
}
finally
{
if (thisAssembly is null)
thisAssembly = Assembly.GetExecutingAssembly();
}
FullAssemblyName = thisAssembly.Location;
var versInfo = FileVersionInfo.GetVersionInfo(FullAssemblyName);
..
}
}
Product version vs. file version:
ProductVersion of a file is shown in Windows Explorer too. I would recommend to maximally differentiate ProductVersion and FileVersion in the most "customer-visible" file (mostly the main .exe of application). But it could be of course a choice to differentiate for every file of the "main" app and let them all have them all the "marketing" ProductVersion which is seen by customer.
But experience shows that it is neither necessary nor cheap to try to synchronize technical versions and marketing versions too much. Confusion doesn´t decrease really, costs increase. So the solution described in the first part here should do it mostly.
History: Assembly version vs. file version:
One reason for having different versions is also that one .NET assembly can originally consist of several files (modules)- theoretically. This is not used by Visual Studio and very seldom used elsewhere. This maybe one historical reason of giving the possibility to differentiate these two versions.
Technically the assembly version is relevant for .NET related versioning as GAC and Side-by-side versions, the file version is more relevant for classic setups, e.g. overwriting during updates or for shared files.

In the accepted answer a reference is made to "pathToExe".
This path can be retrieved and used as follows:
var assembly = Assembly.GetExecutingAssembly();
var fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
var version = fvi.FileVersion; // or fvi.ProductVersion
Hope this saves someone from doing some unnecessary extra steps.

Where Program is your class name:
Console.WriteLine("Version = " + typeof(Program).Assembly.GetName().Version.ToString()) ;

I'm not sure if this is what you are looking for, but:
http://www.daniweb.com/software-development/csharp/threads/276174/c-code-to-get-dll-version
It says,
// Get the file version info for the notepad.
FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(Environment.SystemDirectory + "\\notepad.exe");
// Print the file name and version number.
Console.WriteLine("File: " + myFileVersionInfo.FileDescription + '\n' + "Version number: " + myFileVersionInfo.FileVersion);

Use this, it works:
using System.Reflection;
string v = AssemblyName.GetAssemblyName("Path/filename.exe").Version.ToString();

This works good and returns the version provided in AssemblyVersion:
using System.Reflection;
infoFileVersionInfo versInfo = FileVersionInfo.GetVersionInfo("path.exe");
string version = $"v{versInfo.FileMajorPart}.{versInfo.FileMinorPart}.{versInfo.FileBuildPart}";

Solution 1
Dim fileVer As FileVersionInfo = FileVersionInfo.GetVersionInfo(Environment.CurrentDirectory + "\yourExe.exe")
yourLabel.Text = fileVer.FileVersion
Solution 2
Get File Version Number
yourLabel.Text = Application.ProductVersion
Both solutions will give 1.0.0.0

Related

How to replace a native dynamic library file permanently and appropriately

I try to develop a thirdparty unixODBC driver, it is a secondary development based on the original file libodbc.so.2.0.0.
so I want to rename 'libodbc.so.2.0.0' to 'libodbc.so.2.0.0_renamed'. And soft link my dynamic library file to libodbc.so.2.0.0.
But I found an issue bothering me, when I rename native file and run 'sudo ldconfig', the file named 'libodbc.so.2' automatically linked to the renamed file 'libodbc.so.2.0.0_renamed', as below:
I could not understand that:
why it occurs;
how to appropriately replace the library.
I don't have enough ackownledge about linux, so that I failed to get any keyword to search and deal with it.
Could you help me, thank you very much!
Shared objects under GNU/Linux follow a specific version naming scheme, which is known by the loader (and OS component, actually part of libc framework) to determine if a newer library is retro-compatible with some older version to which a binary was originally linked against. By adding the renamed suffix, you are violating the convention and the dynamic linking system is getting confused. You should renamed as suggested by #Bodo above.
In addition, perhaps rather than using rename, you might consider using the very versioning scheme. From GNU Build System (aka Autotools) manual, the version cheme is like it follows:
Versioning: CURRENT:REVISION:AGE
CURRENT The latest interface implemented.
REVISION The implementation number of CURRENT (read: number of bugs fixed...)
AGE The number of interfaces implemented, minus one.
The library supports all interfaces between CURRENT − AGE and CURRENT.
If you have
not changed the interface (bug fixes) CURRENT : REVISION+1 : AGE
augmented the interface (new functions) CURRENT+1 : 0 : AGE+1
broken old interface (e.g. removed functions) CURRENT+1 : 0 : 0
Therefore a possible history of your lib might be:
1:0:0 start
1:1:0 bug fix
1:2:0 bug fix
2:0:1 new function
2:1:1 bug fix
2:2:1 bug fix
3:0:0 broke api
3:1:0 bug fix
4:1:1 bug fix
5:0:0 broke api
You might, for instance, call the older and newer versions of libodbc.so.x.y.z, according to your needs. Just an idea.

Finding the default project settings file

I'm trying to write a plugin for 3ds max, I went through the entire sdk installation process to the letter as described in the help files.
The problem I'm facing though is intellisence complaining about an invalid macro definition
"IntelliSense: command-line error: invalid macro definition:_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT =1"
I found the definition in project settigs -> c/c++ -> preprocessor definitions as inherited from parent or project default.
I tried disabling the inherited definitions and re-entered them, this time without the space between the name and the = and all works fine so I'm guessing its a typo on their part?
Anyway, I want to change the default project or whatever to not repeat it every time i start a new project. The project is created with a wizard which required me to copy over some files to appear and after which I had to enter the sdk path.
The files I copied are plain text with some fancy extensions and not much in them so I'm guessing the defaults are described in the sdk directory.. somewhere. Does anybody know what kind of a file I'm looking for?
EDIT: I found a file called root.vcxproj_template and it has a section for preprocessor definitions but all it contains is
<PreprocessorDefinitions>_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
and no mention of the broken one
EDIT2: in another part of the file there was a path to a property sheet (maxsdk\ProjectSettings\propertySheets\3dsmax.common.tools.settings) which included the faulty definition. I fixed it an no more complaints from VS.
_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT = 1 means that compiler should replace all old C run-time routines such as sprintf, strcpy, strtok with new versions such as strprintf_s, strcpy_s, strtok_s and similar. It goes in pair with following definition _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES = 1.
More you can find here: (MSDN) https://msdn.microsoft.com/en-us/library/ms175759.aspx. However I tried to use this but without success. It says that you can use this only for statically allocated buffers like char buffer[32], but compilers was still complaining bout unsecure strcpy.

Warning MIDL2346 in Visual C++ 6 source: The specified lcid is different from previous specification

I have a strange warning in some code I'm trying to maintain. I'm currently testing it out in its current environment (Visual C++ 6.0, yes, I know, ancient) before moving it up to a more modern VC++ version. I don't understand this warning, and what effect it might be having on the EXE target I'm compiling. During compilation I get this output in the build tab:
Processing C:\OSDK\Libraries\PSDll\OSDKDefs.idl
OSDKDefs.idl
.\Server\Interfaces\InterfaceDef.idl(109) : warning MIDL2346 : the specified lcid is different from previous specification
Compiling...
The above IDL file is a slightly hacked up version of an IDL file provided by a vendor which no longer provides any support for the above libraries. I believe that this comment in the IDL file was added by a former maintainer of this project, who has hacked this IDL file. My question is, I can make the warning go away by changing the lcid back to the value in the comment, possibly reintroducing some unwanted problem that the original modifier of this idl file wanted to avoid. What is an lcid and what would the difference between the behaviour with lcid(0x409) and lcid(0x09) be? A single bit with value 0x400 hex is being toggled, but what does that bit do?
The line that is causing the warning is marked and commented below, formerly lcid(0x409)
changed to lcid(0x09) for "compatibility" with some kind of test tool that this vendor provides for their DCOM/COM code, the tool is mentioned in the comments below.
//
// Component and type library descriptions
//
[
uuid(bbf92ab1-5031-40c2-864d-1c301f51d0ce),
// mvs04042000 - Changed back the lcid from 0x409 to 0x09. Else we have problems
// connecting from the PowerTool.
lcid(0x09), /// <<----- WARNING HERE
version(7.16),
helpfile("OsdkTlb.hlp"),
helpstring("OPC Server 7.16 Library"),
helpcontext(0x00000010)
]
library ED3Drv
{
importlib("stdole32.tlb");
[
uuid(b66ac2ca-d99e-4319-8fc0-08c0b65e65df),
appobject
]
coclass ED3Server
{
[default] interface IED3Driver;
interface IDriver;
interface IDriverMessage;
interface IDataScopeConnect;
interface IDispatch;
[source] interface IDataScopeSink;
};
};
The IDL above is part of a toolkit that was designed to help people write C++ DCOM clients and servers that match a specification called OPC (OLE for Process Controls).
lcid is LocaleID. 0x409 equals to 1033, which is English (United States). 0x09 is not a valid locale id value.
See http://msdn.microsoft.com/en-us/library/ms912047(v=winembedded.10).aspx for a complete list of valid values.

Can you use assembly.load in monotouch?

I'm currently trying to load a plugin assembly dynamically in a monotouch app.
To do this, I'm referencing the plugin dll in my app project, setting the limker to 'sdk only' and then i'm trying to call Assembly.Load(filename) within my app when the plugin is required.
This is the same approach that I've previously successfully used in monodroid. However currently, this is failing in monotouch with a FileLoadException.
Is this approach possible in monotouch? Is there a special file path you need to include? Or is this not supported in the aot environment?
Note: Obviously there are other ways I can achieve a similar effect - and I do have a backup plan... but this is my preferred route (if I can make it work)
Code like:
var a = Assembly.Load ("mscorlib.dll");
Assert.NotNull (a);
works fine with both the simulator and devices. However the parameter for Load is assemblyString which is not a filename (even if the exception thrown make you think it is).
Many other overloads exists (for Load) and other methods too (e.g. LoadFrom) but they might not all work inside MonoTouch (since some runtime support might be missing).
NOTE
Handling of mscorlib.dll is special (and works in more cases than other assembles, i.e. shortcuts). However the reflection-based methods seems to work as expected in more cases, e.g.:
string filename = System.IO.Path.GetFileName (GetType ().Assembly.Location);
Assembly assembly = Assembly.ReflectionOnlyLoadFrom (filename);
Assembly.Load (or any other way of loading code dynamically) is not supported in MonoTouch.
This is an iOS restriction - all the executable code has to be in the app (and it has to be native code, which is why we use AOT to generate native code at compile time).

How to use Protobuf-Net with MonoTouch?

Has anyone actually managed to accomplish this?
I tried the approach suggested here, but no matter how i generate the precompiled serializer, mtouch fails to copy it to the app bundle, thus resulting in a runtime exception. I think this happens because the resulting binary may not be compatible with MonoTouch.
I have tried the following:
1) I used the provided iOs and Mono binaries included in the latest (r450 as this time) build in order to generate the precompiled serializer.
2) I used the source code to produce two different assemblies, built for MonoTouch. The first assembly is built using the symbols FEAT_SAFE;MONOTOUCH;NO_RUNTIME and the second is built using the symbols FEAT_SAFE;MONOTOUCH;FEAT_COMPILER. I have defined the symbol MONOTOUCH and used it the same as MONODROID symbol is used (see file CallbackAttribute.cs and Helpers.cs in the protobuf-net source).
I the used this two assemblies and tried to generate the precompiled serializer from a MonoTouch application in the simulator.
But no matter which version of the precompiled serializer i use, the assembly is still not included in the app bundle, with mtouch issuing: "Warning: Library 'MyLibrary.dll' missing in app bundle, cannot extract content", despite the fact that i do reference it in my code.
I finally got it. It seems that when the actual assembly name is different from the file name that contains it mtouch will not include it in the application bundle. And that was happening in my case. I am generating the assembly like this:
model.Compile("Taxi.ProtoBufSerializers.MQTTContractsSerializer", "MQTTContractsSerializer.dll");
So, given that Protobuf-Net sets the assembly name to the first parameter of this method and saves it in the file name given by the second parameter, mtouch will fail to include it in the application bundle.
However, i wanted to keep my namespace so i fiddled with Protobuf-Net's source code to generate the assembly like this:
File path: Given as the second parameter;
Assembly name: Path.GetFileNameWithoutExtension(path);
Module name: Path.GetFileName(path).
I am not performing any validations on the path at this time, but i don't need to do this just yet.
And voila: The sample works both on the simulator and the device.
Last but not least, i don't know if this is the way mtouch is supposed to behave or if it is a bug. I will however file a bug report against it.
I have only gotten it to work on the simulator. I created the custom serialization assembly on VS.NET 2010. One issue I had was that the IL/DLL that gets created had the wrong namespace. I did something like this:
model.Compile("X.Y.Serializer.MySerializer", "X.Y.Serializer.dll")
But the IL was something like:
.assembly X.Y.Serializer.MySerializer
{
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module X.Y.Serializer.MySerializer
I.e. the class name was in the assembly name.
So I wrote a perl program to:
Decompile DLL -> IL
Fix IL
Compile IL -> DLL
Here is the script:
#!/usr/bin/perl
# Usage: fix-protobuf-assembly assembly bad-namespace
#
# Example: fix-protobuf-assembly X.Y.Serializer.dll X.Y.Serializer.MySerializer
# X.Y.Serializer.MySerializer gets converted to X.Y.Serializer
use strict;
use File::Slurp;
use Cwd;
print "Current directory is " . getcwd() . "\n";
my $asm_file = shift || die "missing assembly file";
my $bad_ns = shift || die "missing namespace";
die "no such file '$asm_file'" if (! -f $asm_file);
my $il_file = $asm_file;
$il_file =~ s#dll$#il#;
Run("ildasm /out=$il_file $asm_file");
my $il = read_file($il_file) || die "error reading $il_file: $!";
my $ns = $bad_ns;
$ns =~ s#\.[^.]+$##;
if (($il =~ s#(\.assembly|module) $bad_ns#$1 $ns#g) == 0)
{
die "$bad_ns not found in input dll; aborting";
}
write_file($il_file, $il);
Run("ilasm /dll $il_file");
sub Run
{
my($command) = #_;
warn "Running $command ...\n";
system($command) && die "error running last command; bailing out";
}
Maybe I just missed the proper way to call Compile() and my hack is unnecessary.
The assembly worked fine on Windows and iOS simulator. But it then gave a runtime JIT compile violation error on the device. I just created a SO question:
JIT compile error with protobuf-net on MonoTouch/iOS device (iPhone/iPad)
I did try using MonoDevelop on Mac w/ standard console project to first create the serialization assembly. I had some issues, but to be honest I was sleepy and grumpy and it could have been user error, and quickly decided to jump over to Windows since my project has other components that I develop there.
I used .NET 4.0 projects on Windows and everything worked OK. I just had to create a lightweight version of two MT-only libraries so that I could access the classes that would be serialized.
Yes, we have been using it on a project since 2012 to improve performance over XML serialization. Mostly because the RESTFul services we had at the time could not do JSON over 1MB in size for some of the files. At this point in 2017, it would be a lot easier for us to use JSON now, instead of the extra hassle of building the custom serializers for each object.

Resources