24
Lock Your Windows! LabVIEW for Windows Security Techniques by Brian Paquette LabVIEW for Windows revolutionizes data acquisition software for the PC, as it has already done for the Mac. LabVIEW is an ideal tool for producing quality applications with low development time, but application robustness and security are issues as well. The flexible nature of LabVIEW and Windows may seem to preclude development of a production- hardened, embedded application, as is possible under DOS. Did you know you could abort any normal LabVIEW for Windows VI simply by pressing CTRL+Period? This is useful during development, but do you want to chance an operator accidentally pressing this key combination? Comment from user: “Hey! Your software crashed on me again for no reason!” Besides application survivability, system security is at stake. In many applications, operator access to the file system and irrelevant applications (games, etc.) must be restricted. You know you will get a more robust application in less time using LabVIEW; now you need to lock the application up tight! Solid, embedded LabVIEW applications can be created with tools you already have. The trick is to identify the weak points of the system and remove or harden them. What are these weak points? How do you handle them? Read on! Running LabVIEW as a Standalone Application The first problem is that Windows is a multi-tasking environment. Multi-tasking shouldn’t be a liability, but in the data acquisition and process control industry, multitasking can't be left unconstrained. Do you really want to chance someone playing Solitaire while you expect user-interaction? And let’s hope no one tries to run a CPU-hogging application while you are trying to achieve precision timing or high throughput! These problems can be handled by putting LabVIEW in charge of the system and forcing Windows to run in a more secure fashion. Easily said, but how do you do it? The first thing to tackle is getting Windows started with LabVIEW in control. Likely, you’ve already seen this need, and possibly, you have even implemented it. If not, here’s how to fire up Windows, without the drapes. You need a way to automatically start your LabVIEW application when the system starts. You must also get rid of things like Program Manager and File Manager that give undesired access to areas of the system you want secured. First, I’ll go over getting rid of Program Manager, et al. Then I’ll go over modifications to autoexec.bat. The autoexec.bat changes will make more sense if presented in this order. Replacing Program Manager A common misconception is that one must run Program Manager in order to run Windows. This is not true. Program Manager is merely an application which is given special significance within the Windows initialization files. In a stock Windows installation, Program Manager is set up as the “shell” application; this indicates that Program Manager is responsible for ending the user’s session and that it is the common interface for launching other applications. This is similar to “shells” in Unix which can be swapped out or modified. Likewise, you can swap out Program Manager and replace it with another application as the “shell”. Let’s replace it with LabVIEW! L ® T R Technical Information for LabVIEW Systems Developers Volume 1, Number 2 Summer 1993 Windows and DOS are open systems. In a production environment, they contain security pitfalls waiting to ensnare your LabVIEW application and its users. Here's how you can protect your LabVIEW application by identifying and defeating those Windows security traps. What’s Inside Lock Your Windows!......................... 1 Editor’s Note..................................... 2 Letters to the Editor .......................... 3 Circular Buffer VIs add Realtime Trend Support to LabVIEW ............. 4 Data Acquisition Hardware Tips Mac System 7.1 Bug causes Interupt Latency Problems .............. 5 Thermocouple & Process Current signals on adjacent channels ............ 5 Facts on Files .................................... 6 Getting Your Priorities Straight ......... 8 How do you do that in LabVIEW? ... 9 CIN Corner Accessing Windows DLLs from LabVIEW for Windows ..................10 LabVIEW Technique “Scooting” front panel and block diagram items ........................16 What’s on the LTR Summer 1993 Resource Diskette ......24 continues on page 13

Vol 1 Issue 2

  • Upload
    tvu134

  • View
    32

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Vol  1 Issue 2

Lock Your Windows!LabVIEW for Windows Security Techniquesby Brian Paquette

LabVIEW for Windows revolutionizes data acquisition software for the PC, as it has alreadydone for the Mac. LabVIEW is an ideal tool for producing quality applications with lowdevelopment time, but application robustness and security are issues as well. The flexiblenature of LabVIEW and Windows may seem to preclude development of a production-hardened, embedded application, as is possible under DOS.

Did you know you could abort any normal LabVIEW for Windows VI simply by pressingCTRL+Period? This is useful during development, but do you want to chance an operatoraccidentally pressing this key combination? Comment from user: “Hey! Your software crashedon me again for no reason!”

Besides application survivability, system security is at stake. In many applications, operatoraccess to the file system and irrelevant applications (games, etc.) must be restricted.

You know you will get a more robust application in less time using LabVIEW; now you needto lock the application up tight! Solid, embedded LabVIEW applications can be createdwith tools you already have. The trick is to identify the weak points of the system and removeor harden them. What are these weak points? How do you handle them? Read on!

Running LabVIEW as a Standalone ApplicationThe first problem is that Windows is a multi-tasking environment. Multi-tasking shouldn’tbe a liability, but in the data acquisition and process control industry, multitasking can't beleft unconstrained. Do you really want to chance someone playing Solitaire while you expectuser-interaction? And let’s hope no one tries to run a CPU-hogging application while youare trying to achieve precision timing or high throughput!

These problems can be handled by putting LabVIEW in charge of the system and forcingWindows to run in a more secure fashion. Easily said, but how do you do it?

The first thing to tackle is getting Windows started with LabVIEW in control. Likely, you’vealready seen this need, and possibly, you have even implemented it. If not, here’s how to fireup Windows, without the drapes.

You need a way to automatically start your LabVIEW application when the system starts. Youmust also get rid of things like Program Manager and File Manager that give undesired accessto areas of the system you want secured. First, I’ll go over getting rid of Program Manager,et al. Then I’ll go over modifications to autoexec.bat. The autoexec.bat changes will makemore sense if presented in this order.

Replacing Program ManagerA common misconception is that one must run Program Manager in order to run Windows.This is not true. Program Manager is merely an application which is given special significancewithin the Windows initialization files. In a stock Windows installation, Program Manageris set up as the “shell” application; this indicates that Program Manager is responsible forending the user’s session and that it is the common interface for launching other applications.This is similar to “shells” in Unix which can be swapped out or modified. Likewise, you canswap out Program Manager and replace it with another application as the “shell”. Let’s replaceit with LabVIEW!

L® T RT e c h n i c a l I n f o r m a t i o n f o r L a b V I E W S y s t e m s D e v e l o p e r s

Volume 1, Number 2 Summer 1993

Windows and DOS are open

systems. In a production

environment, they contain

security pitfalls waiting to

ensnare your LabVIEW

application and its users.

Here's how you can protect

your LabVIEW application by

identifying and defeating those

Windows security traps.

What’s Inside

Lock Your Windows!......................... 1

Editor’s Note..................................... 2

Letters to the Editor.......................... 3

Circular Buffer VIs add RealtimeTrend Support to LabVIEW ............. 4

Data Acquisition Hardware TipsMac System 7.1 Bug causes Interupt Latency Problems.............. 5Thermocouple & Process Current signals on adjacent channels............ 5

Facts on Files .................................... 6

Getting Your Priorities Straight ......... 8

How do you do that in LabVIEW? ... 9

CIN CornerAccessing Windows DLLs from LabVIEW for Windows..................10

LabVIEW Technique“Scooting” front panel andblock diagram items........................16

What’s on the LTRSummer 1993 Resource Diskette ......24

continues on page 13

Page 2: Vol  1 Issue 2

2 Summer 1993

Volume I, Number 2 Summer 1993

LabVIEW Technical Resource is published quarterly by LTR Publishing. Direct correspondence to:

EditorLTR Publishing5614 AnitaDallas, TX 75206

Purpose: To provide concise and timely technicalinformation to LabVIEW system developers.

Editors: Lynda P. GruggettJeffrey M. Parker

Associate Editor: Grace Parker

Contributing Editors: Brian PaquetteGary Johnson

Publishing Consultant: Alan Klemp

Subscriptions are $95/year and outside the US are$120/year. If ordering from Texas, please add 8.25% sales tax. To order, call (214) 827-9931, or by FAX (214) 827-9932.

© Copyright 1993, LTR Publishing. All rights reserved.

LabVIEW is a registered trademark of NationalInstruments Corporation. Product and company nameslisted are trademarks or trade names of their respectivemanufacturers. LabVIEW Technical Resource is anindependently produced publication of LTR Publishing.Readers who wish to share LabVIEW programming tips,techniques or VIs should submit their contributions to theaddress above. LTR Publishing reserves the right, withrespect to submissions, to revise, republish, and authorize itsreaders to use the tips and VIs submitted for both personaland commercial use. LTR Publishing assumes noresponsibility for performance or use of items described inthis newsletter or on the disk.

Call for LabVIEW tips and questions

Do you have a LabVIEW technique or VI to share, or an idea or question about LabVIEWprogramming? We want to hear about it! Submit your LabVIEW questions, programmingproblems, instrument driver requests, article ideas and disk contributions to Editor,LabVIEW Technical Resource, LTR Publishing, 5614 Anita, Dallas, TX 75206, (214) 827-9931, or FAX (214) 827-9932.This issue is printed on recycled paper.

L T RTechnical Information for LabVIEW Systems Developers

Editors’ Note

Dear LabVIEW Developers:

Many thanks to the many folks who helped us through the launching of LTR at theMarch1993 NI User Symposium! It was exciting to see that first issue hit the streets,and the response we have received since then is quite encouraging. Many of youLabVIEW users out there in the real world must agree that a forum for distributing no-nonsense LabVIEW technical information is an idea whose time has come! We oweour special thanks to our new subscribers, and we pledge to give you your money’sworth in LabVIEW information you can use.

You can help us deliver on that pledge by telling us about your needs and preferences.Any particular topics you’d like to see covered? Is your favorite platform gettingadequate coverage? Are you getting too much or too little information on hardwareissues? Do you need continuing support for older versions of LabVIEW? With twoversions of LabVIEW on the market, one nearly six years old and one just over a year,running on three computer systems, we know our readers have varying levels ofexpertise as well as distinct platform preferences. LabVIEW 3.0, when it is available,promises to unite all platforms with a single version, which will help. Meanwhile, we’llstrive to cover topics that relate to all versions of LabVIEW, and cover them at varyingdepths, so there’s something in LTR to benefit novice and power user, Mac aficionadoand PC fan alike. Just tell us if it ain’t so and we’ll do our best to fix it.

Don’t miss the great articles that were contributed by two of our readers. On the facingpage you’ll find an innovative circular buffer technique submitted by Gary Johnson.You’ll find more good tips from Gary in the solution to last issue’s “How do you do thatin LabVIEW”. The cover story, by Brian Paquette, will tell you everything you wantedto know about hardening LabVIEW for Windows applications. In this issue’s CINcorner, Brian discusses the mysteries of calling DLLs from LabVIEW for Windows.

Several readers have asked how to submit material for publication in LTR, so here aresome guidelines. First, and most important, your article or tip must be LabVIEW-related and technical in nature, free from commercial solicitation. All text and/or VIsyou submit must be in the public domain. Your contribution stands a better chance ofbeing published if, in the judgement of the editors, it is general in nature and/or usefulin a broad range of applications. Finally, we reserve the right to edit articles and VIsbefore publication.

If you don’t have time for a full-fledged feature article, you can still make a valuablecontribution to LTR with your tips, questions, and ideas for articles. Of course,comments on prior issues are always welcome. And don’t forget to try your hand at the“How do you do that in LabVIEW” programming puzzle.

Please give us your comments so we can make LTR your newsletter!

Enjoy reading and learning about LabVIEW!Lynda and Jeff

Page 3: Vol  1 Issue 2

Tools

Summer 1993 3

Letters to the EditorLTR Editors:I enjoyed the first issue of the LTRnewsletter and I’m sure it will prove to be a great source of interesting and usefulLabVIEW information.I would like to submit an alternate designfor the Keymap VI. Instead of using aFor loop to reverse each byte, assign thebytes in reverse order in the CIN, thenjust wire the CIN’s output array to theReverse 1D Array primitive.In the CIN source code, change:kp->Key[0] = k[0];kp->Key[1] = k[1];kp->Key[2] = k[2];kp->Key[3] = k[3]; to:kp->Key[0] = k[3];kp->Key[1] = k[2];kp->Key[2] = k[1];kp->Key[3] = k[0];

Keep up the good work!Meg KayNational Instruments

(Thanks, Meg, for your clever modificationto the source code of the Keymap CIN,which makes its diagram smaller andsimpler! Interested readers will find anupdated Keymap VI on this month’s LTRdisk. —The Editor.)

