Jump to content

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


Recommended Posts

Hello to everyone

I want to control IP PTZ camera via labview using Hikvision Device Network SDK. For this I want to use SDKs shared by Hikvision on their site.
I want to use the DLL files of the sample application from this SDK in labview. The code of this application's C# application is also available. The labview crashes every time I run the sample code I created by looking at the C# code.
What is the reason and solution for this?

Anyone who has dealt with this before and can interpret the C# code in a labview would really appreciate some help.

Every opinion given is worthy of respect

hikvision 4.vi

Link to comment

I have no experience with these cameras or Hikvision SDK, but some things on your BD caught my eye immediately.

  • Looks like the HCNetSDK.dll developer made all the functions to have stdcall calling convention, whereas your CLFN's use cdecl calling convention.
  • You've set NET_DVR_Login_V30 CLFN to accept only 4 input parameters, but the function wants 5 parameters.
  • You've set NET_DVR_Logout CLFN to accept 4 parameters, but the function needs only 1 parameter.
  • In some CLFN's the parameter types don't match the prototypes exactly, e.g. wPort should be U16 (WORD), not U32 (DWORD). Use Windows Data Types table to find out, what WinAPI types represent.

These are the prototypes for NET_DVR_Login_V30 and NET_DVR_Logout (as written in Device Network SDK Programming User Manual V4.2):

LONG NET_DVR_Login_V30(
char *sDVRIP,
WORD wDVRPort,
char *sUserName,
char *sPassword,
LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo
)
BOOL NET_DVR_Logout(LONG lUserID)
  • Like 1
Link to comment

Still not everything is correct on your diagram. Since lpDeviceInfo is an output parameter of that NET_DVR_Login_V30 function, it requires the memory to be allocated before the function is called. You can't feed an uninitialized pointer into the function. In LabVEW to pass a struct into a function you have to make a properly sized cluster (of 80 bytes in our case) and wire it to the CLF Node. This is how NET_DVR_DEVICEINFO_V30 struct is declared:

struct{
  BYTE     sSerialNumber[SERIALNO_LEN];
  BYTE     byAlarmInPortNum;
  BYTE     byAlarmOutPortNum;
  BYTE     byDiskNum;
  BYTE     byDVRType;
  BYTE     byChanNum;
  BYTE     byStartChan;
  BYTE     byAudioChanNum;
  BYTE     byIPChanNum;
  BYTE     byZeroChanNum;
  BYTE     byMainProto;
  BYTE     bySubProto;
  BYTE     bySupport;
  BYTE     bySupport1;
  BYTE     bySupport2;
  WORD     wDevType;
  BYTE     bySupport3;
  BYTE     byMultiStreamProto;
  BYTE     byStartDChan;
  BYTE     byStartDTalkChan;
  BYTE     byHighDChanNum;
  BYTE     bySupport4;
  BYTE     byLanguageType;
  BYTE     byVoiceInChanNum;
  BYTE     byStartVoiceInChanNo;
  BYTE     byRes3[2];
  BYTE     byMirrorChanNum;
  WORD     wStartMirrorChanNo;
  BYTE     byRes2[2];
}NET_DVR_DEVICEINFO_V30,*LPNET_DVR_DEVICEINFO_V30;

This NET_DVR_DEVICEINFO_V30 struct is a bit bulky to form, so here's a VI from which you can copy it and paste to your own VIs.

NET_DVR_DEVICEINFO_V30.vi

Now in your CLFN set this 5th parameter as Adapt to Type -> Handles by Value. With such a setting LabVIEW will pass a pointer to the NET_DVR_DEVICEINFO_V30 cluster and after the function call you should receive it filled with some device data.

Also to note, LONG is I32 on Windows, not I64.

Link to comment

I have made corrections according to your answers. I think it works. But when I enter 8000 ports, the labview is completely closed, if I set the port as 554 and 80, I get an error code 10 return and the labview does not crash.
Error code of network communication library
Error code 10= ''Timeout when receiving the data from the device''
The application I want to create is on (Device Network SDK Programming User Manual)Page 26-27. What do you think is the solution to this problem?

 

The updated code is as follows.

hikvision 6.vi

Edited by alvise
Link to comment

