I want to remind once again that all this information is just to have fun playing with LabVIEW and not intended for real projects use. I believe you all understand that. 🙂
Not that a big opening here and even not an opening for some ones, but I found this interesting enough to make a thread. As you may already know, when some library is being called using CLF Node, LabVIEW enters ExtFuncWrapper first to do some guard checks to prevent itself from a silent crash and output some error message to the user instead. I've always considered that wrapper boring enough to study, thus never looked inside. But when once again I faced that I can't call some function through CLFN and have to write my own wrapper library, I asked myself why we cannot call some code by its pointer as in almost any well-known text language?.. Therefore I decided to know how ExtFuncWrapper calls the function. It turned out that ExtFuncWrapper receives the function's pointer (along with the parameters struct pointer) and calls that pointer later as it is (i.e., not doing any manipulations with it). So we can use it to call any function and even any code chunk directly from the diagram! After further research I found ExtFuncWrapper not very convenient to use, because to bypass some checks the parameters struct should be prepared accordingly before the call. But there are many ExtFunc... wrappers in labview.exe and ExtFuncCBWrapper is much easier to use. It has the following prototype:
int32_t ExtFuncCBWrapper(uintptr_t CodeChunk, int32_t UseTLS, void *CodeParams); Here CodeChunk is our func / code pointer, UseTLS is 0 as we don't use LabVIEW's Thread Local Storage and CodeParams is our parameters struct. When called ExtFuncCBWrapper runs that CodeChunk, passing CodeParams to it, so we can freely use it later to do what we want. Nuff said, here are the samples.
This one increments a Numeric.
As you can see, I'm passing a Numeric value as CodeParams pointer into ExtFuncCBWrapper and in the assembly I have to pull that pointer out to deal with my parameters. I'm not that excellent in asm codes, so I used one of many online x86 compilers-decompilers out there. It's even simplier in 64-bit IDE as the first parameter is already written into RCX. Okay, here goes a more advanced example - it calculates a sum of two input Numerics.
Here I'm passing a cluster of three parameters as CodeParams pointer (two Numerics and the resulting Sum) and in the asm I'm grabbing the first parameter, adding it to the second one and writing the result into the third one. Pretty simple operations. Now let's do some really wild asm on the diagram! 😉 The latter example calls MessageBox function from user32.dll.
This is what Rolf calls a diagram voodoo. 😃 I have to provide 4 parameters to MessageBox, 2 of which are string pointers. Thus I'm getting these pointers and writing them into my params cluster (along with the panel handle and the dialog type). When ExtFuncCBWrapper is called, in the asm code I have to use the prologue and epilogue pieces to prevent the stack corruption as I'm pushing 4 parameters later onto the stack to provide them to MessageBox. After the call I'm writing the result into the function return parameter. In 64-bit IDE the prologue/epilogue is somewhat simplier.
Maybe you already noticed that I'm doing VirtualProtect before calling ExtFuncCBWrapper. This is done to pass through Windows Data Execution Prevention (DEP) protection. I'm setting execute and read/write access for the memory page with my code, otherwise LabVIEW refuses to run my code and throws an exception. Surprisingly it is thrown only in 64-bit IDE, but in 32-bit LV I can just wire the U8 array to ExtFuncCBWrapper, not going through that DSNewPtr-MoveBlock-VirtualProtect-DSDisposePtr chain. I did not start to figure out such a behaviour.
Well, to be honest, I doubt that someone will find all these samples really useful for his/her tasks, because these are very low-level operations and it's much easier to use a common CLFN or a helper DLL. They are here just to show that the things described are definitely doable from an ordinary diagram, and that doesn't require writing any libraries. With a good asm skills it's even possible to realize callback functions or call some exotic functions (like C++ class methods). Some things might be improved also, e.g. embedding a generic assembly compiler to have a possibility to write the codes instead of raw bytes on the diagram. Ideally it's even possible to implement an Inline Assembly Node. Unfortunately, I have neither the time nor much desire to do it myself.
Allows new functions to be compiled during runtime by using libtcc. http://bellard.org/tcc/
Features Full ANSI C compiler ISO C99 extensions (Missing only complex and imaginary numbers) GNU C extensions (See TCC Docs) TinyCC extensions (See TCC Docs) GNU-like inline assembler 32bit & 64bit opcodes depending on DLL (See TCC Docs) Compile to memory to call as function or disk as exe Allows for dynamic code Pointer safe checks
Adding 2 numbers and using return to get the result
Using system to call cmd
Inline x86 assembly
Passing in information using argc and argv
Using pointers to pass a string in and an SHA512 hash out
Uses libtcc unmodified, so for security reasons you can download the dll from the author's website or compile your own from source. The dll is included if you wish to use it.
Some very basic examples that show off only a tiny subset of the features this compiler offers. Unless you are very careful, compiling functions during runtime can lead to unstable code. (Test before you deploy) All examples should run without issue but modification can and will lead to crashing. (Save often)
I have been trying to use VIPM to distribute drivers that rely on a .NET framework that is unsigned (i.e not in the global assembly cache). My issue is that after the package is installed, none of the VIs will work because LabVIEW cannot locate the .net assembly. However, if I launch labview by opening the library VIPM installed, all of the VIs will work, and LabVIEW is able to locate the the .Net framework and it appears in the main application instance. I need to be able to use the installed vis all the time, not just when LabVIEW is launched in this particular way.
Here is a link to all the all the files I used:
Here are the steps I went through:
1) We put all the .NET dlls and the LabVIEW.exe.config file in the Labview directory.
2) We installed the package on our computer.
3)We closed everything and relaunched Labview from the start menu. Then accessed the BioRobotics/Vicon palette.
4)We placed the Get Ref subVI on the block diagram, opened it up, and ran it it.
5) We got the following error:
We also get a similar error for any VI that uses a method associated with the .NET dll.
6) However, if we again start with everything closed and launch Labview by clicking on the VICON.lvlib located in the vi.lib
7) Then repeat steps 3 and 4. We do not get any errors in the VIs on the palette, and the .Net assembly loads fine. We can even close the library and everything still works. Somehow opening the library first makes LabVIEW know to load the ViconDataStreamSDK_DotNet assembly when using functions on the Vicon palette.
If anyone does attempt to build a new package, it is worth noting that I included the dlls in the source files, and in the same folder as the vipb:
I am trying to export a class in LabVIEW 2013 to a .NET Assembly. According to this I can just select the members of the class that I want to export and it will generate a .NET class for them.
I am able to export the individual members of the class, but when I run the code in .NET it starts searching for mydllname.dll/myclassname.lvclass (the file of the class that the exported members belong to) and can't find it. My next step was to add the class to the the Always Included list, but it seems that when I do that some of the members that I have in the Exported VI's list don't show up in the .NET assembly. The class I'm trying to export is inhereted from another class, so I tried adding both classes to the Always Included list and all of the base class members to the Exported VI's list, but I still have members missing in the .NET classes. Thinking it could be something releated to exporting LVOOP classes, I tried ditching the LVOOP class altogether and rewrote the labview code to use generic VI's and a cluser typedef to store the member data. However, it seems like the labview builder doesn't recognize that the control and indicator clusers that I use to pass the member data belong to the same typedef, so it exports a different .NET class for each control and indicator cluster. This creates a problem because I have no way of passing the output of one funtion to the next in .NET since I cannot convert between the two .NET types.
Has anyone had problems like this/know how to fix it??? I couldn't find much online about building a .NET interop assembly beyond the basic configuration steps, so any help would be much appreciated!
I am trying to open shell32.dll with .NET but an exception is being thrown. I'm seeing this type of exception all over when I search google but really not much related to LabVIEW (mostly vb.net, c#.net etc). I have tried loading shell32.dll from system32/shell32.dll and SysWOW64/shell32.dll and both fail. I am running 32 bit LabVIEW on Windows 7 64 bit. I'm guessing it has something to do with that. I am going to try on a coworkers 32 bit computer when I get a chance, but does anyone have suggestions?
Edit: Tried on 32 bit labview on a 32 bit machine and it still fails.