Jump to content

Can someone help me with an example for an existing wrapper DLL which uses function pointer with callback function


Recommended Posts

Hello I hope someone can help me, I have been trying to get this to work for days but no success yet.

 

What I want to do

I got a dll with a wrapper, this dll and wrapper can be used for a special datalogger. The wrapper contains multiple functions, I have got some of them working using a CLFN, for instance I can read a jumper setting from the datalogger in LabView. So far everything is fine.

Of course I am not that interested in the jumper setting, I would rather use the datalogger to log data.

I need to run one function to start logging. When there is enough data in the databuffer of the driver dll it will call a callback function I need to write in Labview, here is the function which starts the logging as described in the header file:

 

Int LOGEXPORT __sdcall LOG_StartLogging{const char ** logFilename, ptLogCallbackfunction ptFunction, ptObject ptObject}

logFilename needs to be a NULL pointer, from my understanding I do not need to do anything with it. Only provide it. If I do not do anything with it some data is saved at a default location.

ptLogCallbackfunction, as far as I know I need to provide a pointer to the callback function

ptObject ptObject, this must be a void pointer

 

The header also provided how the callback function could look like in 😄

 

Void __stdcall callbackLog(ptObject object, const int ArraySize, const StructLogdata *const logDataArray)

{

// copy data from logDataArray for use in my code

}

 

StructLogdata is a struct with different datatypes.

 

What I did try

I did a search on internet there are some examples about callback functions, most of them point to NET and active X. They use a reg Event Callback. I did read the helpfile at the end of the helpfile there is the text:

“Use the Event structure or the Register For Events function to register and handle non-.NET or non-ActiveX events dynamically” I am having a hard time to find a proper example. I did find this site with some information:

https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z000000P8XJSA0&l=nl-NL

and this one about the refnum:

https://forums.ni.com/t5/LabVIEW/Passing-Event-Refnum-to-Call-Library-Function/td-p/4107748

So I did make a user event, I wired a static Vi ref containing a callback vi to the input of this user event. I did wire the user event to a Reg event and wired the event registration refnum to the start logging dll call library function node function pointer input and also to an event structure. I did place a counter in the event structure. But nothing happens besides for an exception which makes Labview crash.

The parameters I did use in the call library function are:

logFilename: type numeric, datatype: Signed Pointer-sized int Pass: pointer to value

ptLogCallbackfunction: type: adapt to type, Data format handles by value (tried all options)

ptObject: same as logFilename

 

I did try a lot of different things. Writing them in this post will result in chaos and I don’t want that. I hope someone can help me with a simple example how to make this work, or point me into the correct direction.

Thank you all for the help!

Link to comment

LabVIEW cannot supply callbacks for unmanaged function calls. You will have to create a C/C++ wrapper DLL that creates and registers the callback with the function and inside that callback use PostLVUserEvent to send it to LabVIEW.

You've read those articles but haven't quite understood that you need a DLL wrapper and it is what actually registers and executes the callback with the function.

Edited by ShaunR
Link to comment

Well the header file I mention is from the wrapper someone else wrote. I have got some functions working from this wrapper. The only part I havent managed to get working is the part with the callback. So what you are saying I need a wrapper to use this wrapper because it uses a callback function? I will read the example you did provide thank you!

Link to comment
16 hours ago, Neon_Light said:

Well the header file I mention is from the wrapper someone else wrote. I have got some functions working from this wrapper. The only part I havent managed to get working is the part with the callback. So what you are saying I need a wrapper to use this wrapper because it uses a callback function? I will read the example you did provide thank you!

Do you have the source code of that wrapper? If so you can modify it, otherwise you will have to create a wrapper around this wrapper or around the original lower level API.

Or maybe that wrapper implements this callback functionality and the lower level API is simply a function API where the caller has to implement its own task handling. In that case it may be simpler to directly go to this lower level API and implement the parallel task doing the logging monitoring entirely in LabVIEW.

Edited by Rolf Kalbermatter
Link to comment
12 hours ago, Rolf Kalbermatter said:

Do you have the source code of that wrapper? If so you can modify it, otherwise you will have to create a wrapper around this wrapper or around the original lower level API.

Or maybe that wrapper implements this callback functionality and the lower level API is simply a function API where the caller has to implement its own task handling. In that case it may be simpler to directly go to this lower level API and implement the parallel task doing the logging monitoring entirely in LabVIEW.

Hello Rolf and ShaunR, Thank you for the help!

