Jump to content


LabVIEW Codewire



Photo

LuaVIEW going into the next round

Posted by rolfk , 30 July 2012 - - - - - - · 939 views
LuaVIEW, text script and 1 more...
I've been working on and off on getting the next version of LuaVIEW ready for a release. While there has been little change on LuaVIEW for several years, it was done well enough to only cause a few minor issue on the most recent LabVIEW versions. Issues that in itself did not require a new LuaVIEW release.

But there have been a lot of new feature requests from various directions over the years and so at the end of 2011 we decided that a new major release was justified to bring some of those features to current and new applications using LuaVIEW.

Feature requests that we have received over the last few years include support for running Lua scripts on NI realtime targets, as well as full support for LabVIEW for Windows 64 Bit and LabVIEW for Intel Macs.

Some voiced concerns about the fact that LuaVIEW was using a CIN to implement its core functionality and NI might be discontinuing CIN support at some point altogether. And indeed, while the latest version of LabVIEW for Windows 32 Bit still supports loading CINS developed in earlier versions of LabVIEW, NI never released any support for creating CINs for realtime platforms (except the Pharlap ETS based ones which use simply the LabVIEW for Windows 32 Bit CIN), as well as LabVIEW for Windows 64 Bit, and LabVIEW for Intel Macs. So moving to a shared library based LuaVIEW backend got an important step.

Other requests where support for running Lua binary modules such as LuaCom for interfacing to ActiveX or LuaInterface for interfacing to .Net as well as a possibility to access NI-VISA and DAQmx functionality directly from inside a Lua script, without having to create a module interface in the LabVIEW VI to relay the API calls to the according LabVIEW nodes.

I’m excited to announce that we are now in the final stages of testing and finalizing a package for the Beta of LuaVIEW 2.0B1.

This new release has a number of changes to the previous release but efforts have been made to keep it as compatible as possible to the last LuaVIEW release.
Following characteristics are valid for this release:
  • LabVIEW 7.1 or newer
  • Uses Lua 5.1.5 as Lua engine (LuaVIEW 1.2.x used Lua 5.0.3)
  • The core library has been changed into a DLL/shared library
  • Supports LabVIEW for Linux x86, Windows x86 and x64
  • Distributed as OpenG package, can be installed with the OpenG package installer or with VIPM
This Beta is time limited and will stop working after the end of 2012.

If no serious problems are found during the Beta test, the 2.0 release version is expected to be released around end of August.

The release version will include runtime support for LabVIEW for Mac OS X and NI realtime systems (cRIO and Pharlap ETS). It will also include a binary module to access NI-VISA directly from within a Lua script for at least Windows (for other OSes we are looking at the options and needed effort). A link library for Windows will allow linking your own binary modules to be included in LuaVIEW, by replacing the lua51.lib file in the linking stage of the binary module with the luaview.lib file.

To receive a download link to the Beta package please send me a pm and specify which LabVIEW version and OS you plan to use with this Beta.


Photo

Taming the Windows Taskbar for LabVIEW

Posted by rolfk , 26 June 2012 - - - - - - · 874 views
OS interface, Taskbar
Note: The current VI library can be found here.

Prompted by a post here on Lava several days ago, I started to dig into the possibilities to control the Windows 7 Taskbar interface from a LabVIEW application. This Taskbar is in fact a feature that has evolved over time from various concepts such as the Windows start menu, the Quick Launch bar, the Shell Notification area to the current Windows 7 taskbar that combines some of the mentioned features with newer features added in the Vista and Windows 7 release.

A quick search showed a little LabVIEW library to use the progress bar functionality in the taskbar buttons. This utility was based on a .Net component to access the Windows taskbar API. This is not really ideal since the Windows taskbar API is in fact unmanaged, and incorporating a .Net intermediate library makes the whole solution somewhat heavy weight. More importantly, the taskbar API is based on Windows COM, a technology that builds on top of OLE and is the basis of ActiveX. But COM is only a building block of ActiveX and not equal to ActiveX, so there is no way to use the ActiveX functionality in LabVIEW for accessing this API. The involvement of COM however adds extra obstacles, since COM is by default using an apartment threading model, which is not exactly single threaded, but for the not so technically versed reader, it can be mostly seen as single threaded component. It does support access from multiple threads but at a horrible cost, that is mostly invisible to a casual user.

This complication gets especially important if one wants to use some of the other features of the taskbar that require more complex data interfaces than just sending scalar integers to the taskbar manager.

One example would be thumbuttons, which can be used to allow control of some application operations through small little buttons underneath the thumbnail preview. The probably best known example for this would be media players such as the Windows Media Player shown below.

Attached Image

But in order for this, the component managing the taskbar has to be able to send messages to the application, whose taskbar button is shown. So we need to be able to let the taskbar manager message into LabVIEW, but in a way that lets us react to those messages in our own LabVIEW application. A .Net interface could use .Net events that get mapped to callback VIs. This would be a relatively elegant solution, but above mentioned COM limitations make this a little difficult to handle.

Since I have a lot more experience with interfacing to Windows APIs through DLLs, than with .Net, I decided to take a look what would be needed for this. The messaging from the taskbar manager to a LabVIEW program can be solved relatively easily by using user events and calling the documented PostLVUserEvent() C function from the external code. The taskbar manager sends Windows messages to the application in question (here LabVIEW) so we need to install also a message filter hook that intercepts those messages and translates them into the desired user event.