Well, it's time when things get more complicated. The NET_DVR_RealPlay_V30 function needs a callback function to be registered, in order to transfer live stream data. But it's not that easy to implement callbacks in LabVIEW. You would have to write a small wrapper DLL, that would receive the data and pass it to LabVIEW with PostLVUserEvent function and then in LabVIEW you'd be able to catch those events in your Event Structure. Are you sure, you can't work with these cameras using NI-IMAQ(dx) and NI Vision? Can you see your camera in NI-MAX? As an alternative, you could try to use VLC API, if the camera transfers common RTSP stream and you know its address.

Link to comment

Thanks for your help.

-With this camera, it does not appear as a direct usb com port with NI-IMAQdx. Because it needs to encode MPEG4 or H.264 video, but labview only supports MPJEG.
-Video can be streamed over VLC RTSP, but the video is delayed.

The C# code I want to create is as attached. It contains the PTZ control.
I guess I need to search for the wrapper DLL.

While examining the C# example(Preview.cs), I saw that ''HCNetSDK.NET_DVR_RealPlay_V40 '' is used for video streaming. I guess this does not change the situation.

Preview.cs PreSet.cs

Edited by alvise
make it easier to find the answer to the question
Link to comment
2 hours ago, alvise said:

I guess I need to search for the wrapper DLL.

I'm afraid you'll have to write it on your own. It's not that super tricky, but requires some basic C knowledge. Here's the post, that could be a good starting point (as it was for me many years ago):

 

Link to comment

How exactly can I create the callback function in labview. The callback event is a bit complicated I guess. Does the wrapper Dll you mention have to be written specially?
Now this situation is starting to seem quite complicated for me :)

Link to comment

Looking at the C# example, I'm trying to gather the labview code and understand how to use the callback event, and I added the renewed code (I don't know if I'm progressing correctly). There are some things I still don't understand.
In the C# example, "pUser" and

        public void RealDataCallBack(Int32 lRealHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser)
		{
            if (dwBufSize > 0)
            {
                byte[] sData = new byte[dwBufSize];
                Marshal.Copy(pBuffer, sData, 0, (Int32)dwBufSize);

                string str = "ʵʱ������.ps";
                FileStream fs = new FileStream(str, FileMode.Create);
                int iLen = (int)dwBufSize;
                fs.Write(sData, 0, iLen);
                fs.Close();            
            }

IntPtr pUser    also in this line. 

m_lRealHandle = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, null/*RealData*/, pUser)

 

Extra: What I want to create now is just a screen that shows the video and the PTZ control. Is it possible that this is that hard in Labview?

 

Am I the only crazy one who wants to control these cameras with labview why no examples :)

hikvision 7.1.vi

Link to comment

You need to create a standard native Windows library (DLL). You may use any IDE of your choice, that's able to do that, e.g. Microsoft Visual Studio (Community Edition is fine as well). In that IDE you need to export the function with the following prototype:

typedef void(CALLBACK *REALDATACALLBACK)(
  LONG      lRealHandle,
  DWORD     dwDataType,
  BYTE      *pBuffer,
  DWORD     dwBufSize,
  void      *pUser
);

Make sure your exported function matches it exactly. Also you need to include "extcode.h" from [LabVIEW]\cintools directory, because you're going to use PostLVUserEvent LabVIEW Manager function. The logic is that you don't do anything in your callback except calling PostLVUserEvent, passing pBuffer into it. But if you want to use more than one camera in parallel, then more logic is needed. You could try to use lRealHandle or pUser parameters to distinguish the cameras. Start with an easy setup of one camera for now. In LabVIEW you need to call LoadLibrary and GetProcAddress functions from Windows API, in order to load you DLL and get the address of your callback. You pass this address into NET_DVR_RealPlay_V40 upon the call. After that you register your user event and wait for it in your Event Structure. If everything is done right, you should receive the events right after calling NET_DVR_RealPlay_V40. Read vugie's post in the topic, I linked above, to get the main idea.

Also please don't mix C# and C/C++ here, they are different beasts. Of course, you may learn from C# examples, but you're trying to use C/C++ written library through CLFN's, so you need to use C/C++ language to create the callback. If you were to use C# and .NET assemblies, you'd use instruments from the .NET palette.

Edited by dadreamer
Link to comment

There is a reason why so many pleas for support of camera access are out there and no single properly working solution except paid toolkits: Actually it's not one but a plethora of reason.

- cameras use lots of different interfaces

