LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Get pointer from an array for C DLL

I wrote a C++ DLL with Visual Studio and add a C wrapper to use it on several langages (C++, Python, LabVIEW, ...). In this one, I am dealing with images, so 2D array. I created a labview library using LabVIEW tools so I attached this library to my project.

 

First, the function to allocate and free the handle for the DLL is working correctly so the commuincation seems okay.

Moreover, my DLL function take as parameter a pointer on the first pixel of the image, so on the first value of the tab, in order to recreate a matrix (library OpenCV) to perform some operations.

 

But I don't know how to get the memory address of the array on LabVIEW and the different posts on internet are not always clear.

I attached a screenshot of my simple VI and the function of my DLL.

 

Here is the C function:

 

__declspec(dllimport) unsigned short* __stdcall imAdjustBrightness(void* handle, void * ptrImg, int width, int height, int inputType, int brightnessValue)
{
	if (handle)
	{
		EpsImageProcessing* data = (EpsImageProcessing*)handle;
		return data->imAdjustBrightness(ptrImg, width, height, inputType, brightnessValue);
	}
	return NULL;
}

 

 

Any advice/help will be appreciated 😉

 

image.pngimage.png

 

 

 

 

 

 

 

 

Mathieu Gauquelin
0 Kudos
Message 1 of 15
(4,721 Views)

Hello Mathieu,

 

It is not that easy to obtain the memory address !

But I hope following topic will help you a lot:

https://forums.ni.com/t5/LabVIEW/How-can-I-pass-the-adress-of-a-cluster-to-a-dll/m-p/169033/highligh...

 

Have a nice day,

 

Armando

0 Kudos
Message 2 of 15
(4,699 Views)

You can create a pointer in C, and copy the data from a LabVIEW handle to the pointer in C.

You will need extcode.h and libs.

 

George Zou
0 Kudos
Message 3 of 15
(4,694 Views)

Why are you starting a new thread with exactly the same problem I already gave you an answer for? For this particular case you do NOT need to do anything special in terms of DSPtr, MoveBlock, or such. LabVIEW has everything in house already to make this work for you.

 

Read my answer to your problem in that thread again. Basically all you need to do is to reconfigure the second parameter of your Call Library Node. It should be:

 

Type: Array

Dimensions: 2

Data type: whatever your 2D array uses as integer type

Array Format: Aarray Data Pointer.

Maximum Size: <None> (leave empty)

 

Of course you need to pass in the 2D array to that subVI and wire it to that second parameter on the Call Library Node. I would also move the part to determine the width and height values of the image array into that subVI. and as mentioned earlier you better make sure that the inputType that you pass into the function is absolutely certain to be compatible with the image data array that is passed in. A mismatch here could in the best case cause distorted image data but in other cases cause crashes as the DLL might try to access data in the passed in array that is beyond the end of that array. It's a good idea to add such safety to the subVI logic. LabVIEW VIs that are just very dumb wrappers around a Call Library Node are generally a sign of bad design for that library.

 

Alternatively you could even write a LabVIEW specific version of your C function that accepts directly a native LabVIEW array handle but in this particular case that is not really necessary and hence probably not a good idea to do. Such a function will only work when called from a LabVIEW VI.

 

Things will get a lot harrier though as soon as you want to call functions that return a 1D or 2D array from the DLL. Here it will depend what the function that you call really does. It could expect the caller to pass in a preallocated array in which it copies the data. This is the safest method in terms of calling external functions and can be handled exactly the same as this case here in LabVIEW, but requires usually extra overhead as you first need to determine somehow how big of an array you need to preallocate before it can be passed to the function. Preallocation of an array in LabVIEW is done through the use of the Initialize Array function or the use of the Maximum Size parameter configuration but for multi dimensional arrays this last option is not so handy as you usually will have multiple parameters describing the size of each dimension while the maximum Size value requires a single parameter value to be selected (and using a fixed constant size is in most of these cases impossible as especially image data can have very different size requirements).

 