Attention info-labview Users:The info-labview electronic mailing listdescribed in the last issue of LTR haschanged its archive site name from“caesar.pica.army.mil” to“ftp.pica.army.mil”. The“ftp.pica.army.mil” ftp site archivesLabVIEW questions and answers anduser contributed LabVIEW VIs. Readthe “Get help from other LabVIEWusers...” article in the Spring 1993 issueof LTR for more information on accessingthis Internet mailing list and archive.

National Instruments’ ftp archive host“fpt.natinst.com” has also moved to a newmachine. Most users can continue toaccess this archive by the same host name.However, if you are using a hard-codedIP address to reach “ftp.natinst.com”,you will need to access a new IP addressof 130.164.1.12.

Circular Buffer VIs add RealtimeTrend Support to LabVIEWby Gary W. Johnson

Ever find that LabVIEW’s stripchart comes up short in terms of timebase calibration andscrollback capabilities? Well, here’s a solution: a VI package that contains a memory-basedcircular buffer for realtime trending. At the core is Circular Buffer, a “smart” global variableVI that stores many channels worth of data in a circular buffer with high efficiency. You canread back any range of data (varying the number of samples and starting point) from thebuffer. Timestamps in epoch seconds are stored and retrieved automatically, so this VI canbe called at irregular intervals.

The example VI includes some nice features. The graph’s timebase can be scaled to seconds,hours, minutes, or days. Also, the start and end times of the graph are displayed in hh:mm:ssformat for convenience. Statistics on the displayed data are also shown.

CirBuf to Multiplot Graph is a handy multi-channel plotter for use with the Circular Buffertrending VI. It calls the Circular Buffer driver to return the desired quantity of data for oneor more channels. It displays data as a multigraph plot and returns the last values for thespecified channels. All channels share a common time base. CircBuf to Multiplot Graphsupports all the features of the Circular Buffer VI.

Circ Buf to Multiplot GraphTo see CircBuf to Multiplot Graph in action, start running the Circ Buf Example VI, thenrun the CircBuf to Multiplot Graph VI. Since the Circular Buffer is a kind of global variable,its data can be shared between these independent, top-level VIs.

Another way-cool use for the circular buffer is to make a realtime x-y chart. All you have todo is call Circular Buffer twice: once for the x data and once for the y, then plot them as anx-y graph. You now have a realtime x-y chart that displays a programmable number of points.The usual alternative, accumulating a never-ending pair of arrays in a While loop, yields anx-y plot that gradually slows down as the arrays grow. Not so with the circular buffer. Itsspeed is constant since the arrays never change size (except when you tell them to).

CircBuf to Multiplot Graph VI

continues on page 4

Page 4: Vol  1 Issue 2

Using the Circular Buffer VI Figure 1 shows the Circular Buffer VI's controls and indicators and their terminals.

Setting Initialize to True allocates a circular buffer to hold the desired number of channelsand samples/chan. During the initialization process, the inputs Channels and Samples/chanare used to determine the buffer size. They are not used at any other time. NOTE: This stepcan take a fairly long time if a large buffer has to be created, but it only has to be done once.After that, this VI is very fast.

Set Write? to True to write data from the Data to Write array into the buffer. The VI usesReplace Array Element to prevent reallocation of memory. When Write? is set to False, onechannel worth of data, plus the associated timestamps, are returned.

Channel to read determines which channel to read. Range: 0 to Channels-1.

Data Scroll determines where in the buffer the data shall come from when reading. It has arange of zero to 1.0. Zero returns the latest data, while 1.0 returns the oldest. This permitsyou to scroll through a long history.

The Points in graph window control determines how many values will be returned, startingat the location set by Data Scroll.

Values is an array containing the channel’s data. All data are in SGL floating point format formemory conservation purposes. Timestamps is an associated array of [U32] epoch seconds(since 1-Jan-1904). You can do an x-y plot of Values vs Timestamps, with Timestamps scaledas desired.

Memory usageFor N channels and M samples, this example requires (N+1) * M * 8 bytes of memory. Forinstance, 10 channels and 10,000 samples consumes 880,000 bytes of memory. This doesnot include memory required for any graphs, other indicators, or sources of data.

BenchmarksOn a Mac IIfx, running LabVIEW 2.2.1, 8-bit color, reading two channels from the CircularBuffer and plotting them as an X-Y graph, I measured the following speeds.

Number of points displayed Auto scaling on Uniform scaling

10 4.1 Hz 19.0 Hz

100 4.0 12.0

1000 2.7 5.2

4 Summer 1993

Tools

What is a circular buffer?The term “circular buffer” conjures upan image of a fixed size buffer that neverfills up because it has no beginning or end.Instead, “old” locations are continuallyoverwritten. A write pointer keeps trackof the next location at which to depositdata. A read pointer keeps track of thelast data read. Both pointers advancearound the circle in the same direction.The read pointer can never advance pastthe write pointer; if it does, it will returninvalid data. Similarly, the write pointercan’t get too far ahead of the read pointer,or it will overwrite data that hasn’t beenread yet.

In practice, a circular buffer must beimplemented from a chunk of linearmemory. The circular buffer managerdetects when a read or write pointerreaches the end of the buffer and redirectsit to the beginning of the buffer. This iseasy to do using modulo (remainder)arithmetic, as illustrated in the Readfrom circ buffer VI.

Circular buffers are used to couple acontinuous producer of data with acontinuous consumer of data that runsat a different rate (but fast enough tokeep up overall). You may be familiarwith one such application: double-buffered data acquisition. The “doublebuffer” is actually a circular buffer.Both double-buffered acquisition andthe Realtime Trend Circular Buffer havean additional wrinkle - they supportbuffering of blocks of data, rather thanjust single elements.

Figure 1: Circular Buffer VI

Note that autoscaling slows down graphing speed, as does increasing the number ofdisplayed colors.

CreditsThanks to Marty Vasey for coming up with the original concept.About the author: Gary W. Johnson is a LabVIEW consultant and longtime user who cut his teeth on LabVIEW 1.0.Gary also offers HIST, a disk-based circular buffer implementation for LabVIEW.

Continued from page 3

writepointer

readpointer

Page 5: Vol  1 Issue 2

Data Acquisition Hardware Tips

Summer 1993 5

If you’ve experienced unexplained errors when using LabVIEW data acquisition with System 7.1, read on! There’s a bug in System 7.1 thatyou should be aware of. It results in longer interrupt latency and can cause data acquisition errors.

The SymptomsData acquisition overflow and chaining errors are more likely to occur on Quadras or Macintosh IIci machines running System 7.1. Theproblem is not evident on Macintosh IIfx computers.

Overflow errors occur when using the NB-MIO-16 or Lab-NB boards without a dma board in the system. Data acquisition without dma(programmed I/O) relies the Macintosh to respond to interrupts to retrieve or send out each data point. The data acquisition boards havesmall on-board FIFOs, so an increase in interrupt latency (time it takes for the Macintosh to respond to a “data ready” signal from the dataacquisition board) results in overflow errors. Applications using dma can experience chaining errors when short block sizes are used indouble-buffered acquisition.

The CauseThe longer interrupt latency was introduced by changes in a section of Apple’s System software, ironically called the Reliability Manager.The Reliability Manager installs a time manager task that executes every five minutes to provide accurate data for Apple service providers. A bug exists in the setup of the “egret” chip that handles time manager traps and the interrupt mechanism. Every five minutes interruptsare disabled for too long, and this interferes with system interrupt handling. The increased interrupt latency affects high-speed modemperformance as well as data acquisition.

The FixApple has made available a “Hardware Extensions” system file that you can place in your system folder. It patches System 7.1 to fix thelatency problem. Contact National Instruments to obtain Apple’s bug fix.

Mac System 7.1 Bug Causes Interrupt Latency Problems

Thermocouple & Process Current signals on adjacent channelsIf you’ve ever tried using the same multifunction board or SCXI module to read both low-level signals from thermocouples and high-levelsignals from process-current inputs, you may have run into problems. If your sensors are connected directly to the board’s analog inputs (orto an SCXI 1120 or 1121 module), you canset individual channel gains to cope with thedifferent input levels. But a comparativelylong settling time must still be used to allowthe input electronics and cabling RCconstants to adjust to the radically differentinput levels. If you’re working with an SCXI-1100 multiplexer, you have a worse problem- all channels must have the same gain!

Here’s a workaround: adjust the value of yourprocess current resistor to provide a voltagecompatible with low-level inputs.

Process current signals, which swing between0-20 or 4-20 milliamps, are interfaced to voltage input channels by putting a resistor in the current loop. By Ohm’s law (E = IR), thevoltage across the resistor will be proportional to the current through it, as shown in the accompanying figure.

The usual value for this process current resistor is 250 ohms. This value of resistance converts 4-20 mA to 1-5 volts (or 0-20 mA to 0-5volts), compatible with the typical voltage swing of a DAQ board channel. You can use different values of resistor to convert to differentvoltage swings. For example, a 1 ohm resistor converts 4-20 mA to 4-20 millivolts, a voltage range compatible with other low-level signalssuch as thermocouples.

The accuracy of this method depends on the accuracy with which you know the value of your process current resistor. Either choosecomponents with a tolerance tight enough for your needs, or measure the value of the resistor accurately. Once the value of the resistor is known, it’s easy to scale the voltage read by the DAQ hardware into engineering units in your LabVIEW Program.

Thanks to the NI application engineer, name unknown, from whom this tip originated.

Conversion of Process Current to Voltage

Page 6: Vol  1 Issue 2

IntroductionOne article could not do justice to the manyuses and intricacies of file I/O in LabVIEW.This first installment in a series of articleswill explore file I/O as used for datalogging.

LabVIEW’s file functions for bytestream andstructured file I/O give us three basic techniquesfor storing periodically acquired data:

■ convert data to ASCII representation and store in a bytestream file;

■ store data in a bytestream file in its binary representation; and

■ store data in record form using structured “datalog” files.

Ever wonder which technique is best? Asusual, there’s no simple answer. Each is well-suited to some applications, but works poorlyin others. Besides, there are many points ofview from which to judge performance. Themost obvious performance criteria are speedand space: how fast can you write (and read)data, and how much space does it take up ondisk? However, there are other criteria toconsider, such as:

Ease of implementation. Your developmentand debugging time are a measure ofperformance of the technique, too. Whendevelopment time is amortized over a longapplication life, more attention to performanceis warranted. But for “quick’n’dirty”implementations, minimizing developmenttime may be more valuable than squeezingthe last millisecond out of the runtimeperformance.

Random access capability. Do you need toread from or write to arbitrary locations inthe file? If so, the time it takes to “seek” to a particular location in the file, and theresolution of random access (e.g. byte, orrecord) will be important to you.

Data precision. Does the data format ondisk retain the full precision of its binaryrepresentation?

Interoperability. Can applications other thanLabVIEW read your data?

Reliability. Suppose a datafile becomescorrupted. Can you salvage anything, or isall of your data lost?

In this article, we will discuss the threetechniques for datalogging, comparing theirrelative performance, advantages anddrawbacks. To provide a focal point for ourcomparison, and to put the three techniqueson equal footing, we will show how a datafilecan be treated as a 2-dimensional array ondisk. Then we will build some VIs that useeach of the file I/O techniques to providearray operations such as subset and appendon our “disk array” datafile. Finally, we’llanalyze our implementation to gain someinsight into how the techniques compare.

As you evaluate the conclusions presentedhere, keep in mind that datalogging is notthe only context in which file I/O can becompared. In future issues of LTR, we willexamine other uses for file I/O where theadvantages and disadvantages of the differenttechniques are weighted differently.

LabVIEW file typesIf you’ve used File I/O in LabVIEW, you’reprobably aware that LabVIEW furnishes twobasic file I/O mechanisms. In LabVIEW2.5.2, these two methods are called “bytestream” and “datalog”, and are implementedby a common set of file I/O functions. InLabVIEW 2.2.1, byte stream file I/Ofunctions and datalogging file I/O functionsare completely separate; byte stream functionsare referred to in the manual simply as “FileI/O functions.”

Byte stream files are just what they soundlike — the file is a “sea of bytes” with noinherent structure.

One way to log data to a bytestream file isto first convert the data from its binaryrepresentation to an ASCII text representation.One advantage: ASCII text is readable, byhumans as well as by other applications, suchas spreadsheets. There are disadvantages aswell: ASCII representation of data takes upmore space than its binary representation, soASCII file I/O is slower than binary for the

same amount of data. Also, the conversionfrom binary to ASCII is time-consuming.