- they often claim to follow a certain standard but usually don't do so to the letter

- there are about several dozen different communication standards that a camera manufacture can (try) to follow

- it involves moving lots of data AFAP which requires good memory management from the end user application down to the camera interface through many layers of software often from different manufacturers

- it costs time, time and even more time to develop

- it is fairly complex and not many people have the required knowledge to do it beyond a "Look mom it keeps running without needing to hold its hands (most of the time)"

 

Callback function are not really magic, but there is a reason they are only mentioned in the advanced section of all programming textbooks I know (if they are mentioned at all). Most people tend to have a real hard time to wrap their mind around them. It starts for many already with simple memory pointers but a call back function is simply a memory pointer on steroids. 😀

And just when you think you mastered them you will discover that you haven't really started, as concurrency and multithreading try to not only throw a wrench in your wheels but an entire steam roller.

Edited by Rolf Kalbermatter
  • Haha 1
Link to comment

good answer :)
This camera's SDK is shared, but I have insufficient knowledge of C++ or C# when trying to generate the required code. After a long hiatus from using the C++ language, even looking at the visual studio code editor, I feel like I was forgotten on mars. This indicates that I need to work again to create the required dll file.
Although at first it seemed like something I could only do with labview, now I'm starting to understand the depth of it.
With dadreamer help, we can read the information from the camera with the labview, but there is a problem in the video stream part.

I'm reviewing the code here. I am researching and reading useful information.
https://forums.ni.com/t5/Sample-Code/Post-Events-to-a-LabVIEW-Event-Structure-From-a-Dll/ta-p/3996283

 

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

And just when you think you mastered them you will discover that you haven't really started, as concurrency and multithreading try to not only throw a wrench in your wheels but an entire steam roller.

Callbacks is the one instance when I would suggest a .NET solution in LabVIEW (in the absence of anything else) for all of these reasons and everybody knows what I think about .NET :)

image.png.c217ce52684434afe9fef4123054bde9.png

Edited by ShaunR
Link to comment

Thanks everyone for the replies.
Right now, I'm pretty confused. I've looked through all the searches on Google, but I've been looking blankly as there are a lot of things I can't understand at the moment.

Some reasons why I am confused:
-First of all, I'm trying to prepare a dll file with C++, but how can I create it? For example: Here is the code

 

Quote
typedef void(CALLBACK *REALDATACALLBACK)(
  LONG      lRealHandle,
  DWORD     dwDataType,
  BYTE      *pBuffer,
  DWORD     dwBufSize,
  void      *pUser
);

How am I going to use the code here as an output function.

-second case, I'm looking at the examples here.Is ''iCube Camera in'' here a wrapper dll file? what?

-third case: How is the "Reg Event Callback" mentioned by ShaunR used in my case and what is the problem in its use?

-fourth case: dadreamer , what do you mean by labview may bite you in addition to not fully understanding how to use the event you mentioned?

-finally: I know there are many ways to reach that stage, but I'm asking to get the whole thing in my head.How do I use the video screen output? Is the .Net function used or how?

It would really help if someone could tell me how to proceed step by step because I can understand it with practice. Everything is abstract for me right now.

Thank you for any ideas given.


 

 

 

 

Link to comment
2 hours ago, alvise said:

How am I going to use the code here as an output function.

1) You don't, since it is not code. It is the function prototype (actually the function pointer declaration) of a function that YOU have to implement. And then you pass the name of that function as parameter to the other function that wants this callback function. Whenever that other function thinks it wants to tell YOU something it calls that callback function with the documented parameters and YOUR callback function implementation does then something with that data. But your function is called in the context of the other function at SOME time after you called the original function that you passed your callback function too. Are you still with me? If not, don't worry, most people have big trouble with that. If yes then you might have a chance to actually get this eventually solved. But don't expect to have this working tomorrow or next week. You have a steep learning curve in front of you.

2) The iCube Camera in is simply a LabVIEW class that handles the whole camera management in LabVIEW, and in some of its internal methods accesses the DLL interface, and creates the event message queue, and starts up an event handler, and ..., and ..., and ....