It could also return just a pointer that points to some internal memory that is only valid for the duration of the call. This is often done for performance reasons but highly unsafe to use in multithreading environments like LabVIEW. If you don't know exactly what you are doing here, you will create a perfect random crashomat.

 

Or it might also return a newly allocated pointer that you own after the function returns. This is multithreading safe but not ideal performance wise as LabVIEW can't do anything useful with this pointer. You will have to copy the data from this pointer into a LabVIEW allocated array and then deallocate the pointer to avoid memory leaks.

Rolf Kalbermatter
My Blog
0 Kudos
Message 4 of 15
(4,681 Views)

In this particular case, if you had attached the VIs rather than just images and in a version of LabVIEW at least two versions earlier than the current one (File->Save for Previous Versions...), I would have made that modification to your VI and attached it to my answer in your first post in the other thread already. Smiley Very Happy

Rolf Kalbermatter
My Blog
0 Kudos
Message 5 of 15
(4,671 Views)

Sorry but when I created my post, someone mark it as "spam" or something like this and it was the first time one of my post was marked like this. After this, it was written 0 reading on 4 like this my post wasn't visible anymore. It is why I reply to the other post where you answered me.

My mistake so 😞

Mathieu Gauquelin
0 Kudos
Message 6 of 15
(4,666 Views)

At a second glance I do see something that does worry me even about this particular function:

 

The function return value of 

unsigned short*

 

That is going to be a tricky one to solve and one of those things the Import Library Wizard (which you clearly used as demonstrated by the dumb CLN only VI wrappers and the ugly icons Smiley Very Happy) has absolutely no way to get right. The C header as well as the DLL simply does not provide enough information to know what one should do with this return value even for a human without additional information in the form of a function description in prosa form. And it seems the Import Library Wizard simply ignores this and does something to at least generate a VI, but one that will very likely cause problems when executed.

 

This is my thing I have with this Import Library Wizard. It is an amazing piece of software that tries to automate a highly complicated process. But the input it has (the C header file and the DLL in question) simply do not contain enough information to create always correct code. Basically the VIs generated by the Import Library Wizard ALWAYS will need a very knowledgeable person to review and verify them to be right, by not only verifying the code to the header file declaration but also consulting additional information in form of Function Description Manuals written in prosa by a human and accordingly requiring a human to read and interpret. But those people who are knowledgeable enough to be able to do that review and correction of the Wizard generated VIs will very likely start to more or less rewrite the Wizard generated code anyways to the point were creation of the VIs from scratch in a manual way is at least as efficient.

 

To summarize this: Without the actual Function Description for this function there is absolutely no way to get this right in any way.

Rolf Kalbermatter
My Blog
0 Kudos
Message 7 of 15
(4,662 Views)

@Mathieu33800 wrote:

Sorry but when I created my post, someone mark it as "spam" or something like this and it was the first time one of my post was marked like this. After this, it was written 0 reading on 4 like this my post wasn't visible anymore. It is why I reply to the other post where you answered me.

My mistake so 😞


I still can see your post in that thread and my answer with the (partial, after careful review as pointed out in my previous post) solution.

Basically the problem you have with the image array pointer is by far the least of your problems here. In fact it is no problem at all as LabVIEW provides the means to solve that completely with a simple reconfiguration of the Call Library Node parameter.

You need to worry about the return value of that function! As it is, it is absolutely wrong and without more information it is impossible to solve.

 

Another problem you might get in the future are your stringent assumption that sizeof(void*) == sizeof(int32). This will seem to be ok as long as you only use a 32-bit compiled DLL in 32-bit LabVIEW but will fatally break if you ever decide to move to 64-bit.

 

