Problems with juce 1.50

Hi!

I recently upgraded to version 1.50 and I found some problems:

  1. When I construct an OpenGLPixelFormat object, e. g.
setPixelFormat(OpenGLPixelFormat(8, 8, 24, 8));

then a linker error is generated that says:
error LNK2001: unresolved external symbol “public: __thiscall juce::OpenGLPixelFormat::OpenGLPixelFormat(int,int,int,int)” (??0OpenGLPixelFormat@juce@@QAE@HHHH@Z)

I see that there’s the OpenGLPixelFormat constructor in juce_OpenGLComponent.cpp so I can’t figure out why it’s not found by the linker.

  1. this code snippet makes the app crash (it worked well in previous versions):
OwnedArray <File> roots;
File::findFileSystemRoots(roots);
roots.clear();

Thanks for any help or workaround
kend

  1. works for me fine, i use it in my NortCommander like FileBrowser and i use the latest juce from git.

Maybe you’ve not actually enabled the JUCE_OPENGL flag? Unless that’s set, none of the GL code will be built.

Maybe you could post a stack trace of findFileSystemRoots crashing? Could be that there’s some kind of strange device attached to your machine that’s confusing it, but I can’t begin to try to reproduce that myself.

I think I use the latest version too. I never used git before, I only installed it and tried the simple

git clone git://juce.git.sourceforge.net/gitroot/juce/juce

in its command line to get juce. It doesn’t noted however which revision was downloaded.

In juce_config I commented almost everything except the JUCE_OPENGL flag. I compiled the dll target and used that. There could be one “strange” device, a virtual partition created with truecrypt. As far as I remember it crashed at the line when actually the elements member was deleted with delete[].

Now I try it in my home computer too.

kend

It’s the same on my home computer.
The roots array contains all root volume names properly (here there’s no truecrypt volume, but there’s a daemon tools virtual cd).

It crashes in ArrayAllocationBase::setAllocatedSize at the line
delete[] elements (no matter which branch it takes)

But only after the use of File::findFileSystemRoots(roots);

My juce_config.h is:

/*
==============================================================================

   This file is part of the JUCE library - "Jules' Utility Class Extensions"
   Copyright 2004-9 by Raw Material Software Ltd.

  ------------------------------------------------------------------------------

   JUCE can be redistributed and/or modified under the terms of the GNU General
   Public License (Version 2), as published by the Free Software Foundation.
   A copy of the license is included in the JUCE distribution, or can be found
   online at www.gnu.org/licenses.

   JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

  ------------------------------------------------------------------------------

   To release a closed-source product which uses JUCE, commercial licenses are
   available: visit www.rawmaterialsoftware.com/juce for more information.

  ==============================================================================
*/

#ifndef __JUCE_CONFIG_JUCEHEADER__
#define __JUCE_CONFIG_JUCEHEADER__

//==============================================================================
/*
    This file contains macros that enable/disable various JUCE features.
*/

//=============================================================================
/** The name of the namespace that all Juce classes and functions will be
    put inside. If this is not defined, no namespace will be used.
*/
#ifndef JUCE_NAMESPACE
  #define JUCE_NAMESPACE juce
#endif

//=============================================================================
/** Normally, JUCE_DEBUG is set to 1 or 0 based on compiler and project settings,
    but if you define this value, you can override this can force it to be true or
    false.
*/
#ifndef JUCE_FORCE_DEBUG
  //#define JUCE_FORCE_DEBUG 1
#endif

//=============================================================================
/** If this flag is enabled, the the jassert and jassertfalse macros will
    always use Logger::writeToLog() to write a message when an assertion happens.

    Enabling it will also leave this turned on in release builds. When it's disabled,
    however, the jassert and jassertfalse macros will not be compiled in a
    release build.

    @see jassert, jassertfalse, Logger
*/
#ifndef JUCE_LOG_ASSERTIONS
//  #define JUCE_LOG_ASSERTIONS 1
#endif

//=============================================================================
/** Comment out this macro if you haven't got the Steinberg ASIO SDK, without
    which the ASIOAudioIODevice class can't be built. See the comments in the
    ASIOAudioIODevice class's header file for more info about this.

    (This only affects a Win32 build)
*/
#ifndef JUCE_ASIO
  //#define JUCE_ASIO 1
#endif

/** Comment out this macro to disable the Windows WASAPI audio device type.
*/
#ifndef JUCE_WASAPI
//  #define JUCE_WASAPI 1
#endif

/** Comment out this macro to disable the Windows WASAPI audio device type.
*/
#ifndef JUCE_DIRECTSOUND
  //#define JUCE_DIRECTSOUND 1
#endif

