Jump to content

Using the DLL files of an application compiled with C# with labview


Recommended Posts

11 minutes ago, alvise said:

for the dadreamer I took on what he said :) and created an example using System.windows.form and picturebox and it works too.I do not know if it is the right way.
When I test the sample you sent, sometimes random numbers appear on the screen.

Remove the numeric indicator on that Empty.vi. It is a left over from the earlier test. As to using the .Net Picture box for a canvas area to let the SDK library draw its image in, that's also an option. I simply have a distaste for .Net things, especially when using it inside LabVIEW. It feels very dirty. 😀

Quote

What I need is to use this image with IMAQdx afterwards.

I was afraid you would say something like this! Good luck on that! You will need it! And you do not want to use IMAQdx here but the IMAQ Vision library. Still, you will need a lot of patience. This so far was just foreplay in comparison to what expects you to get that one working! And I'm absolutely not kidding here, or even slightly exaggerating. Expect to suffer and feel a lot of pain on the path there.

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

Edit: I'll be damned! A VI inserted into a Subpanel does not have a window handle at all. I thought I had tested that but somehow got apparently misled in some ways. LabVIEW seems to handle that all internally without using any Windows support for that. So back to the drawing board to make that not a Subpanel window but instead using real Windows Child window functionality. I don't like to use the main VIs front panel as the drawing canvas as the library would draw all over the front panel and fighting LabVIEWs control and indicator redraws.

I managed to check that on few machines with few LabVIEW versions, including 2011, 2013, 2018 and 2019 (32- and 64-bit) as I seldomly use subpanels and never ever wondered about how the VIs are embedded. Looks like this is the case, when an old-fashioned MDI relation has an advantage of providing handles to operate the windows on OS level. Sure, you know, that it could be done with SetParent function. But there are a lot of disadvantages and odd issues too, so it's a doubtful method. As I remember, there's private Open In Native Window method, that tries to supersede an obsolete Open In Window method. The latter works well in LV8.5, but doesn't work absolutely in LV 2009 and higher. But the new method doesn't work anywhere at all! I have spent more than a week trying to understand why. Still sort of a mystery, but I think there was a mistake made in the code, when introducing the new method. There's something wrong with the window styles and that's why the child window doesn't get embedded into the parent window. Interesting puzzle but almost an off-topic here. 🙂

Edited by dadreamer
Link to comment
On 5/14/2022 at 1:00 PM, Rolf Kalbermatter said:

The biggest problem is providing a callback function pointer that is matching exactly what the library expects. If you compile a C source code that implements that function then you can let the C compiler do all that work, but I was under the impression that you were looking for a solution that avoids the need to have the end user of the solution to compile a C code file that has to be also specifically adapted to the callback interface that library expects.

I still think this is possible. It's been a couple of years since I wrote C++ so will have to brush up to investigate.

Link to comment
25 minutes ago, ShaunR said:

I still think this is possible. It's been a couple of years since I wrote C++ so will have to brush up to investigate.

If you use libffi or another like library it's relatively simple.

C or C++ features alone won't cut it!

Unless maybe if you talk about C25 or something like that. 😀

Edited by Rolf Kalbermatter
Link to comment
Posted (edited)
1 hour ago, Rolf Kalbermatter said:

I was afraid you would say something like this! Good luck on that! You will need it! And you do not want to use IMAQdx here but the IMAQ Vision library. Still, you will need a lot of patience. This so far was just foreplay in comparison to what expects you to get that one working! And I'm absolutely not kidding here, or even slightly exaggerating. Expect to suffer and feel a lot of pain on the path there.

Sometimes when I can't remember the names of some jobs, I remember the names of the functions inside, I say it right away, it's not a problem because it's mostly clear what I mean :)

I realize I have a lot more work to do since I'm trying to build an SDK exactly.I am aware of the mountain standing in front of me :)
-Reading 2 channels of video from one ip address at the same time.
-Using reading videos with NI-VISION.
-Control the PTZ.

Edited by alvise
Link to comment
1 hour ago, alvise said:

Sometimes when I can't remember the names of some jobs, I remember the names of the functions inside, I say it right away, it's not a problem because it's mostly clear what I mean :)

I realize I have a lot more work to do since I'm trying to build an SDK exactly.I am aware of the mountain standing in front of me :)
-Reading 2 channels of video from one ip address at the same time.
 

