LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Windows Keyboard Entry

The DLL was created in a C version for which you have not the correct C runtime version installed. That's just one of many problems with providing compiled DLLs for random users to download! In this particular case it has to do with the CVI Runtime needed since the DLL was compiled in LabWindows/CVI. But using Microsoft Visual C is unfortunately no guarantee to avoid this kind of trouble.

Rolf Kalbermatter
My Blog
0 Kudos
Message 11 of 21
(277 Views)

@rolfk wrote:

The DLL was created in a C version for which you have not the correct C runtime version installed. That's just one of many problems with providing compiled DLLs for random users to download! In this particular case it has to do with the CVI Runtime needed since the DLL was compiled in LabWindows/CVI. But using Microsoft Visual C is unfortunately no guarantee to avoid this kind of trouble.


Yes, this is true. Attached project contains DLL compiled with Visual Studio 2022 (required to install the latest Microsoft Visual C++ Redistributable if not installet yet). I didn't check it thoroughly, just copypasted code from CVI to MSVC, but seems to be still functional.

 

0 Kudos
Message 12 of 21
(270 Views)

It works perfectly - exactly what I was looking for!

If I'd like to add more keystrokes (or) change the keystroke in the future, what should I do?

0 Kudos
Message 13 of 21
(263 Views)

@Sable wrote:

It works perfectly - exactly what I was looking for!

If I'd like to add more keystrokes (or) change the keystroke in the future, what should I do?


Glad to see that this was helpful for you.

Well, in ideal case you shall be able to modify source code of the DLL and recompile it.

Technically you should provide list of the hotkeys (to the RegisterHook(), for example). 

By the way — which version works for you - the first one (CVI based after Run-Time install) or last one compiled with MSVC?

 

0 Kudos
Message 14 of 21
(258 Views)

@Sable wrote:

It works perfectly - exactly what I was looking for!

If I'd like to add more keystrokes (or) change the keystroke in the future, what should I do?


That's exactly why I hesitate more and more to provide such ready made solutions here in the forum. As Andrey already answered you, you would have to modify the C code accordingly and compile a new DLL from it. Yes it could be made more universal by adding a list of keypress combinations to the register hook function that the hook function then uses to filter key presses. That would likely also require a more complex value return through the user event. And before you have thought twice, you spend many times the initial amount of time to create the quick and dirty proof of concept, want that's basically what you have so far gotten from Andrey.

 

Rolf Kalbermatter
My Blog
Message 15 of 21
(252 Views)

The solution worked after the CVI-based runtime installation.

 

I understand that adding more keys to the C code could be challenging and complex, but I don’t see this solution as a simple drop-in fix. It’s more of a guide that allows people like me to reverse-engineer and learn from how you approach these tasks, ultimately enhancing my own skills.

 

This forum continues to impress me with its support. I am sincerely grateful to the LabVIEW community for consistently going above and beyond to assist users like myself. While it sometimes introduces new challenges or confusion, it also offers opportunities for personal growth and improvement.

 

Thank you all for your support and assistance.

Message 16 of 21
(221 Views)

@Sable wrote:

The solution worked after the CVI-based runtime installation.

 

I understand that adding more keys to the C code could be challenging and complex, but I don’t see this solution as a simple drop-in fix. It’s more of a guide that allows people like me to reverse-engineer and learn from how you approach these tasks, ultimately enhancing my own skills.


I still recommend to get this compiled. Just obtain CVI from NI, it is relative simple IDE (in comparizon with Visual Studio), but if you will be able to create DLL and call it from LabVIEW (and understand how it works), then it will open much mo possibilities for you and enhance your skills.

 

Anyway, quick change which I can made for you is the following:

 

snippet2.png

Now array of modifiers and hot keys provided externally.

Technically LabVIEW's array of clusters passed to DLL like this:

 

#include "cintools/lv_prolog.h"

/* Typedefs */

typedef struct {
	uint16_t Modifier;
	uint16_t Key;
	} TD2;

typedef struct {
	int32_t dimSize;
	TD2 HotKey[1];
	} TD1;
typedef TD1 **HotKeysHdl;

#include "cintools/lv_epilog.h"

 

 Prolog/Epilog guard is needed for proper alignment in case if used in 32-bit environment.

 

DLL function is modified:

 

//==============================================================================
// Exported function
//
int RegisterHook(LVUserEventRef *LVevent, HotKeysHdl hot_keys)
{
	Keys_Amount = ((*hot_keys)->dimSize > MAX_HOT_KEYS) ? MAX_HOT_KEYS : (*hot_keys)->dimSize;
	for (int i = 0; i < Keys_Amount; i++){
		Modifiers[i] = (*hot_keys)->HotKey[i].Modifier;
		Keys[i] = (*hot_keys)->HotKey[i].Key;
	}
	lvEvent = LVevent;
	return 0;
}

 

 

And how Hot key checked in callback:

 