/** Comment out this macro to disable building of ALSA device support on Linux.
*/
#ifndef JUCE_ALSA
  //#define JUCE_ALSA 1
#endif

/** Comment out this macro to disable building of JACK device support on Linux.
*/
#ifndef JUCE_JACK
  //#define JUCE_JACK 1
#endif

//=============================================================================
/** Comment out this macro if you don't want to enable QuickTime or if you don't
    have the SDK installed.

    If this flag is not enabled, the QuickTimeMovieComponent and QuickTimeAudioFormat
    classes will be unavailable.

    On Windows, if you enable this, you'll need to have the QuickTime SDK
    installed, and its header files will need to be on your include path.
*/
#if ! (defined (JUCE_QUICKTIME) || JUCE_LINUX || JUCE_IPHONE || (JUCE_WINDOWS && ! JUCE_MSVC))
  //#define JUCE_QUICKTIME 1
#endif


//=============================================================================
/** Comment out this macro if you don't want to enable OpenGL or if you don't
    have the appropriate headers and libraries available. If it's not enabled, the
    OpenGLComponent class will be unavailable.
*/
#ifndef JUCE_OPENGL
  #define JUCE_OPENGL 1
#endif

//=============================================================================
/** These flags enable the Ogg-Vorbis and Flac audio formats.

    If you're not going to need either of these formats, turn off the flags to
    avoid bloating your codebase with them.
*/
#ifndef JUCE_USE_FLAC
  //#define JUCE_USE_FLAC 1
#endif

#ifndef JUCE_USE_OGGVORBIS
  //#define JUCE_USE_OGGVORBIS 1
#endif

//=============================================================================
/** This flag lets you enable support for CD-burning. You might want to disable
    it to build without the MS SDK under windows.
*/
#if (! defined (JUCE_USE_CDBURNER)) && ! (JUCE_WINDOWS && ! JUCE_MSVC)
  //#define JUCE_USE_CDBURNER 1
#endif

//=============================================================================
/** Enabling this provides support for cameras, using the CameraDevice class
*/
#if JUCE_QUICKTIME && ! defined (JUCE_USE_CAMERA)
//  #define JUCE_USE_CAMERA 1
#endif

//=============================================================================
/** Enabling this macro means that all regions that get repainted will have a coloured
    line drawn around them.

    This is handy if you're trying to optimise drawing, because it lets you easily see
    when anything is being repainted unnecessarily.
*/
#ifndef JUCE_ENABLE_REPAINT_DEBUGGING
//  #define JUCE_ENABLE_REPAINT_DEBUGGING 1
#endif

//=============================================================================
/** Enable this under Linux to use Xinerama for multi-monitor support.
*/
#ifndef JUCE_USE_XINERAMA
  //#define JUCE_USE_XINERAMA 1
#endif

/** Enable this under Linux to use XShm for faster shared-memory rendering.
*/
#ifndef JUCE_USE_XSHM
  //#define JUCE_USE_XSHM 1
#endif

//=============================================================================
/** Enabling this builds support for VST audio plugins.
    @see VSTPluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_AU
*/
#ifndef JUCE_PLUGINHOST_VST
//  #define JUCE_PLUGINHOST_VST 1
#endif

/** Enabling this builds support for AudioUnit audio plugins.
    @see AudioUnitPluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_VST
*/
#ifndef JUCE_PLUGINHOST_AU
//  #define JUCE_PLUGINHOST_AU 1
#endif

//=============================================================================
/** Enabling this will avoid including any UI code in the build. This is handy for
    writing command-line utilities, e.g. on linux boxes which don't have some
    of the UI libraries installed.
*/
#ifndef JUCE_ONLY_BUILD_CORE_LIBRARY
  //#define JUCE_ONLY_BUILD_CORE_LIBRARY  1
#endif

/** This lets you disable building of the WebBrowserComponent, if it's not required.
*/
#ifndef JUCE_WEB_BROWSER
  //#define JUCE_WEB_BROWSER 1
#endif


//=============================================================================
/** Setting this allows the build to use old Carbon libraries that will be
    deprecated in newer versions of OSX. This is handy for some backwards-compatibility
    reasons.
*/
#ifndef JUCE_SUPPORT_CARBON
  //#define JUCE_SUPPORT_CARBON 1
#endif

//=============================================================================
/*  These flags let you avoid the direct inclusion of some 3rd-party libs in the
    codebase - you might need to use this if you're linking to some of these libraries
    yourself.
*/
#ifndef JUCE_INCLUDE_ZLIB_CODE
  #define JUCE_INCLUDE_ZLIB_CODE        1
#endif