The two video streams should be not a problem. The existing library should be able to do that already, you simply need to start the two streams separately with their respective lChannel and direct them to two different windows.  And then eventually stop the two streams also separately by calling the Stop Real Play function on each of the respective lRealHandle. That library is meant to do that which is, why the Start Real Play function returns a handle that manages the specific stream.

It's what follows after that which will test your patience and your seating leather as you will smack on your ass over and over again when your LabVIEW process crashes on you.

Edited by Rolf Kalbermatter
Link to comment
Posted (edited)

I created it as you said, now I can get images from two channels at the same time. I turn it off and on every time, there is no problem. Of course, I don't know if there is still a problem.It detects two users at each login. Each user uses a different channel.

Session values are based on one channel opening earlier than the other.login count 12-11/12-13

image.png.dbb08fa96034dc1596d519588d9318bf.png

image.png.47508cfc9b690ed76879af59cd851709.png

Your comment is important in this regard.If that's good I'll switch to PTZ control.

 

113624656_Hikvision-labviewSDK-v1.0.1.rar

Edited by alvise
Link to comment
Posted (edited)

I'm currently struggling with PTZ control and I haven't really figured out how to implement it.

image.png.5fdc1306ea3f0e69585df88ae9cb8120.png

image.png.6d888db787ca89366a08e624e671d2fb.png

I have come to the final stage of this ip camera.

Here it says that the LPVOID structure receives PTZ_POS information, but I don't know if I am giving it correctly. It wants as buffersize(byte) how these values should be given. I am controlling the zoom with the code below, but I think I made a mistake and the motors are making noise. Can someone help me before I burn the motors :)

PTZ POS SET.vi

Edited by alvise
Link to comment
3 hours ago, alvise said:

I'm currently struggling with PTZ control and I haven't really figured out how to implement it.

image.png.5fdc1306ea3f0e69585df88ae9cb8120.png

image.png.6d888db787ca89366a08e624e671d2fb.png

I have come to the final stage of this ip camera.

Here it says that the LPVOID structure receives PTZ_POS information, but I don't know if I am giving it correctly. It wants as buffersize(byte) how these values should be given. I am controlling the zoom with the code below, but I think I made a mistake and the motors are making noise. Can someone help me before I burn the motors :)

PTZ POS SET.vi 20.87 kB · 0 downloads

It seems you have placed transparent nodes in your VI and wired them all up with transparent wires. 😀

That function is simply expecting specific parameters in the lpInBuffer, and what data should be in there depends on the value of dwCommand.

So you have to do some manual work here. First you need to figure out what command you want to use. Look its numeric value up in the header file.

Then look the definition of the data structure up in the header file that is in the same row behind the command name in your SDK documentation.

 

As example if you may want to change PTZPOS you need to find the NET_DVR_SET_PTZPOS value which is 292, also documented in the last column of the Remarks table. This number must be passed to the dwCommand value.

According to the SDK this command parameter requires the NET_DVR_PTZPOS data structure which is defined like this:

struct{
  WORD     wAction;
  WORD     wPanPos;
  WORD     wTiltPos;
  WORD     wZoomPos;
}NET_DVR_PTZPOS, *LPNET_DVR_PTZPOS;

You need to build this data structure as a LabVIEW cluster but EXACTLY. In this specific case you need to create a cluster that contains the 4 numeric values of uInt16 integers. You can pass this directly to the functions lpInBuffer parameter by configuring it as Pass Native Datatype.

Then you need to calculate the bytes size of that data structure and pass that in as dwInBufferSize. This is 4 times 2 bytes, so 8.

 

Edited by Rolf Kalbermatter
Link to comment
Posted (edited)

Oh my god I didn't realize I added an empty VI :) I'm adding it again. By the way, am I going right with the method I added? 

WORD wPanPos;
     WORD wTiltPos;
     WORD wZoomPos; takes floating values. how do I do this

As in the example, if I configure the Numeric control directly as float, it will not cause a problem, right?

PTZ POS SET.vi

Edited by alvise
Link to comment

Seems about right. A few comments:

- You don't need the numeric conversion nodes. They do nothing as the incoming type is already what you convert it to.

- That function returns a Boolean error indicator. If the value is TRUE it was successful. Otherwise you should retrieve the last error code to get an indication what went wrong. Just use the error handler VI I used in the same way as I did in "Init Driver.vi" of my little "LabVIEW SDK".

 