There’s no law that says that data must beconverted to ASCII before writing to abytestream file; binary data can be writtento a bytestream file without conversion for a more compact representation. However,the burden is on the programs that generateand read such files to “know” how the datain the file is represented and organized.Also, if you try to read a binary bytestreamfile in an editor or spreadsheet, you will beconfronted with garbage.

Unlike bytestream files, datalog files have an inherent structure. They store data as aseries of records, where a record is anarbitrary LabVIEW data type. When youwrite a datalog file, you provide data onerecord at a time, which is appended to theend of the file. When you read a datalogfile, you request a single record by its index.LabVIEW takes care of locating and returningthe record to you.

Datalog files are a convenient way to readand write data that is to be used solelywithin LabVIEW, but there are somedrawbacks. While LabVIEW does thebookkeeping to keep track of the structureof the file, it does its bookkeeping in its ownproprietary way; datalog files are almostuseless outside of LabVIEW. Also, there is aperformance price to be paid for letting thesystem do the bookkeeping; LabVIEW’sdatalogging file mechanism must be general,so you may be paying for complexity youdon’t need.

By the way, LabVIEW for Windows userswill find a good discussion of these file I/Otechniques and their tradeoffs in the “UsingFile I/O” section of the LabVIEW 2.5 manual.

Implementing a disk-based arrayTo compare these techniques, let’s invent adatalogging torture-test and implement itusing the three techniques at our disposal.

Consider the common problem of periodicallylogging several channels of data to a file. Ifwe require that the same number of channels

6 Summer 1993

Technical Notes

Facts On FilesPart 1: Applying LabVIEW File I/O To Data Logging

Page 7: Vol  1 Issue 2

are logged each time, then we can think ofthe data on disk as a two- dimensional arraywith a fixed number of columns, where eachcolumn represents one channel. There arean arbitrary number of rows in the file,depending on how much data has been logged.

We need some operations on this disk-baseddatatype to make it useful:

■ Initialize - create a new example of the datafile type

■ Open - open an existing file■ Append - add data to an open file■ Close - close the file■ Subset - return an arbitrary subset of the

data in the file.■ Replace Element - replace a single element

in the file with a new value.

The Initialize, Open and Close operations, arenecessary only because our array exists ondisk. Append, Subset, and Replace Elementare operations you would expect on an arraydata type. These aren’t the only usefuloperations on disk arrays, merely the set weneed to wring out the file techniques. Forexample, Subset forces us to implementrandom read functionality; Replace Elementrequires random write capability. Otheroperations, ArraySize, IndexArray, etc. areleft as an exercise for the interested reader.

Please note that, while this disk-based arrayimplementation is probably useful in its ownright, it is “optimized” for illustration purposes.You would probably want to modify the VIsbefore using them in a real application. Forexample, real programs do error checking, butonly minimal error checking is implemented.Also, there are numerous enhancementsuseful in one technique or the other. Again,the purpose of these VIs is to try to equalizethe techniques so we can compare Appleswith Apples (apologies to you LabVIEW forWindows aficionados!).

Implementation OverviewWe will implement each file operation as asingle VI, with three cases, one for each ofthe three methods. Before we discuss theimplementation, let’s agree on the followingconvention for naming the three file I/Otechniques:

■ ASCII will refer to the ASCII bytestream technique;

■ Binary will refer to the binary bytestream technique;

■ Structured refers to the datalog file I/O technique.

Now, consider the characteristics that adatafile must have to behave like a 2D array:

In addition to the data, the file must carryinformation that lets us determine the shapeof the array, i.e. how many rows andcolumns it contains. For the two bytestreamimplementations, we need only keep trackof how many columns are in the array, andhow many bytes each element occupies.Assuming that only full rows are stored, thenumber of rows can be determined bydividing the size of the file (which we can getfrom the Get EOF function) by the lengthof a row, in bytes (which we can figure out,given element size and number of columns).So, for the ASCII and binary bytestreamtechniques, we will write element size, inbytes, and row size, in elements, to thebeginning of the file when it is created. Wewill use the same representation (ASCII orbinary) for this header that is used for thedata. For the Structured File I/O technique,we will specify the record type to be a singlerow at file creation time. LabVIEW will takecare of locating rows, and we can figure outhow many columns are in a row by using thearray size function. So, we don’t need to doany bookkeeping of our own for thestructured method.

To efficiently implement the Array Subsetoperation, random access to elements in thearray is needed. Sure, you can always readthe file sequentially until you get to the datayou want, but that isn’t good enough for ourpurposes. We will force the followingconstraint on our disk array file: all of itselements must be the same size so we cancompute where to look instead of searching.This only affects the ASCII method, sincebinary elements are naturally the same size.The only fixed size ASCII representation thatwill handle the full dynamic range of ourchosen element, a floating point number, isscientific notation. For the Structured method,we let LabVIEW worry about element size.

The datafiles must store the data such thatno precision is lost. We impose thisrequirement to equalize the techniques andmake the point that, for the same precision,

ASCII representation of data is substantiallylarger than binary representation. Thisrequirement doesn’t affect the binary orstructured representations, both of whichnaturally retain full precision.

Implementation DetailsThe array datafile VIs have beenimplemented in both LabVIEW 2.2.1 andin 2.5.2. The implementations attempt tomake the best use of the functions availablein the two LabVIEW versions, but otherwisethe implementations are as similar as possiblebetween techniques as well as between versions.You will want to open the appropriate VIsfrom your LTR disk so you can refer tothem during the following discussion.

There are differences in how LabVIEW 2.2and 2.5 specify files prior to opening.LabVIEW 2.5 files are specified using fullpaths, so to make the author’s life easier, the2.2.1 implementation also requires acomplete pathname; directory refnums arenot used. In both versions, to keep thingssimple, the datafiles are written to a fixedlocation. In the LabVIEW 2.5.2implementation, datafiles go to the defaultdirectory, while in the LabVIEW 2.2.1implementation, they are directly on theinternal drive.

All of the VIs have in common a File Infocluster, used to pass around informationabout open datafiles. This provides notonly the file’s identifier (“refnum”), but alsoinformation describing the shape of the arrayin the file, that is, its element size and rowsize. There is a difference in the refnumdatatype between version 2.2 and 2.5. InLabVIEW 2.2, file refnums are just integers.In 2.5, file refnums are a dedicated datatype;furthermore, the refnum datatype for astructured file can’t be connected to therefnum datatype for a bytestream file.Therefore the File Info cluster in 2.5 containstwo refnums, one for the structured techniqueand one that serves the two bytestreamtechniques.

Other differences between 2.2 and 2.5implementations are covered under theoperation where they are found.

Datafile InitThe purpose of the Datafile Init VI is to

Summer 1993 7

Technical Notes

continues on page 21

Page 8: Vol  1 Issue 2

diagram. Starvation occurs when VIs arenever allowed execution time because higherpriority VIs are always running. You canavoid starvation by not assigning highpriorities to VIs that constantly run.

Figure 2 shows an example of starvation byimplementing the same application withoutasynchronous waits. If the three levels ofpriority were assigned the same way in thisdiagram, then the Control VIs, having thehighest priority, will always be scheduled torun. This will starve the lower priority VIsin the diagram and prevent the other loopsfrom executing.

What is the “subroutine” selectionin the VI Priority menu?In addition to the four priority settings of 0through 3, there is a “subroutine” selectionin the priority pop-up menu that isundocumented. This is not a priority level,but rather a different execution mode.

Selecting “subroutine” for a VI preventsexecution interleaving while that VI isrunning. This guarantees that no othernode will run while this VI is executing.

The advantages to selecting “subroutine” isthat the raw overhead time of calling a VI iscut by more than half. When a subroutineVI is executed, time is saved because the VIis not queued, no scheduling is notperformed and controls and indicators arenot updated.

Keep in mind that if you select “subroutinepriority” for your VI, no data will be shownon the front panel during execution becauseupdates to controls and indicators aredisabled. Subroutine priority also disablesthe VI’s Run button. A subroutine VI willstill break out for user events, such asclicking the Abort button.

A subroutine VI can only call subroutineVIs within its diagram. If you drop a non-subroutine subVI within a subroutine, thenthe VI will have a broken arrow.

The best VIs to make subroutines are shortnon-interface VIs that are called repeatedly.Non-interface VIs are VIs whose frontpanels are never shown during execution.Select subroutine priority only for VIs withsmall diagrams. Selecting subroutine for alarge diagram is not efficient because saving

Getting Your Priorities StraightAssigning priorities to LabVIEW for Windows VIs improves execution performance. Usethe VI Setup... dialog to influence execution order by selecting one of four levels of priority,0 (low priority) through 3 (high priority). Higher priority VIs execute before lower priorityVIs. Select higher priority for important tasks. Higher priority VIs interleave and shareexecution time exclusively. Lower priority VIs execute after higher priority VIs complete.

How priorities affect executionThe best way to understand priorities is to think of how LabVIEW’s internal execution queueoperates. As each node of a diagram is called, it is placed in line on the execution queue andwaits its turn to execute. In this way diagram nodes running in parallel are interleaved. Whena node reaches the front of the queue, LabVIEW executes the node. When the node’sexecution is complete, LabVIEW removes it from the front of the queue and beginsexecuting the next node in the queue.

Priorities allow nodes to “cut” in line; high priority nodes move to the front of the executionqueue. Nodes from high priority VIs take turns executin until all high priority nodes complete.Then, nodes from lower priority VIs move up in line and begin interleaving execution time.

Priorities are particularly useful in applications with critical tasks. For example, Figure 1shows a typical use of priorities that optimizes execution. Consider an application thatconsists of three loops running in parallel: 1) a display loop to graph data, 2) a datalog loopto acquire and store timestamped data to disk, and 3) a control loop to monitor a processand control two safety valves. Each loop executes at independent rates: a display rate, a lograte, and a control rate. Asynchronous timer wait icons control the independent loop rates.

Typically the Control safety VIs would be assigned highest priority (for example, priority 3),the Datalog VI second highest (priority 2), and the Display VI given a lower priority(priority 1). This would give execution preference to the Control VIs where critical safetytasks are performed.

In the example above, all called VIs would be scheduled on the execution queue. Becausethe Control VIs have the highest priority, they would share execution time and completebefore the Datalog VI (priority 2) executes. While the control loop sleeps, the Datalog VIexecutes until completion before allowing the lowest priority Display VI to run.

When the control loop wakes up, LabVIEW schedules calls to the Control safety VIs. TheseVIs will not pre-empt a lower priority VI, but will move to the front of the queue and shareexecution exclusively beginning at the next available time slice.

Avoid StarvationWhen assigning VI priorities, be careful that you do not starve out other VIs in your

8 Summer 1993

Technical Notes

Figure 1. Using VI Priorities

Page 9: Vol  1 Issue 2

Summer 1993 9

Technical Notes

subroutine call time is less significantcompared with the VIs execution time.Another advantage of subroutines is thatthey save time by avoiding front panelupdates, but updates are avoided anyway ifthe VI window is closed during execution.

If you are a C programmer, you can thinkof LabVIEW subroutines as analogous to C

macros and use them in the sameinstances to lower subroutine calloverhead and avoid duplicate code.

Experiment with PrioritiesUsing priorities adds execution preferenceto your diagram, but does not turnLabVIEW into a real-time system thatguarantees VIs execute at defined responsetimes. Even with priorities, LabVIEW isstill a non-preemptive, non-realtimesystem.

Interestingly, LabVIEW does add further priority optimization internally as VIs are running.If LabVIEW executes a VI that calls a lower priority VI, LabVIEW trys to temporarily boostthe lower priority to a higher priority. After the call, LabVIEW resets the VI to its originalassigned priority.

Knowing how priorities and subroutines work gives LabVIEW users a powerful optimizationtool. Try experimenting with priority settings and subroutines to get the optimumexecution performance for your LabVIEW application.

Figure 2. Starvation Situation to Avoid

How do you do that in LabVIEW?This issue’s LTR challengeIn this issue, we pose the “list box” problem. A list box displays a list of items for the user toselect. This list can vary in content and length depending on the current state of variables inthe program. The Open... file dialog prompts on the Macintosh and in Windows areexamples of list box interfaces that you have used to select filenames.

This is a challenging task to implement in LabVIEW because the list box has aspects ofboth an indicator and a control. A list box acts as an indicator by displaying a variablelength list. This list must be set up programmatically because the items in the list maychange. The list box acts as a control by allowing users to scroll through an item list andselect an option.

So, this issue’s LTR challenge is as follows:

Create a list box interface that lets a user select from a variable list of items.