#ifndef JUCE_INCLUDE_FLAC_CODE
  #define JUCE_INCLUDE_FLAC_CODE        1
#endif

#ifndef JUCE_INCLUDE_OGGVORBIS_CODE
  #define JUCE_INCLUDE_OGGVORBIS_CODE   1
#endif

#ifndef JUCE_INCLUDE_PNGLIB_CODE
  #define JUCE_INCLUDE_PNGLIB_CODE      1
#endif

#ifndef JUCE_INCLUDE_JPEGLIB_CODE
  #define JUCE_INCLUDE_JPEGLIB_CODE     1
#endif

//=============================================================================
/** Enable this to add extra memory-leak info to the new and delete operators.

    (Currently, this only affects Windows builds in debug mode).
*/
#ifndef JUCE_CHECK_MEMORY_LEAKS
  #define JUCE_CHECK_MEMORY_LEAKS 1
#endif

/** Enable this to turn on juce's internal catching of exceptions.

    Turning it off will avoid any exception catching. With it on, all exceptions
    are passed to the JUCEApplication::unhandledException() callback for logging.
*/
#ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS
  #define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1
#endif

/** If this macro is set, the Juce String class will use unicode as its
    internal representation. If it isn't set, it'll use ANSI.
*/
#ifndef JUCE_STRINGS_ARE_UNICODE
  #define JUCE_STRINGS_ARE_UNICODE 1
#endif

//=============================================================================

#endif

My sample program:

#include <windows.h>
#include <GL/gl.h>
#include <juce.h>


// ------------------------------------------------------------------------
//  LeoOpenGLComponent
// ------------------------------------------------------------------------
class LeoOpenGLComponent : public OpenGLComponent,
                           public Timer
{
    public:
        LeoOpenGLComponent();
        ~LeoOpenGLComponent();

        virtual void renderOpenGL();
        virtual void newOpenGLContextCreated();
        virtual bool renderAndSwapBuffers();

        virtual void resized();

        virtual void timerCallback();
};
// ------------------------------------------------------------------------

LeoOpenGLComponent::LeoOpenGLComponent()
{
}


LeoOpenGLComponent::~LeoOpenGLComponent()
{
    stopTimer();
}


void LeoOpenGLComponent::renderOpenGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
}


void LeoOpenGLComponent::newOpenGLContextCreated()
{
    // if it is uncommented there's a linker error
    // setPixelFormat(OpenGLPixelFormat(8, 8, 24, 8));

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    startTimer(5);
}


bool LeoOpenGLComponent::renderAndSwapBuffers()
{
    if (!makeCurrentContextActive())
    {
        return false;
    }

    renderOpenGL();
    swapBuffers();

    return true;
}


void LeoOpenGLComponent::resized()
{
    glViewport(0, 0, getWidth(), getHeight());
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0, 2.0, -1.0, 2.0, 0.0, 1.0);
}


void LeoOpenGLComponent::timerCallback()
{
    renderAndSwapBuffers();
}
// ------------------------------------------------------------------------



// ------------------------------------------------------------------------
//  LeoMainWindow
// ------------------------------------------------------------------------
class LeoMainWindow : public ResizableWindow
{
    public:
        LeoMainWindow(const String &name, const Colour &backgroundColor, const bool addToDesktop);
        ~LeoMainWindow();

        virtual bool keyPressed(const KeyPress &key);

    private:
        LeoOpenGLComponent *opengl_component_m;
};
// ------------------------------------------------------------------------

LeoMainWindow::LeoMainWindow(const String &name, const Colour &backgroundColor, const bool addToDesktop) : 
ResizableWindow(name, backgroundColor, addToDesktop)
{
    opengl_component_m = new LeoOpenGLComponent();
    setContentComponent(opengl_component_m);
}

LeoMainWindow::~LeoMainWindow()
{
    //deleteAllChildren();
    removeFromDesktop();
}


bool LeoMainWindow::keyPressed(const KeyPress &key)
{
    if (key.getKeyCode() == KeyPress::escapeKey)
    {
        JUCEApplication::quit();
    }

    return false;
}
// ------------------------------------------------------------------------



// ------------------------------------------------------------------------
//  LeoJuceApp
// ------------------------------------------------------------------------
class LeoJuceApp : public JUCEApplication
{
    /* Important! NEVER embed objects directly inside your JUCEApplication class! Use
       ONLY pointers to objects, which you should create during the initialise() method
       (NOT in the constructor!) and delete in the shutdown() method (NOT in the
       destructor!)

       This is because the application object gets created before Juce has been properly
       initialised, so any embedded objects would also get constructed too soon.
   */

    public:
        LeoJuceApp();
        ~LeoJuceApp();