The SDK states: Actual PTZ value is one-tenth of the got value, for example:

if the got P value is 0x1750, the actual P value is 175 degree;
if the got T value is 0x0789, the actual T value is 78.9 degree;
if the got Z value is 0x1100, the actual Z value is 110 degree.

So use a floating point value as VI input, multiply it by 10. And then the fun starts as they seem to want to get hex values that correspond to the actual degree value. I'm sure there is a mathematical formula for that but my jerk reaction to this would be to convert the result into a string with the %d format specifier and then back into a 16-bit integer number with the %x format specifier. Dirty, non-performant but it does the job.

 

Note: After fetching a coffee the enlightening idea came to me. The mathematical formula for this would be

hexval = exp16(log10(inputvalue) + 1)

image.png.e5bf14d98881217824fc0d252c4f945a.png

Edited by Rolf Kalbermatter
Link to comment
Posted (edited)

When I test it this way, it gives wrong results. wPanPos: Min=0 It is in the range of Max=360 degrees.
But if I say go to 20 degrees, it goes to 13 degrees.

image.png.c1b700ba8e1bdd0f3b06f0a4001dfb5f.png

Edited by alvise
Link to comment
3 hours ago, alvise said:

When I test it this way, it gives wrong results. wPanPos: Min=0 It is in the range of Max=360 degrees.
But if I say go to 20 degrees, it goes to 13 degrees.

image.png.c1b700ba8e1bdd0f3b06f0a4001dfb5f.png

Yes of course it was a little to short in thought. Although what you report sounds wrong. It should give you something like 23 degree. It scales the decades correctly but also tries to scale the interval in between each decade which it should not. This makes that the results like 1.0, 10.0, 100.0 are correct but values in between get over scaled, not under scaled.

 

Decimal to Hex.png

Link to comment
Posted (edited)

In this example, I want to use the stream displayed in the pictureBox with IMAQ, but I can't get the picture from the picture box. I tried many ways, but I'm encountering problems.
I've gone through the examples in the forum and tested, but haven't been able to find the exact solution.I read the discussion here, I did some tests, but I didn't get any results.

In the examples here, I just added a picture to the Picturebox. I couldn't read the video from the Picturebox.

I am getting an error like in the picture, what could be the reason?

image.png.9de5b7beec70df4097c987fe560f3d9c.png

Can you help with this ?

 

Get Image Data From PictureBox.vi

Edited by alvise
Link to comment

You happen to read the Image object, when it's not instantiated yet, hence you receive 1172 error. You need to read it out only after your image data is loaded into the PictureBox control.

2022-05-26_10-11-27.jpg.e2a59bbb1e5e2a4131af446ec26352d3.jpg

Try to add your code piece into the Value Change frame plus add a simple NULL check. That should work, but if not, then you need to find a way to synchronize image write thread with image read thread (with callback that would be easier).

Link to comment

As I understand from you, I made an arrangement like the one below, but I did not add the event structure to read the picture because the event structure only works once when the start button is pressed.
But this shouldn't be a problem. Also, I can't read a picture from the picturebox at the moment, I'm just adding a picture to the picturebox. What is the reason for this?

image.png.75279184373279dc508913e49aed9e35.png

it tries to show the photo I added on the display screen (picturebox) and the image from the camera at the same time.I just want to convert the image in the picturebox to an IMAQ image :)

image.png.e8c0f75c079fada9ba1f39ff9dfe2b30.png

 

Link to comment

You don't need this!

image.png.75279184373279dc508913e49aed9e35.png.4b1ea86e1cb9bea35600f1fda1740ed3.png

This was just to demonstrate that when the Image object is initialized, no errors occur on reading after.

22 minutes ago, alvise said:

but I did not add the event structure to read the picture because the event structure only works once when the start button is pressed.

My bad, I didn't realize that when answering 😃 Then you should move that PictureBox reading into a parallel While loop and see, what will happen. This way you're not synchronizing the threads and may miss some data frames though (due to different rates of the loops).

Link to comment
Posted (edited)

In 2D picture, the image of the camera is not taken, if I add different while loops, it still does not solve the problem because it cannot read the video from the picturebox.

If I press the quit button, I get an error as follows.

image.png.4edfb232980068f19b1a515868fbafe6.png

 

image.png.fb40dec9336a70c50ac7725f44a9ee92.png