Last issue’s “Which button?” problemIn the last issue, we posed the menu button problem. A common mechanism that appearsin LabVIEW applications is to have a few pushbuttons with SpringLatch mechanical actionthat form a “menu” of choices. Depending on which one of the pushbuttons is pressed, someaction is taken on the LabVIEW diagram. Even if more than one pushbutton is pressed(rather unlikely, since the buttons have SpringLatch action), only one action is performed.If we perform the required action for pressing button i inside frame i of a LabVIEWconditional, as illustrated, then the problem can be stated as follows: Given N booleans, oneof which may be TRUE, produce an integer that identifies the TRUE boolean.

Solutions to the “Which button?” problemThanks to all the LTR readers who sent in solutions. Gary Johnson, a LabVIEW user well-known in the LabVIEW community, submitted a concise comparison of two of the bestsolutions. Turn to Page 12 and check them out.

Each issue of LTR poses a LabVIEW

programming problem, and

challenges our readers to solve it!

LTR examines the solutions sent in

by readers, and discusses the pros

and cons of the best ones in the next

issue. LabVIEW programming can

be judged by many standards —

performance, elegance and

understandability, to name a few —

so the solutions are analyzed from

these different viewpoints. Our goal

is to provide a forum for sharing

ideas about LabVIEW programming,

learn from each other, and have

some fun to boot!

continues on page 12

Page 10: Vol  1 Issue 2

CIN Corner

10 Summer 1993

by Brian Paquette

IntroductionOn the Macintosh, access to operatingsystem functions from within a LabVIEWCIN is as simple as making a trap to theToolbox. Attempt to compile and link toWindows functions from within your CIN,though, and you will get a variety ofcompiler and linker errors. However, amechanism does exist whereby you canaccess many Windows functions from yourCIN. This issue’s CIN Corner will showyou how.

Windows provides for system objects calledDynamic-Linked Libraries (DLLs). Theseare discrete modules of code, separate fromLabVIEW or your CIN, which you link toat run-time, not compile-time. In fact, themajority of modules which make upWindows itself are constructed as DLLs.LabVIEW, too, makes use of this feature, as evidenced by the file LVDEVICE.DLLlocated in your LabVIEW directory.

Through the use of DLLs, you can addfunctionality to your applications notavailable from within LabVIEW. Forexample, LabVIEW for the Mac provides a Shutdown function; nothing similar isprovided in LabVIEW for Windows.Admittedly, the PC itself has no means ofprogramatically shutting itself down, but itcould be useful to be able to exit Windowsfrom within your app. Looking through aWindows functions manual reveals theExitWindows function which looks like itwill do the job. The catch is, if you call itdirectly from a CIN, you get compilerwarnings and linker errors. However, youcan get to the ExitWindows function bycreating a Windows DLL which callsExitWindows, then link to this DLL fromwithin your CIN.

If you’ve already read the Lock Your Windows!article in this issue of LTR, you may rememberthe VI, Exit Windows. That utility VI callsthe Windows function ExitWindows in justthis fashion. As you continue reading, you’lllearn how to do it yourself.

Some effort is required to create and accessDLLs, but if you strongly desire Windows

functionality not expressly available fromwithin LabVIEW, such as access tomultimedia functions, it can be well worththe extra effort.

Technical ConsiderationsI’m going to assume you are comfortableworking with CINs already. Likewise, youshould have some knowledge of availableWindows functions. Just as it would beunwise to attempt making MacintoshToolbox calls without having a workinggrasp of how the Mac works, you’re welladvised to have some knowledge ofWindows before tackling your own DLL!

But you can read this article even if youaren’t familiar with Windows. Details ofWindows operations used here will beexplained sufficiently for anyone who atleast knows how to write a CIN. If youwant to learn more about Windows, anexcellent book is Programming Windows 3.1by Charles Petzold, available from MicrosoftPress. For detailed function descriptions,you should obtain as well the MicrosoftPress Windows Programmer’s Referencevolumes.

Secondly, I’m assuming your DLL will bewritten using the 32 bit Watcom Ccompiler. Since you are writing DLLs, youalready have that compiler; also, certainaspects of writing DLLs are simpler if theyare written for the Watcom compiler. Thetradeoff here is DLL size. A DLL writtenwith the Watcom compiler will generally beabout 100k larger than one written with a16 bit compiler, because of the 16 to 32 bitinterfaces incorporated by the Watcomlinker. This is a reasonable tradeoff whenyou consider that all Windows functionsyou want to access can be incorporatedwithin one DLL, and you can call that DLLfrom any of number of CINs. You incurthe 100k overhead just once, no matter howmany functions you call from your DLL.

There are some differences in calling a 32bit DLL as compared to calling a 16 bitDLL. These will not be noted. Only the32 bit implementation details will beprovided. Information on calling 16 bitDLLs may be discussed in a future article.

A third consideration is applicationportability. You can transport normal CINsource code from the PC to a SPARCstation, and merely recompile to utilize it on the SPARC, but DLLs are not portable.You are including system specific code whenyou rely on DLLs. Keep this in mind.

Implementation DetailsThe Watcom C/386 User’s Guide containsseveral chapters on how it interfaces 32 bitcode to the 16 bit environment provided byWindows. You should study those chaptersin conjunction with the informationprovided here(they’re located in the back ofthe 4th edition of the manual; if you have anewer edition, they may be locatedelsewhere). You may also find it helpful tofirst build some of the Watcom sampleWindows files. Follow the instructions inyour Watcom User’s Guide and build theapps to ensure that the compiler end ofthings is set up correctly.

Due to the length of the code listings, thereisn't room to include them here. Please printout Listing 1, Listing 2, and Listing 3, fromthe LTR Resource diskette, so you can referto them as you read what follows.

Writing The DLLWe’ll discuss how to write a DLL first; laterwe will see how to call it. If you look atListing 1 you will see the code required toimplement Exit Windows.

The first item to note is the header filewindows.h. This is the Watcom header thatdefines and prototypes the various Windowsprogramming components. You mustinclude this in any DLL you write.

The next thing to notice is the firstfunction: WinMain. This function isrequired in every Watcom DLL. It isautomatically called when the DLL isloaded and its primary purpose is to definehow to access the individual functionswithin your DLL.

When WinMain is called, it is passed fourparameters. Only two of these contain validvalues within a DLL (WinMain is also theentry point for normal Windows

Accessing Windows DLLs from LabVIEW for Windows

Page 11: Vol  1 Issue 2

CIN Corner

the Windows function you want to call. Youwould ordinarily check the WindowsProgrammer’s Reference or a similar reference,but to simplify matters, I’ll describe thefunction here. ExitWindows takes twoparameters. The first parameter (typeDWORD) is a constant, defined inwindows.h, that indicates how to exitWindows: exit to DOS, exit to DOS andreboot the computer, or exit, then restartWindows. A simple exit to DOS takes noflags; rebooting takes the flagEW_REBOOTSYSTEM; and restartingWindows takes the flagEW_RESTARTWINDOWS. The secondparameter (type UINT) is unused and mustalways be zero.

Since you shouldn’t presume any specialknowledge of the Windows flags, use aswitch statement to match up the properexit flag with the mode supplied by theVI.The VI will define the modes as 0) simpleexit to DOS, 1) reboot system and 2) restartWindows.

Next, you call the ExitWindows function.The function reference notes thatExitWindows will return zero if one or moreapplications refuse to terminate, in whichcase Windows will not exit. If the functionis successful, ExitWindows will not return.Pass the return value from ExitWindows asthe return value of the DLL function. Thiswill be examined in your CIN to detect afailure to exit Windows.

Now you need to compile the DLL. Asample makefile is included on the LTRResource Diskette. To use it for your ownDLL, you only need to change the NAME=definition within the makefile.

After compiling the DLL, it needs to beplaced where Windows can find it when youtry to load it. Windows will look for DLLsin a variety of locations, including thedirectory containing the executable file forthe current task. LABVIEW.EXE is theexecutable file when LabVIEW is thecurrent task, so placing your DLL in theLabVIEW directory makes it locatable aswell as keeps it associated with LabVIEW.You could also put it in the Windowsdirectory, the Windows system directory, or in any of the directories in the PATHenvironment file.

Writing the CINNext you need to write your CIN. Thesource code for the Exit Windows CIN iscontained in Listing 2.

The first thing to note is the inclusion of the header file lvdll.h. The Watcom andWindows functions necessary for accessingDLLs are available from withing a CIN, butthey are not prototyped in the usual CINheader files. Lvdll.h includes the necessaryprototypes as well as useful constants. Thisfile is on the LTR Resource Diskette andyou should place it in your CIN toolsdirectory. Include it in your source afterincluding extcode.h.

Four CIN functions will be used to handlethe DLL. In addition to CINRun, you willuse CINInit and CINLoad to load the DLLand CINDispose to unload the DLL.CINInit and CINLoad implement identicalcode. If the global DLL handle is notNULL, either will attempt to load the DLL.I’ve found it is safest to put loading code inboth of these functions.

LOADLIBRARY is the function to use toactually load the DLL. Normally this isspelled LoadLibrary; due to the way it isexported to your CIN, you must call it withall caps. (This also applies to the functionsFREELIBRARY andGETPROCADDRESS which you will alsobe using.) LOADLIBRARY will returneither a handle to the DLL or a value from 0 to 21 indicating an error. If an error isdetected while trying to load the DLL, youset the global DLL handle back to 0, soyour code can check if the DLL wassuccessfully loaded.

FREELIBRARY is used to unload the DLLin the CINUnload function. FREELIBARYdoes not return a value. Once again, set theglobal DLL handle back to 0, so your codeknows the DLL is no longer loaded.

Both LOADLIBRARY and FREELIBRARYare standard Windows functions and aredocumented in any Windows functionreference manual.

You could load and unload the DLL in yourCINRun function rather than inCINLoad/CINInit/CINUnload, but yourapplication would have to spend the time

Summer 1993 11

applications, in which all four parametersare valid.) hInstance will contain the DLLinstance; this is needed for many Windowsfunctions. lpCmdLine will contain thecommand line argument(s) passed to theDLL. Ordinarily you will call DLLs with noarguments, and lpCmdLine can be ignored.

In Listing 1, the invalid parameters, as wellas lpCmdLine, are “touched” with theUnused() macro, to eliminate compilerwarnings. It is not necessary to do this; it’syour call.

As mentioned in the Watcom User’s Guide,to call a function in a 32 bit DLL, you accessit indirectly, through an ordinal value. InListing 1, WinMain calls the functionDefineDLLEntry to declare LVExitWindowsas the DLL function with ordinal value 1,and describes the parameters which will bepassed to it. Parameters are described interms of size and whether they are values orpointers. (See the entry for DefineDLLEntryin the Library Functions and Macros chapterof the Watcom User’s Guide for a completelist of parameter description constants.) Inthis case, the parameter is described asDLL_DWORD, which means a four bytevalue will be passed as the first parameter.

DefineDLLEntry takes a variable number of arguments, and you indicate the end ofarguments with the constantDLL_ENDLIST. In Listing 1,LVExitWindows is defined as having onlyone parameter (a 32 bit value).

DefineDLLEntry will return 0 if successful,and non-zero otherwise: test its result todetermine your return value for WinMain.WinMain should return 1 if initialization is successful, and should return 0 ifinitialization fails.

Now that the DLL is initialized, the nextthing to do is to write the function forwhich the DLL is being created. Thesecond function in Listing 1 isLVExitWindows. As defined withDefineDLLEntry, this function has oneDWORD (32 bit) parameter. The functionis declared as type int FAR PASCAL(mandatory).

Calling the Windows FunctionHere you need to know something about

continues on page 16

Page 12: Vol  1 Issue 2

Gary writes:

“Included on the LTR diskette are two solutions to last issue’s ‘How doyou do that in LabVIEW...'. quiz question, the ‘Which Button?’problem. Method A uses a numerical algorithm that you might expectto be pretty fast because the number of CPU instructions is minimal.On a Quadra 950 with an array of eight elements, it takes 106 µs toexecute. It has one limitation: no more than 32 elements can behandled.

“Method B, as seen in the latest Advanced LabVIEW Class and in afew example VIs, uses the Search 1D Array function, so it can handlean arbitrary-size array. It executes in just 52 µs, or more than twice asfast as Method A. The reason for this is the lack of data typeconversions, and the fact that the output indicator does not have to do

