MFC + JUCE Combination


#1

DISCLAIMER: Yes, I do realize MFC is pretty trash and that I should avoid it at all costs. However, as of the moment, I'm stuck in a MFC project that I'm trying to integrate with JUCE to start migrating away from MFC - eventually we'll move everything to JUCE.

I created a JUCE project with a few customized controls (Sliding Panel Component, Image buttons, SVG resources, a TableListBox.. nothing too crazy) and exported it to VS2013. Everything compiles, runs, works, etc. which is perfect. However, when I choose to include MFC in a shared DLL, the project generates 67 errors, all of which are unresolved symbols. There were a few threads already on the forum with this same problem discussed (http://www.juce.com/forum/topic/jucequake-use-mfc-static-library-unresolved-symbols) but no true solution as to what is occurring. Suggested in the previous threads were to toy with the VS2013 project settings to try and get rid of the errors but so far, no luck.

Is there any information on just doing the above? Taking a JUCE project that compiles fine and just telling it to use MFC in a shared DLL? I get the same errors whether I choose static or shared, which is strange, since my project itself doesn't utilize any MFC at all, yet. Just the act of attaching MFC on causes the errors. I have cleared the project via VS2013, changed settings, etc.


#2

Add these to your Project's Properties->Linker->Input->Additional Dependencies settings:

Ole32.lib;Shell32.lib;Gdi32.lib;Comdlg32.lib;OleAut32.lib

#3

Note to JUCE devs:

The above mentioned libs should perhaps be added to: trunk\modules\juce_core\native\juce_BasicNativeHeaders.h ??

At line 129:

 #if JUCE_MSVC && ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
  #pragma comment (lib, "kernel32.lib")
  #pragma comment (lib, "user32.lib")
  #pragma comment (lib, "wininet.lib")
  #pragma comment (lib, "advapi32.lib")
  #pragma comment (lib, "ws2_32.lib")
  #pragma comment (lib, "version.lib")
  #pragma comment (lib, "shlwapi.lib")
  #pragma comment (lib, "winmm.lib")

 

 


#4

Thanks, but no, those shouldn't go in the core library.

If you want to add them to your own project, then that's easy - you can add the pragmas to any cpp file. But it'd be a bad move for us to add them to everyone's code when almost nobody uses them!


#5

... But it'd be a bad move for us to add them to everyone's code when almost nobody uses them!

Fair enough, but IIUC, the #pragma comment(lib) only adds to the linker search path. It should not add any bloat to programs that do not use any of the libs' functions.

 


#6

My earlier post (#3) may have been confusing, as I showed a block of code that is already there. Here are the actual pragmas that I added in my

MainComponent.h to get it to build after adding MFC to a project.

  #pragma comment (lib, "ole32.lib")
  #pragma comment (lib, "shell32.lib")
  #pragma comment (lib, "gdi32.lib")
  #pragma comment (lib, "comdlg32.lib")
  #pragma comment (lib, "oleaut32.lib")

I am not using MFC, so there may be others that you will have to add depending on your use of MFC.

Also note that this is an alternate to the method shown in post #2. You don't need to do both.

 


#7

Thanks for getting back to me so quick.

I created a sample project and confirmed that the above works. When I take my existing MFC project and just in the main header for my CWinApp class, include the JUCE header, everything still works. However, Once I start adding components, things fail very quickly, with a similar slew of errors, here are a few examples but all of them are similar unresolved external symbols:


Error    155    error LNK2001: unresolved external symbol "public: void __thiscall juce::TextEditor::setText(class juce::String const &,bool)" (?setText@TextEditor@juce@@QAEXABVString@2@_N@Z)

Error    156    error LNK2001: unresolved external symbol "public: void __thiscall juce::TextEditor::setPopupMenuEnabled(bool)" (?setPopupMenuEnabled@TextEditor@juce@@QAEX_N@Z)

Error    105    error LNK2001: unresolved external symbol "public: __thiscall juce::Colour::Colour(void)" (??0Colour@juce@@QAE@XZ)

Since I got my JUCE project to work with MFC, I'm very tempted to start down the path of using JUCE as the main class and go at it from that angle (which is a bit more work but eh, I like JUCE more than MFC). I think the big hurdle for me would be that I'm developing an image software ( SDI ) but I use a highly modified class that inherets from the CView MFC class and I haven't found a synonomous class in JUCE to CView in MFC.

So I guess:

  • 1) Any ideas on the above errors?
  • 2) Synonymous class to CView (MFC) in JUCE?

#8

It just looks like you've not included the juce cpps in your project - JUCE unfortunately isn't header-only! The introjucer will do all this stuff for you, but if you're hand-building your project then you might want to copy one of the demo projects.

I've not looked at MFC for a decade, and have no idea what CView does, but I'd have thought Component would be the nearest thing.


#9

That was it! Thanks!


#10

I got everything working well. I have a TopLevelWindow as a child within my CView class in a SDI environment which has me going well and accepting all inputs. I do not inherit the JuceApplication under my main application (CWinApp class).

I currently have the TopLevelWindow defined with only one component, which I define as such:


class MainWindow : public TopLevelWindow
{
public:
    ScopedPointer<Component> maincontent;
    MainWindow(String name = "", bool bAddToDesktop = true) :
        TopLevelWindow(name, bAddToDesktop)
    {
        setSize(1200, 1200);
        maincontent = createMainContentComponent();
        addAndMakeVisible(maincontent);
        setDropShadowEnabled(false);
    }
    virtual ~MainWindow()
    {
        maincontent = nullptr;
    }
    void paint(Graphics& g)
    {
        //[UserPrePaint] Add your own custom painting code here..
        //[/UserPrePaint]
        g.fillAll(Colours::white);
        //[UserPaint] Add your own custom painting code here..
        //[/UserPaint]
    }
    /* Note: Be careful if you override any DocumentWindow methods - the base
    class uses a lot of them, so by overriding you might break its functionality.
    It's best to do all your work in your content component instead, but if
    you really have to override any DocumentWindow methods, make sure your
    subclass also calls the superclass's method.
    */
private:
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainWindow)
};

I have the MainWindow class defined in my main application class (CWinApp) as ScopedPointer<MainWindow> mainWindow;

During the application closing, I set the mainWindow = nullptr and I have followed to ensure that all my destructors are being called and confirmed that.

It seems that even with all of the above, that outside of the application in a standard JUCEApplication, that everything goes well and is destructed. In this particular case, I am getting a few (10+) assertions with the leak detector when I take out the JUCEApplication side of things. I attempted to doubly inherit both CWinApp and JUCEApplication and call the quit() function explicitly during the destruction to see if it would clean up the errors to no avail. This TopLevelWindow class is the main and only class called where all of JUCE spirals out of for my application, currently. I do not have the luxury to call START_JUCE_APPLICATION (xxx) since I'd have competing main() function calls ultimately..

The assertions don't give me much to go on but I did notice that the JUCEThread as being listed as not being destroyed. Is there a destructor in this situation that I may call to get rid of my remaining components?