How do find 32BitProcess running on 64BitOperatingSystem using C# Preprocessor directivies.
For More info, i need to declare the dll name(based on the bit) to access the extern function. I need the following code using Preprocessor way.
public String WABDll;
if (64Bit)
{
WABDll = "Win-64.dll";
}
else if(32Bit Process on 64BitOS)
{
WABDll = "Win-32on64.dll";
}
else if(32Bit)
{
WABDll = "Win-32.dll";
}
i tried the following way
#if _64BIT
public const String WABDll = "Win-64.dll";
#elif _32BIT
public const String WABDll = "Win-32on64.dll";
#else
public const String WABDll = "Win-32.dll";
#endif
Any Suggestions.
Don't do this with preprocessor directives; determine the environment at runtime using the Environment class. The Is64BitOperatingSystem and Is64BitProcess properties should give you the information you need.
You can't solve this:
else if(32Bit Process on 64BitOS)
{
WABDll = "Win-32on64.dll";
}
compile time, since compiler does not know in advance where the program will run.
I can suggest you creating more solution "paltform", declaring some custom compiler flag and using them accordingly. Of course you need to know deploy time which executable must run on which platform.
Related
Is it possible to "gray out" the code if it doesn't exist like we do in Platform Dependent compilation (ex: #If UNITY_EDITOR)?
For example I don't want the compiler to complain if the code doesn't exist in the project. Specifically, I want to "hide" "GoogleMobileAds.Api;" package, which I don't have in the project, but it may be in the future.
Preprocessors are not an invention of Unity but is a c# thing.
If there are no specific defines listed in the Platform dependent compilation first make sure that your packages don't bring their own custom defines. Photon PUN e.g. actually does bring own defines like PHOTON_UNITY_NETWORKING, PUN_2_OR_NEWER, etc. But that's totally up to the providers of such libraries.
You can see/check this in the Edit -> Project Settings -> Player Settings -> Other Settings -> Scripting Define Symbols
Scripting Define Symbols
Set custom compilation flags. For more details, see the documentation on Platform dependent compilation.
Then you can just invent your own ones and add them to your code like e.g. USE_GOOGLE, USE_FIREBASE, etc
#if USE_GOOGLE
// some Google API related stuff
#endif
and later once you actually have according package in your project add these defines to the Scripting Define Symbols mentioned above.
If you know the full qualified assembly name of one type contained in the optional package you are looking for you can use e.g.
[assembly: OptionalDependency("Namespace.SubNameSpace.TypeName", "YOUR_DEFINE_SYMBOL_HERE")]
which is well hidden in Unity.XRTools.Utils!
This will internally on compile time check if the type Namespace.SubNameSpace.TypeName exists and if so define YOUR_DEFINE_SYMBOL_HERE so you can again in your code wrap the optional stuff in
#if YOUR_DEFINE_SYMBOL_HERE
...
#else
...
#endif
Alternative
For packages you own/implemen yourself there is a way to do this kind of automatically I used in the past. The following script as soon as it exists in a project it automatically adds the given define to the PlayerSettings if it doesn't exists yet
#if !USE_GOOGLE
public static class UseGoogleDefineSetter
{
const string DEFINE = "USE_GOOGLE";
[InitializeOnLoadMethod]
private void Init()
{
// Get current defines
var currentDefinesString = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
// Split at ;
var defines = currentDefinesString.Split(';').ToList();
// check if defines already exist given define
if (!defines.Contains(DEFINE))
{
// if not add it at the end with a leading ; separator
currentDefinesString += $";{DEFINE}";
// write the new defines back to the PlayerSettings
// This will cause a recompilation of your scripts
PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, currentDefinesString);
}
}
}
#endif
Update Unity 2020+
The method was semi replaced by a better one operating on a list/array instead of an entire string which is expensive. And in the newest version also the build pipeline slightly changed.
So in newer Unity versions I would rather use something like e.g. (assuming 2020 is the oldest version you want to support/use)
#if !USE_GOOGLE
public static class UseGoogleDefineSetter
{
const string DEFINE = "USE_GOOGLE";
[InitializeOnLoadMethod]
private void Init()
{
EditorUtils.AddScriptingSymbol(DEFINE);
}
}
#endif
and to make it easy and general
public static class EditorUtils
{
#if UNITY_2021_2_OR_NEWER
private static NamedBuildTarget GetActiveNamedBuildTarget()
{
var buildTargetGroup = GetActiveBuildTargetGroup();
var namedBuildTarget = NamedBuildTarget.FromBuildTargetGroup(buildTargetGroup);
return namedBuildTarget;
}
#endif
private static BuildTargetGroup GetActiveBuildTargetGroup()
{
var buildTarget = EditorUserBuildSettings.activeBuildTarget;
var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget);
return buildTargetGroup;
}
public static void AddScriptingSymbol(string define)
{
#if UNITY_2021_2_OR_NEWER
var namedBuildTarget = GetActiveNamedBuildTarget();
PlayerSettings.GetScriptingDefineSymbols(namedBuildTarget, out var defines);
#else
var buildTargetGroup = GetActiveBuildTargetGroup();
PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup, out var defines);
#endif
var defineList = defines.ToList();
if (!defineList.Contains(define))
{
defineList.Add(define);
}
#if UNITY_2021_2_OR_NEWER
PlayerSettings.SetScriptingDefineSymbols(namedBuildTarget, defineList.ToArray());
#else
PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, defineList.ToArray());
#endif
}
}
Both scripts go of course either in a folder called Editor and/or in an assembly only compiled for the Unity Editor or need to be wrapped additionally in #if UNITY_EDITOR
I have a class in my .NET Core 3.1 library project, where I want to initialize the field key at build time:
using System.Text;
namespace MyNamespace
{
public class Myclass
{
private string key;
....
}
}
I am publishing my library via simple publish command:
dotnet publish -c release -r linux-x64
I am exploring an option where I could pass some attribute during build which will be set in key property during compilation/build process.
I am also obfuscating my DLL as well after this process via some third party tool.
This DLL will then be embedded in an application where this class one method is being called via reflection (reflection and calling method is already done).
Using the Roslyn API you can parse and compile a source programatically. The question linked by vasil oreshenski gives you working examples. The missing piece is to get your desired value (somehow) and then embed it into the syntax tree before compilation.
First, to make our lives easier, create a custom attribute and mark the key field with it.
using System;
public class BuildTimeParameterAttribute : Attribute
{
}
namespace MyNamespace
{
public class Myclass
{
[BuildTimeParameter]
private const string key1 = "", key2 = "";
[BuildTimeParameter]
private const string key3 = "";
....
}
}
I also changed the field to be a const and added additional fields to test the behaviour. Now when you have a syntax tree from the RoslynAPI you can do this:
var parsedSyntaxTree = Parse(
source,
"",
CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8));
// Get those values from commandline arguments or however you like.
var replacementValues = new Dictionary<string, string>
{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
var root = (CompilationUnitSyntax) parsedSyntaxTree.GetRoot();
// Retrieve all fields marked with the BuildTimeParameterAttribute.
var fields = root.DescendantNodes().OfType<FieldDeclarationSyntax>().Where(
s => s.AttributeLists.SelectMany(a => a.Attributes)
.Any(a => a.Name.ToString() == "BuildTimeParameter"));
var newRoot = root.ReplaceNodes(
fields,
(_, field) =>
{
var variables = field.Declaration.Variables;
var newVariables = from variable in variables
let newValue = replacementValues[variable.Identifier.ValueText]
let newInitializer = variable.Initializer.WithValue(
SyntaxFactory.LiteralExpression(
SyntaxKind.StringLiteralExpression,
SyntaxFactory.Literal(newValue)))
select variable.WithInitializer(newInitializer);
return field.WithDeclaration(
field.Declaration.WithVariables(
SyntaxFactory.SeparatedList(newVariables)));
});
The procedure is a bit complicated, because a single field declaration can contain many variables (in our case the first field declaration contains key1 and key2).
Now you can create a compilation using the newRoot.SyntaxTree. Decompiling the resulting dll yields:
namespace MyNamespace
{
public class MyClass
{
[BuildTimeParameter]
private const string key1 = "value1";
[BuildTimeParameter]
private const string key2 = "value2";
[BuildTimeParameter]
private const string key3 = "value3";
}
}
The above code doesn't handle errors and will fail with an NRE if there is no initializer, so for example if you write private string key;. It will work with const, as they are required to have an initializer. Making this code production-worthy I leave for you.
Note
With .NET 5 this could be much more easily done using source generators. You could declare your class as partial and then generate a file with the key constant field declaration using a source generator.
I can think of two options:
1. Using external file for the key - You are trying to have inversion of control at build time.
Why hard coding it in the dll when you can use text file with the key in it and your class will read the key from the file. As part of the build process you can define command to create the file with the specified key in the expected location where your dll will read it.
The down side - you need to have the file everywhere you are going to use the dll.
If this is a problem you can add the file as embeded resource to the dll and replace the value as part of the build script - before the actual build of the csproject, this way you will produce dll with embbeded resource which will be synced with the physical file.
2. You can use the roslyn API to create dlls at runtime - this way you can create console application which will read the key from a file or as CMD argument and this application will produce a new dll file with the required class with the key embbeded in the class as property / field.
More info on Roslyn API - you can check this SO answer for complete example how to use the API to produce dll file
Just some thoughts - If this key is some sensitive information you will need different approach (hard coded in the dll is not an option because it can be extracted pretty easy with programs like .NET Reflector - obfuscation won't do much)
This solution is not sophisticated as the other presented, but it probably can achieve your goal with a minimal effort.
I'd use preprocessor directives:
using System.Text;
namespace MyNamespace
{
public class Myclass
{
#if MY_DEBUG_KEY
private string key = "debug";
#elif MY_RELEASE_KEY
private string key = "release";
#else
#error key value has not been set
#endif
}
}
Then you can edit your csproj adding thw following PropertyGroups:
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;MY_DEBUG_KEY</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE;MY_RELEASE_KEY</DefineConstants>
</PropertyGroup>
So if you'll compile using Debug configuration the key value will be "debug", if you'll compile with Release it will be "release" and if you are going to use a new configuration it won't compile remembering you that you need to set a value for your key.
And you will be able to do it by adding another #elif directive and a PropertyGroup setting in your csproj:
.cs:
#if MY_DEBUG_KEY
private const string key = "debug";
#elif MY_RELEASE_KEY
private const string key = "release";
#elif MY_OTHERCFG_KEY
private const string key = "another value";
#else
#error key value has not been set
#endif
.csproj:
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='OtherCfg|AnyCPU'">
<DefineConstants>TRACE;MY_OTHERCFG_KEY</DefineConstants>
</PropertyGroup>
The dead easiest way to do this would be to declare the class you want the variable in as partial. This ads a little overhead on the build management side, but the C# compiler does not allow or defining terms with values like a c++ style compiler
Then in the build system swap in a cs file with the defined value you want.
swap.cs
namespace MyNamespace
{
partial class MyClass
{
const string myspecialstring = "Super duper value";
}
}
then
MyProgramSource.cs
namespace MyNamespace
{
partial class MyClass
{
// Lots of awsome code
System.Diagnostics.Trace.Writeline($"{myspecialstring}"); //works no problem
}
}
I have a C++ code which I need to rewrite to C# and looks like this:
class dppServerError: public dppBaseError
{
public :
dppServerError(DWORD ActionCode, const TCHAR* Desciption)
#ifdef POSTER_VER
: dppBaseError(Desciption)
#else
: dppBaseError(TEXT("Server text response: \"%s\""), Desciption)
#endif
, m_AC(ActionCode), m_ErrorCode(dppERR_SERVER)
{
};
Problem is I am not using #defines in my C# code and instead using public const Enums. Now, how can I duplicate above code in C#? the #ifdefs part?
Can't I normally initialize member variables of base class in the body of the constructor of derived class? (without : syntax). Then I could do (in C#):
dppServerError(uint ActionCode, string Desciption)
{
// Initialize base class member
if(Globals.ConfigEnum == POSTER_VER)
dppBaseError = Desciption; // Can I initialize this base class ivar like this? without : syntax?
else
dppBaseError = "Smth else" + Desciption;
// These are just ivars from This class
m_AC = ActionCode;
m_ErrorCode = dppERR_SERVER;
};
PS. Someone told me this about #defines in C#
"Be aware though: there is no guarantee that the conditional
compilation symbol is the same for all projects in your solution. This
will hinder reuse of your DLLs by other solutions that want different
conditional compilation symbols."
And I decided to move to enums because I didn't really get what this meant. I am a bit new to .NET.
To get the same c++ behaviour in c#, use this:
#if POSTER_VER
dppBaseError = Desciption;
#else
dppBaseError = "Smth else" + Desciption;
#endif
or also:
dppServerError(uint ActionCode, string Desciption)
#if POSTER_VER
:base(Desciption)
#else
:base("Smth else" + Desciption)
#endif
Use a #define POSTER_VER directive, or better, define the symbol in project properties -> build -> Conditional compilation symbols.
Usually a source file is included only in one project (unless you use "add as link " in visual studio to add same file to two or more projects), so the remarks "be aware" does not apply. if it does, use the same care you would use for c++ code.
In you c# code , the variable Global.ConfigEnum is evaulated at runtime, in my c# code, as in your c++, the symbol POSTER_VER is checked at complile time, resulting in different compiled binary files.
see #if, #define and ProjectProperties on MSDN
If dppBaseError is a field, you can initialize it as you have shown in your code.
If it's a base class constructor, you could do this:
dppServerError(uint ActionCode, string Desciption)
: base( (Globals.ConfigEnum == POSTER_VER) ? Desciption : "Smth else" + Desciption)
{
...
This question already has answers here:
C# !Conditional attribute?
(8 answers)
Closed 8 years ago.
What is the C# System.Diagnostics.Conditional equivalent of #if (!DEBUG)?
I want to encrypt a section of the app.config file of a console application if it has not been compiled in DEBUG mode. This is achieved like so:
public static void Main(string[] args)
{
#if (!DEBUG)
ConfigEncryption.EncryptAppSettings();
#endif
//...
}
but somehow, I prefer decorating the encrypt method with a conditional attribute:
[Conditional("!DEBUG")]
internal static void EncryptAppSettings()
{
//...
}
however this makes the compiler sad: The argument to the 'System.Diagnostics.ConditionalAttribute' attribute must be a valid identifier...
What is the correct syntax for negating the Conditional argument?
EDIT:
Thanks to #Gusdor, I used this (I preferred to keep the Program.cs file free of if/else debug logic):
#if !DEBUG
#define ENCRYPT_CONFIG
#endif
[Conditional("ENCRYPT_CONFIG")]
internal static void EncryptAppSettings()
{
//...
}
Using the attribute will be a bit of a hack but it can be done.
#if DEBUG
//you have nothing to do here but c# requires it
#else
#define NOT_DEBUG //define a symbol specifying a non debug environment
#endif
[Conditional("NOT_DEBUG")]
internal static void EncryptAppSettings()
{
//...
}
#if DEBUG
// do nothing
#else
//your code here
#endif
I'm using VS2010/2012 and I was wondering if there is a way (perhaps using reflection) to see how an assembly is build.
When I run in Debug, I use the #if DEBUG to write debug information out to the console.
However, when you end up with a bunch of assemblies, is there then a way to see how they where build? Getting the version number is easy, but I haven't been able to find out how to check the build type.
There are 3 ways:
private bool IsAssemblyDebugBuild(string filepath)
{
return IsAssemblyDebugBuild(Assembly.LoadFile(Path.GetFullPath(filepath)));
}
private bool IsAssemblyDebugBuild(Assembly assembly)
{
foreach (var attribute in assembly.GetCustomAttributes(false))
{
var debuggableAttribute = attribute as DebuggableAttribute;
if(debuggableAttribute != null)
{
return debuggableAttribute.IsJITTrackingEnabled;
}
}
return false;
}
Or using assemblyinfo metadata:
#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyConfiguration("Release")]
#endif
Or using a constant with #if DEBUG in code
#if DEBUG
public const bool IsDebug = true;
#else
public const bool IsDebug = false;
#endif
I prefer the second way so i can read it both by code and with windows explorer
Once they are compiled, you can't, unless you put the metadata yourself.
For example, you could use either AssemblyConfigurationAttribute or .NET 4.5's AssemblyMetadataAttribute
#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyConfiguration("Release")]
#endif
or
#if DEBUG
[assembly: AssemblyMetadata("DefinedVariable", "DEBUG")]
#endif