        void initialise (const String& commandLine);
        void shutdown();
        const String getApplicationName();
    
    private:
        LeoMainWindow *main_window_m;
};
// ------------------------------------------------------------------------

LeoJuceApp::LeoJuceApp() : main_window_m(0)
{
    // NEVER do anything in here that could involve any Juce function being called
    // - leave all your startup tasks until the initialise() method.
}

LeoJuceApp::~LeoJuceApp()
{
    // Your shutdown() method should already have done all the things necessary to
    // clean up this app object, so you should never need to put anything in
    // the destructor.

    // Making any Juce calls in here could be very dangerous...
}


void LeoJuceApp::initialise (const String& commandLine)
{
    main_window_m = new LeoMainWindow("Juce example", Colour(0, 0, 0), true);
    main_window_m->setVisible(true);
    main_window_m->setBounds(10, 10, 800, 600);

    OwnedArray<File> roots;
    File::findFileSystemRoots(roots);

    for (int i = 0; i < roots.size(); i++)
    {
        OutputDebugString(roots[i]->getFileName());
    }

    // JUCE crash here
    roots.clear();
}


void LeoJuceApp::shutdown()
{
    delete main_window_m;
}


const String LeoJuceApp::getApplicationName()
{
    return "Juce example";
}

START_JUCE_APPLICATION(LeoJuceApp)

…so is it Mac, Windows, Linux…?

Home computer is XP 32bit with SP3
Office computer is Vista 64 bit with SP1

I can’t reproduce this, and can’t honestly see how it could possibly be a bug in findFileSystemRoots.

Can you try getting the unaltered jucedemo code , and adding
OwnedArray f;
File::findFileSystemRoots (f);
f.clear();
just before the end of JuceDemoApplication::initialise() method. That’s what I did to test.

If that works, then I bet there’s something else corrupting the stack in your app.

If it still crashes, I’d be interested to see what your list of root files actually is.

As I said, I tried to compile juce into a dll and use that dll. I think that was the difference.

I tried the jucedemo. At first I had to alter it some way to not use the amalgamated code. Additionally I had to change some project settings for the jucedemo vcproj to search the generated juce libs at the right place.

At first I tried with static lib, and there was no problem, even with the additional code that used the findFileSystemRoots.

After I tried dll. Besides the previous changes I added JUCE_DLL to the preprocessor macros for the jucedemo project. Then I’ve got a lot of OpenGL-related unresolved externals. I added OpenGL32.lib and glu32.lib to the linker dependencies. Then there were only one unresolved external for OpenGLPixelFormat::getAvailablePixelFormats
I commented out the code that uses this function. Then it finally could run, but it crahsed in
MainDemoWindow::MainDemoWindow at the line
commandManager->registerAllCommandsForTarget(contentComp);
And I can’t debug that function becouse there’s no symbol defined. Ok, had to change the JUCE project DLL Debug configuration to generate debug info. The crash occurs when the function ends (not when the if brach left the scope).

Windows DLL’s are sucks.

Ah. I missed the vital clue about it being a DLL build.

Sounds like the compiler has inlined the OwnerArray::clear() method, so that it’s trying to delete the array contents from your module’s heap - but the file objects in the array were actually created in the juce dll’s heap. That’d certainly go bang.

If you’ve got JUCE_DLL set before including juce.h, that should never happen, though… Are you sure you’ve got that flag set?

In jucedemo, JUCE_DLL is added to the preprocessor macros, so before any includes this is set.

I think JUCE_API is missed from the definition of OpenGLPixelFormat, because after I added it, the unresolved external problem is no longer occured.

The crash problem occurs in the ArrayAllocationBase::setAllocatedSize function. I see that ArrayAllocationBase isn’t really for public use. I don’t too familiar with this dll export stuff, but maybe the problem is that ArrayAllocationBase is not exported? I tried to add JUCE_API for its class definition, but then a lot of linker error appeared.

Ah, thanks for spotting the missing JUCE_APIs there - I’ll add them.

Yes, there are problems with DLLs, when you have templated classes like the arrays. I wonder if your problem might be caused by ArrayAllocationBase not containing a juce_UseDebuggingNewOperator statement… That macro contains the cunning memory stuff that works around these problems.

[quote=“kend”]
The crash problem occurs in the ArrayAllocationBase::setAllocatedSize function. I see that ArrayAllocationBase isn’t really for public use. I don’t too familiar with this dll export stuff, but maybe the problem is that ArrayAllocationBase is not exported? I tried to add JUCE_API for its class definition, but then a lot of linker error appeared.[/quote]

Please check the runtime library option. The dll and also the application using the dll should have the same value.(preferably Multi-Threaded DLL).