I do not have the source code of the wrapper but they included 2 files a Typedefs.h and a interface.h

The:

Int LOGEXPORT __sdcall LOG_StartLogging{const char ** logFilename, ptLogCallbackfunction ptFunction, ptObject ptObject}

is implemented in the dll and I can call it with a CLFN, first I tried to wire the output of a Register For Events function to the "ptLogCallbackfunction" as I understood this would provide a function-pointer to a Labview function/vi which would then behave as a callback function. It makes Labview crash though. When the driver is not running it returns a error message. I think the function does not try to use the callback pointer when the driver is not running.

My communication might not be completely correct as I am new to callback functions. Maybe this helps, above example text:

Void __stdcall callbackLog(ptObject object, const int ArraySize, const StructLogdata *const logDataArray)

there is also the text:

typedef Void( __stdcall *callbackLogFunction)(ptObject object, const int ArraySize, const StructLogdata *const logDataArray)

12 hours ago, Rolf Kalbermatter said:

In that case it may be simpler to directly go to this lower level API and implement the parallel task doing the logging monitoring entirely in LabVIEW.

I can give it a try, but how do I approach this?

I can also try to code it in C, think it is interesting and fun but it has been a while since I did code C. Although I planned to refresh my C knowledge, this would take time and focus on one thing to learn at a time might be more successful. It is late now, I will read trough the examples and Using External code pdf tomorrow. Thank you for the help you provided! 

 

Link to comment
1 hour ago, Neon_Light said:

this would provide a function-pointer to a Labview function/vi which would then behave as a callback function.

No. You cannot call LabVIEW VI's as function pointers in unmanaged code ... period!

I will reiterate:

On 1/15/2023 at 3:42 PM, ShaunR said:

You will have to create a C/C++ wrapper DLL that creates and registers the callback with the function and inside that callback use PostLVUserEvent to send it to LabVIEW.

It's only worth going to the original driver and interfacing directly with LabVIEW *IF* it means you don't need a callback.

Edited by ShaunR
Link to comment

Hello ShaunR, thank you for the answer. I have to admit it was not the answer I hoped for as this will take more time, on the other side learning new things is always a great thing 🙂 . I did read this forum:

 

And I think for me the most important points are:

Although the document is old I can use most parts of: "Using External Code in LabVIEW". The link to the Ni site contains more recent info: https://www.ni.com/docs/en-US/bundle/labview/page/lvhelp/labview_help.html

One part which is outdated of the external code document is how to set up the environment in the IDE. At this time I am using VSC, as a IDE. Do you have a link to a VSC setup to develop a DLL for Labview? 

 

 

Link to comment
10 minutes ago, Neon_Light said:

One part which is outdated of the external code document is how to set up the environment in the IDE. At this time I am using VSC, as a IDE. Do you have a link to a VSC setup to develop a DLL for Labview? 

The principle is still very much the same. The only thing that won't match are possible screen shots and maybe the naming is not always the same. DLL development was implemented with Windows 3.0 and has only changed VERY little over time. IDE settings may have changed somewhat more but it is not really feasible to make a new document for every new Visual Studio version. (And Visual Studio Code, and Intel C, and Bloodshed's DevC++, Watcom C++, Gnu C++, etc, etc).

Edited by Rolf Kalbermatter
Link to comment

Hello I  did give it a try I am able to compile some C code send some data to the created DLL and receive data from the DLL. So that is great 🙂 thanks !

The original DLL however will return a array with structs to my C DLL I will try to implement thePostLVUserEvent part there . When I try to make an even structure as an experiment I am not able to get the array out again. This makes me think I am not using the event method in the correct way. what will be the best way to get an array from the DLL back to the Labview event? Do I need to send every array element back with a PostLVUserEvent?

 

 

 

 

 

1178281110_Arraytoevent.PNG.28988f4090ea13fdea7c8a38a43e74f1.PNG

 

Link to comment
1 hour ago, Neon_Light said:

Hello I  did give it a try I am able to compile some C code send some data to the created DLL and receive data from the DLL. So that is great 🙂 thanks !

The original DLL however will return a array with structs to my C DLL I will try to implement thePostLVUserEvent part there . When I try to make an even structure as an experiment I am not able to get the array out again. This makes me think I am not using the event method in the correct way. what will be the best way to get an array from the DLL back to the Labview event? Do I need to send every array element back with a PostLVUserEvent?

