locked
Exporting symbols from WinRT component

    Question

  • Hi, I have what I hope is a simple beginners' question.  I've been working on getting XAML and DirectX working together, and I have a version of this working in C++.  What I really need is to get it working with a C# implementation of XAML, though.  The "DirectX and XAML interop" page indicates this is possible, stating "you can create a Metro style C# XAML app that uses DirectX if you wrap the DirectX calls in a separate Windows Runtime type library."

    My first step toward this goal was to attempt breaking my C++ app into two sections, one with the XAML code and one with the DirectX code.  To do this I created a C++ Metro style WinRT Component DLL project, and added the DirectX code to it.  The code builds fine, but I'm having trouble figuring out how to export these classes' symbols in the DLL.

    These classes are managed classes, and my understanding was that if they were declared public, this would be enough for their public symbols to be exported to the DLL.  But that has not been my experience - when linking the XAML project with this DLL, the methods on the classes are unresolved.  dumpbin does not find these classes' symbols, and if I try to reference this DLL in a C# project, I get an error that the DLL could not be added.  My classes are defined in the following style : "public ref class XXX { }".  I'm not sure which part of this I'm botching - using the wrong type of project to produce the DLL?  Exporting the managed classes?  The syntax I'm using to declare the classes?  Something else I'm completely missing?  Thanks for your help.

    Tuesday, April 17, 2012 7:21 PM

Answers

  • I tried your sample app on the Consumer Preview and could reproduce a couple issues:

    1. BasicReaderWriter assumes it's loading from the installed location's root (e.g. ..\XamlDXInterop\XamlDXInterop\bin\x86\Debug\AppX\) which works as expected for a single project app, but after splitting it into a separate component project your compiled shaders are being placed in a subfolder (i.e. ..\XamlDXInterop\XamlDXInterop\bin\x86\Debug\AppX\Direct3DInterop\), resulting in a runtime exception when it can't locate them.

    2. It looks like you may be hitting an issue in the Consumer Preview with being unable to resolve public virtual methods that are implemented in both an inherited and base class - as a workaround for now you may have to fold your Direct3DBase class into your CubeRender class and just have one public class.  I'll follow up on this issue.

    If you haven't already, enabling unmanaged debugging (go into the properties of the managed project, Debug -> Enable unmanaged code debugging) can help with tracing errors when calling into the native component.

    • Marked as answer by DerekMuk Tuesday, April 24, 2012 4:30 PM
    Thursday, April 19, 2012 6:32 PM

