DLL fails to load if unused ref class is removed

1

I'm running into a very strange problem trying to compile and use a windows runtime component within an UWP application (VS2017 community 15.9.13 with NetCore.UniversalWindowsPlatform 6.2.8, compiled without /clr but with /ZW).

It is basically something like the Grayscaletransform. The runtime component is actually working as expected, now I wanted to remove some unused code. However, as soon as I remove it from a particular file and recompile, it indeed compiles, links, but the DLL does not load any more.

Here's some example code that I have to put in:

ref class DummyU sealed
{
public:
    DummyU() {}
};

DummyU^ CreateDummyU()
{
    return ref new DummyU();
}

The code just makes it work, although it is a) not referenced at all and b) does not do anything useful.

The result of removing it:

Exception thrown at 0x0EFF322F (vccorlib140d_app.dll) in TestAppUWP.exe: 0xC0000005: Access violation reading location 0x00000000.

in

STDAPI DllGetActivationFactory(_In_ HSTRING activatibleClassId, _Deref_out_ IActivationFactory** ppFactory)
{
    return Platform::Details::GetActivationFactory(Microsoft::WRL::Details::ModuleBase::module_, activatibleClassId, ppFactory);
}

function in dllexports.cpp which is part of VS. The module_ becomes NULL.

Does anyone have an idea if there are any known bugs with respect to the windows runtime not being initialized/used properly if there is no explicit instantiation of a ref class in a file?

EDIT 1:

Here's the link to the full source code:

c++
visual-studio
visual-c++
uwp
windows-runtime
asked on Stack Overflow Jul 1, 2019 by Clemens Arth • edited Jul 2, 2019 by Clemens Arth

2 Answers

1

You might have wrong .winmd file for your component. WinRT components made in C++ produce two outputs, dll and winmd. Both must match. It's possible you have them from different builds.

Another possible reason is error in manifest. The manifest of the app must include all referenced runtime components.

BTW, for native DLLs written in classic C++ and exposing C API, deployment is simpler, you include a DLL in the package and they just work, with [DllImport] if you're consuming them from C#.

Update: You can replace that ref class with the following code, works on my PC.

struct ModuleStaticInitialize
{
    ModuleStaticInitialize()
    {
        Microsoft::WRL::Module<Microsoft::WRL::InProc>::GetModule();
    }
};
static ModuleStaticInitialize s_moduleInit;

Probably a bug in Microsoft's runtime somewhere.

answered on Stack Overflow Jul 1, 2019 by Soonts • edited Jul 2, 2019 by Soonts
1

What's happening here is that you're mixing modes a bit. Since you've compiled your C++ code with the /CX flag, you've told the compiler to enable winrt extensions to produce a WinRT DLL. In practice though, none of your code is actually using the CX extensions to implement classes. You're using WRL and standards C++. The compiler looks at the DLL, finds no CX-style WinRT classes, and doesn't set up the module, accordingly.

This is basically an untested & unsupported case, since you've chosen to say that you want to expose ref classes by picking a UWP component library project type, but then didn't actually provide any ref classes. It happens that under the hood, /CX effectively uses WRL, so you can nudge it along and initialize the state to work correctly, but you're kinda hacking the implementation details of the system.

There are two options I would recommend, either works: just make the project a non-CX Win32 DLL and init the module as described above. Or, better yet, flip over to C++ /WinRT, which will give you better support for the WinRT types than /CX and allow you to more easily mix in the classic COM types in your implementation. You can get started by just turning off the /CX flag in the compiler switches, then start updating the code accordingly.

Ben

answered on Stack Overflow Jul 3, 2019 by Ben Kuhn

User contributions licensed under CC BY-SA 3.0