any range checking. This is an interesting tradeoff. Search algorithms normally require many, many instructions as compared to Method A,above, which technically should only require one instruction (a very slow, transcendental instruction, but one instruction nonetheless). Infact, the search takes longer as you add more elements to the array. I tested it with 80 elements, and measured 112 µs and 800 elements,which took 630 µs, as you might expect. But in LabVIEW, we must battle the Memory Manager, so the guy with the fewest memorymanagement calls generally wins, and that’s Method B.

“Both of these methods return zero if no buttons are pressed. Therefore, your Case structure would typically have an empty frame zero,which is the ‘idle’ condition.

“Surprisingly, the best solution in this case is more elegant, understandable, and faster than the other solution! In most cases, the bestchoice for a LabVIEW solution will have trade-offs beween these criteria and may depend on the type of application. For example, asolution chosen for a production application may emphasize ease-of-use or reusability, whereas a research application may be concernedwith performance.”

Thanks again to all readers who submitted solutions and to Gary Johnson for his solution comparisons and benchmarks. Look for moreLabVIEW technique discussions in Gary’s upcoming book, LabVIEW Graphical Programming Techniques, to be published by McGraw-Hilllater this year.

12 Summer 1993

How do you do that in LabVIEW?

Method A

Method B

Last issue’s puzzle.

Continued from page 9

Page 13: Vol  1 Issue 2

LabVIEW completes initialization, it opens“c:\labview\myapp\coolapp.vi” rather thanputting up the Untitled 1 VI.

This presumes “c:\labview\myapp\coolapp.vi”is a legitimate VI. If it isn’t, LabVIEW willdisplay its “Searching for SubVI” dialog. Inother words, LabVIEW expects only validVI filepaths as arguments.

By now, you’ve probably noticed that thepreceeding examples assume that ProgramManager is the “shell” application. Sincethis isn’t the case (you’ve set up LabVIEW as the “shell” for security reasons), will thisstill work?

It will if it is done slightly differently.Remember: the mechanism here is thatWindows passes the arguments to the“shell” application; the “shell” then handlesthem. Since LabVIEW is now the “shell”and since the first argument has been“c:\labview\labview”, attempting any of the command lines above will result inLabVIEW attempting to look for itself asa VI! The solution is simply to omit the“c:\labview\labview” argument from theWindows command line:

win c:\labview\myapp\coolapp.vi

To automatically start both LabVIEW aswell as your application upon power up, edit your autoexec.bat file so the last line has“win” plus the full pathname of your VI onit. (You should also specify the full path to“win” if the Windows directory is not onyour DOS path.) When Windows starts, itwill launch LabVIEW and pass the VIpathname to LabVIEW. LabVIEW willthen open the VI.

These examples have used “regular” VIsstored in DOS directories. You can also usethis technique to launch VIs stored inLabVIEW “.LLB” libraries:

win c:\labview\myapp\main.llb\top_panel.vi

Neither DOS nor Windows attempts todecode the argument being passed toLabVIEW; consequently, it doesn’t matterthat .LLBs are not understood as libraries by DOS or Windows. On the other hand,when LabVIEW receives the argument,there is no problem in decoding the VIfilepath, because LabVIEW knows how toaccess LLBs!

Summer 1993 13

If you examine the system.ini file usuallyfound in the Windows directory, you willfind a line stating: “shell=progman.exe”.

This is the Windows specification whichputs Program Manager in charge. All youneed to do is change “progman.exe” to read“labview.exe” (you may need to include thefull path if LabVIEW is not in your DOSpath):

shell=c:\labview\labview.exe

Now when Windows runs, it won’t fire upProgram Manager. Instead, LabVIEW willbe considered the “shell” application andWindows will start by launching LabVIEW.This also has the effect of causing Windowsto quit when you exit LabVIEW. Assumingyou truly want an embedded application,this is a desirable effect.

Another beneficial result of this modificationis that the StartUp Group items in ProgramManager are ignored as well as any itemsspecified on the run= and load= lines in theother main Windows initialization file,win.ini. These items provide a way toautomatically start other applications (clock,screensavers, faxware, etc.) whenever ProgramManager launches . If you want to runanother application, such as a spreadsheet, amethod to do this from within LabVIEW isdescribed later in this article.

Task ManagerTask Manager. is what you see if you double-click on the Windows desktop outside of awindow: a dialog box with a list of runningapplications and six buttons for managingthem. Task Manager provides a means ofswitching between tasks (applications) aswell as ability to change their settings,arrange windows and desktop icons, and toterminate applications. The last ability isthe dangerous one. You don’t want the userto terminate LabVIEW. Now that you’vereplaced Program Manager with LabVIEWas the “shell” application, Windows itselfwould exit!

Just as there is a “shell=” setting in thesystem.ini file, there can be a setting in yoursystem.ini file for “TaskMan=”. Often, thissetting is not found in the file; if not there,Windows will default to “taskman.exe” (thefilename for Task Manager). If “taskman=”

is in your system.ini file, then you will editit; if it isn’t there, then you will add it.

To eliminate Task Manager, you set the“TaskMan=” setting to nothing:

TaskMan=

That’s right! Just an equal sign with nothingafter it. Windows will understand this tomean that there is no task manager. Thisdoes not affect the running of Windows atall. Windows does not use Task Manager toschedule tasks, and Task Manager is not partof the Windows kernel. It is only a utility.

After making these changes to the shell andTaskMan settings, we have put LabVIEW incharge of the system, and we have eliminatedthe possibility of another task interfering.When Windows starts, LabVIEW will belaunched, and LabVIEW will be the onlyapplication launched. Now we need to getour VIs loaded and executed by LabVIEW.

Autoexec.batYou most likely start Windows by typing“win” or having “win” as the last line of yourautoexec.bat file.

Windows can also take arguments when youcall it; it passes these arguments to the “shell”application. If Program Manager is set upas the “shell” application, you could startLabVIEW at the same time as Windows byusing the following command:

win c:\labview\labview

Windows passes “c:\labview\labview” as anargument to Program Manager. WhenProgram Manager starts, it checks its commandline, and since an argument exists, it loadsand executes LabVIEW.

If multiple arguments exist, ProgramManager will pass the remaining ones alongto the application being executed. Forexample, consider starting Windows withthe following command line:

win c:\labview\labview c:\labview\myapp\coolapp.vi

Windows starts up and passes ProgramManager the arguments “c:\labview\labview”and “c:\labview\myapp\coolapp.vi”.Program Manager loads and executes“c:\labview\labview” and passes LabVIEWthe remaining argument:“c:\labview\myapp\coolapp.vi”. When

continues on page 14

Technical NotesContinued from page 1

Page 14: Vol  1 Issue 2

One warning here: to use this technique of calling VIs within LLBs from a DOS commandline, you can have no spaces in your VI name. DOS uses spaces as delimiters in argumentslists. Calling “mylib.llb\top panel.vi” will not work because DOS will pass that to Windowsas two separate arguments: “mylib.llb\top” and “panel.vi”; these are in turn passed to LabVIEWas two arguments and since neither argument by itself is a valid VI path, things won’t work.To get around this, you can replace any spaces in your VI names with underscores or hyphenswhen you want to fire them up this way.

You will also want to fix your VI setup options so the VI runs automatically when it isopened. More on this next.

Beefing up LabVIEWBy making the above changes, you’ve bulletproofed the surrounding DOS/Windows layersof your application. Your LabVIEW app will run when you want it to, and it won’t beinterrupted from outside. So what about interruptions from within?

Running your VI automaticallyWe have set up the system to load LabVIEW as well as your application automatically uponsystem start. You should also set up your main VI to automatically run when it is opened.This way the operator won’t have to know to press on “that button with the arrow puttingto the right”.

For those of you who aren’t already familiar with this feature: if you pop up on the icon foryour main VI, you will see a menu with three options. Choose the third option “VI Setup...”.A dialog box will appear listing various execution options, one of which is “Run WhenOpened”. Check this box, press OK, and then save your VI. Now when LabVIEW opensyour VI, LabVIEW will also start it running!

Setting up Window/Execution OptionsYou can utilize the windowing options available under LabVIEW for Windows version2.5.2 to increase security within LabVIEW. These options are not available under version2.5.1, and if you are still using 2.5.1, you should contact National Instruments to obtain an upgrade.

When you access the VI Setup dialog, notice the control at the top of the panel. It isoriginally set to Execution Options, but if you press on it, you can access more settingscalled Window Options. These powerful tools allow you to lock in the look and feel ofyour application and can keep the user from inadvertently messing things up. Normallythey are used only with VIs that will be opened during operation. There is no point inusing them with VIs that never show their front panel.

Rather than simply re-hash information available in the LabVIEW manuals, let’s examinesome of the implications and benefits of the use of VI Setup Options.

Dialog BoxUsing popup VIs as dialog boxes is a common method of user-interface technique in LabVIEW.Problems can arise with this technique because the user has the option of clicking on one ofthe other panels which are open. While your dialog panel is waiting for input, the user mayactivate some other panel and attempt to operate its controls. Confusion can result whenthose controls don’t respond and your application may appear to be locked up. If this otherpanel hides your dialog panel, the situation is aggravated; there is no indication that thedialog panel is waiting because it can no longer be seen.

The Dialog Box option in VI Setup was intended to prevent this situation by forcing the userto interact with your panel. Unfortunately, this potentially powerful option does not correctlyfunction in LabVIEW for Windows version 2.5.2. Apparently, its only effect is to cause thepanel frame to change style. You can still interact with other VIs and can still obscure yourdialog panel.

Oh well... have to forget about that one.The good news is that during the NationalInstruments User Symposium at the end ofMarch, this feature was included (andworking correctly) in the LabVIEW 3.0installations demonstrated by NationalInstruments; it looks like this helpful toolwill be available in the future!

Window has Title Bar

Disabling this option eliminates the title barfrom your VI, and prevents the user frommoving the panel around the screen(because you drag the title bar to drag thepanel). By also disabling “Allow User toResize Window”, you can be certain thatpanels will be located on the screen whereyou want them and the way you want them.I disable the Title Bar frequently, because itdefinitely gives an embedded feel to myapplications. If you place the panel whereyou want it while in edit mode (the title barwill be visible then), and save your VI withthese options disabled, it will always showup at that location. If the “Save” option isdisabled (because you haven’t made anychanges) you can always use “Save as...”Specify the original name and then choose“replace” when the file overwrite warningshows.

Allow User to Close Window

Letting the user close panels can bedangerous. Closing a VI is not the samething as stopping it. If the VI is waiting forthe user to press a button to completeexecution, and the user closes the VI beforepressing the button, it will go on waitingforever. Your application will appear to belocked up. The user can recover byaccessing the VI from the LabVIEW“Windows” menu (with Unopened SubVIs,for example), but this method of recovery isfar from intuitive.

I feel it is better if panel closure is kept underprogrammatic control (with the ExecutionOptions), rather than chance user frustration.On the other hand, if you hide the menubar, title bar and use the method describedlater in this article to defeat keyboard menushortcuts, the user cannot give a commandto close the window, as all avenues of issuingthe command are eliminated. In this case, itwould be superfluous to disable this option.

14 Summer 1993

Technical NotesContinued from page 13

Page 15: Vol  1 Issue 2

CIN Corner

Allow User to Resize Window

As mentioned above, I generally disable thisone for an embedded application. I’ve laidout my screens the way they should be, and Idon’t want to chance a user messing them up.

Allow Run-Time Pop-up Menu

This is normally benign. You may want todisable it if you think your users will beconfused if they get a popup data operationsmenu. I leave it enabled.

Auto-Center

This is also a benign option. Keep in mindthat if you want to put up multiple panels,you might be better off leaving it disabled;disable the title bar and window sizing, andthen save your panels after laying out theirpositions.

I use auto-centering if I have one big panelthat I want to have fill the screen. Then Idon’t have to worry about getting it positionedright. It will always be in the center.

Show Scroll Bars

A favorite item to disable: too muchopportunity for user confusion exists if thereare controls placed outside the normal limitsof the panel.

Show Menu Bar

Another frequently disabled option: in acorrectly-constructed embedded application,there should be no need for the user tointeract with any of the menu items. It ismuch safer to get rid of these.

On the other hand, disabling this optiondoesn’t completely eliminate menu access.Though the menu cannot be seen, nor canit be accessed with a mouse, a user can stillaccess menu functions with CTRL+key andALT+key access. Later in this article, youwill learn a method to prevent these keyboardmenu shortcuts.

Show Execution Palette

I put this one in the same category as menubars. There is no need for the user to accessany of these in a correctly designed system.The only access you might want to give auser is for Printing, but even there it is saferto go ahead and set the VI toprogrammatically print and then disable