All replies

  • Hi,

    I found a sample codes about  using DirectX (Direct3D 11.1, Direct2D, XInput, and XAudio2) and XAML in a Metro style C++ app. XAML is used for the heads-up display and game state message

    http://code.msdn.microsoft.com/windowsapps/Metro-style-DirectX-18f98448

    I hope this sample can help you.

    Best regards,
    Jesse


    Jesse Jiang [MSFT]
    MSDN Community Support | Feedback to us

    Wednesday, April 18, 2012 7:58 AM
  • Hi Jesse, thanks for the response.  But I already have XAML and DirectX running together in C++.  My problem is when I create a WinRT component with the DirectX code.  The DirectX code is in two managed classes, and I want these classes' symbols to be exported so the DLL's client can reference them.  From what I understand, the export of public managed classes is supposed to just "magically" happen when creating the DLL, but in my case it's not working for me.  I hope this makes the question clearer.  Thanks again for your help.
    Wednesday, April 18, 2012 4:17 PM
  • If your classes in the C++ WinRT component looks similar to the following:

    namespace MyComponentNamespace
    {
       public ref class MyClass sealed
       {
       public:
          MyClass();
    		
         void MyMethod();
    
       private:
          // non-WinRT compliant types, e.g. DirectX COM variables
       };
    }

    Then you should be able to add a reference from the C# project (right click project -> Add Reference), create an instance of MyComponentNamespace.MyClass, and call any public methods.

    Are you able to instantiate instances of your component's classes from the C# project?  If this works and you just aren't seeing any methods, are they marked public in the class's header file as above?

    Wednesday, April 18, 2012 6:28 PM
  • Hi Jesse.  I believe I'm doing what you describe.  Once going through the steps you've outlined, if the referencing project is C++ it will fail to link, giving unresolved symbols for the methods of the class I'm trying to access.  If the referencing project is C# it will build successfully, but fail with a COM related runtime error when attempting to call any method of the class.

    One thing that perhaps is complicating matters, there are two classes in the DirectX project - an abstract class and a concrete class that inherits from it.  There seems to be a catch-22 in that I have to make the abstract class public in order to make the concrete class public but I can't make it sealed.  That leads the compiler to warn that I won't be able to access the abstract class from JavaScript because it's not sealed.  Is this related to my problem?  Is there a better way to structure the classes so I don't see the warning?

    I've put the projects out on SkyDrive if you've got time to take a look, at https://skydrive.live.com/#cid=7992D3CB5931903C&id=7992D3CB5931903C%21105&sc=documents

    And I almost forgot, when looking at the projects above the classes in question are D3DInterop::Direct3DBase and D3DInterop::CubeRenderer. 
    • Edited by DerekMuk Wednesday, April 18, 2012 7:22 PM added names of classes
    Wednesday, April 18, 2012 7:16 PM
  • The error suggests it can't resolve one or more of your virtual methods that don't have an implementation and therefore won't export - try adding an implementation for any such methods, e.g. Direct3DBase::Update - either add an empty implementation for this in Direct3DBase, or override them in CubeRenderer.

    As a side note it's generally reasonable to have a DirectX base class that isn't consumable in JS - if desired you can suppress this warning:

    #pragma warning (disable: 4449)

    Wednesday, April 18, 2012 8:04 PM
  • I'm not sure I fully understand your suggestion.  The pure virtual method in Direct3DBase is already overridden in CubeRenderer.  At any rate, it didn't hurt to remove the pure virtual and throw an empty implementation into Direct3DBase.  But it didn't have any impact - I still get the errors described above.

    If I didn't make it obvious before, this code was part of a fully functional C++ program.  Only after attempting to split the DirectX code into the DLL did I start running into issues with unresolveds.

    Wednesday, April 18, 2012 8:48 PM
  • I tried your sample app on the Consumer Preview and could reproduce a couple issues:

    1. BasicReaderWriter assumes it's loading from the installed location's root (e.g. ..\XamlDXInterop\XamlDXInterop\bin\x86\Debug\AppX\) which works as expected for a single project app, but after splitting it into a separate component project your compiled shaders are being placed in a subfolder (i.e. ..\XamlDXInterop\XamlDXInterop\bin\x86\Debug\AppX\Direct3DInterop\), resulting in a runtime exception when it can't locate them.

    2. It looks like you may be hitting an issue in the Consumer Preview with being unable to resolve public virtual methods that are implemented in both an inherited and base class - as a workaround for now you may have to fold your Direct3DBase class into your CubeRender class and just have one public class.  I'll follow up on this issue.

    If you haven't already, enabling unmanaged debugging (go into the properties of the managed project, Debug -> Enable unmanaged code debugging) can help with tracing errors when calling into the native component.

    • Marked as answer by DerekMuk Tuesday, April 24, 2012 4:30 PM
    Thursday, April 19, 2012 6:32 PM
  • Ok, I now understand what you are saying.  The problems I was seeing were in fact due to unhandled exceptions in my code due to the different location of the resource files.  The COM error lead me to think there was a problem contacting the component's code, when in reality this must be the 'standard' way an unhandled error in the component code is handled.  In addition the fact I couldn't put breaks in the component code added to the misconception that there was a communication problem with the component.

    BTW, I found that updating Visual Studio resolved the issue with being unable to debug unmanaged code.  Thanks for your help Jesse!

    Tuesday, April 24, 2012 4:30 PM