c++/cli static constructor of derived class is not called - .net-4.0

As described in another SO post of me I saw a strange behaviour of my application after moving from VS 2008 (.net 3.5) to VS 2013 (and using .net 4.0, not 4.5). I found that the static constructor (cctor) of a class was not called any more. Therefore I broke the application down into a small test program:
DLLs testAssembly_2-0 and testAssembly_4-0
(similar content; testAssembly_4-0 has names with 40instead of 20)
namespace testAssembly_20
{
public ref class Class20
{
public:
Class20 ()
{ Console::WriteLine (__FUNCTION__"()"); }
static Class20 ()
{ Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue);
ms_iValue = 2;
Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue); }
void func20 ()
{ Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue); }
protected:
static int ms_iValue = 1;
};
}
main VS2008
When compiling testAssembly_2-0 and main in VS 2008 (making .net 2.0 assembly and application of it), it runs as expected in both execution ways (starting debugging mode in IDE, starting exe directly):
int main ()
{
testAssembly_20::Class20^ oC20 = gcnew testAssembly_20::Class20;
oC20->func20 ();
}
// output:
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=1
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=2
// testAssembly_20::Class20::Class20()
// testAssembly_20::Class20::func20() ms_iValue=2
main VS2013
When compiling testAssembly_4-0 and main in VS 2013 (creating .net 4.0 assembly and application), and including the existing .net 2.0 testAssembly_2-0 (using app.config, see my linked post), it still works, but it behaves differently compared IDE debugging to exe start.
IDE debugging produces the result as above (once with Class20 and once with Class40).
exe start calls the cctor not at class instantiation, but when the static member is first time accessed. This must be due to the so-called lazy initialization that was introduced with .net 4.0, as far as I know now by my research during the last couple of hours.
int main ()
{
testAssembly_40::Class40^ oC40 = gcnew testAssembly_40::Class40;
oC40->func40 ();
testAssembly_20::Class20^ oC20 = gcnew testAssembly_20::Class20;
oC20->func20 ();
}
// output of exe start:
// testAssembly_40::Class40::Class40 (static class constructor)() ms_iValue=1
// testAssembly_40::Class40::Class40 (static class constructor)() ms_iValue=2
// testAssembly_40::Class40::Class40()
// testAssembly_40::Class40::func40() ms_iValue=2
// testAssembly_20::Class20::Class20()
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=1
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=2
// testAssembly_20::Class20::func20() ms_iValue=2
DLLs enhanced
As this did not yet reproduce my failure, I added a property to the class to access the static member, as I also do it in my original application. Querying this property in main() just led to a different order of function calls (the Class20 cctor was now called first of all functions, directly at the beginning of main()). But the behaviour was correct.
Therefore I went one step further towards my original application and added derived classes to both assemblies:
public ref class Class20derived : Class20
{
public:
Class20derived ()
{ Console::WriteLine (__FUNCTION__"()"); }
static Class20derived ()
{ Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue);
ms_iValue = 3;
Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue); }
void func20derived ()
{ Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue); }
};
Class40derived is similar again.
main VS2008 new
The test program now creates an object of the derived class. It runs as expected in both execution ways (IDE, exe directly):
int main ()
{
testAssembly_20::Class20derived^ oC20D = gcnew testAssembly_20::Class20derived;
oC20D->func20 ();
}
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=1
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=2
// testAssembly_20::Class20derived::Class20derived (static class constructor)() ms_iValue=2
// testAssembly_20::Class20derived::Class20derived (static class constructor)() ms_iValue=3
// testAssembly_20::Class20::Class20()
// testAssembly_20::Class20derived::Class20derived()
// testAssembly_20::Class20::func20() ms_iValue=3
main VS2013 new
The test program now creates objects of both derived classes. It runs as expected when being started from the IDE (same result as in VS2008 new, once with Class40 and once with Class20).
But when starting the exe, the result is faulty:
int main ()
{
testAssembly_40::Class40derived^ oC40D = gcnew testAssembly_40::Class40derived;
oC40D->func40 ();
testAssembly_20::Class20derived^ oC20D = gcnew testAssembly_20::Class20derived;
oC20D->func20 ();
}
// testAssembly_40::Class40::Class40 (static class constructor)() ms_iValue=1
// testAssembly_40::Class40::Class40 (static class constructor)() ms_iValue=2
// testAssembly_40::Class40derived::Class40derived (static class constructor)() ms_iValue=2
// testAssembly_40::Class40derived::Class40derived (static class constructor)() ms_iValue=3
// testAssembly_40::Class40::Class40()
// testAssembly_40::Class40derived::Class40derived()
// testAssembly_40::Class40::func40() ms_iValue=3
// testAssembly_20::Class20::Class20()
// testAssembly_20::Class20derived::Class20derived()
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=1
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=2
--> where is the Class20derived cctor??
// testAssembly_20::Class20::func20() ms_iValue=2
Why is the derived cctor() of the .net 2.0 assembly not called?
Is this an intended behaviour of the .net 4.0 lazy initialization or, which I assume, is it a bug in the compiler? The strange thing here is, that the .net 4.0 assembly is used correctly, but the .net 2.0 assembly isn't.
Also, at the base classes at the top:
Why is the .net 4.0 cctor called at class instantiation, but the .net2.0 cctor is called on demand?
Edit 1
I just found that one and the same application (VS2008, DLLs enhanced) behaves differently when being executed as exe with or without an app.exe.config!
When the app.config is present, the application works as being compiled in VS2013, which means, it is faulty.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
But as soon as I delete the app.config, the application works well.
So I think that the bug is not inside the VS C++/CLI compiler, but inside the .net 4.0 CLR itself...

