Question

I'm trying to join an old piece of code in C to my present VC++ project:

// .h
    class DMSinv : public CDialog {
        double finte(double z);
        double ITFStolz(double Zp1, double Zp2, double Zc);
    };

// .cpp
    double Zcglob;
    double DMSinv::finte(double z) 
    {
       return TFStolz(z, Zcglob);
    }

    double DMSinv::ITFStolz(double Zp1, double Zp2, double Zc)
    {
        int ierr;
        Zcglob = Zc;

        return (coteglob(&DMSinv::finte, Zp1, Zp2, 1.0e-10, &ierr));
    //error C2664: 'DMSinv::coteglob' : cannot convert parameter 1 from 'double (__thiscall DMSinv::* )(double)' to 'double (__cdecl *)(double)'    

    }

the coteglob function comes from the old C part, and finte is a intermediate function to pass the TFStolz function to coteglob.

I've searched in the forums and found this related question: How to convert void (__thiscall MyClass::* )(void *) to void (__cdecl *)(void *) pointer which I tried to apply in this way:

// .h
    class DMSinv : public CDialog {
        virtual double finte(double z);
        double ITFStolz(double Zp1, double Zp2, double Zc);
    };

// .cpp
    double Zcglob;
    extern "C"
    {
        static double __cdecl finteHelper(double z)
        {
            DMSinv* datainv = reinterpret_cast< DMSinv > (z); //error C2440: 'reinterpret_cast' : cannot convert from 'double' to 'DMSinv'  

            datainv->finte(z);
        }
    }

    double DMSinv::ITFStolz(double Zp1, double Zp2, double Zc)
    {
        int ierr;
        Zcglob = Zc;
        double solution = coteglob(&finteHelper, Zp1, Zp2, 1.0e-10, &ierr);
        return solution;
    }

but is still not working. Can somebody guide me on how to adapt it? I'm quite a newbie yet and this seems far from my knowledge.

Thanks in advance!

Was it helpful?

Solution

Not sure it is possible to do as you want. Only option that comes to my mind is to use some static variable to store address of DMSinv object. This limits you to 1 thread with simple implementation...

Try this:

// .h
class DMSinv : public CDialog {
    double finte(double z);
    double ITFStolz(double Zp1, double Zp2, double Zc);

private:
  static DMSinv* _current;
  static double __cdecl finteHelper(double z);
};

// .cpp
double Zcglob;
DMSinv* DMSinv::_current = 0;
double DMSinv::finte(double z) 
{
   return TFStolz(z, Zcglob);
}

double DMSinv::ITFStolz(double Zp1, double Zp2, double Zc)
{
    int ierr;
    Zcglob = Zc;

   _current = this;
   return (coteglob(DMSinv::finteHelper, Zp1, Zp2, 1.0e-10, &ierr));
}

double __cdecl DMSinv::finteHelper(double z)
{
    return _current->finte(z);
}

This is not good solution IMO, but I'm not sure that there is other way.

PS To remove limit of one thread you can use TLS slots or in VC++ just __declspec(thread). With latter just add __declspec(thread) to _current like this: static __declspec(thread) DMSinv* _current;. BUT!!! be aware of that number of per-thread variables is limited for process. Read more on this in MSDN.

UPDATE

Disclamer: Just for fun.

Theoretically, there is other opportunity. You can store assembly code in array, attached to object. This assembly code should be a __cdecl function that simply translates __cdecl to __thiscall based on eip register. But this should never be done though... :D

OTHER TIPS

I don't think you can do it this way. You need to somehow pass the reference to your object (this). In the linked question the parameter to the function was defined as type void * thus you could pass whatever you need to the function, including pointer to this. Your function accepts double, so you can't pass this to it.

I think the easiest would be to define your intermediate function out of class, since it appears to be independent of class internals. Something like this:

double finte(double z) 
{
   return TFStolz(z, Zcglob);
}

You can also store the instance pointer in a public global/static in-class variable that the static function can read.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top