1178281110_Arraytoevent.PNG.28988f4090ea13fdea7c8a38a43e74f1.PNG

 

There is no real problem to create such an array directly in the callback function, to be sent through the user event. But you must understand that the actual array must be a LabVIEW managed array handle. 

Basically something like this will be needed (and you will need to adjust the typedef of the cluster to match what you used in your LabVIEW code, since you "forgot" to attach your code):

#include "lv_prolog.h"

typedef struct {
    int32_t status;
    double value;
} DataRecord;

typedef struct
    int32_t size;
    DataRecord elm[1];
} DataArrayRec, *DataArrayPtr, **DataArrayHdl;

#include "lv_epilog.h"

/* if the callback can be reentrant, meaning it can be called while another callback is already executing,
use of a global variable for the data array is NOT safe and needs to be handled differently!!!! */

static DataArrayHdl handle = NULL;

void yourCallback(.......)
{
    int32_t i, size = somewhereFromTheParameters;
    MgErr err;

    if (!handle)
    {
        handle = DSNewHandle(sizeof(DataArrayRec) * (size - 1));
        if (!handle)
            err = mFullErr;
    }
    else
    {
        err = DSSetHandleSize(handle, sizeof(DataArrayRec) * (size - 1));
    }
    if (!err)
    {
        (*handle)->size = size;
        for (i = 0; i < size; i++)
        {
            (*handle)->elm[i].status = status[i];
            (*handle)->elm[i].value = values[i];
        }
        err = PostLVUserEvent(lvEventRefnum, &handle);
    }
}

The easiest way to actually get the datatype declaration for the array that you need to pass to PostLVUserEvent() would be to create a dummy Call Library Node with a parameter configured as Adapt to Type, and then right click on the node and select "Create C Souce code". After choosing where to write the file it will create a C source file that contains the necessary data type declarations.

Edited by Rolf Kalbermatter
Link to comment

Thank you Rolf !! 

but the thing I can still not find is how do I get acces to the array in the event structure. If I wire a number for example index to the create user event it ends up in the event structure. Wile the callback array does not appear. I added a screenshot, hope that helps. 

No Array .PNG

Link to comment
10 minutes ago, Neon_Light said:

Thank you Rolf !! 

but the thing I can still not find is how do I get acces to the array in the event structure. If I wire a number for example index to the create user event it ends up in the event structure. Wile the callback array does not appear. I added a screenshot, hope that helps. 

No Array .PNG

It's unclear since you still don't want to post VIs but only images so we have to guess. But I would say the array simply has no label. The node inside the event structure only lets you select named elements. The "CallBack" word looks like it may be a label, but it is probably just a free label like the "Test" in the image below. 

Edited by Rolf Kalbermatter
Link to comment
  • 5 weeks later...

Hello  Rolf,

 

thank you, you were completely correct. The label was missing.

 

I did spent a lot of evenings coding and most of it seems to work. To setup the IDE I did use this site it describes how to setup the C environment in VSC and tips how to debug the DLL software.

https://gitlab.com/serenial/talks/11-20-labview-and-vscode-shared-libraries 

 

I did also try to get rid of the array  changing this code:

typedef struct {
    int32_t status;
    double value;
} DataRecord;

 

into 

typedef struct {
    int32_t status;
    double value;
} DataRecord, *dataHdl;

......
......

dataHdl handle = NULL;

the rest of the code I did keep the same. This does not work. How can I send one cluster back at a time? Does the handle always need a size even when the size is one cluster / struct? The reason I ask is because the size of the array is different every call, I did find out when using a debug window as described in the link above.

 

Another question I have is how to transport the  Labview LVUserEventRef data to the callback function? Is the part below legal?

 


LVUserEventRef giveReftoCallback;


FuncCalledFromLabviw(LVUserEventRef *rwer,int bla)
{
....
giveReftoCallback = rwer;
.....
}


void __stcall MyCallback(....)
{
....
err = PostLVUserEvent(giveReftoCallback, &handle);	
}

 

You also did write:

Quote
/* if the callback can be reentrant, meaning it can be called while another callback is already executing,
use of a global variable for the data array is NOT safe and needs to be handled differently!!!! */

Yes the callback function will be called ever time there is new measurement data. So I there is a change the callback function is still sending data to Labview when it is called for new data. Is there a easy way to fix this?

 

 

thank you for the help!!

 

 

 

 

 

Edited by Neon_Light
Link to comment

A LabVIEW handle is however:

typedef struct {
    int32_t status;
    double value[];
} DataRecord, *DataPtr, **DataHdl;

......
......

DataHdl handle = NULL;

The important part is the double pointer in front of the handle datatype.

The array declaration of the value element is more a cosmetical thing and may not work like this with your compiler. You may have to add a 0 or even 1 in the brackets to let your compiler accept it. It has no real influence on the code unless you try to use sizeof(DataRecord) somewhere, which is not recommended. 

Link to comment
  • 4 months later...

Hello Rolf, thanx for all the help you give,

 

This start working fine now!! It has been a great learning experience for me !

(1) The next question might be kind of silly but how do I change the 1D array to a 2D array ?  

 

 (2)With one adapter everything seems to work out okay! Now I got the question to make it work for multiple adapters. I can receive the data in my wrapper from multiple adapters. So the question is: How can I put the 1D array in a cluster with another int to indicate which adapter the array comes from? Ho do I change the C code so Labview can receive something like this:

 

 1427597583_Knipsel-kopie.PNG.3ae2e3950cc102cfac34558e7100b4ba.PNG

 

Thanx !!

 

 

 

 

 

Link to comment

The first step in trying to create a DLL that uses LabVIEW data types natively, is to configure a Call Library Node to have a parameter which is configured Adapt to Type. Then connect the datatype you want to use to this parameter, right click on the Call Library Node and select "Create .c file". The resulting C file has an exact C type declaration for the parameter. Copy paste and start programming your code you want in your own C file.

#include "extcode.h"

#include "lv_prolog.h"

typedef struct
{
    int32_t status;
    int32_t value;
} DataRecord;

typedef struct
{
    int32_t dimSize;
    DataRecord elms[1];
} DataArrayRec, *DataArrayPtr, **DataArrayHdl;

typedef struct
{
    int32_t adapterNr;
    DataArrayHdl dataRecords;
} DataBlock;
#include "lv_epilog.h"

This is what your type will probably look like. Obviously the int32_t is just a guess, can't see that from an image.

Edited by Rolf Kalbermatter
Link to comment

Hello Rolf, thanx !!

Yesterday it was late and I was behaving stupidly, I should stop sooner. I did connect the cluster to a create user event and that one to a Reg  event and that one to a function node. I should have connected the cluster directly to the function node that creates the correct C file I think.

 

 

/* Call Library source file */

#include "extcode.h"

/* lv_prolog.h and lv_epilog.h set up the correct alignment for LabVIEW data. */
#include "lv_prolog.h"

/* Typedefs */

typedef struct {
	int32_t Status;
	int32_t Value;
	} TD3;

typedef struct {
	int32_t dimSize;
	TD3 elt[1];
	} TD2;
typedef TD2 **TD2Hdl;

typedef struct {
	TD2Hdl DataRecord;
	int32_t AdapterNr;
	} TD1;

#include "lv_epilog.h"

void funcName(TD1 *TestInput);