(hide) the entire execution palette (the VI will still programmatically print).

If you need to allow the user to choose when to print, enable only the printing button andshow the execution palette; otherwise, hide the whole thing.

Message Filters: What are They? Why are They Necessary?As mentioned above, hiding the menu bar does not completely prevent access to it; eventhough mouse access is prevented, the user can still access menu functions by pressingCTRL+key or ALT+key combinations. For example, pressing CTRL+Period will stop yourapplication dead; pressing ALT+O brings up the Operate menu.

Windows provides a mechanism for filtering out these key combinations, and LabVIEWprovides a way to activate this mechanism within Windows.

Windows offers the ability for an application to install “hooks” for various system messages.Among other things, these messages are used to convey keyboard input to an application. A hook receives system messages before the application they are being sent to does, and canmodify or throw away these messages rather than allow them to be passed on to theapplication. These hooks can be installed by a Dynamic-Link Library (DLL). DLLs aremodules of compiled code, separate from an application, which can be linked to and executedby an application at runtime.

LabVIEW allows you to run functions located within DLLs by accessing them through aCode Interface Node (CIN).

The LTR Resource diskette contains a utility VI, Message Filter, which provides messagefiltering through this mechanism. Message Filter will let you eliminate menu access throughthe keyboard, and will let you make your application even more solid.

Filter UseThere are many “keyboard accelerators” available within LabVIEW. These accelerators arethe CTRL+key combinations that you use to automatically execute menu options withoutactually opening the menu. Examples of these are CTRL+C for Copy and CTRL+O forOpen. I picked the ones which can be dangerous to use from within an application andhave provided a means to individually enable or disable each of these key combinations.

The accelerators you can opt to eliminate are Exit (CTRL+Q), Get Info (CTRL+I), New VI(CTRL+N), Open VI (CTRL+O), Run (CTRL+R), Stop (CTRL+Period), Toggle Modeedit/run (CTRL+M), Show Diagram (CTRL+F), Show Help (CTRL+H) and Tile Windows(CTRL+T). Most of these are actions you won’t want a user to inadvertently access. If youwant to allow some of them, you can let those messages pass through while filtering others.(See Figure 1 for an illustration of the front panel of the Message Filter VI.)

You’ll notice that each filter is controlled with a Boolean. Setting a Boolean to “Remove”(True) will cause that filter to discard the specified key combination thereby preventingLabVIEW from receiving it. Setting the Boolean to “Pass Thru” (False) will allow that keycombination to be sent to LabVIEW.

In addition to the CTRL+key filters, there is also a filter to prevent ALT+key access. Turningthis filter on will prevent the key combinations of ALT+F, ALT+E, ALT+O, ALT+C andALT+W from popping up any of the LabVIEW menus. Hiding the menu bar does notprevent ALT+key access to the menu. Installing this filter does.

Filtering ALT+key access also eliminates rotation among the open windows through use ofthe ALT+ESCAPE key combination (this rotation can be confusing) as well as eliminates theWindows task switching window accessed with ALT+TAB (this key combination preventsyour application from getting any CPU time as long as it is pressed). The converseoperations ALT+SHIFT+ESCAPE and ALT+SHIFT+TAB are also filtered.

Any of these filters only operate when LabVIEW has the focus and is the recipient of the

Summer 1993 15

Technical Notes

Continues on page 18

Page 16: Vol  1 Issue 2

LabVIEW Technique

Technical Notes

locating the DLL each time you run the CIN.

CINRun contains the code which accessesand executes the function within the DLL.There are several steps involved:

First, you should verify the DLL handle isnot 0. If it is, then some problem occurredin loading it, and you better not try toaccess it.

Next you need to get the address for thefunction you are going to call in the DLL.Though it may seem that you will be callingthe function as you named it in your DLLsource code, this is not the case. WatcomDLL functions are accessed through acommon entry point: Win386LibEntry.This is to allow parameter massaging tointerface 32-bit LabVIEW to 16-bit

Windows. Since you are calling a 32 bitDLL from 32 bit code, it may seem that noparameter massaging is required; it doesn’twork that way in practice. When you callany DLL function from Watcom code, theparameters are first converted to 16 bit-styleReason: you may be calling a 16 bit DLL;there is no way for the compiler to detectwhat type of DLL you plan to call!Likewise, a 32 bit DLL must receive 16 bit-style parameters, as it doesn’t know whethera 16 bit or a 32 bit program is calling it.You have to call the same number offunctions in order to access a 32 bit DLL asyou would have to call to access a 16 bitDLL, so from the standpoint of your sourcecode, it all looks much the same.

You get an address for Win386LibEntry bycalling GETPROCADDRESS. This

function takes two arguments: a handle to the DLL and a string containing“Win386LibEntry”.GETPROCADDRESS returns either a far pointer (type FARPROC) to the DLLfunction, or NULL if unsuccessful. So you need to check it to avoid crashes.GETPROCADDRESS is documented inany Windows function reference.

The next step is to obtain an “indirectfunction handle” using the Watcomfunction GetIndirectFuntionHandle (note:this function is not all caps).GetIndirectFunctionHandle is documented in the Library Functions and Macros sectionof the Watcom User’s Guide. It takes aFARPROC pointer as its first parameter,and then it takes a variable number ofinteger parameter description constants

16 Summer 1993

Have you ever built a complicated block diagram and discovered that you need more room in the middle of your diagram? You probablygrow nested looping structures one by one, starting from the outermost loop, tediously moving objects out of the way until all embeddedloops are adjusted.

Luckily there’s an easier way! A little-known editing feature in LabVIEWfor Windows adds space anywhere in front panel or block diagram windows.To open a clear gap in the middle of your diagram, simply hold down thecontrol key and drag the positioning tool across empty space (don’t select

anything). This action scoots allobjects in the direction that you aredragging. Figure 1 shows the actionand Figure 2 shows the result. Thisfeature is undocumented so we tookthe liberty to name it “scooting” justfor fun!

You can scoot front panel or block diagram objects in one or two directions. Dragging the positioning tool diagonally with the control key pressedcreates a square selection rectangle that moves all items proportionallyin both directions. You can restrict the expansion to one direction bydragging the positioning tool in astraight line across empty space.

Technically, any front panel or blockdiagram item (node, terminal, control,

indicator, etc...) whose hot point is in the direction that you are scooting willbe moved proportional to the positioning tool move.

Try scooting nested loops on your block diagram, or embedded clusters onyour front panel! This is a great way to grow an embedded while loop andhave every outer loop and its contents automatically adjust.

“To open a clear gap

in the middle of your

diagram, simply press

the control key and

drag the positioning

tool across empty

space.”

“Scooting” front panel and block diagram items

Continued from page 11

Figure 1: Scooting action

Figure 2: Result after scooting

Page 17: Vol  1 Issue 2

Summer 1993 17

similar to those use in DefineDLLEntry.These constants are not the same, so becareful which constants you use. You putone constant parameter descriptor in the callfor each parameter in the DLL function (inthis case, there is only one parameter).Then you put a parameter descriptor for theordinal value of the function you want tocall. Finally you add an end of list marker.These descriptors are described in theWatcom GetIndirectFunctionHandledocumentation. In Listing 2, you will seethat INDIR_DWORD is used to describethe “exit mode” parameter, INDIR_WORDis used to describe the ordinal value (theordinal value should always be marked withINDIR_WORD as it must be passed as a16 bit value), and finallyINDIR_ENDLIST is used to mark the endof the parameters.

GetIndirectFunctionHandle returns either ahandle to use in calling the DLL, or NULLif it was unable to allocate handle, so be sureto check its result. The Watcomdocumentation does not indicate a need forfreeing this handle once you are done withit, nor does it outline a method for doing so.

The last step is to call the DLL functionwith the Watcom functionInvokeIndirectFunction. This function takesthe indirect function handle you justobtained as its first parameter. Then it takesthe parameters you are passing to the DLLfunction; in this case, there's just one. Itsfinal parameter is the ordinal value of theDLL function as defined in the DLL call toDefineDLLEntry. InvokeIndirectFunctionreturns a 32 bit integer, which is the valueyou returned from the DLL function. TheDLL function returned FALSE if it wasunable to exit Windows. It never returns if Windows does exit.

Debugging Debugging DLLs and CIN interfaces tothem can be tricky. It is very easy to getGeneral Protection Faults (GPFs) so youshould keep your work backed up. Themost common sources of GPFs are notsetting up your parameter lists correctly(both in the GetIndirectFunctionHandle call in the CIN as well as in theDefineDLLEntry call in the DLL), andinvoking the indirect function with the wrong

ordinal value. These will usually crash yourCIN, your DLL and LabVIEW instantly!Take a little extra time to make sure they’reright when writing your source code.

You can use the Windows functionMessageBox for seeing what's going on inyour DLL MessageBox puts up a simpledialog box. You can call it like this:

MessageBox(NULL,”message”,”title

of dialog”,MB_OK);

A pitfall of developing DLLs is the“module-still-loaded-syndrome”, which canoccur in several ways. If you load yourCIN, it will load the DLL you are workingon. When you modify the DLL source,recompile and move it to the LabVIEWdirectory, the old DLL is still loaded. Youneed to unload your CIN to get the newDLL loaded into memory. More subtle iswhen you crash a CIN after it loads a DLL.In this case, even though the CIN is notloaded, the DLL still is. There is nostraightforward way to get rid of the DLLshort of exiting Windows, although utilitiesexist which forceably unload modules. Asafe rule of thumb is to always exit andrestart Windows after crashing whileworking with CINs and DLLs.

Another pitfall is failing to move the DLLto the LabVIEW directory after modifyingit. You’ll probably be building it in someproject directory, and Windows won’t find itthere. Instead it will find the last versionwhich is still in the LabVIEW directory. Ina similar vein, beware of placing the DLL inmultiple locations. The current directory,the Windows directory and the Windowssystem directory are searched before theLabVIEW directory, so if you’ve placed theDLL in any of those locations, upgradingthe DLL in the LabVIEW directory will notresult in change. My rule here is to only usethe LabVIEW directory; the Windows andWindows system directories are generallyoverstuffed anyway.

Other IssuesKeep in mind that CINs are notasynchronous. When you call a CIN, yourentire application pauses until the CINexecution completes. Since you are gettingto the DLL from a CIN, your applicationwill pause while you are in the DLL as well.

CIN Corner

In this example, only a single integer wasreturned from the DLL. If you want toreturn more than one integer value from aDLL, you have to pass pointers. Be sure to define pointer parameters correctly inDefineDLLEntry and inGetIndirectFunctionHandle. Since thepointers you are using in your CIN are 32bit near pointers, they will not be directlyaccessible from your DLL, since it isrunning in a different address space. Whenyou pass pointers as parameters, Watcomconverts them to 16 bit far pointers; this ishow your DLL receives them. 16 bit farpointers are not directly useable in 32 bitcode, and you must first convert them to 32 bit far pointers using the Watcom macroMK_FP32. Your code would look like theexample in Listing 3.

ConclusionThese are the basics of accessing DLLs fromLabVIEW. You should write simple DLLfunctions to become familiar with thenuances of this technique before attemptinganything involved.

The listings for this article are excerpts ofthe source code for LTRUTILS.DLL and its associated CINs that you will find on the Resource Diskette.. The source code for the DLL is more involved as it alsocontains the message filtering functionsdiscussed in the LabVIEW security articleelsewhere in this newsletter.

continues on page 21

GetThe

LabVIEWProgramming

Edge –Subscribe

to

Today!

LTR

Page 18: Vol  1 Issue 2

Technical Notes

keystrokes (i.e. when a LabVIEW frontpanel is the foreground window). Of course,if you set up Windows to run LabVIEW andLabVIEW only, the filters will operate all ofthe time, because a LabVIEW panel willalways have the focus!

The easiest way to use this VI is to call itonce at the beginning of your application.Place it on the diagram of one of your VIs,copy the filter settings cluster from theMessage Filter VI’s front panel, and paste itonto the panel of the VI from which you aregoing to call Message Filter. Configure thefilter settings on your VI’s front panel theway you want them, set those settings todefault, wire up the control to the MessageFilter VI on your diagram, then hide thefilter settings control on your front panel(pop up on the terminal on your diagram toaccess the Hide Control option). Lastly,wire a TRUE constant to the Install/Removeterminal of the Message Filter VI to indicateyou are installing a filter.

You could also call Message Filter with dynamically created filter settings, though this is probably unnecessary; you will likely only need oneway of setting the filters for your entire application.