Everything seemed fairly straightforward at first after reading the documentation for ITaskbarList3 on MSDN. And my first attempts at controlling the progress bar functionality seemed very promising. Below code is all that is needed to access the method to set the progress state of a taskbar button.

MgErr SetProgressState(HWND hwnd, uInt32 state)
{
    	ITaskbarList3 *ptbl;
    	HRESULT hr = CoCreateInstance(&CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, &IID_ITaskbarList3, &ptbl);
    	if (SUCCEEDED(hr))
    	{
            	hr = ITaskbarList3_HrInit(gPtbl);
            	if (SUCCEEDED(hr))
            	{
                    	hr = ITaskbarList3_SetProgressState(ptbl, hwnd, state);
            	}
            	ITaskbarList3_Release(ptbl);
    	}
    	return hr;
}

For anyone wondering here, yes above code is standard C code and while COM objects are in fact using OOP techniques their ABI is defined in such a way that they stay constant independent of the used C++ compiler in order to allow calling of COM interfaces from code created with different compilers than what was used to create the COM object. And the Windows headers also define a standard C interface mechanism for most COM interfaces. Compiling this code into a DLL and calling it correctly with the Call Library Node works like a charm.

So this initial and quick success asked of course for more and I started to look into adding thumbbar buttons. This requires to first send a list of images to the taskbar manager, to be used for the visuals of the buttons. This is quite a bit more involved as it basically requires some form of bitmap and creating the code to do this translation is quite cumbersome. I took a few shortcuts here in the beginning but immediately seemed to run into a road block. Even with the most trivial code of just loading an existing bitmap into an imagelist and passing this to the taskbar API ITaskbarList3::ThumbBarSetImageList() function, this always returned with a generic failure. However a quick C test program doing exactly the same worked flawlessly. Some googling showed that the image list is in fact implemented in the Windows Common Controls library. There exist two different versions that are very different in nature. The old 5.x version is a simpler version not supporting any theming, while the newer 6.x version implements theming support. Supposedly the Windows taskbar uses of course the newer version, but checking the LabVIEW executable showed that it also uses this version, yet it seemed my DLL was using the older version and the Windows taskbar manager was failing to recognize my imagelist because it used a different internal implementation. But no magic seemed to help to make the imagelist created in my DLL to be recognized by the taskbar manager. Several hours later and after having stepped through lots of assembly code in debug mode, I suddenly realized that the imagelist that was passed to the taskbar manager, was not at all implemented in the memory area that was used by the Common Controls library but rather in the Remote Procedure Call library. How could that be?

Suddenly the fog started to clear up and I remembered various bits about COM apartment threading. Basically any Windows application wanting to use COM functionality has to call CoInitialize() before trying to access any COM object. I knew that LabVIEW was doing that early on during initialization, as otherwise the whole ActiveX interface inside LabVIEW would be simply impossible. However each COM component can specify in the registry if it is apartment, or free threading. Apartment threading means that the component needs to be always called from the same thread, while a free threading component can deal with being called from any thread. Most COM components only support apartment threading, and this includes most Windows COM components and in fact just about any ActiceX component out there. So LabVIEW calls CoInitialize() early on during initialization but of course in the UI thread. And if our DLL then calls CoCreateInstance() from a different thread, Windows correctly determines that this would violate the apartment threading contract for the ITaskbarList object and instantiates an intermediate marshaling layer that is using the RPC library. This marshaling layer basically translates the entire object and all method parameters into a stream of binary data, that can be transmitted through memory streams or even network sockets in the case of remote invocation through DCOM (Distributed COM). The serialized stream is then send to an RPC daemon that hooks into the application message queue, and sends the data to the server (here the taskbar manager) whenever the application is retrieving messages from the Windows message queue. The same happens in reverse order for any return parameters the server sends to the client. This message queue hooking is also the reason that you can end up with deadlocked applications when using ActiveX and not being very carefully. If there is any marshaling involved in the execution of the COM/ActiveX object, this will only work if the application in question is still servicing the Windows event message queue, by regularly calling GetMessage() to retrieve new messages from the OS. But if you happen to lock out that loop in your application because you run the marshalled code execution in the same thread, a classical dead lock occurs.
This marshaling seems to use the old Common Control 5.x format for the Image-lists, and the taskbar manager expecting 6.x image-lists simply fails when it tries to verify the image-list object before accessing its content. I'm not sure there is any way to make the RPC serialization in COM to use Common Control 6.x image-lists, but this was not really necessary, once I realized what the cause was. Setting the Call Library Node that was calling my DLL to run in the UI Thread was all that was really necessary. Since now the CoCreateInstance() was executed in the same thread that LabVIEW had called CoInitialize() earlier on, the whole marshaling was left out and the image-list that I had created got passed directly to the taskbar manager and the functions started to simply work.

There was a bit more work to be done in converting the LabVIEW Pixmap data structure into a Windows bitmap that could be used as image-list source. Bitmaps are tricky to handle and even trickier to translate between different formats, but a bit of trial and error eventually resolved that too. I chose to use Pixmaps instead of a file path to a bitmap file, because the Windows API for image-lists only supports Windows BMP bitmaps, and initial tests had shown, that it was a bit difficult to get the necessary 32 bit bitmaps for the required transparency to show without any artifacts. Allowing to use LabVIEW pixmaps instead, one can easily load 32 bit PNG files with alpha channel, but it's possible to use JPG or BMP image sources as well with the according LabVIEW VIs.

And here is the current result of this work:

Attached Image
Tree of VIs

Attached Image
Thumbar functionality





Search My Blog

Recent Comments