-
Posts
361 -
Joined
-
Last visited
-
Days Won
36
Content Type
Profiles
Forums
Downloads
Gallery
Everything posted by dadreamer
-
Assistance with Old Tabor plug and play drivers- can't find .dll file
dadreamer replied to Ronin7's topic in LabVIEW General
As I see, ww257x_32.dll statically depends on the following: TE5351.dll TeViEnet.dll cvirt.dll The first two are in the same "WW-257X IVI Driver 1.1.14" archive and for the latter you may try installing LabWindows/CVI Runtime (Legacy) or LabWindows/CVI Runtime for 8.5 version as suggested on the driver page. Besides of that both TE5351.dll and TeViEnet.dll depend on VISA32.dll, so you should have NI-VISA 4.6 (or above) installed too. Plus there's IVI Compliance Package 3.2 requirement. -
Usual disclaimer. Method described below is strictly experimental and not recommended to use in real production. N.B. This is based on .NET, therefore Windows only. This text is sorta lengthy, but no good TL;DR was invented. You may scroll down to the example, if you don't want to read it all. One day I was stalking around NI forums and looking at how folks implement their callback libraries to call them from LabVIEW. After some time I came across something interesting: How to deal with the callback when I invoke a C++ dll using CLF? There someone has figured out how to make LabVIEW give us a .NET delegate using a dummy event. This technique is different from classic way of interfacing to callbacks, because it allows to implement the callback logic inside a VI (not inside a DLL), but still it requires writing some small assembly to export the event. Even though Rolf said there that it's not elegant, I decided to study these samples better. Well, it was, yeah, simple (no wonder it was called SimpleProxy/SimpleDemo/SimpleCallBack) and very instructive at the same time. It worked very well in both 32- and 64-bit LabVIEW, so I had fun to play around and learn some new things about .NET events and C#. After all I started to think, whether we really need this dummy assembly to obtain a delegate... Initially I was looking for a way to create a .NET event at the run-time with Reflection.Emit or with Expression Trees or somehow else, but after googling for few days and trying many things in both C# and F# I came to a conclusion that it's impossible. One just can create event handlers and attach them to already existing events, not create events on their own. Okay. First I decided to know how exactly LV native Register Event Callback node works. Looking ahead I'll say it was a dead end, but interesting. Ok, the Register Event Callback node in fact consists of two internal functions - DynEventAllocRegInfo and DynEventRegister - with the RegInfo structure filling between them. The first one creates and returns a new RegInfo with a Reg Event Callback reference, the second one actually registers the RegInfo and the reference in the VI Data Space (the prototypes and the struct fields are more or less figured out). But when I started to play with the CLFN's to replace the Register Event Callback node, I ran into few pitfalls. To work properly the DynEventRegister function needs one of the RegInfo's fields to be a type index of (hidden) upper left terminal of the Constructor node. This index is stored in the VI's Data Space Type Map (DSTM) and determined at the compile time. I did not find a reliable way to pull it out of the DSTM. Moreover the RegInfo struct doesn't have a field for the VI Entry Point or anything like that. Instead LabVIEW stores the EP in some internal tables and it's rather complicated to get it from there. For these reasons I have given up studying the Register Event Callback node. Second I turned my attention to the delegate call by its pointer. I soon found out that LabVIEW generates some middle layer (by means of .NET) to convert the parameters and other stuff of the native call to the VI call. That conversion was performed by NationalInstruments.LabVIEW###.dll in the resource folder (a hidden gem!). This assembly has almost everything that we need: the CallbackInfo and CallbackHandler classes, and the latter has two nice methods: CallLabView and CreateCallbackHandlerDelegate. Referring to the SimpleDemo/SimpleCallBack example, when we call the delegate by its pointer, LabVIEW calls this chain: CallLabView -> EventCallbackVICall internal function -> VI EP. All that was left to do was to try it on the diagram with .NET nodes, but... there was another obstacle. Sure that you'll connect the inputs right? You will not. These parameters are not what they seem (at least, one of them). The viref is not a VI reference, but a VI Entry Point pointer. It's not a classic function EP pointer, but a pointer to a LabVIEW internal struct, which eases the VI calls (it's called "Vepp" in the debug info). The userParam is a pointer to the User Parameter as for the Register Event Callback node. The cookie is a pointer to the .NET object refnum from the Constructor node (luckily NULL can be passed). And the type and flags are 0 and 0x80000000 for standard .NET callbacks. Now how and where could we get that VI EPP? Good question. There is a function inside LabVIEW, that receives a VI ref and returns an allocated VI EPP. But sadly it's not exported at all. Of course, this ain't stoppin' us. I used a technique to find the function by a string constant reference in the memory of a process. It's known to be not very reliable between different versions of the application, therefore many tests were made on many versions of LabVIEW. After finding the function address, it's possible to call it using this method (kind of a hack as well, so beware). Is this all enough to run .NET nodes now? For the CallLabView yes. It's simplier than CreateCallbackHandlerDelegate, but doesn't provide a delegate. It passes the parameters to the VI, calls it and returns. The return and parameters could be utilized onwards, of course, but nothing more. To obtain a delegate it's necessary to call the CreateCallbackHandlerDelegate. This method wants the handlerType input wired and to be valid in .NET terms, so proper type must be made. Initially I tried to use .NET native generic delegates: Action, Predicate and Func. Everything went fine except the GetFunctionPointerForDelegate, which didn't want to work with such delegates and complained. The solution was in applying some obscure MakeNewCustomDelegate method as proposed here. Now the GetFunctionPointerForDelegate was happy to provide a pointer to the delegate and I successfully called the callback VI both "manually" and by means of Windows API. So finally the troubles were over, so I could wrap everything into SubVI's and make a basic example. I chose EnumWindows function from WinAPI, because it's first that came to my mind (not the best choice as I think now). It's a simple function: it's called once with a callback pointer and then it starts looping through OS windows, calling a callback on each iteration and passing a HWND to it. This is top-level diagram of the example: I won't be showing the SubVI's diagrams here as they are rather bulky. You may take a look at them on your own. I'll make one exception though - this is the BD of the callback VI. As you could know, EnumWindowsProc function must return TRUE (1) to continue windows enumeration. How do we return something from a callback VI? Well, it's vaguely described here, I clearly focus on this. You must supply first parameter as a return value in both Event Data clusters and assign these two to the conpane. On the diagram you set the return as you need. These are the versions on which I tested this example (from top to bottom). Some nuances do exist, but generally everything works well. LabVIEW 2023 Q3 32 & 64 (IDE & RTE) LabVIEW 2022 Q3 32 & 64 (IDE & RTE) LabVIEW 2021 32 & 64 (IDE & RTE) LabVIEW 2020 32 & 64 (IDE & RTE) LabVIEW 2019 32 & 64 (IDE & RTE) // 32b - on one machine RTE worked only w/ "Allow future versions of the LabVIEW Runtime to run this application" disabled (?), 64b - OK LabVIEW 2018 32 & 64 (IDE & RTE) LabVIEW 2017 32 & 64 (IDE & RTE) // CallbackInfo& lvCbkInfo, not ptr LabVIEW 2016 32 & 64 (IDE & RTE) // same LabVIEW 2015 32 & 64 (IDE & RTE) // same LabVIEW 2014 32 & 64 (IDE & RTE) // same LabVIEW 2013 SP1 32 & 64 (IDE & RTE) // same + another string ref + 64b: "lea r8" (4C 8D 05) instead of "lea rdx" (48 8D 15) LabVIEW 2013 32 & 64 (IDE & RTE) // same + no ReleaseEntryPointForCallback, CreateCallbackHandler instead of CreateCallbackHandlerDelegate LabVIEW 2012 32 & 64 (IDE & RTE) // same + forced .NET 4.0 LabVIEW 2011 32 & 64 (IDE & RTE) // same LabVIEW 2010 32 & 64 (IDE & RTE) // same LabVIEW 2009 32 & 64 (IDE & RTE) // same EnumWindows (LV2013).rar EnumWindows (LV2009).rar How to run: Select the appropriate archive according to your LV version: for LV 2013 SP1 and above download "2013" archive, for LV 2009 to 2013 download "2009" archive. Open EnumWindows32.vi or EnumWindows64.vi according to the bitness of your LV. When opened LV will probably ask for NationalInstruments.LabVIEW###.dll location - point to it going to the resource folder of your LV. Next open Create Callback Handler Delegate.vi diagram (has a suitcase icon) and explicitly choose/load NationalInstruments.LabVIEW###.dll for these nodes marked red: It's only required once as long as you stay on the same LV version. For the constant it may be easier to create a fresh one with RMB click on the lvCbkInfo terminal and choosing "Create Constant" entry. Now save everything and you're ready to run the main VI. Remarks / cons: no magic wand for you as for the Register Event Callback node, you create a callback VI on your own; the parameters and their types must be in clear correspondence to those of the delegate; obviously .NET callbacks are X times slower than pure C/C++ (or any other unmanaged code) DLL; search for CreateVIEntryPoint function address takes time (about several seconds usually); on 64 bits it lasts longer due to indirect ref addressing; no good way to deallocate VI EPP's; the ReleaseEntryPointForCallback function destroys AppDomain when called (after such a call the VI must be reopened to get .NET working) - usually not a problem for EXE's. Conclusion. Although it's a kind of miracle to see a callback VI called from 'outside', I doubt I will use it anywhere except home. Besides its slowness it involves so many hacks on all possible levels (WinAPI, .NET, LabVIEW) that it's simply dangerous to push such an application to real life. Likely this thread is more of a detailed reference for the future idea in NI Idea Exchange section.
-
Since LV 2021 hooking CfgGetDefault is not enough. There are two new classes in the mgcore library: LazyConfigValue_Bool32 and LazyConfigValue_PathRef. I assume, they're introduced for faster access to the token values. I always used good ol' WinAPIOverride by Jacquelin Potier to catch API calls (including LV ones), but now it seems that it lacks some necessary functionality (e.g., custom actions on a BP hit). So I decided to adapt that Lua script. LVEXEPath = "C:\\Program Files (x86)\\National Instruments\\LabVIEW 2023\\LabVIEW.exe" MGCore = "mgcore_SH_23_3.dll" FoundIt = false Tracing = false list = createStringlist() list.Sorted = true list.setDuplicates(dupIgnore) -- attach before any dynamically loaded modules, so break on EP (last arg) createProcess(LVEXEPath, "", true, true) CfgGetDefault = getAddress("LabVIEW.CfgGetDefault") debug_setBreakpoint(CfgGetDefault) LoadLibraryExA = getAddress("kernelbase.LoadLibraryExA") debug_setBreakpoint(LoadLibraryExA) function debugger_onBreakpoint() if EIP == CfgGetDefault then local tType = readString(ESP+4, 4) local size = readBytes(readInteger(ESP+8), 1, false) local token = readString(readInteger(ESP+8) + 1, size) local addr = readInteger(ESP+12) if (list.IndexOf(token) == -1) then list.add(token) print(string.format("%s (0x%X) [%s]", token, addr, tType)) end debug_continueFromBreakpoint(co_run) return 1 elseif EIP == LoadLibraryExA then local mod = readString(readInteger(ESP+4), 255) if (string.find(string.lower(mod),string.lower(MGCore))) then print("MGCore loaded") Tracing = true debug_continueFromBreakpoint(co_stepover) return 1 else debug_continueFromBreakpoint(co_run) return 1 end elseif EIP == mgc_f1 then --LazyConfigValue_Bool32::LazyConfigValue_Bool32 --print(getNameFromAddress(EIP)) local token = readString(readInteger(ESP+4), 50) if (list.IndexOf(token) == -1) then list.add(token) print(string.format("%s [Bool]", token)) end debug_continueFromBreakpoint(co_run) return 1 elseif EIP == mgc_f2 then --LazyConfigValue_PathRef::LazyConfigValue_PathRef --print(getNameFromAddress(EIP)) local token = readString(readInteger(ESP+4), 50) if (list.IndexOf(token) == -1) then list.add(token) print(string.format("%s [Path]", token)) end debug_continueFromBreakpoint(co_run) return 1 elseif EIP == mgc_f3 then --LazyConfigValue_Bool32::FindExposedValue --print(getNameFromAddress(EIP)) local token = readString(readInteger(ESP+4), 50) if (list.IndexOf(token) == -1) then list.add(token) print(string.format("%s [Bool]", token)) end debug_continueFromBreakpoint(co_run) return 1 elseif EIP == mgc_f4 then --LazyConfigValue_Bool32::operator bool --print(getNameFromAddress(EIP)) local token = readString(readInteger(ECX+4), 50) local tType = readString(ECX+8, 4) if (list.IndexOf(token) == -1) then list.add(token) print(string.format("%s (_) [%s]", token, tType)) end debug_continueFromBreakpoint(co_run) return 1 else if (Tracing) and (not FoundIt) then debug_continueFromBreakpoint(co_stepover) extra, opcode, bytes, addy = splitDisassembledString(disassemble(EIP)) RetFound = string.find(opcode, "ret") if RetFound then print(string.format("RET found as %s", opcode)) FoundIt = true Tracing = false debug_removeBreakpoint(LoadLibraryExA) reinitializeSymbolhandler(true) mgc_f1 = getAddress("mgcore_SH_23_3.LazyConfigValue_Bool32::LazyConfigValue_Bool32") debug_setBreakpoint(mgc_f1) mgc_f2 = getAddress("mgcore_SH_23_3.LazyConfigValue_PathRef::LazyConfigValue_PathRef") debug_setBreakpoint(mgc_f2) mgc_f3 = getAddress("mgcore_SH_23_3.LazyConfigValue_Bool32::FindExposedValue") debug_setBreakpoint(mgc_f3) -- ! USE WITH CAUTION -- This func is called THOUSANDS of times -- LV becomes lagging and badly responsive mgc_f4 = getAddress("mgcore_SH_23_3.LazyConfigValue_Bool32::operator bool") debug_setBreakpoint(mgc_f4) return 1 end else debug_continueFromBreakpoint(co_run) return 1 end end end Not that I'm a big fan of scripting languages, plus Lua in CE acts odd sometimes, so this script is far away from ideal. It also hooks only a few LazyConfigValue functions as the rest doesn't really matter. Now here's what I've got. Launching LabVIEW: Creating a new VI: Doing various stuff in there (incl. building an EXE as the last operation): No new tokens on the VI close or LabVIEW exit. Did I grab them all? Very unlikely. But I think, tokens for most common scenarios are on the list. And there are some interesting ones.
-
I'd add here Rolf's excellent revelations on interfacing external code to LabVIEW External Code in LabVIEW, Part1: Historical Overview External Code in LabVIEW, Part2: Comparison between shared libraries and CINs External Code in LabVIEW, Part3: How to use the Call Library Node properly to ease multi platform support
-
I would post here a link to LabVIEW 2.5.2 distro as well, but I don't know if I'm allowed to. I found it in the web archive years ago, there was no registration number or any owner's information. It was just LabVIEW + Advanced Analysis Library, without extra toolkits. Latest OS where it works is Windows 98 (with few non-fatal errors). It should have worked with some hardware too as daqdrv, gpibdrv and serpdrv plus ther VI wrappers are included, but as I've been running it in a VM, no such tests have been done. Even in such a minimalistic form it was quite an interesting version. For example, the cintools folder did contain more sources than in later versions. Many internal Managers, such as Dialog Manager or Window Manager, were exposed there. Some of them still exist in the modern code base, although NI has started to clean up the obsoleted functions few years ago. Also this is the only Windows version with most Mac OS relicts, e.g. Size Handle, Handle Peek, Handle Poke (I mentioned them on the other side). In theory those thin wrappers might be expanded onto many other Memory Manager functions, eliminating the need of calling them through CLFNs. But they were simply removed from the palettes and abandoned.
-
Since my last post somebody has uploaded LV 2.2 to macintoshgarden. I didn't have time to try it though. This and last year I have also seen a screenshot of LV 1.x in some Mac emulator at NI forums. Maybe that guy even would be willing to share his archive for historical reasons, if properly asked. So no longer much of a reason to request anything, I assume? 5 or so years back I was planning to ask for Picture Control Toolkit (seen your posts at NI forums), but something distracted me and that did never happen. Now I'm even unsure I'm ready to waste time for that old tech.
-
Okay, it's relatively easy to get access to those extra decorations. In modern LabVIEW's they start at 986 (0x3DA) and then, when you increment the index, you go through the columns from top to bottom, looking at@flarn2006's picture in the very first post of this thread. To find the memory address of the image index, you may use any debugger or helper tool of your choice, like CheatEngine or ArtMoney etc. In Heap Peek you can get the address of the decoration object and the image index assigned to it. Then in CheatEngine/ArtMoney search for that index and pick up the nearest higher address. Now you may alter the value at that address and watch how the decor is changing on the panel. In fact,@flarn2006discovered not extra images, but extra handler procedures, that perform the drawing with the Drawing Manager API. It looks like LabVIEW has many of them reserved for some purpose. Or maybe they're just leftovers of the early versions. Indeed, some of them could be useful in real applications. But I still don't see how a modified decoration could survive the save without hooking into LabVIEW internals at least. Seems, like it works! Here's the VI with the most decorations from the first post: Extra Decor.vi And if anyone wants to recreate the VI, here's the script that I used: Adding Objects (Extra Decor).vi Not guaranteed to behave well on anything different than LV 2022. Also requires a couple of SubVIs from here.
-
Seems like NI has changed the indexing scheme in some version. For example, in LabVIEW 2011 32-bit Flat Right Triangle image is at 0xFF910460, but in LabVIEW 2022 32-bit it's at 0x43A. Moreover, those high contrast extra decorations, that@flarn2006discovered, are not sticky on the VI save - LabVIEW reverts them to the regular squares (just tested).
-
I tried to be a little ironic, but failed, it seems. To clarify, I almost don't believe, LV interaction with OS native callbacks will get same enhancements that were made for .NET. The Call Library Function Node didn't get enough love since LV6 or 7.0 and a little more attention has been given to the Register Event Callback node, introduced in LV7.0. Of course, I could propose an idea at NI Idea Exchange section, but I'm pretty sure it won't receive enough kudos to even shift the priorities in the NI's internal development list.
-
It should also automagically install Visual Studio, write the callback wrapper, compile it into a DLL and connect it to the VI with a CLFN. Moreover it would be nice to have a .NET translator from textual code to G code, as the current way of calling .NET assemblies is too awkward. It may take 10 minutes to find a good combination of Assembly -> Constructor -> Method/Property, especially when dealing with the OS native API.
-
I would first increase the timeout input on the Create Network Stream node in ApplicationA.vi, so the value would be equal or higher than 160 ms, as I recall some problems related to the timeout being small: Timeout influence at Create Network Stream Endpoint Of course, it may be not your issue exactly, but worth trying anyway.
-
Implementing complex structs using clusters
dadreamer replied to thenoob94's topic in LabVIEW General
For that I have left this sentence with a reference to your message and the next ones after: But I would say that size_t type rather depends on a target bitness, than on a platform bitness. On 32-bit OS we can compile 32-bit applications and cross-compile 64-bit ones, if supported by the compiler. On 64-bit OS we can freely compile both. So sizeof(size_t) is either 4 bytes for 32-bit target or 8 bytes for 64-bit target. I've just checked that in MS Visual Studio. -
Implementing complex structs using clusters
dadreamer replied to thenoob94's topic in LabVIEW General
First, C unions are special data type that allows for multiple data types to be stored in the same location. Therefore you don't need to bundle each and every field defined in your header for that union. The union length is set by the longest field. So you should pass 4 bytes in both of your cases. It's up to the code on how to interpret that union onwards: either as uint32_t "value" or as four uint8_t fields struct. Second, you have two pointers in your main struct (pImagePtr and pUserPtr). You should pass them as 32-bit fields in 32-bit LabVIEW or 64-bit fields in 64-bit LabVIEW. To satisfy both cases, use Conditional Disable Structure with two cases for 32- and 64-bits accordingly. Now you're passing U8 fields, that will likely lead to writing to the neighboring fields inside the shared library. The same applies to size_t parameters (read here for details). Maybe it would even be easier to make two different structs for 32- and 64-bits in Conditional Disable Structure instead of defining each parameter separately. -
-
passing a struct to a labview library function
dadreamer replied to thenoob94's topic in LabVIEW Community Edition
No, don't pass LabVIEW arrays straight to the cluster! They are different entity than those in C/C++. In order to match your struct definition, you have to turn each array into a separate cluster. Use Array To Cluster primitive for that. RMB click -> Cluster size on it allows you to specify the output cluster size. Then bundle all the clusters into one (plus three int parameters), then pass that resulting cluster to your CLFN. I assume, you know your .so's calling convention. Oh, I forgot to add, that Array To Cluster node doesn't accept more than 256 elements. So, if SV_STRING_SIZE is 512, you need to make a pairs of 256+256 elements (e.g., two "id" clusters, two "vendor" clusters etc.). There's another way with DSNewPtr+MoveBlock, but it's a bit more advanced. -
Display a image with .net
dadreamer replied to Youssef Menjour's topic in Object-Oriented Programming
So instead of the "IMG tab" wire, shown on your diagram, you now have a memory pointer to the data (of the same representation and layout)? If so, just MoveBlock it to a common LabVIEW array and proceed as usual. Also I slightly don't get the reason why you're doing two Marshal.Copy operations... On the diagram above that empty bitmap's data is copied into the LabVIEW array, then it is replaced with the "IMG tab" data (Replace Array Subset on zero row) and then the array is copied into the empty bitmap. Isn't it enough to copy the "IMG tab" data to the empty bitmap and do the rest of the code (UnlockBits etc.)? I can't run the snippet, as LAVA seem to strip the metadata out of the snippets. -
I'm afraid, no way around that. I mean, without A LOT of low-level hackery. IMAQ images have borders 3 pixels wide by default, whereas LabVIEW arrays don't have those. And not every VI from the Array palette works in-place, not producing a copy. Of course, you may read/write pixels data by its pointer using MoveBlock. Like this: But I wouldn't expect more than that. You can always move the image processing into your DLL/SO and write everything in pure C/C++, C# et cetera.
-
If you are using VDM, you should already have the basic example on how to manipulate the IMAQ image in a shared library: IMAQ GetImagePixelPtr Example Don't know, if you will gain anything in terms of performance, but worth a try at least.
-
-
Maybe this will help: Programmatically Scroll Front Panel Using LabVIEW
-
-
You can download PID and Fuzzy Logic Toolkit 2012, then unpack it somewhere (e.g., on your Desktop). Run this command in the admin command line: msiexec.exe /a "C:\Users\User\Desktop\2012PIDFuzzy\Products\LabVIEW_PID_Toolkit_2012\NIPID00\NIPIDToolkit.msi" /qb TARGETDIR="C:\Users\User\Desktop\2012PIDFuzzy\Products\LabVIEW_PID_Toolkit_2012\NIPID00\NIPIDToolkit" (Replace "User" with your username). Now go to \2012PIDFuzzy\Products\LabVIEW_PID_Toolkit_2012\NIPID00\NIPIDToolkit\ProgramFilesFolder\National Instruments\LabVIEW 2012\vi.lib\addons\control\pid\pid.llb and there you should have PID.vi along with many other VIs from that toolkit. Also note that some VIs use 32-bit lvpidtkt.dll, so it won't go in 64-bit LabVIEW.
-
They introduced a token for smooth lines: SmoothLineDrawing=False
-
The Type Spec Structure is accessible in LabVIEW 2017, if SuperSecretPrivateSpecialStuff=True is written to labview.ini and the user RMB clicks on the Diagram Disable Structure and chooses "Replace With Type Specialization Structure" menu entry.
-
Darn, I'm slow Started to upload my disks to GDrive and on finish saw your message. Anyway, good to know it's resolved.