Once installed, the filters operate transparently in the background. You do not need to do anything else to enjoy this higher level ofapplication security. On the other hand, trying to do VI development while the filters are activated will be difficult, so you should wait toactivate them until final testing of your application.

Please note that you only need to call this VI once to set up the message filters. Filtering is a background operation. Once installed, nofurther attention is needed from your application.

If you want to change the filter settings, you could call the VI again with the modified filter settings, and Install/Remove set to TRUE. You do not need to first de-install the previous filters to change the filter settings.

To remove the filters completely, call Message Filter with a FALSE constant wired to the Install/Remove terminal. You need not providefilter settings when removing filters, as these are ignored during removal. You will probably want to remove the filters before stopping yourapplication. Even if filters are not installed, it is safe to call the Message Filter VI in Remove mode. The VI will detect the lack of filtersand will not attempt removal.

You do not need to do anything special to access the DLL once it is installed. The CIN contained in the Message Filter VI has theappropriate code for unloading and loading the DLL.

For robustness, the filters will automatically be removed if the DLL containing the filters (LTRUTILS.DLL) is unloaded; the DLL isunloaded when the Message Filter VI and any other VIs accessing LTRUTILS.DLL are unloaded.

DLL installationThe DLL is automatically linked to your application when the Message Filter VI is loaded. If there is some problem in linking to the DLL,you will see a dialog box containing a brief explanation of the trouble. When the DLL cannot be loaded the Message Filter will not attemptto call the DLL function, to avoid an attempt to run non-existent code.

The most common problem in linking to a DLL is that Windows cannot find the DLL. The DLL must be on the normal file search path,within the Windows directory, or in the directory of the application attempting to load the DLL. For this reason, a good place to putLTRUTILS.DLL is within the LabVIEW directory (the directory in which the “labview.exe” file is found). Even if the LabVIEW directoryis not on your normal file search path, Windows will know where it is Windows tracks the filepaths of all loaded modules, includingapplications.

18 Summer 1993

Figure 1: Message Filter VI

Continued from page 15

Page 19: Vol  1 Issue 2

Summer 1993 19

Saving Without DiagramsOne more thing you can do to beef up yourapplication is to save it without diagrams.How to do this is covered in full in yourLabVIEW manual (see information on theFile Menu item “Save with Options...”).

Saving without diagrams has the addedbenefit of preventing the user from goinginto edit mode with your VIs even withouthiding the menu bar or installing themessage filters. On the other hand, if youdo plan to hide the menu bar, and installmessage filters, then the user won’t be ableto get to your diagrams, or edit your frontpanels anyway.

Run File VIEven though you want increased securitywithin your application, you may still wantthe freedom to access another application.By replacing Program Manager withLabVIEW as the “shell” application, youhave prevented normal access to otherapplications. However, launching otherapps can be performed from within LabVIEWwhere you retain control of what getslaunched when.

Another utility VI provided in this issue ofLTR will let you launch another applicationfrom within LabVIEW. Give this Run FileVI the pathname of any executable file andit will load and execute it for you. You caneven specify whether you want to run it asan icon (minimized) or in a regular window.See Figure 2 for its front panel.

This VI will also run regular DOS programs,though you must provide a ProgramInformation File (PIF) for these if you wantto run them in a window. Otherwise, DOSapplications will run in a full DOS screen.See your Windows manual for informationon creating PIFs.

You could run only specific applications, or you could provide a file dialog or othermechanism to let the user pick whatprogram he would like to run. Applicationlaunching is a good candidate for passwordrestriction.

Keep in mind that by running anotherapplication, you are opening the door forpossible system interruption. And bewareof applications such as File Manager that let

Technical Notes

continues on page 20

you spawn other tasks, lest your system goesout of control.

A last caution: since this VI enters a CIN inorder to start another application, and sinceCINs are not asynchronous, your LabVIEWapplication will pause for as long as it takesto load and start the other application.Some applications get going rapidly; othersare slackers. Use prudence as to when youallow this VI to be called.

Exit Windows VIAfter implementing your application asoutlined out above, you have set it up to bevirtually impenetrable while it is running.But what about exiting? Do you have to letthe user see the menu bar in order to chooseExit? If so, how can you if the menu barsare hidden? Is there a better way?

The final VI in this suite of LTR utilitiesgives your LabVIEW application the abilityto exit Windows in one of three ways. Youcan simply exit to DOS; you can exitWindows and restart it; or, you can exitWindows and reboot your hardware. Thisis done by calling a standard Windowsfunction “ExitWindows” fromwithinLTRUTILS.DLL, so it is safe to use.The function is accessed through the ExitWindows VI. See Fig. 3 for its front panel.

You could put an “Exit” control in yourapplication which would allow the user toenter a password. If this password is valid,then you can call the Exit Windows VI togracefully terminate LabVIEW and Windows.Naturally you should do any neededhousekeeping, such as closing files andstopping double-buffered data acquisition,before calling the Exit Windows VI.

Accomodating Later EditingAll of the application constraints you haveintroduced can make editing your applicationdifficult if not impossible. It would be niceto regain control of your system in somepredictable manner.

One method would be to use the Run FileVI to launch Program Manager (progman.exe),found in the Windows directory. OnceProgram Manager is running, you’ve obtainedsystem flexibility.

Another technique is to set up Windows in

the original manner (with Program Manageras the “shell”) and then restart Windows orreboot your computer.

A straightforward way to do this is to createtwo backup system.ini files. Once of theseshould be a copy of the original system.inifile that starts Windows with ProgramManager as the “shell” application. (Callthis one, say, system.win.) The other backupshould be a copy of the modified system.inifile that starts Windows with LabVIEW asthe “shell” (Call this once system.lv). Bycopying system.win over system.ini and thenrestarting Windows with the Exit WindowsVI, you can launch Windows with ProgramManager as the “shell”.

You could set up a special password inaddition to the password for simply shuttingthe system down. The special one would setit up for editing. The normal password wouldshutdown the system without modifyingsystem.ini.

Another method is to create a dummy VIwhich does not have the Run WhenOpened option enabled. On the diagramof this VI, place a copy of your main VI andthen save this dummy VI. Since your mainVI is set up for “Run When Opened”, yourmessage filters will get activated if you loadit as a top level VI. By placing it onanother, dummy VI’s diagram and loadingthe dummy VI first, you can load your “toplevel” VI without starting it, therebykeeping yourself from locking yourself outwhile editing. As your “top level” VI is asubVI of the dummy VI, it won’t autoruneven if you open its panel.

Finally, if you are using the Message FiltersVI and you want to edit your application, itis safest to create another VI, separate fromyour application, which calls the MessageFilters VI to remove all filters. This way, ifthe filters accidentally get turned on, you canturn them off. You could even load in thissafety VI first, before loading your securedapplication.

Other issuesThere are a couple of remaining weak linksin your system. One is the point at whichautoexec.bat is executing when the systemstarts. Since this is a batch file, it can beinterrupted by pressing Control-C or Control-

Page 20: Vol  1 Issue 2

If you have comments on this article, or have additional ideas on increasing applicationrobustness and security, please let us hear from you!

About the Author: Brian Paquette is a member of the technical staff at MetricSystems. When he’s not busy writing LabVIEW applications, you'll usually find him taking apart Windows to see what makes it tick.

Break. If this happens, the user can get toDOS without having your application start.

By setting various escape sequences in yourDOS prompt, you could eliminate Control-C problems, but Control-Break cannot behandled this way. To fully handle this problem,you would probably need to replaceCOMMAND.COM with another DOScommand interpreter. Writing a commandinterpreter capable of executing batch filesand starting up your system is no lightundertaking, and since the risk is minimaland only during powerup, I don’t worryabout it and you shouldn’t either.

Another issue is breaking into the system bybooting off the floppy drive. This can beprevented on some computers through oneof the system parameters stored in non-volatile memory on the motherboard. Inthese systems, there is an option to force thesystem to boot from the hard drive even if abootable floppy disk is in place. Check themanual for the system or the motherboardfor this option. On other computers, youcan completely remove the floppy drive ifyou or your customer are that worried aboutit. Once again, this is really only a problemduring powerup and only if you are reallyparanoid about system security.

ConclusionThere are many stepsyou can take to increasethe security andembeddedness of yourLabVIEW application.Likewise, there are manylevels of security thatyou might want. Oneapplication may need to be more secure thananother. Are yousecuring the system frominadvertent mistakes?Or are you trying toprevent malicioustampering? You canpick from the variousoptions that have beenpresented here, as wellas choosing any of your own devising.

20 Summer 1993

Technical Notes

Figure 2: Run File VI

Continued from page 19

Figure 3: Exit Windows VI

Page 21: Vol  1 Issue 2

Initializing the ASCII File I/O method (Frame 0) is similar to initializing the Binary FileI/O method, with two exceptions. First, since we are converting each element to an ASCIIrepresentation, element size in the file is larger than the size of the element’s floating pointrepresentation. The subVI, ASCII Datafile Elt Size, computes and returns the number ofcharacters in the smallest ASCII exponential representation that retains the precision of the

floating point number. Second, since the file format is ASCII, we convert thebookkeeping information in the front of the file to a tab-delimited, carriage-return(LV2.2) or CR/LF (LV2.5) terminated series of ASCII values for storage at the front of thefile, rather than simply casting the numbers to a string as we did for the Binary method.

Datafile OpenFor the ASCII and Binary File I/O methods (Frames 0 and 1), opening an existing datafile

is much like creating a new one, except for the file I/O function we use. Also, instead ofcomputing and writing the “file shape” information to the beginning of the file, we need to read back the information that Datafile Init deposited at the beginning of the file. Thedifference between the two File I/O methods is in how the array shape info is read andconverted to numbers for the File Info cluster.

With structured data files, one detail that LabVIEW doesn’t take care of is storing row length.There’s a good reason for this: since a row is simply a 1D array, they can be of any size as faras the structured file I/O functions are concerned. So, when opening a Structured Methoddatafile, we need to compute row size by retrieving a data record from the file. If nothinghas been logged to the file, we can’t compute row size, so a -1 is returned in this case.

Datafile AppendThe Datafile Append VI adds data to the end of the file. Itaccepts a File Info cluster that describes an open datafile of thespecified type, and a block of data in the form of a 2D arraywhose columns correspond to channels. It appends this blockof data to the end of the datafile. Accepting a block of dataat a time is more useful than accepting a row at a time, sincemany data acquisition operations, e.g. double-bufferedacquisition, return a block at a time. A single row at a time can be accomodated by building itinto a 2D array in LabVIEW 2, or simply reshaping the array in LabVIEW 2.5.

The append operation is fairly simple for all of the File I/O methods. However, it wasmuch easier to implement in LabVIEW 2.5 because of the advanced features of 2.5’s fileI/O functions.

For the ASCII and Binary methods, we need to position the file pointer (where new byteswill be written in the file) to the end of the file, since we don’t know where the file pointer iswhen the VI is called. The File Seek function is used for this in LabVIEW 2.2; in LabVIEW2.5, the offset can be wired directly to the File Write function. The ASCII File I/O methodcalls a subVI, “ASCII Datafile Element Format”, to return a format string for the data, givenits element size, which is taken from the File Info cluster. A single call to the Array ToSpreadsheet String converts the data block to a string, which is written to the file.

The Binary File I/O method for LabVIEW 2.2 first seeks to the end of the file, then caststhe data block to a string and writes it to the file one row at a time (since the type cast won’tcast a 2D array to a string all at once). The LabVIEW 2.5 file write function has the abilityto internally cast any datatype to a bytestream, so the Binary Datafile Append in LabVIEW2.5 is about as easy as it gets; the 2D array is simply wired to the file write function.

The Structured method must write the data block to the file one row at a time, since we havedefined the file’s native type to be one row. However, no conversion to string is necessary ineither version of LabVIEW; the array is wired directly to the file primitive (after bundling, inthe case of LabVIEW 2.2).

create a new, empty datafile and initialize itwith the bookkeeping information that isneeded to determine the shape of the array.The caller supplies the row size in elements,which corresponds to the number of

channels to be logged. The only purpose ofthe Element Data Type control on the frontpanel is to specify the type of the data; theelement size (single, double, or extended) isautomatically calculated from thisrepresentation.

Let’s look at the structured data initializationcase first. Initialization is simplest for theStructured File I/O method (Frame 2),because LabVIEW takes care of all of thebookkeeping. About the only thing we needto compute is the element size of the floatingpoint representation we want to use for thedata. Element size is obtained by casting anelement of the datatype specifier to a stringand measuring its length. The file path anddatatype specifier is wired to the New DatalogFile function (in LV2.2.1) or the New Filein LV2.5. Row size is passed through fromthe input control.