void funcName(TD1 *TestInput)
{

	/* Insert code here */

This makes sense If I look at it. Thanx again 🙂

 

 

 

 

 

Link to comment

Thanks but how do I get the data in? I get confused because there is another level added by "testStructArray"

(And it is 36 C in my room now and I am melting )

 

 

 

TD1 testStructArray;
testStructArray.AdapterNr = 1;  // give te adapter a number

 (*handle)->elm[i].status = status[i];  // in the example above this was used to fill the array elements
										// what must I do now to get the data in? The "testStructArray" made it a level deeper 

 

thanx

Link to comment

Yes! its not 36C anymore!! There is even a cold wind blowing in my room !!

 

From what I read I am not allowed to use C memory functions, but there is a Labview function called MoveBlock:

void MoveBlock(ps, pd, size);


ps      UPtr    Pointer to source.
pd     UPtr    Pointer to destination.
size  int32   Number of bytes you want to move.

 

When I take a look here to see how it is used: 

https://lavag.org/topic/23177-send-cluster-struct-from-dll-with-a-couple-of-ints-and-a-string-of-text-to-labview/#comment-150817

I see it is used here:

{
		MoveBlock(stringData, LStrBuf(**lvStringHandle), len);
		LStrLen(**lvStringHandle) = (int32_t)len;
	}

 

The pdf "Using External Code in Labview " shows:

uChar *LStrBuf(s);

Returns the address of the string data of a long Pascal string, that is, the address of s->str.

So do I need to do something like:

 

Datablock testDataBlock;

testDataBlock.adapterNr = 1;
MoveBlock(*handle, testDataBlock->elms, len);

 

I'll give it a try, am I going in the correct direction?

 

 

Link to comment

No, no, no!

#include "extcode.h"

#include "lv_prolog.h"

typedef struct
{
    int32_t status;
    int32_t value;
} DataRecord;

typedef struct
{
    int32_t dimSize;
    DataRecord elms[1];
} DataArrayRec, *DataArrayPtr, **DataArrayHdl;

typedef struct
{
    int32_t adapterNr;
    DataArrayHdl dataRecords;
} DataBlock;
#include "lv_epilog.h"
  
static MgErr PostDataMessage(LVUserEventRef rwer, int32_t adapterNr, DataRecord *dataPtr, int32_t numElements)
{
    DataBlock testDataBlock = {0};
    MgErr err = NumericArrayResize(uL, 1, (UHandle*)&testDataBlock.dataRecords, 2 * numElements);
    if (!err)
    {
        testDataBlock.adapterNr = adapterNr;
        MoveBlock(dataPtr, (*(testDataBlock.dataRecords))->elms, numElements * sizof(DataRecord));
        (*(testDataBlock.dataRecords))->dimSize = numElements;
        err = PostLVUserEvent(rwer, &testDataBlock);
        // PostLVUserEvent  does a deep copy so we need to deallocate this handle to avoid a memory leak
        DSDisposeHandle(testDataBlock.dataRecords);
    }
    return err;
}

And yes, my order of the elements in DataBlock seems the other way around than yours, I did it according to the optical order in your image, as that was all I had to go by.

 

Edited by Rolf Kalbermatter
Link to comment

Hello Rolf thank you for your patience,

I did copy a piece of your code and added some comment, can you please check if I am correct?

 

static MgErr PostDataMessage(LVUserEventRef rwer, int32_t adapterNr, DataRecord *dataPtr, int32_t numElements)
{
    // when you create the variable "testDataBlock" everything in the block is made 0 with the use of {0}
  	// dataRecords points to a memory location which has got an unknow size. At this time the pointer is a Null pointer maybe ?
  	DataBlock testDataBlock = {0};
  	// Here you use the function "NumericArrayResize" to resize the memorylocation dataRecords points to,  
    MgErr err = NumericArrayResize(uL, 1, (UHandle*)&testDataBlock.dataRecords, 2 * numElements);
    if (!err)
    {
        testDataBlock.adapterNr = adapterNr;
      	// Here you use MoveBlock to Move the data from the source location where dataPtr points, to the
      	// correct location of testDataBlock. You use the (*(..)) because if you would have used 
      	// *testDataBlock.dataRecords->elms you did point at the beginning of testDataBlock and not to the begining of elms
        MoveBlock(dataPtr, (*(testDataBlock.dataRecords))->elms, numElements * sizof(DataRecord));
        (*(testDataBlock.dataRecords))->dimSize = numElements;
        err = PostLVUserEvent(rwer, &testDataBlock);
        // (this was your comment): PostLVUserEvent  does a deep copy so we need to deallocate this handle to avoid a memory leak
        DSDisposeHandle(testDataBlock.dataRecords);
    }
    return err;

I hope I start to understand what's going on, then it is easier to remember. 

How do I change the code when I want to change the array from int int,  to int double? Can I use this piece of code you gave earlier:

 

 if (!handle)
    {
        handle = DSNewHandle(sizeof(DataArrayRec) * (size - 1));
        if (!handle)
            err = mFullErr;
    }
    else
    {
        err = DSSetHandleSize(handle, sizeof(DataArrayRec) * (size - 1));
    }

and change the adres where  to testDataBlock.dataRecords points ?

the handle is it easy to explain whats done here is it that the Labview functions add some extra bytes to make every variable the same size e.g. when I have char and a int they ad 3 chars for the char to make the size the same as a int or is there more going on? 

thank you for the help you are great !!

 

 

 

 

 

Link to comment

I added my comments in the comments behind ////

static MgErr PostDataMessage(LVUserEventRef rwer, int32_t adapterNr, DataRecord *dataPtr, int32_t numElements)
{
    // when you create the variable "testDataBlock" everything in the block is made 0 with the use of {0}
    // dataRecords points to a memory location which has got an unknow size. At this time the pointer is a Null pointer maybe ?
    //// => wrong!! It is a NULL pointer so it is not an unknown size but an invalid pointer pointing nowhere!
  	DataBlock testDataBlock = {0};
  	// Here you use the function "NumericArrayResize" to resize the memorylocation dataRecords points to
    //// yes, it is a LabVIEW handle and needs to be accordingly setup, but since it is never really passed to the LabVIEW diagram
    //// it would not strictly be necessary to allocate it as LabVIEW handle but it needs to have the exact memory layout so it is 
    //// easiest to do that in this way, anything else is going to confuse you simply more!!!!
    MgErr err = NumericArrayResize(uL, 1, (UHandle*)&testDataBlock.dataRecords, 2 * numElements);
    if (!err)
    {
        testDataBlock.adapterNr = adapterNr;
      	// Here you use MoveBlock to Move the data from the source location where dataPtr points, to the
      	// correct location of testDataBlock. You use the (*(..)) because if you would have used 
      	// *testDataBlock.dataRecords->elms you did point at the beginning of testDataBlock and not to the begining of elms
        //// wrong!! It is simply for correct C operator precedence evaluation, -> has higher precedence and would be evaluated
        //// before the * (pointer dereference) operator and would give you a compiler error since testDataBlock.dataRecords
        //// has no elms member, but *testDataBlock.dataRecords has, and I prefer to use more brackets to make it simply more
        //// clear, so (*(testDataBlock.dataRecords)) but the inner brackets are not strictly needed as operator precedence
        //// rules work fine here (. structure access has higher precedence than * pointer dereference, just as we want it here)
        MoveBlock(dataPtr, (*(testDataBlock.dataRecords))->elms, numElements * sizof(DataRecord));
        (*(testDataBlock.dataRecords))->dimSize = numElements;
        err = PostLVUserEvent(rwer, &testDataBlock);
        // (this was your comment): PostLVUserEvent  does a deep copy so we need to deallocate this handle to avoid a memory leak
        //// right! the testDataBlock memory area is going away at exit of this function and the handle stored in too, so we need
        //// to deallocate it otherwise it is lost
        DSDisposeHandle(testDataBlock.dataRecords);
    }
    return err;
}

 

32 minutes ago, Neon_Light said:

How do I change the code when I want to change the array from int int,  to int double? Can I use this piece of code you gave earlier:

 if (!handle)
    {
        handle = DSNewHandle(sizeof(DataArrayRec) * (size - 1));
        if (!handle)
            err = mFullErr;
    }
    else
    {
        err = DSSetHandleSize(handle, sizeof(DataArrayRec) * (size - 1));
    }

No no! Doing it yourself instead of letting LabVIEW do it is only making things only really worse. And you definitely and absolutely are doing the calculation wrong although it will be simply a to big allocation so at least you won't blow up your harddisk. 🙂

Something like this would be more accurate:

    size_t len = offsetof(DataArrayRec, elms) + size * sizeof(DataRecord)
    if (!handle)
    {
        handle = DSNewHandle(len);
        if (!handle)
            err = mFullErr;
    }
    else
    {
        err = DSSetHandleSize(handle, len);
    }

 

32 minutes ago, Neon_Light said:

And change the adres where  to testDataBlock.dataRecords points ?

the handle is it easy to explain whats done here is it that the Labview functions add some extra bytes to make every variable the same size e.g. when I have char and a int they ad 3 chars for the char to make the size the same as a int or is there more going on?

Sorry mate, but this sounds gibberish and I have no idea what you mean.

Edited by Rolf Kalbermatter
Link to comment

So I can give the adres of handle to testDataBlock.dataRecords, like this:

 

size_t len = offsetof(DataArrayRec, elms) + size * sizeof(DataRecord)
    if (!handle)
    {
        handle = DSNewHandle(len);
  		// testDataBlock.dataRecords = Null 
		testDataBlock.dataRecords = & handle
  		// testDataBlock.dataRecords != Null 
          
        if (!handle)
            err = mFullErr;
    }
    else
    {
        err = DSSetHandleSize(handle, len);
      	// do I need to repeat this:
      	// testDataBlock.dataRecords = & handle 
      	// or does the adres not change ?    
      
      
    }

 

and thats it ? 

 

when I try the code above I get:

a value of type "DataArrayHdl*" cannot be assigned to an antity of type "DataArrayHdl"

in the line: 

testDataBlock.DataRecords = &handle;

Can anyone tell me what I might be doing wrong ?

 

 

thanx !!

 

 

 

 

 

 

 

Edited by Neon_Light
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.