05-10-2025 06:05 AM - edited 05-10-2025 06:05 AM
@Andrey_Dmitriev wrote:
Well, hopefully NI will fix it. But to be honest, not many users open VIs directly from Explorer; usually, they are organized in projects and libraries
I'd argue the exact opposite. Most users in the science and engineering field aren't professional software devs who work on neatly organized huge projects (just look at the typical forum questions). Most of the time they need to create or use a small one-off tool to make a measurement work or process some data which wouldn't necessitate proper full-blown project organization or making libraries - a few vis in Windows explorer will do just fine. And the first thing these "casual" users come across is a buggy/unexpected UI behavior.
Maybe some decades from now NI will provide an actual modern IDE for Labview (as is the norm for all relevant text-based languages) instead of the horrible mess of separate windows we have since the beginning. Then it would actually make more sense to use the built-in file browser instead of Windows explorer. I know it will never happen because it would scare away all the old people 🙂 ...
05-11-2025 01:20 AM
@Novgorod wrote:
Maybe some decades from now NI will provide an actual modern IDE for Labview (as is the norm for all relevant text-based languages) instead of the horrible mess of separate windows we have since the beginning. Then it would actually make more sense to use the built-in file browser instead of Windows explorer. I know it will never happen because it would scare away all the old people 🙂 ...
NI has done this twice (2 and 1 decades ago, if we're counting):
While I agree that the current experience is not ideal, I'm not sure that just shoving all the VIs into a single window would be better. I expect some solutions are possible for better management of open VIs, but I don't know what they are.
05-11-2025 03:02 AM
@Novgorod wrote:
@Andrey_Dmitriev wrote:
Well, hopefully NI will fix it. But to be honest, not many users open VIs directly from Explorer; usually, they are organized in projects and libraries
I'd argue the exact opposite. Most users in the science and engineering field aren't professional software devs who work on neatly organized huge projects...
You’re absolutely right — I shouldn’t generalize my experience or specific use case to the entire community.
By the way, I was completely wrong when I described the “double-click” mechanism. It’s not based on Windows messages, of course. Sorry for forgetting such a basic detail. I’m still learning.
We can «fix it», but I should first explain how it works. There’s no rocket science here.
The *.VI file type is registered in Windows under the Registry key HKEY_CLASSES_ROOT\.VI
:
Below also see the according LabVIEW Instrument entry:
when you double-click (or press Enter on) a VI file, Windows checks the extension from the first entry, proceeds to the second, and launches LabVIEW as if from the command line.
It’s important to understand that these two keys are updated every time LabVIEW starts. If you work with multiple LabVIEW versions, the most recently used version will always be launched-this is how LabVIEW “remembers” which version was last used.
I rarely use double-click myself, but when I do, it’s annoying that the “wrong” LabVIEW version is launched sometimes.
Additionally, when LabVIEW is already running, then I’ve seen with Spy++ that, in this case, all open LabVIEW windows receive a WM_ACTIVATEAPP message. From that point, I’m not sure if this is really a LabVIEW issue.
Anyway, let’s take everything into our own hands. The idea is simple: I’ll replace the «default» LabVIEW launcher with my own. This will also help me in the future to launch the correct LabVIEW version according to the VI’s saved version.
First, we’ll change the HKEY_CLASSES_ROOT\.VI
(Default) key from LabVIEWInstrument to LabVIEWHelper:
But manual replacement replacement only works until the next LabVIEW start. Therefore, I’ll develop a small resident app that continuously overwrites this key (every 5 seconds). As I’m learning Rust, the code will be in Rust (you can do the same in LabVIEW). Not very elegant, but fine for a Sunday morning exercise:
rust#![windows_subsystem = "windows"]
use std::thread;
use std::time::Duration;
use winreg::RegKey;
use winreg::enums::*;
fn main() {
loop {
// Open HKEY_CLASSES_ROOT\.VI with write access
let hkcr = RegKey::predef(HKEY_CLASSES_ROOT);
match hkcr.open_subkey_with_flags(".VI", KEY_SET_VALUE) {
Ok(subkey) => {
// Set the (Default) value to "LabVIEWHelper"
if let Err(_e) = subkey.set_value("", &"LabVIEWHelper") {
// Handle error (optional: log or ignore)
}
}
Err(_e) => {
// Handle error (optional: log or ignore)
}
}
// Sleep for 5 seconds
thread::sleep(Duration::from_secs(5));
}
}
cargo.toml:
text[package]
name = "lv_helper_reg"
version = "0.1.0"
edition = "2024"
[dependencies]
winreg = "0.55.0"
windows = "0.61.1"
Now, simply launch this app and the key entry will be maintained.
Next, we need a second Registry entry to launch our helper app:
complete registry file:
textWindows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\LabVIEWHelper]
@="LabVIEW Instrument"
[HKEY_CLASSES_ROOT\LabVIEWHelper\DefaultIcon]
@="C:\\Program Files\\National Instruments\\LabVIEW 2024\\LabVIEW.exe,-2"
[HKEY_CLASSES_ROOT\LabVIEWHelper\shell]
@="Open"
[HKEY_CLASSES_ROOT\LabVIEWHelper\shell\open]
@="&Open"
[HKEY_CLASSES_ROOT\LabVIEWHelper\shell\open\command]
@="\"C:\\Program Files\\National Instruments\\LabVIEW 2024\\lv_helper_2024x64.exe\" \"%1\""
[HKEY_CLASSES_ROOT\LabVIEWHelper\shell\open\ddeexec]
@="\"C:\\Program Files\\National Instruments\\LabVIEW 2024\\lv_helper_2024x64.exe\" \"%1\""
[HKEY_CLASSES_ROOT\LabVIEWHelper\shell\open\ddeexec\application]
@=" "
[HKEY_CLASSES_ROOT\LabVIEWHelper\shell\open\ddeexec\ifexec]
@=" "
The helper application code is straightforward:
rust#![windows_subsystem = "windows"] // prevent console window
use std::env;
use std::process::{Command, exit};
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() != 2 {
eprintln!("Usage: {} <file>", args[0]);
exit(1);
}
let file_arg = &args[1];
// Start LabVIEW.exe and immediately return without waiting
if let Err(e) =
Command::new("C:\\Program Files\\National Instruments\\LabVIEW 2024\\LabVIEW.exe")
.arg(file_arg)
.spawn()
{
eprintln!("Failed to start LabVIEW.exe: {}", e);
exit(1);
}
}
Now, instead of LabVIEW, my own application will be launched in the background:
this will launch LabVIEW, resolving the issue:
The only disadvantage — if you work with [allowmultipleinstances=TRUE]
(which is OFF by default), this will launch a separate instance for each VI.
I’ll attach the complete code, executables, and reg files.
If you’d like to try:
Place both lv_helper_reg.exe
and lv_helper_2024x64.exe
into the LabVIEW folder:
Launch lv_helper_reg.exe, it will stay in memory, using 0% CPU and about 400 kB RAM:
good idea to add it to the startup folder. The easiest way is to press Win+R then type `shell:startup`:
then place shortcut there:
now launch LabVIEWHelper.reg
to add the HKEY_CLASSES_ROOT\LabVIEWHelper
entry to the Registry (this only needs to be done once). Then, log out and back in (or restart Windows). If everything is set up correctly, you’ll see the app here:
If you would like to revert back, simply kill `lv_helper_reg.exe` from the Task List (and remove it from startup if needed), then change the association back — and the issue will return.
If you don’t trust my executables (or if you use a different LabVIEW version), or if you’d like to modify something, download Rust from https://www.rust-lang.org and recompile the provided source code with the command cargo build -r
.
05-11-2025 04:25 AM - edited 05-11-2025 04:39 AM
Now I've achieved what I wanted, with the help of a LabVIEW-written DLL
an and the following Rust code:
#![windows_subsystem = "windows"]
use libloading::{Library, Symbol};
use std::env;
use std::ffi::CStr;
use std::os::raw::{c_char, c_int, c_short, c_uint};
use std::process::{Command, exit};
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() != 2 {
eprintln!("Usage: {} <file>", args[0]);
exit(1);
}
let file_arg = &args[1];
let dll_path = "get_vi_version.dll";
// Path to your VI file
// Get the path to the VI file from command line arguments
let vi_path = &args[1];
// Check if the path is valid
if !std::path::Path::new(vi_path).exists() {
eprintln!("The specified VI file does not exist: {}", vi_path);
exit(1);
}
// Prepare input and output buffers
let mut vi_path_buf = [0u8; 260]; // adjust size if needed
let vi_path_bytes = vi_path.as_bytes();
vi_path_buf[..vi_path_bytes.len()].copy_from_slice(vi_path_bytes);
let mut code: c_int = 0;
let mut status: c_short = 0;
let mut version_number: c_uint = 0;
let mut version_string = [0u8; 64]; // adjust size if needed
unsafe {
// Load the DLL
let lib = Library::new(dll_path).expect("Could not load DLL");
// Define the function signature
type GetViVersionFn = unsafe extern "C" fn(
vi_path: *mut c_char,
code: *mut c_int,
status: *mut c_short,
version_number: *mut c_uint,
version_string: *mut c_char,
len: c_int,
);
// Get the function
let func: Symbol<GetViVersionFn> =
lib.get(b"Get_vi_version").expect("Could not find function");
// Call the function
func(
vi_path_buf.as_mut_ptr() as *mut c_char,
&mut code,
&mut status,
&mut version_number,
version_string.as_mut_ptr() as *mut c_char,
version_string.len() as c_int,
);
// Convert version_string to Rust String
let c_str = CStr::from_ptr(version_string.as_ptr() as *const c_char);
let version_str = c_str.to_string_lossy();
println!("Code: {}", code);
println!("Status: {}", status);
println!("Version Number: {}", version_number);
println!("Version String: {}", version_str);
// Extract the version number from the version string
let version_year: u32 = version_str
.split('.')
.next()
.and_then(|v| v.parse::<u32>().ok())
.unwrap_or_else(|| {
eprintln!(
"Failed to parse version number from version string: {}",
version_str
);
exit(1);
});
// Determine the LabVIEW version year based on the version number
let labview_year = if version_year == 24 {
"2024"
} else if version_year == 25 {
"2025"
} else {
eprintln!("Unsupported LabVIEW version: {}", version_year);
exit(1);
};
// Start LabVIEW.exe and immediately return without waiting
let labview_exe_path = format!(
"C:\\Program Files\\National Instruments\\LabVIEW {}\\LabVIEW.exe",
labview_year
);
if let Err(e) = Command::new(labview_exe_path).arg(file_arg).spawn() {
eprintln!("Failed to start LabVIEW.exe: {}", e);
exit(1);
}
} // Close the unsafe block
} // Close the main function
Not only this issue above fixed, but the launcher now automatically starts the correct LabVIEW version according to the VI's version-2024 for VIs saved in 2024, and 2025 for VIs saved in 2025.
No more annoying messages
and no more (or less at least) accidentally saving VIs in a higher version!
Thank you so much for starting this topic! I need to polish this a löittle bit for project and libraries and deal with bitness, but in general it works.
05-11-2025 01:27 PM
@Andrey_Dmitriev wrote:
Anyway, let’s take everything into our own hands. The idea is simple: I’ll replace the «default» LabVIEW launcher with my own. This will also help me in the future to launch the correct LabVIEW
Making your own "class handler" for the .vi file type is clever, also the version handling part (though there's more confusion to deal with the 32bit vs. 64bit version of the same major LV version since a vi has no "bitness" and can be opened with both). However, I'm not quite understanding how calling Labview from the external helper tool (instead of through the Windows shell) fixes the window restore bug. I don't know much about Rust but it looks like your helper is calling the Labview executable from the command line with the double-clicked vi as an argument - how is that different than what Windows does when you double-click the vi (apart from choosing the correct LV version)?
05-11-2025 01:39 PM
@tst wrote:
While I agree that the current experience is not ideal, I'm not sure that just shoving all the VIs into a single window would be better. I expect some solutions are possible for better management of open VIs, but I don't know what they are.
Somehow I completely ignored NXG, so I can't comment much on that implementation of an "IDE". To your point of having a single (tabbed) vi window as an option - that would be a gigantic step forward. Imagine clicking through 5 levels of nested sub-vis, which would spit 10 additional windows onto your taskbar and desktop (BD + FP for each sub-vi). This could be completely avoided with some simple tab organization, since the window geometry is pretty much irrelevant for sub-vi in most cases. Of course there can always be exceptions and options for vis that are actual GUI elements and it should be possible to "undock" any window from the main tabbed IDE window. The possibilities are endless, the future is now (or long overdue 😉)... At least they can ease it in purely as an option to combine separate windows (including project and file explorer) into a proper IDE.
05-11-2025 03:20 PM
@Novgorod wrote:
@tst wrote:
While I agree that the current experience is not ideal, I'm not sure that just shoving all the VIs into a single window would be better. I expect some solutions are possible for better management of open VIs, but I don't know what they are.
Somehow I completely ignored NXG, so I can't comment much on that implementation of an "IDE". To your point of having a single (tabbed) vi window as an option - that would be a gigantic step forward.
I am still using NXG for several reasons, and the tabbed interface has both pros and cons. Anyway, my overall coding performance is higher in LabVIEW Classic. The issue of multiple windows is partially "mitigated" by using a large monitor (a 30-inch is a must-have; you might even try a 40-inch and curved). From the block diagram (BD), I can open another BD directly using the Ctrl button, so these windows do not disturb me much.
From a usability point of view, tabbed panes can be appropriate when there are multiple supporting panes for a primary work area that are not used at the same time, which is not always my case.
05-11-2025 04:38 PM - edited 05-11-2025 04:40 PM
@Andrey_Dmitriev wrote:
From a usability point of view, tabbed panes can be appropriate when there are multiple supporting panes for a primary work area that are not used at the same time, which is not always my case.
I agree it's sometimes useful to have several BDs or FPs open simultaneously for referencing or copying stuff, but in text-based languages this has been more or less solved since forever. In a comparable tabbed Labview IDE window you could enable tiled or side-by-side view (the dreaded Ctrl+T button now) or undock (pop out) a window you want to be open all the time. I'm not trying to convince anyone to switch their favorite UI concept (god knows that's impossible), I'm just saying it would be such a great improvement in usability as an option, especially for casual users and those with a background in text-based IDEs, and maybe even fix my original issue along the way...
05-12-2025 02:18 AM - edited 05-12-2025 02:20 AM
@Novgorod wrote:
To your point of having a single (tabbed) vi window as an option - that would be a gigantic step forward. Imagine clicking through 5 levels of nested sub-vis, which would spit 10 additional windows onto your taskbar and desktop (BD + FP for each sub-vi). This could be completely avoided with some simple tab organization, since the window geometry is pretty much irrelevant for sub-vi in most cases.
You do have the option of creating your own VI with a listbox/tree (your "tabs", ordered and managed in whichever way you wish) and showing the FP and BD of VIs in a subpanel and use that as part of your editing experience. I'm pretty sure I saw something like somewhere (I have Norm in my head), but a quick search did not find anything.
To do this, you might need some of the supersecret or scripting events, such as VI Activation or Window Opened to detect the double clicking of subVI and hijacking them into your own editor. I haven't done any playing around with this.
Another option might be using the parenting functions in the Windows API to set your window as a parent window and then manage which Windows appear and when, but that might not play nicely with how LV manages the windows.
05-12-2025 07:19 AM
@tst wrote:
You do have the option of creating your own VI with a listbox/tree (your "tabs", ordered and managed in whichever way you wish) and showing the FP and BD of VIs in a subpanel and use that as part of your editing experience.
Oh right, apparently you can frankenstein block diagrams into subpanels, I thought that was just for front panels.Then I guess it may be possible to cobble something together in pure Labview, which is intriguing - but certainly no comparison to native support.