0

I'm having trouble sending messages from a DLL's logging function to the client's logging function. I'm fine using a function pointer like this:

DLL:

class InnerLogger
{
public:
    static std::function<void(const std::string& message, int level)> loggerCallback;
    static std::stringstream logMsg;
    static int logSend(LogLevel logLevel);
};

void setLoggingFunction(const std::function<void(const std::string& message, int level)>& logFunction)
{
    InnerLogger::loggerCallback = logFunction;
}

Client:


void outerLogger(const std::string& message, int level)
{
  // display/save messages
}

main()
{
    std::function<void(const std::string& message, int level)> logFunctionPtr = outerLogger;
    setLoggingFunction(logFunctionPtr);
}

I can use InnerLogger::logSend and outerLogger picks it up.

But I'm doing something wrong when the 'outer' logger is a class member:

(DLL is unchanged)

Client:

class OuterLogger
{
public:
    OuterLogger();
    ~OuterLogger();

    void logFunction(const std::string& message, int level);
};

void OuterLogger::logFunction(const std::string& message, int level)
{
    // display/save messages
}

main()
{
    OuterLogger outerLogger;
    std::function<void(const std::string& message, int level)> logFunctionPtr = outerLogger.logFunction;
    setLoggingFunction(logFunctionPtr);
}
Wezzoid
  • 21
  • 2

2 Answers2

0

Here is a sample of how a class can be bind to a function:

#include <iostream>
#include <functional>

class A {
    public:
    int x = 1;
    void func() {
        std::cout << x;
    }
    ~A() {
        x = 2; // just to test the destructor
    }
};

int main()
{
    std::function<void(void)> f;

    {
        A a;
        f = std::bind(&A::func, a); // do not bind &a because it will be out of scope
    }

    f();

    return 0;
}

In your situation you can use:

std::function<void(const std::string& message, int level)> logFunctionPtr = std::bind(&OuterLogger::logFunction, outerLogger, std::placeholders::_1, std::placeholders::_2);

Instead of bind you can use a lambda function:

std::function<void(const std::string&, int)> logFunctionPtr =
    [outerLogger](const std::string& message, int level) mutable {
        outerLogger.logFunction(message, level);
    };
Victor Padureanu
  • 604
  • 1
  • 7
  • 12
  • Thanks Victor. I tried this when I saw it elsewhere, but I get: Error C2440 'initializing': cannot convert from 'std::_Binder' to 'std::function' – Wezzoid Oct 02 '19 at 16:26
  • My bad, I forgot about the placeholders. – Victor Padureanu Oct 03 '19 at 08:32
  • this worked: `std::string str; // placeholder to satisfy bind int x; // placeholder to satisfy bind logFunctionPtr = std::bind(&TestLogger::logFunction, this, str, x);` and use as std::function. Or it appeared to. weirdly, it would be accepted by the function and be set as the var, but as soon as the setter went out of scope the var would return to null, which it never did before. I've given up on this and made the bloody thing global static for now.(how tf do you do a new line in a comment?) – Wezzoid Oct 03 '19 at 10:38
  • use *this instead of this. The problem with this is that it is only a pointer and when the class gets out of scope the entire structure collapses. Also make sure you have a copy constructor. – Victor Padureanu Oct 03 '19 at 10:43
0

I tried several different variations on ways to pass the function pointer, none of which worked BUT it turns out there was nothing wrong with that code.

When I used code of whatever form that successfully got accepted by the DLL logger, debug showed it would immediately go null afterwards.

I am using VS' Test explorer. Turns out some tested process instances weren't shutting down properly so I had stuck testhost processes in the background, and I think the addresses were getting messed up somehow.

The clues were the intermittent inability to run a test more than once, and very odd behaviour in debug mode - the execution marker going backwards and skipping around and producing mysterious WINRT_ASSERT(!is_sta()) exceptions. The answer is to run Process Explorer and check for stuck processes under VS. (bit annoying that VS couldn't tell me there was a problem with the process it was testing but nvm)

My code uses the WinML lib. If I run in CPU mode it's fine. If I use GPU it gets stuck on shutdown, so I need to figure out why.

Thanks for the help everyone.

Edit: my initial assumption in my question was that it was a problem moving the code from non-object to object - this was totally wrong. The original non-object version of the code worked because it was in a demo client, a single executable console program calling the DLL, which was never impacted by the dodgy shutdown issue. In the unit test suite with multiple instances it became an issue.

Wezzoid
  • 21
  • 2