I have an OpenGL library written in c++ that is used from a C# application using C++/CLI adapters. My problem is that if the application is used on laptops with Nvidia Optim
My solution working both on NVidia and AMD, without DllExport (without NuGet package UnmanagedExports), based on exported functions NvOptimusEnablement and AmdPowerXpressRequestHighPerformance:
On VS2019 the aforementioned UnmanagedExports package doesn't seem to work properly. I couldn't find another working package for .NET framework that provides DllExport capability. That's why I developed my own solution using direct MSIL code with great help from Writing IL code on Visual Studio and IL Support.
Steps to follow:
To .csproj file (.csproj for exe, not for any dll) add the following section which enables direct usage of MSIL code (you may put it generally anywhere, i.e. after
HideILFromCoreCompile;
$(CoreCompileDependsOn);
HideILFromCompile;
$(CompileDependsOn);
InitializeIL;
CoreDecompile;
CoreCompileIL;
@(IntermediateAssembly->'%(RootDir)%(Directory)%(Filename).il', ' ')
@(IntermediateAssembly->'%(RootDir)%(Directory)%(Filename).res', ' ')
"$(FrameworkSdkPath)bin\ildasm.exe" /nobar /linenum /output:"$(ILFile)" @(IntermediateAssembly->'"%(FullPath)"', ' ')
"$(FrameworkSdkPath)bin\NETFX 4.0 Tools\ildasm.exe" /nobar /linenum /output:"$(ILFile)" @(IntermediateAssembly->'"%(FullPath)"', ' ')
"$(FrameworkSdkPath)bin\NETFX 4.5.1 Tools\ildasm.exe" /nobar /linenum /output:"$(ILFile)" @(IntermediateAssembly->'"%(FullPath)"', ' ')
"$(FrameworkSdkPath)bin\NETFX 4.6 Tools\ildasm.exe" /nobar /linenum /output:"$(ILFile)" @(IntermediateAssembly->'"%(FullPath)"', ' ')
"$(FrameworkSdkPath)bin\NETFX 4.6.1 Tools\ildasm.exe" /nobar /linenum /output:"$(ILFile)" @(IntermediateAssembly->'"%(FullPath)"', ' ')
"$(FrameworkSdkPath)bin\NETFX 4.6.2 Tools\ildasm.exe" /nobar /linenum /output:"$(ILFile)" @(IntermediateAssembly->'"%(FullPath)"', ' ')
$([System.IO.File]::ReadAllText($(ILFile)))
// method ${method} forwardref removed for IL import
\.method [^{}]+ cil managed forwardref[^}]+} // end of method (?<method>[^ \r\t\n]+)
$([System.Text.RegularExpressions.Regex]::Replace($(ILSource), $(Pattern), $(Replacement)))
\.method [^{}]+ cil managed[^\a]+"extern was not given a DllImport attribute"[^}]+} // end of method (?<method>[^ \r\t\n]+)
$([System.Text.RegularExpressions.Regex]::Replace($(ILSource), $(Pattern), $(Replacement)))
"$(FrameworkPath)\ilasm.exe" /nologo /quiet /output:@(IntermediateAssembly->'"%(FullPath)"', ' ')
$(ILAsm) /alignment=$(FileAlignment)
$(ILAsm) /base=$(BaseAddress)
$(ILAsm) /dll
$(ILAsm) /pdb
$(ILAsm) /debug
$(ILAsm) /optimize
$(ILAsm) /pe64 /x64
$(ILAsm) /pe64 /itanium
$(ILAsm) /key:"$(AssemblyOriginatorKeyFile)"
$(ILAsm) /resource:"$(ILResourceFile)"
$(ILAsm) "$(ILFile)"
Paste the code below to this file (instead of 'WindowsApplication1' you may enter your namespace):
.class public WindowsApplication1.ForceDedicatedGraphicCard
{
.method public static int32 NvOptimusEnablement() cil managed
{
.export [1]
ldc.i4.1
ret
}
.method public static uint32 AmdPowerXpressRequestHighPerformance() cil managed
{
.export [2]
ldc.i4.1
ret
}
}
Check if the functions are exported using dumpbin.exe
dumpbin.exe /exports your_project.exe