The picturebox only works once and then there is no visible data exchange. Because of this, no picture can be taken from here. What I don't understand is how does this happen?

Edited by alvise
Link to comment
8 minutes ago, dadreamer said:

2022-05-26_17-41-55.jpg.00f7b9dbe306b2849b1727b43f719e2c.jpg

Are you sure the handle can not get negative? In fact I'm pretty sure the handle could get 64 bit on LabVIEW 64-bit. It usually shouldn't as Microsoft tried to keep the handle values below the 32 bit boundary by somehow not directly making it a pointer, but I have seen cases where Windows handles did use the upper 32-bit for something and failed if you treated the handle only as 32-bit, effectively clearing out the top most 32 bits. I think the safest here would be to use ToUInt64(). It shouldn't hurt even if Windows never uses more than 32-bit but it may prevent potential problems in the future.

Edited by Rolf Kalbermatter
Link to comment

image.png.23f2b0df900176f142ce63f61cbf03ec.png

image.png.6b0f10aafb24c1b4a59bac03ad960efe.png

 

There is no error but it is not in the picture. What I don't understand is if I use a case structure that runs when a number other than 0 comes up, I get this error.I think it's like this because it didn't get any stream from the picturebox

 

image.png.df643a0082f49487d445532b6fedc607.png

Link to comment
32 minutes ago, Rolf Kalbermatter said:

but I have seen cases where Windows handles did use the upper 32-bit for something and failed if you treated the handle only as 32-bit, effectively clearing out the top most 32 bits.

I still don't quite understand this.

Windows Handles are indexes into the Handle Table and is limited to something like 16M

Link to comment
54 minutes ago, ShaunR said:

I still don't quite understand this.

Windows Handles are indexes into the Handle Table and is limited to something like 16M

Well, a handle is in terms of the C signature simply a pointer sized integer.

typedef void * HANDLE;

That it is "usually" a 24-bit index into a Windows object table specific to your handle type, doesn't mean that every API that "exports" a HANDLE data type also uses this. For one it only applies to objects that the Windows kernel manages. Second, the functions to create such handles for your own handle type are located in ntoskrnl and as such considered non-public Windows APIs. While you can call them directly and in some cases some of those APIs are documented at least in the Windows DDK, using them is at your own risk and potentially a compatibility liability as Microsoft does specifically not guarantee these APIs to not change in their signature or behaviour, nor simply disappear at any point in a new Windows version.

Also that 24 bit index is only part of the truth, the rest of the standard 32-bit value is used to encode the type of handle and allows to verify that the handle is actually for the object table the caller claims it to be. As such it is almost exactly like a LabVIEW refnum which implements pretty much the same semantics. Only that LabVIEW refnums are also guaranteed to be always 32-bit entities as that is how NI publically defined them and they did not change that definition in the published API code when adding support for 64-bit LabVIEW in 2009.

Microsoft on the other hand declared a HANDLE to be a pointer sized entity since many moons ago. Only very early Windows SDKs did define the HANDLE to be an alias for a DWORD. At some point they consistently changed that to a LPVOID, respectively a pointer to an anonymous struct (and in some scenarios even a pointer to a struct containing an int value).

So while in most cases a HANDLE indeed is simply a 32-bit integer under the hood, that is always an implementation specific detail that you rely on for that specific type of handle. It may not hold true for every handle, especially APIs that to not refer to kernel objects itself but simply use the HANDLE data type as an opaque parameter to pass their own object identifier between API calls, which in many cases can be a pointer to a struct. And since a HANDLE is defined to be an anonymous identifier whose implementation is implementation specific, that is all very legal.

And in programming it is always a bad idea to rely upon implementation specific details behind abstract interfaces. So if you want to treat your HANDLEs as 32-bit value because it USUALLY works, that is up to you. I prefer to work according to the published definition and if that wastes 32-bit of memory on a 64-bit platform because the higher significant 32-bit are never used, so be it. It will guarantee that the software will keep working when the underlying API one day decides that the private and hence undocumented implementation detail of what the handle really means will change. Will that cause a compatibility nightmare for all the software which never bothered to follow the actual spec rather than private implementation specific details? You bet. Is it likely to happen? Maybe not. 

And for any API using the HANDLE for anything else than Windows kernel objects, it really and absolutely can matter already today. And you may not always know if an API uses this data type for a real kernel object or something entirely different for its internal implementation.

Edited by Rolf Kalbermatter
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.