Note that we boost the dimensionality of thedatatype element to a 1D array before weconnect the datatype to the New File function.This way, we force the granularity of storageto a single row, so we will be able to get thedata back a row at a time, instead of a blockat a time.

For the Binary File I/O method (Frame 1),we need to take care of some bookkeepingat the LabVIEW level, so initialization is alittle more complicated than for StructuredFile I/O. After creating the datafile usingthe New File function and checking forerrors, we write the information about theshape of the file to the beginning of the file.In LabVIEW 2.2, we must cast the clusterof integers to a string prior to writing, butin LabVIEW 2.5, they can be wired directlyto the File Write function. Computation ofelement size is the same as for the StructuredFile I/O method.

Summer 1993 21

Technical NotesContinued from page 7

continues on page 23

Figure 1: LabVIEW 2.2.1 File Info cluster

Figure 2: 2.5.2 File Info cluster

Page 22: Vol  1 Issue 2

Datafile CloseIn the LabVIEW 2.2 implementation, theclose operation for each File I/O Methodpasses the file refnum from the info clusterto either the Close File function or the CloseDataLog File function In the LabVIEW 2.5Close Datafile implementation, the closeoperation passes the appropriate refnum tothe same Close File function.

Datafile SubsetLike LabVIEW’s Array Subset function,Datafile Subset returns an arbitrary (butrectangular and therefore contiguous) subsetof the datafile, given the first row and columnand number of rows and columns in thesubset. Row and column specifiers arerepresented as unsigned integers to precludenegative values. Number of rows and numberof columns default to the largest positiveinteger, so if left unwired all of the rowsand/or all of the columns will be returned.

The ASCII Method is implemented almostidentically in LabVIEW 2.2 and 2.5; theonly difference is that a separate file seek tothe offset of the first data row desired is notnecessary in LabVIEW 2.5, since filepositioning is built into the File Read function.First, the amount of data in the file and theoffset of the first row to be read are computed.Then, the data in the subset are read all atonce, and converted from ASCII to binaryusing the Spreadsheet String To Arrayfunction. Finally, the desired columns areextracted using the Array Subset function.Error checking of column specifiers (firstcolumn and # of columns) is handledautomatically by the array subset function.

The Binary Method is simpler in 2.5 thanin 2.2, because no seek is necessary andbecause the data can be read all at once as a 1D array, and shaped into the desired 2Darray. In LabVIEW 2.2’s Binary Subsetmethod, the data must be read a row at atime and typecast into 1D arrays, which areaccumulated into a 2D array at the boundaryof a while loop. The data can’t be read all atonce since the typecast won’t cast a string toa 2D array.

For both versions of LabVIEW the StructuredFile I/O Method implementations of DatafileSubset are nearly identical. The onlydifferences are in the function used to obtain

the file size (Get EOF in 2.5, Get NumberOf Logs in 2.2), and other minor differencesin how datatypes are cast or bundled.

Datafile Replace ElementAs the name implies, the Datafile ReplaceElement VI replaces a single datum in thefile, located by its row and column offset,with a new value.

The ASCII and Binary methods are quitesimilar, both between each other and betweenversions. The element offset is computed,bounds checked, then a file write is used toreplace the element at the offset with thenew value. The major difference betweenLabVIEW versions is the need for a separatefile seek in 2.2.

For the Structured File I/O method, the onlything Datafile Replace Element does is toput up a dialog box informing the user thatit can’t be done! LabVIEW datalog files areappend only; they don’t support randomwrites at all.

Comparison & AnalysisIn this section, we’ll see how the differenttechniques stack up against each other. We’llshow you how to run the array-on-diskimplementations to get some idea of the speed& space performance of each technique, andfollow that with an analysis of the techniquesusing the other criteria we've discussed.

Speed and SpaceA VI, “Time Datalog Operations”, is providedfor comparing time performance between themethods. Time Datalog Operations firstcreates a data block of random numbers ofa size specified by its front-panel controls.Then, it creates a datafile of the specifiedtype called ASCII .DAT, BINARY.DAT, orSTRUCT.DAT and located in the defaultdirectory (LabVIEW 2.5) or on the internaldrive (LabVIEW 2.2). The append timer isstarted, the previously created block is writtento the file a specified number of times bycalling Datafile Append, the file is closedwith Datafile Close, and the timer is stopped.Then, the subset timer is started, the file isopened with Datafile Open, read back a rowat a time in reverse order by repeated calls toDatafile Subset, closed, and the timer stopped.The total time of the Append and Subsetoperations is displayed in front-panel indicators

and in a table which accumulates the resultsof consecutive runs.

Absolute as well as relative performancedepends on many factors such as CPU anddisk speed, fragmentation, presence of cache,etc., so, as they say, your mileage may vary.Rather than quoting specific runtimes, I’lljust share some general observations.

I expected Binary operations to be fastest,followed by Structured, with ASCII beingthe slowest. On the Mac, this was the casefor Subset (reads), but for Append (writes),Structured was faster than either Binary orASCII, which were about equal. I attributethe Binary method’s disappointing Appendperformance to the fact that it must writeout the data a row at a time, just like theStructured method, as well as index the blockarray with an array indexer instead of at theloop boundary due to a TypeCast functionbug that will be described later.

On the PC, the Binary method’s Appendperformance is best, followed by Structuredand ASCII, as predicted. Here, the surpriseis in the Subset performance, which is thereverse of that predicted! I suspect this hasto do with an extra data copy that's neededbecause of the Array Reshape primitive.

You should run Time Datafile Operations onyour system, with varying block sizes, and seehow your results compare.

As you would expect, the files generated by the Binary method are smallest, for anequivalent amount of data stored.Structured files are only slightly larger,because of the record index they mustmaintain. ASCII files are quite a bit larger,mainly because of the requirements we’reimposing to maintain full data precision and equal size elements to facilitate random access.

Other FactorsAs mentioned earlier, speed is not the onlyfactor to be considered in choosing adatalogging method. Ease of implementationis also a factor. As expected, structureddatalogging is most convenient to implement.Binary bytestream was next easiest, and ASCII slightly more difficult, primarilybecause of the need to ensure equal lengthelements. But the differences in difficulty

22 Summer 1993

Technical Notes

Page 23: Vol  1 Issue 2

of implementation between methods isminimal compared to the difference inimplementation hassle between LabVIEWversions! File I/O in LabVIEW 2.5 is muchsimpler than in LabVIEW 2.2. For onething, there aren’t two different sets offunctions in 2.5 as there are in 2.2. Also,the additional functionality in the 2.5functions means fewer outboard functions,like Seek, are necessary. LabVIEW users whoprefer the Mac will enjoy the benefits ofLabVIEW’s new, improved file system once3.0 is out, since its file I/O is quite similarto LabVIEW 2.5.

Do you need random access? All threemethods support random access to somedegree. The differences between the methodsare in the resolution with which you canfind an arbitrary item in the file, and whetherrandom access is available for both read andwrite. True random access requires one oftwo things: either all elements in the file mustbe the same size, so the offset to any particularelement can be computed, or an index ofpointers to elements must be kept. OurASCII and binary implementations use theformer approach. It’s easy for the binary file— all of its elements are inherently the samesize. We must force the ASCII file elementsto be the same size, resulting in increasedfile size.

If you didn’t want to get to each element inthe ASCII file in a random way, but youcould be satisfied with random access to aparticular row in the file, you could build anindex to row starts by reading once throughthe file and remembering the offset of eachrow (basically, the location of endlines in thefile). This is a reasonable method, and onewhich would reduce the size penalty on theASCII file. LabVIEW’s bookkeeping onstructured files takes this approach whenrecords are variable length as in our example:an index to records is maintained internally.You’ll find evidence that this index exists ifyou compare the size difference between

binary and structured files; for the samearray size, they contain the same number ofbytes of data, but the structured file is largerbecause it contains the index as well.

Note that if you need random write access,you’re stuck with one of the bytestreammethods, since random write is not supportedby LabVIEW’s structured file I/O.

If you need to export data, ASCII is theobvious choice; in fact, the ASCII form ofthe disk array imports nicely into any texteditor and most spreadsheet programs. Youcould use bytestream files to write any binaryformat for which you had a definition, butthat may be a non-trivial task. Datalog filesare useless outside of LabVIEW, practicallyspeaking.

Because of their readability, it would bepossible to recover from a minor corruption— loss of a few bytes, or mutation oraddition of a few — in an ASCII file. Youcould open it in an editor and fix the damage,which would be localized. If binary data hada recognizeable pattern, it’s conceivable thatsomeone with lots of patience could do thesame trick on a minor corruption of a binaryfile, but it’s highly unlikely. Recovery fromcorruption of a datalog file is almostimpossible. You would need to know (andpossibly repair) LabVIEW’s internalbookkeeping, which itself could be corrupted.

These tradeoffs are summarized in the table below.

ConclusionYour choice of file I/O method for dataloggingshould be based on all of your application’srequirements, not just performance. Ifperformance is paramount, give preferenceto the technique that best supports theoperations you perform most often, andremember that the relative performance ofthe techniques isn’t as obvous as it may seem.If your data need to be exported, then anASCII representation is most suitable. For

ease of implementation and debugging, letLabVIEW worry about the bookkeepingdetails and use structured file I/O, but beaware of its limitations.

During implementation, a couple ofLabVIEW bugs were uncovered in the FileI/O and related primitives. On theLabVIEW 2.5.2 side, contrary to what theLabVIEW manual states, if you have adatalog file whose record type is an array,and you wire a number to the “count”input, you don’t get a 2D array of data...instead, you get problems ranging from“Dataspace full” messages to Windowsgeneral protection faults. A call to NationalInstruments confirmed the problem; the“fix” in LabVIEW 3.0 will be to not let youwire up to the count in this case! The reasongiven by NI for not allowing multiple arrayreads is that the arrays in the datafile maynot all be the same length; to combine theminto a 2D array, 1D arrays shorter than themaximum length would have to be paddedwith some arbitrary value, and they don’twant to do that. Since exactly the sameimplementation detail comes up if yougenerate a 2D array by combining arbitrarylength arrays in a for loop, while loop, orarray builder, cases which LabVIEW handlesquite nicely by padding with zeros, it’sinteresting that they don’t wish to supportsuch padding in their datalog file read.

In LabVIEW 2.2.1, there are problems withusing the TypeCast function inside a loop torepeatedly cast the 1D array obtained fromindexing a 2D array at the loop boundary.See the diagram of the VI, Data AppendNOT, to see how it could have been doneexcept for the TypeCast bug.

Hope this article has provided some usefulinsight. We’d be interested in feedback andsuggestions on how you use file I/O fordatalogging other purposes. Look for futureLTR articles on File I/O in LabVIEW.

Summer 1993 23

Technical Notes

File Ease Of Random Random RecoveryType Implementation Read Write Export? if Corrupted

ASCII Bytestream Moderate Yes, by element Yes, by element Yes PossibleBinary Bytestream Moderate Yes, by element Yes, by element Maybe Not UnlikelyStructured Easy Yes, by record Not supported No Almost impossible

Page 24: Vol  1 Issue 2

LTR Disk Contents

Each issue of LTR includes a ResourceDiskette of LabVIEW VIs, utilities, andsource code related to the articles in that issue.At the right is a listing of files distributed onthe Summer 1993 LTR disk.

The LTR Resource Diskette is available oneither Windows/DOS or Macintoshformatted disks. Disk space permitting, allVIs and utilities appear on both disk formats.To transfer DOS files from a Mac formatLTR disk to a DOS format disk, use AppleFile Exchange. To transfer Mac files fromthe DOS format LTR disk, use Apple FileExchange to copy “ltr_mac.hqx” to yourMacintosh, then use a BinHex utility todecode it. If you don’t have a BinHex utilityyou can get one from an electronic bulletinboard, or from LTR.

We encourage you to use and enhance theLTR disk contents. Many disk items arecontributed by fellow LabVIEW users. Readthe articles that describe the VIs and utilitiesbefore using them and follow any precautions.LTR Publishing assumes no responsibility forperformance or use of items described in thisnewsletter or on the disk.

LTR Publishing5614 AnitaDallas, TX 75206

L T RT e c h n i c a l I n f o r m a t i o n f o r L a b V I E W S y s t e m s D e v e l o p e r s

What’s on the LTR Summer 1993 Resource DisketteLTR Article LabVIEW 2.2.1 LabVIEW 2.5.2