I have found a workaround by calling the static constructor manually. I didn't know that this is even possible until I read it a few minutes ago:
System::Runtime::CompilerServices::RuntimeHelpers::RunClassConstructor (
testAssembly_20::Class20derived::typeid->TypeHandle);
Edit:
Recently I had an issue that my program behaved differently depending on being run from VS2008 (not VS2013 this time!) or from exe, even though I called the static cctor manually.
The problem was that the cctor of the WRONG CLASS was executed! Very weird!
My design:
base A
derived B : A
derived C1 : B
derived C2 : B
I called C2.cctor, but C1.cctor was run. When adding some arbitrary logging commands it behaved different again and eventually worked. That's when I decided to remove the cctors completely and introduce a static Init() instead.
Be prepared to encounter the same!
You can still call the cctor manually, it had worked for me for a long time.
I would have loved to investigate further and analyse the MSIL but I was too busy at that time.

Related

How to use WebApplicationFactory in .net6 (without speakable entry point)

In ASP.NET Core 6 default template moves everything from Sturtup.cs into Program.cs, and uses top-level statements in Program.cs, so there's no more (speakable) Program class ether.
That looks awesome, but now, I need to test all of this. WebApplicationFactory<T> still expects me to pass entry-point-class, but I cannot do this (due to it's name now being unspeakable).
How integration tests are expected to be configured in ASP.NET Core 6?
Note that if you are trying to use xUnit and its IClassFixture<T> pattern, you will run into problems if you just use the InternalsVisibleTo approach. Specifically, you'll get something like this:
"Inconsistent accessibility: base class WebApplicationFactory<Program> is less accessible than class CustomWebApplicationFactory."
Of course you can solve this by making CustomWebApplicationFactory internal but it only moves the problem as now your unit test class will give the same error. When you try to change it there, you will find that xUnit requires that tests have a public constructor (not an internal one) and you'll be blocked.
The solution that avoids all of this and allows you to still use IClassFixture<Program> is to make the Program class public. You can obviously do this by getting rid of the magic no class version of Program.cs, but if you don't want to completely change that file you can just add this line:
public partial class Program { } // so you can reference it from tests
Of course once it's public you can use it from your test project and everything works.
As an aside, the reason why you typically want to prefer using IClassFixture is that it allows you to set up your WebApplicationFactory just once in the test class constructor, and grab an HttpClient instance from it that you can store as a field. This allows all of your tests to be shorter since they only need to reference the client instance, not the factory.
Example:
public class HomePage_Get : IClassFixture<CustomWebApplicationFactory>
{
private readonly HttpClient _client = new HttpClient();
public HomePage_Get(CustomWebApplicationFactory factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task IncludesWelcome()
{
HttpResponseMessage response = await _client.GetAsync("/");
response.EnsureSuccessStatusCode();
string stringResponse = await response.Content.ReadAsStringAsync();
Assert.Contains("Welcome.", stringResponse);
}
}
Finally note that Damian Edwards' MinimalAPIPlayground was updated to use this approach after we discussed the issue. See this commit
The problem is was solved on ASP.NET Core RC1, but as of now (September 20, 2021) the docs are incomplete.
The compiler generates a Program class behind the scenes that can be used with WebApplicationFactory<>. The class isn't public though so the InternalsVisibleTo project setting should be used.
Damien Edwards' Minimal API sample uses the latest nightly bits. The test web app class is declared as :
internal class PlaygroundApplication : WebApplicationFactory<Program>
{
private readonly string _environment;
public PlaygroundApplication(string environment = "Development")
{
_environment = environment;
}
protected override IHost CreateHost(IHostBuilder builder)
{
...
In the application project file,InternalsVisibleTo is used to make the Program class visible to the test project:
<ItemGroup>
<InternalsVisibleTo Include="MinimalApiPlayground.Tests" />
</ItemGroup>
RC1 is feature complete and, judging by previous major versions, it will probably be the first version to have a Go Live license, which means it's supported in production.
I tried
<InternalsVisibleTo Include="MinimalApiPlayground.Tests" />
but no cigar! Removed it and added a partial class to program.cs
#pragma warning disable CA1050 // Declare types in namespaces
public partial class Program
{
}
#pragma warning restore CA1050 // Declare types in namespaces
amazingly it worked.

calling a class constructor present in a dll managed C++

I've a class created in a DLL (which uses /clr runtime, ManagedC++) and a constructor defined in that class. Code as follows:
//Following is defined in something.h//
namespace ABC
{
public ref Class XYZ
{
public: int a;
public: XYZ();
};
//In something.cpp, I've the below code to define the constructor of the class created//
#include something.h
namespace ABC
{
XYZ::XYZ()
{
a = 100;
}
}
Above project is built into a DLL
In another project, I try to use the Class XYZ as follows:
#include something.h
using namespace ABC;
//inside main, I've following code
{
ABC::XYZ^ prq = gcnew ABC:XYZ();
prq->a=200;
......
...
}
In this, I get the an error saying -
unresolved token (06000001) ABC.XYZ::.ctor
Could you please help what's the problem here?
The problem is that the linker can't find the definition of the constructor. It is located in another DLL. In a managed project, you solve that by adding a reference to the assembly. Right-click your project, Properties, Common Properties, Framework and References. Click the Add New Reference button. Use the Project tab if the project is located in the same solution. The Browse tab otherwise.
Also note that you now no longer need the .h file anymore. Declarations are imported from the metadata in the assembly.

C++/CLI wrapper not working (LoaderLock exception)

I've made very simple wrapper for unmanaged C++ library (to be used with C#). Wrapper has one unmanaged class and one managed class. Managed class has private member that is of unmanaged class and uses it like that.
I've done very simple setup - I've created wrapper for only one function to see if everything is working. But as soon as I create an instance of wrapper, my application get's exception "LoaderLock was detected" with following message:
DLL 'c:\path\CPPWrapper.dll' is
attempting managed execution inside OS Loader lock. Do not attempt to
run managed code inside a DllMain or image initialization function
since doing so can cause the application to hang.
If I turn off breaking for "LoaderLock" exception, I get "FileLoadException was unhandled":
Could not load file or assembly 'CPPWrapper.dll' or one of its dependencies. Exception from HRESULT: 0xE0434352
Any idea what I am doing wrong and how can I fix this problem?
CPPWrapper.h
// CPPWrapper.h
#pragma once
#include "Native.h"
using namespace System;
namespace CPPWrapper {
public ref class Class1
{
public:
Class1() : mnt(new Native)
{
}
~Class1(void)
{
// call the finalize method
this->!Class1();
}
// Finalize (for garbage collection)
!Class1(void)
{
// Remove unmanaged class
delete mnt;
mnt = NULL;
}
void Napravi()
{
mnt->CreatePK();
}
private:
Native *mnt;
};
}
I found that the correct way to fix this is by adding #pragma unmanaged in the dllmain.c Don't turn off breaking for "LoaderLock" exception.
See Initialization of Mixed Assemblies and scroll down to the DllMain section for details. Basically what is happening is that the project is compiling the DllMain function as managed (MSIL) but it only runs in unmanaged code. This #pragma unmanaged forces the function to be compiled as an unmanaged function.
So my dllmain.c is now:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#pragma unmanaged
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Another potential cause for LoaderLock is initialization of global static objects. In my case, I was compiling a boost::xpressive regex globally and it didn't like doing that when my C++/CLI wrapper was initializing DllMain. I'm not sure why, because it shouldn't have been managed code, but moving it to a function static object fixed it.

RegAsm: Method 'LoadContent' in type 'MyAlgorithms.MyAlgorithm' from assembly 'A' does not have an implementation

I have the following types(see code part below). It is compiled but RegAsm gives the following error: " Method 'LoadContent' in type 'MyAlgorithms.MyAlgorithm' from assembly 'A' does not have an implementation. "
Has any idea why? If I would not implemented LoadContent() method it would not be compiled.
I saw a nearly same question, here:
TypeLoadException says 'no implementation', but it is implemented
but it did not help, because:
A, B and C projects are in the same solution, and the build order is C, B and A.
"Post-build event command line" of all projects contains the next lines:
"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe" /u $(TargetPath)
"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe" $(TargetPath)
"c:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\gacutil.exe" /u $(TargetName)
"c:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\gacutil.exe" /if $(TargetPath)
So I think project A refers to the right assemblies.
And why solves the problem if I added to MyAlgorithmBase class the next:
protected override void LoadContent(PersistenceReader reader) { }
Thanks!
KAte
// C.dll from project C
namespace Microsoft.SqlServer.DataMining.PluginAlgorithms
{
public abstract class AlgorithmBase : IDisposable
{
//....
protected abstract void LoadContent(PersistenceReader reader);
}
}
//in B.dll from project B, refers C.dll
namespace AlgorithmCommons
{
public abstract class MyAlgorithmBase : AlgorithmBase
{
//....
// Why solves the problem if the next line is commented out?
// protected override void LoadContent(PersistenceReader reader) { }
}
}
//in A.dll from project A, refers B.dll and C.dll
namespace MyAlgorithms
{
public class MyAlgorithm : MyAlgorithmBase
{
protected override void LoadContent(PersistenceReader reader)
{
//....
}
}
}
The compiler verifies this. Which almost surely means that at runtime, when Regasm.exe loads the assembly, it doesn't load the assembly you think it does. There's plenty of opportunity for this since you use the GAC. Which can produce an old version of a dependent assembly, based on an [AssemblyVersion] number in the reference assembly.
Troubleshoot this with Fuslogvw.exe, log all the binds. It shows you where every assembly came from.
Stay out of this kind of trouble by not putting your assemblies in the GAC. It is a deployment detail and not appropriate on your dev machine where assembly versions can rapidly change, especially when you let the build system automatically increment them. You do so by using the /codebase option for Regasm.exe

Flex 3 to Flex 4 Conversion and Undefined Methods

I have an application I am attempting to convert from a flex 3 air application to a flex 4 air application.
I am running into an issue in my main class. When calling the Instance method on the class I am getting an error:
Access of possibly undefined property Instance through a reference with static type Class.
My main class is pretty complex but the problem could be broken down to a simple example.
MyClass.mxml
<mx:WindowedApplication>
<mx:Script>
private static var instance:MyClass = null;
public static function get Instance():MyClass {
return instance;
}
</mx:Script>
<mx:Canvas></mx:Canvas>
</mx:WindowedApplication>
For some reason when calling MyClass.Instance in another file I get the above error.
The Outline window in flash builder does not show the static methods of this class, and typing MyClass into a code window the code completion does not show any of my static methods being accessible.
Is there another place I need to define static members outside of the mx:Script bock?
The simple answer is that it is no-longer mx:Script, the namespace for the Script attribute is now fx:Script.