__declspec(dllexport) LRESULT CALLBACK KeyboardEvent (int nCode, WPARAM wParam, LPARAM lParam)
{
	int hotkey = -1;

    if  ((nCode == HC_ACTION) && ((wParam == WM_SYSKEYDOWN) || (wParam == WM_KEYDOWN))) {
		KBDLLHOOKSTRUCT hooked_key = *((KBDLLHOOKSTRUCT*)lParam);

        int key = hooked_key.vkCode;
		
		for (int i = 0; i < Keys_Amount; i++){
			if (key == Keys[i]){
				DWORD Mod_Key = GetAsyncKeyState(Modifiers[i]);
				if (Mod_Key){ hotkey = i; break; }
			}
		}
		if (hotkey >= 0 && lvEvent) PostLVUserEvent(*lvEvent, (void *)&hotkey); //Fire LV Event
    }
    return CallNextHookEx(hKeyboardHook, nCode,wParam,lParam);
}

 

 (also please read suggestion from Rolf above, there is more elegant way to get this).

 

Please try from attachment.

0 Kudos
Message 17 of 21
(198 Views)

The code works perfectly!

If I were to develop an application for installation on a host computer, would I also need to install the 2020 CVI runtime on that host?

My LabVIEW and CVI versions are from 2013. I assume there shouldn’t be any issues compiling the 32-bit version DLL (I haven’t attempted it yet).

0 Kudos
Message 18 of 21
(166 Views)

@Sable wrote:

The code works perfectly!

If I were to develop an application for installation on a host computer, would I also need to install the 2020 CVI runtime on that host?

My LabVIEW and CVI versions are from 2013. I assume there shouldn’t be any issues compiling the 32-bit version DLL (I haven’t attempted it yet).


Great! Yes, you will need to install CVI Run-Time on the target machine, of course. Also, when you recompile it with CVI 2013, CVI Run-Time will be needed (because LabVIEW Run-Time doesn't contain it). LabVIEW Development is shipped with CVI Run-Time, but it was too old in your case. CVI Run-Times are usually backward compatible; the 2020 version is OK for DLLs and executables built in CVI 2013.

You can try to open the given source (workspace *.cws) in your CVI 2013. It may open, but it may not, because there are 7 years between versions. In this case, just create a new DLL with the wizard, then copy the content of the *.c file and header to yours.

 

A few comments:

You will also need to copy the cintools folder, or better, use your own, located in the "\National Instruments\LabVIEW 2013\cintools" folder. Don't forget to change the header in this case. "cin" means "Code Interface Node," by the way.

The object file is linked with labview.lib. This is needed for PostLVUserEvent(), which is called from LabVIEW.exe or from lvrt.dll in Run-Time. I placed this lib into mscv/msvc64 - 32 and 64 bits. You don't need this; link together with your own located in "\National Instruments\LabVIEW 2013\cintools".

The project contains both 32 and 64-bit build specs; you need only one according to the bitness of your LabVIEW. I named the DLLs as DllHook32 and DllHook64, then added this with an asterisk: DllHook*.dll. This asterisk is automatically replaced by LabVIEW with the appropriate bitness according to naming conventions.

The code in DllMain() is the Entry Point, executed when the DLL is loaded in LabVIEW or unloaded (Process Attach/Detach). Personally, I don't like the way the thread is terminated, but as long as it works, it's OK. Without this code, you will not be able to close LabVIEW, and this also works when the VI is stopped with the "Red Button" Abort VI.

For debug and trace purposes, I'm using OutputDebugStringA(). This output can be obtained with DebugView from Sysinternals.

If you've never used a DLL before, start with a trivial add function: int add(int a, int b) {return (a+b);}. Examples are located in \National Instruments\LabVIEW 2013\examples\Connectivity\Libraries and Executables

Manual (skip CIN section): https://www.ni.com/docs/de-DE/bundle/370109b/resource/370109b.pdf?srsltid=AfmBOor2djU7IyvOEkcWqF20H9...

PDF:

https://docs-be.ni.com/bundle/370109b/raw/resource/enus/370109b.pdf?save_local=true

WinAPI functions are documented on MSDN; just search.

 

Good luck!

0 Kudos
Message 19 of 21
(155 Views)

I successfully opened the CVI project file in CVI 2013 and recompiled the DLL.

The process was straightforward. I simply deleted all the unnecessary files, leaving only the essential ones:

 

Sable_0-1729220493457.png

 

Next, I copied the cintools folder from my LabVIEW installation, opened the CVI project file in CVI 2013, updated the path to the labview.dll file to point to the cintools folder, and compiled the project.

 

Sable_1-1729220680651.png

The DLL hook example code continues to function as expected.

 

Could you please clarify the section highlighted in blue?

 

For debugging and tracing purposes, I am using OutputDebugStringA(), and the output can be captured using DebugView from Sysinternals.

0 Kudos
Message 20 of 21
(114 Views)