3) The RegEventCallback function is a LabVIEW node that you can use to register events on CERTAIN LabVIEW refnums. One of them are .Net refnums, IF the object class behind that refnum implements events. .Net events are the .Net way of doing callbacks. It is similarly complex to understand and implement but avoids a few of the more nasty problems of C callback pointers such as datatype safety. But to use that node you will need a .Net assembly that exposes some object class which supports some events of some sort. Since .Net uses typesafe interface descriptions, LabVIEW can determine the parameters that such an event has and create automatically a callback VI and connect it behind the scenes with the .Net event. It works fairly good but has a few drawbacks that can be painful during development. Once the callback VI has been registered and activated, it is locked inside LabVIEW and there are only two ways to get this VI back into an editable state.  Restart LabVIEW or after the object classes on which the event occured have been properly closed (Close Reference node) you need to explicitly call the .Net Garbage Collector in LabVIEW to make .Net release the proxy caller that LabVIEW created and instantiated to translate between the .Net event and the LabVIEW callback VI.

If you have a .Net assembly that exposes events for some of its object classes, it is usually quite a bit easier to interface from LabVIEW than trying to do callback pointers in a C(++) DLL/shared library. Writing an assembly in C# that implements events is also not really rocket science but definitely neither a beginners exercise.

4) If you interface to C(++) in LabVIEW there is no safety net, sturdy floor, soft cushions and a few trampolines to safe your ass from being hurt when something doesn't 100% match between what you told LabVIEW that the external code expects and what it really does expect. It's in the best case a hard crash with error message, the next best case is a hard crash with no error message and after that you are in the lands of maybes, good luck and sh*t storm. A memory corruption does not have to immediately crash your process, it could also simply overwrite your multimillion dollar experiment results without you noticing until a few hours later when the whole factory starts to blow up because it is operating on wrong data. So be warned, thread safely and make sure to have your C(++) solution tested by someone who really understands what the potential problems are, or don't use your code ever in a production environment. This is the biting in your ass that dadreamer talked about, and it is not really LabVIEW that did it, but you yourself!

5) Which video screen output are you talking about? Once you managed to get the camera data into your LabVIEW program without blowing up your lab? Well you could buy IMAQ Vision or start another project where you will need to learn a lot of new things to do it yourself. 🙂

Edited by Rolf Kalbermatter
  • Like 1
Link to comment

OK. You are clearly drowning in the learning curve so lets get back to basics. You need a strategy!

You have a working example (Preview.cs). Do you know how to compile it? If not, that's your first task-get an executable out of the example code. This will be your golden standard for checking your program is doing things right.

Next. That example saves a file in the callback (实时流数据.ps). You may have to change the filename to an ascii one for LabVIEW to read it as LabVIEW doesn't support Unicode. You should be able to read that file from LabVIEW (after is is closed). That is the raw data that you would normally get back from a callback. Read that file in LabVIEW and figure out how to interpret it (it's a byte array [array of u8]. The callback is

public void RealDataCallBack(Int32 lRealHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser)

This callback (for a .NET Assembly or a similar one for C[++]) would be where you put the PostLVUserEvent instead of saving to a file. Your problem at that point is telling the callback to use a LabVIEW refnum.  Don't worry about putting that in for now, we can talk about that later.

Once you get that far, you will be a long way through the learning curve for this API but just by reading the file you can work on presenting the data [U8 array] in LabVIEW (you will feel progress) while you think about how to get the data directly. Look to see what the example code is doing with it and replicate it in LabVIEW.

There are also other functions that you can call directly from LabVIEW that don't require a callback (e.g. NET_DVR_CaptureJPEGPicture & NET_DVR_CapturePicture) and take normal parameters that you can pass directly. Get those working from LabVIEW (more progress)

Edited by ShaunR
Link to comment

thanks for the answer. What I really needed was to go step by step. I will inform you after I have followed each step.

Quote

You have a working example (Preview.cs). Do you know how to compile it? If not, that's your first task-get an executable out of the example code. This will be your golden standard for checking your program is doing things right.

I tested the application created as preview.exe, everything works correctly.I can compile preview.js. I am currently trying to compile it.

Quote

There are also other functions that you can call directly from LabVIEW that don't require a callback (e.g. NET_DVR_CaptureJPEGPicture & NET_DVR_CapturePicture) and take normal parameters that you can pass directly. Get those working from LabVIEW (more progress

I can see the function names you mentioned here in HCNetSDK.dll.
So you're talking about the possibility of using them directly to receive video streams?

 

but I will go through everything step by step and give you feedback.

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.