At least your handle absolutely and certainly should be configured as "(unsigned) pointer sized integer" in the Call Library Node and that requires you to use a 64-bit integer control on the front panel to pass this value between the VIs. That way you won't have to go into this library and change it everywhere when you ever decide to go to 64-bit and that time will come as the times where Windows will simply support everything to run 32-bit applications will sooner or later slowly deteriorate. (You still will need to go into this library and carefully review and check every single VI with scrutiny when you do go to 64-bit though).

 

The fact that your Import Library Wizard code seems to use 32-bit integers for pointer values also makes me wonder which LabVIEW version you are using. Recent versions of LabVIEW should be able to properly determine that the "pointer sized integer" configuration is the right one it should choose.

Rolf Kalbermatter
My Blog
0 Kudos
Message 8 of 15
(4,661 Views)

Hello,

 

Sorry for the late answer.

1) I am using LabVIEW 2013 32bits and my company won't change between 32/64bits because the 64bits version is very restricted (few functions, ...). Moreover my Visual Studio project is configured to be compiled in Debug/Release mode and 32/64bits so it is not a problem for now I think.

2) My functions always return an unsigned short pointer on the first pixel of the image as result of my DLL. The DLL use some libraries as Lapack, OpenCV, ... but my function always return a pointer from a matrix of the OpenCV library.

3) In the past, I had to change the return value of my C wrapper because of Python. I can modify my wrapper to make it work on LabVIEW if there is easier way to exchange a pointer between LabVIEW and my wrapper. I have 0 experience in this field so I begin with unsigned short because my images are on 16 bits, only positive values and in gray scale (not RGB). But I think I can use other type of data if you want.

 

Mathieu Gauquelin
0 Kudos
Message 9 of 15
(4,626 Views)

@Mathieu33800 wrote:

Hello,

 

Sorry for the late answer.

1) I am using LabVIEW 2013 32bits and my company won't change between 32/64bits because the 64bits version is very restricted (few functions, ...). Moreover my Visual Studio project is configured to be compiled in Debug/Release mode and 32/64bits so it is not a problem for now I think.

While it may not seem a problem now, the time will arrive when Windows will not support everything for 32-bit applications anymore and your company will have to move more and more to 64-bit. That may require you to recompile your tools too or use 64-bit LabVIEW to make something work and then you will be in extra troubles since many things you could avoid now with a little planning will need to be done in addition to the original plan.

 

I made you aware of the issue and you can put it aside as unimportant but it would cost you now a fraction of the time to prepare for that than it will cost you or someone else to port everything later.

 

2) My functions always return an unsigned short pointer on the first pixel of the image as result of my DLL. The DLL use some libraries as Lapack, OpenCV, ... but my function always return a pointer from a matrix of the OpenCV library.

And how big ist this memory area? Do you need this pointer at all in LabVIEW to do something with?

 

3) In the past, I had to change the return value of my C wrapper because of Python. I can modify my wrapper to make it work on LabVIEW if there is easier way to exchange a pointer between LabVIEW and my wrapper. I have 0 experience in this field so I begin with unsigned short because my images are on 16 bits, only positive values and in gray scale (not RGB). But I think I can use other type of data if you want.

You can't exchange pointers just like that between LabVIEW and other environments.

You have two options:

 

1) Treat it as pointer sized integer in LabVIEW. But this makes it difficult to do anything in LabVIEW with it. LabVIEW doesn't have a pointer data type on which you can do operations with the various LabVIEW primitives. As a pointer sized integer it can store the pointer value and you can pass it around to other DLL functions but not really much more. Trying to do more will require you to add additional functions to the DLL to which you can pass this pointer. A pointer also doesn't have any meta data such as the size of the memory it points to or the actual data format of the data in the memory (bit per pixel, color mode, row padding, interleaving and whatever, although you say you only use one specific format)

 

2) Put it in a LabVIEW array handle. This will allow you to do operations on the image data directly with LabVIEW primitives but .... there is no way to avoid having to create that handle each time and copy the data from the pointer into that handle. NONE!

 

Rolf Kalbermatter
My Blog
0 Kudos
Message 10 of 15
(4,622 Views)