views:

38

answers:

1

Hello,

I think I'm making just a fundamental mistake, but I cannot for the life of me see it.

I'm calling a method on an Objective-C object from within a C++ class (which is locked). I'm using NSInvocation to prevent me from having to write hundreds methods just to access the data in this other object.

These are the steps I'm going through. This is my first call, and I want to pass s2. I can't really provide a compilable example, but hopefully it's just a DUHRRRRR problem on my part.

float s2[3];
id args2s[] = {(id)&_start.x(),(id)&_start.y(),(id)&s2};
_view->_callPixMethod(@selector(convertPixX:pixY:toDICOMCoords:),3,args2s);

This is the View method being called

invokeUnion View::_callPixMethod(SEL method, int nArgs, id args[])
{
    DataModule* data;
    DataVisitor getdata(&data);
    getConfig()->accept(getdata);
    invokeUnion retVal;
    retVal.OBJC_ID = data->callPixMethod(_index, _datasetKey, method, nArgs, args);
    return retVal;
}

Invoke Union is a union so I can get the float value returned by NSInvocation.

union invokeUnion {
id OBJC_ID;
int intValue;
float floatValue;
bool boolValue;
};

This is the method in the data Object (pthread locked with lock() and unlock());

id DataModule::callPixMethod(int index, std::string predicate, SEL method, int nArgs, id args[] )
{
    // May Block
    DCMPix *pix =[[getSeriesData(predicate) pix] objectAtIndex:index];

    lock();

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    NSMethodSignature *signature;
    NSInvocation *invocation;

    signature = [DCMPix instanceMethodSignatureForSelector:method];
    invocation = [NSInvocation invocationWithMethodSignature:signature];

    [invocation setSelector:method];
    [invocation setTarget:pix];

    if (nArgs > 0) for (int n = 0; n < nArgs; n++) {
        SFLog(@"invocation: i=%d, *ptr=0x%x, valf=%f, vald=%d",n,args[n],*args[n],*args[n]);
        [invocation setArgument:args[n] atIndex:2+n];
    }

    id retVal;

    [invocation invoke];
    [invocation getReturnValue:&retVal];

    [pool release];

    unlock();

    return retVal;
}

The method in the DCMPix object (which I can't modify, it's part of a library) is the following:

-(void) convertPixX: (float) x pixY: (float) y toDICOMCoords: (float*) d pixelCenter: (BOOL) pixelCenter
{
    if( pixelCenter)
    {
        x -= 0.5;
        y -= 0.5;
    }

    d[0] = originX + y*orientation[3]*pixelSpacingY + x*orientation[0]*pixelSpacingX;
    d[1] = originY + y*orientation[4]*pixelSpacingY + x*orientation[1]*pixelSpacingX;
    d[2] = originZ + y*orientation[5]*pixelSpacingY + x*orientation[2]*pixelSpacingX;
}

-(void) convertPixX: (float) x pixY: (float) y toDICOMCoords: (float*) d
{
    [self convertPixX: x pixY: y toDICOMCoords: d pixelCenter: YES];
}

It's crashing when it tries to access d[0]. BAD_EXC_ACCESS which I know means it's accessing released memory, or memory outside of it's scope.

I'm getting lost keeping track of my pointers to pointers. the two float values come across fine (as does other info in other methods) but this is the only one asking for a float* as a parameter. From what I understand the convertPixX: method was converted over from a C program written for Mac OS 9... which is why it asks for the c-array as an out value... I think.

Anyway, any insight would be greatly appreciated.

I've tried sending the value like this:

float *s2 = new float[3];
void* ps2 = &s2;
id args2s[] = {(id)&_start.x(),(id)&_start.y(),(id)&ps2};
_view->_callPixMethod(@selector(convertPixX:pixY:toDICOMCoords:),3,args2s);

But that gives a SIGKILL - plus I'm sure it's bogus and wrong. ... but I tried.

anyway... pointers! cross-language! argh!

Thanks,

A: 

An array is not a pointer. Try adding the following line

NSLog(@"%p, %p", s2, &s2);

just above.

id args2s[] = {(id)&_start.x(),(id)&_start.y(),(id)&s2};

s2 and &s2 are both the address of the first float in your array, so when you do:

[invocation setArgument:args[n] atIndex:2+n];

for n = 2, you are not copying in a pointer to the first float, but the first float, possibly the first two floats if an id is 64 bits wide.

Edit:

To fix the issue, this might work (not tested).

float s2[3];
float* s2Pointer = s2;
id args2s[] = {(id)&_start.x(),(id)&_start.y(),(id)&s2Pointer};
_view->_callPixMethod(@selector(convertPixX:pixY:toDICOMCoords:),3,args2s);

s2Pointer is a real pointer that will give you the double indirection you need.

JeremyP
gah... right. because `s2[i]` is really `*(s2 + i)`. so how do I point to `s2`??
Stephen Furlani
oh for the love of.... I was doing `float* s2Pointer = `
Stephen Furlani