Monday, December 24, 2007

[FORTRAN] Making a DLL for VB6

As a break from trying to figure out how to get a pattern matching library DLLified (and UTF-32 sensitive), my boss gave me something else to do, something on the one hand similar (wrap something in a DLL) and on the other quite different (wrap two knapsack algorithms done in Fortran 90).

The knapsack code is derived from
Algorithm 4.9, Donald Kreher and Douglas Stinson, Combinatorial Algorithms, CRC Press, 1999, page 125.
and was downloaded from FORTRAN Source Codes, specifically, the COMBO library. Many thanks to John Burkardt for making this resources available.

The files used from the COMBO library were knapsack_01.f90, knapsack_rational.f90, knapsack_reorder.f90, rvec_backtrack.f90 and r_swap.f90, and were compiled using Compaq Visual Fortran.

Seeing as CVF is no longer available (except perhaps on eBay) you might get away with the
Intel® Fortran Compiler for Windows, SilverFrost's FTN95 or g95.

Don't try it with
Watcom Fortran, however, because that only does Fortran 77. Mind you, if the algorithms you're wrapping are F77 ones from NIST's 'Dictionary of Algorithms and Data Structures' or Steven Skiena's The Stony Brook Algorithm Repository you may do okay with the Watcom offering or even GNU's g77.

I really like Fortran. I remember writing some VAX-11 FORTRAN back in 1983 (along with a bit more VAX-11 COBOL) and found it quite powerful and expressive. I know that there's been a fairly widespread pooh-pooh-ing of Fortran in recent years, but I try not to be influenced by peer-group pressure, preferring to actually see for myself whether a language is any good or not.

Okay, off the soap box and down to the code. I'm not going to bother posting all the COMBO code, just what I wrote to wrap it.

These are the three exposed routines and have essentially the same framework: a subroutine header, two declarations controlling symbol names and method of access, the call to the COMBO routine, the return and the end of subroutine. Really, really, simple. Gobsmackingly simple, compared to some other languages I could mention. Rather embarrasing really ... so little to show.

If you're wondering why I explicitly state that the parameters are being passed by reference (!dec$ attributes reference ...), it's because a side effect of specifying "stdcall" is that it forces the passing mechanism into pass-by-value, and in this case, quite a few of the parameters are being modified by the subroutine.



The other routines are linked in during the compile and I end up with a nice little .DLL.

Okay, so maybe there's something more to show on the VB6 side.

First off, the declares. VB6 defaults to pass-by-reference, thus the missing "ByRef" ahead of each parameter.



Next the test code which is derived from TEST094 and TEST095 found inside COMBO's combo_prb.f90.

Do note that the floating point variables are defined here as Single. This seems to be the best match to an undecorated Fortran REAL. Maybe if I'd tweaked the COMBO code to REAL*8, I could have used Double on the VB6 side.



Hmm ... nothing much amazing there either. But that's how it was with wrapping the Fortran. Simple and powerful at the same time. So far as I'm concerned, if we ever have to rewrite Protium, Fortran's going to be very near the top of the list.

© Copyright Bruce M. Axtens., 2007

Thursday, December 20, 2007

[Visual BASIC 6] BOOST (v2)

I revisited BOOST this week. A friend had pointed out to me some time back that /P: and /L: were a bit of a pain when one wanted to speed something up quickly, or kill it quickly. So this version changes the command line handling.

This version also demonstrates how to kill a process. In fact it kills every process of the same name. I wish I'd had this a couple of years ago when I was doing stuff with Excel -- I'd end up with multiple Excel sessions which I would then have to kill off one-by-one through the Task Manager. (I eventually ended up installing Cygwin so that I could script the process.)

If you remember the original VBScript of BOOST and the first VB6 version, you'll see some similarities.

I've given up on using
setsubsys in favour of using VBAdvance (which is now freeware) to handle the compile-to-console-app process. I'm still compressing the app using UPX.

First a few constants and the declarations, found on
vb.mvps.org, for doing console I/O.



Next, a few supporting functions. First off the rank, is an invocation syntax display. Notice that priority can now be specified either by a number (0 to kill, 1-6 for low to realtime) or by name (kill, low, belownormal, normal, abovenormal, high, realtime).



Second, the command line parser. This splits on space and tab and is based on code found at
microsoft.public.vb.winapi



Third, the two routines which wrap the WMI functions to set priority and to kill process. The latter was found at
tek-tips. If I remember correctly, the places in each routine where it says
sComputer = "."
could, in fact, have some other computer's name. If you had sufficient privilege you could be tweaking or killing a process on someone else's machine.



Finally, the Main subroutine. Notice the additions to the priorities collection. Note also the change in the way the command line is handled.

Because there's no .Exists method on Collections, the .Item call is wrapped in an 'On Error' so that a non-existent item situation is caught appropriately.



What's next with this thing? I suppose one could explore the possibility of influencing the lives of applications on other computers:
BOOST Skype.exe kill /C:GUEST_01
There's also the fact that the commandline parser doesn't properly handle double-quoted names. If an .exe had a space it its name, you wouldn't be able use BOOST on it.

Finally, here's a short batch file (killall.bat) I use for killing applications en masse. It was originally designed to get around the 'typing the /P and /L' issue, but I'm so used to using it now ...



An example invocation:
killall excel.exe outlook.exe


© Copyright Bruce M. Axtens, 2007

Monday, December 17, 2007

[Programming] Okay, Ignorance is Bliss ...

If by Ignorance you mean an implementation of the Bliss programming language, then yes, Ignorance is Bliss.

After two and half weeks of Ada, I had to have a break. I wandered over to the
Retrocomputing Museum and downloaded the Ignorance source code. While I was at it I also downloaded the source for CUPL, the Cornell University Programming Language. Interestingly, the same interpreter also works for CORC, the CORnell Compiler. The man behind the website, Eric Raymond, has the following, less than flattering, words to describe CUPL:
"Another hideous old design, CUPL — Cornell University Programming Language. It looks something like a really archaic BASIC with linear-algebra builtins."
And what's wrong with BASIC and linear algebra? (That was a rhetorical question.)

I've been able to get CUPL to work, but haven't had any success with Ignorance. Or, for that matter, with
JOSS.

To find out more about these languages, HOPL is your friend:
Bliss, CUPL and JOSS.

as is Wikipedia:
Bliss, CORC (CUPL precursor) and JOSS.

© Copyright Bruce M. Axtens., 2007

Thursday, December 13, 2007

[Ada (GNAT)] Who said, "Ignorance is bliss"?

Ignorance isn't bliss. For the past two days I've been trying to do what I expect an Ada freak could do in 2 minutes. It's been a very frustrating, sleep-depriving process.

After trying to do amazing things with GNAT.Spitbol, I'm now trying to do the same to Dr. Dmitry A. Kazakov's
match library. And, as usual, it has not been an easy journey.

UTF-32 aside for now, I've been trying this week simply to make the Matching and Pattern packages available to the Windows programmer via the DLL mechanism.

At this point, all I have is a wrapper for the match() function.

I really hope there is an easier way of doing this. As I've said a few times before, I'm a newbie when it comes to Ada but have been forced to jump into the deep end of the pool. Please, if you know a better way, tell me!!

Oh, and I should point out that, though it seems I'm passing the right stuff to match(), in its current form the VB6 code keeps receiving an error code from the Matching package. It may be because I'm not declaring the pattern properly.

Okay, to the code. First up, the BOS.ADS spec file:



Next, the body (BOS.ADB). There are lots of Put calls in here for debugging. These are what appear if you run the VB6 code as a console app.



For the sake of completeness, BOS.DEF, BUILD.GPR and BUILD.BAT. Note that in BUILD.BAT, I specify match\match.o as an object file for gnatlink.



Finally, the VB6 code being used to test it all. Please note that I'm using
SetSubSys to turn the resulting EXE into a Console application. If you don't do that, the output from Ada's Put() statements will not be made visible.

It's not pretty code, but it does the job. By the way, if you don't do the StrConv, you'll be passing UTF-16 strings.



© Copyright Bruce M. Axtens., 2007

Tuesday, December 11, 2007

[Google] AdSense and Analytics

On the suggestion of my eldest, I've added Google Analytics. In the next couple of days I should hear back from Google AdSense and will trial having Google Ads on the page. If it earns, fine. If not, I think I'll give it a miss. "Suck it and see," as my late father would have said.

Monday, December 10, 2007

[Ada (GNAT)] A 32bit GNAT.Spitbol.*

It is said that, "a wise man knows his own turnips." In my case, I've run into some difficulty converting GNAT.Spitbol to UTF-32. The compiler error messages are marvellously helpful, but I'm a newbie to Ada and ... yeah, well, you get the idea.

The source code is up on Box.net, if you feel so inclined as to download it and tell me where I'm going wrong.

Monday, December 03, 2007

[Ada (GNAT/GCC)] VARPTR, GNAT and data "transput"

Okay, have got it figured (soli Deo gloria!)

The following listings demonstrate the passing of a two part Type containing two Singles from VB6 into a GNAT/GCC DLL. Once inside, the elements of the Type are swapped and control returns to VB6. VB6 then displays the results.

As before, the code has been worked out in the context of the afore-posted api project. If you want to play with this, just take the earlier work and tweak it appropriately.

First up, the additions to api.ads:



Next, the additions to api.adb:



API.DEF must also be modified, adding swapsingles to the list of EXPORTS.

Next, some VB code to demonstrate ...



... and part of a sample output.



The project that all this was part of was done in both GNAT/GCC and ObjectAda 7.2.2. Interestingly, ObjectAda's Float is equivalent to VB6's Double, whereas GNAT/GCC's Float is equivalent to VB6's Single. Does anyone know why?

By the way, regarding "transput", Wikipedia's article on
Algol states:
ALGOL 60 as officially defined had no I/O facilities; implementations defined their own in ways that were rarely compatible with each other. In contrast, ALGOL 68 offered an extensive library of transput (ALGOL 68 parlance for Input/Output) facilities.
A extensive library of transput facilities is something you'll find in Protium, too.

© Copyright Bruce M. Axtens, 2007

Wednesday, November 28, 2007

[Ada (GNAT/GCC)] Passing data with VB6's VARPTR to Ada

In the current project, I've been trying to figure out how to pass data to Ada. Because I'll be passing Long, Double (Float), and two Types to emulate a LongLong and a DoubleDouble, I decided I'd use VB's VarPtr and have Ada sort the mess out on its side.

After the loss of a little hair, the reading of bits of Michael B. Feldman's
Software Construction and Data Structures with Ada 95, and with help from Martin Krischik and Simon Wright, I came up with the following.

The code was worked out in the context of the afore-posted api project. If you want to play with this, just take the earlier work and stuff this into it.

First up, the additions to api.ads:



Next, the additions to api.adb:



Next, some VB code to demonstrate ...



... and a sample output.



I'm in the process now of working out how to access the LongLong and DoubleDouble Types. Shall keep you posted.

By the way, the return value will eventually be a pointer as well. That'll keep the VB programmer on his toes.

© Copyright Bruce M. Axtens, 2007

Monday, November 26, 2007

[Ada (GNAT/GCC)] Better build automation

Just after I notified comp.lang.ada of my posting re GNAT/GPL, Martin Krischik wrote suggesting I use a .gpr file and gnat make rather than a direct reference to gcc.

After reading a
friendly manual, I came up with the following .grp file and a batch file to control it.

I have stayed with the batch file, simply because I can't yet see how to have a multiple-program linkage (gnatlink, dlltool and gnatlink a second time).

First, build.gpr



And then, build.bat. Note the call to
UPX, which compresses the release version of the .DLL. Note also that the debug and release subdirectories must already exist (though it wouldn't have been difficult to check-for-and-create-if-missing.)



Trust that's helpful.

© Copyright Bruce M. Axtens, 2007

Friday, November 23, 2007

[Ada (GNAT/GCC)] Creating DLLs for VB6

And finally, after much prayer and perspiration, the GNAT/GCC version. Again, thanks to Roger Pearse for The Noddy Guide to using ADA code with Visual Basic. I'm sure there was someone else [This space set aside for an attribution.]

First up, api.ads, which declares the functions and exports them.
  • function Factorial, which accepts a Win32.LONG and returns a Win32.LONG (I gave up on C.int as it was too small for a Factorial of 16)
  • function GetCount, which returns the value of the global Count (another Win32.LONG)
  • procedure Mangle, which accepts a Win32.LPWSTR and attempts the same dangerous stuff that Bob6 does in the ObjectAda version.
  • function Pattern, which returns a long pointer to some string data
  • procedures Initialize_API, and Finalize_API, which I understand are mandatory. (If someone knows better, please tell me.)


Next, api.adb, where the declarations are explained.

I'm still working through the issue of what to do with Mangle. Perhaps two routines are needed. The first to ask the DLL how much space is needed, with VB the allocating it, and the second then actually poking the data into the allocated space.

Pattern returns a pointer to the string data. I rediscovered the technique for reading it out and that's in the VB code below. It also seems that, for as long as the DLL is loaded, the data stored in foo is available for transfer.



api.def lists the symbols exported, and is needed by gnatdll.



Now, pulling it all together requires some handwaving on the commandline. From one of the demos I modified the make.bat to look like this:



The output from a run of these is as follows:



Now the VB code. Take note of a few things:
  • Exporting as DLL generates decorated names, but dlltool was able to resolve the decorated ones with the undecorated ones specified in api.def
  • For reasons I remember reading somewhere, initialize_api and finalize_api are mandatory, and must be the first and last calls to the DLL
  • Seeing as woof woof woof woof is longer than foo man chew, s ends up containing foo man chew f woof
  • As mentioned before, I rediscovered some code for getting data from a pointer and put that in. It's the PointerToString function at the bottom.


Finally, a sample run under VB6



Next? Well, there's the issue of how to export overloaded functions and procedures. And there's the question of how to pass in complex data types, like records and the like. I'll keep you posted.

(By the way, I'm not doing this merely for the fun of it, but also in pursuit of the fulfillment of my employer's expectations. So more will follow.)


© Copyright Bruce M. Axtens, 2007

Thursday, November 22, 2007

[Ada (GNAT/GPL)] Creating DLLs for VB6

As promised, the GNAT/GPL code. Based on Roger Pearse's The Noddy Guide to using ADA code with Visual Basic.

How I ended up with the names api.ads, api.adb and api.def is an artefact from something I was reading. [This space set aside for an attribution.]

First up, api.ads, which declares the functions and exports them.
  • function Factorial, which accepts a C.int and returns a C.int
  • procedure Mangle, which accepts a Win32.LPWSTR and attempts the same dangerous stuff that Bob6 does in the ObjectAda version. Still working on this one.
  • function Pattern, which returns a Win32.LPWSTR
  • procedures Initialize_API, and Finalize_API, which I understand are mandatory. (If someone knows better, please tell me.)


Next, api.adb, where the declarations are explained.

Mangle replaces the incoming string with something of its own. If the incoming string is larger or the same size then everything's more or less okay. (Less in the latter case, but at least it doesn't crash.) However, if the incoming string is shorter, VB truncates up to the length it knows about, and who knows what damage we've done with whatever gets overwritten by the rest of foo.

Pattern returns a pointer to the string data. Not knowing a lot about Ada, I don't know if the contents of foo will still be there by the time VB looks it and reads out.


api.def lists the symbols exported, and is needed by gnatdll.


Now, pulling it all together requires some handwaving on the commandline.


The output from a run of these is as follows:


Now the VB code. Take note of a few things:
  • Exporting as DLL generates decorated names, but gnatdll was able to resolve the decorated ones with the undecorated ones specified in api.def
  • For reasons I remember reading somewhere, initialize_api and finalize_api are mandatory, and must be the first and last calls to the DLL
  • Seeing as woof woof woof woof is longer than foo man chew, s ends up containing foo man chew woof


Next stop is to get this working with "GNAT/GCC MS-Windows MinGW 4.2.1 R0". I would prefer to be working under the GMGPL.


© Copyright Bruce M. Axtens., 2007

Tuesday, November 20, 2007

[Ada (ObjectAda 7.2.2)] Creating VB6 DLLs

Creating DLLs for use by VB6 seems to be somewhat of a dark art. From what Roger Pearse, in his The Noddy Guide to using ADA code with Visual Basic says, it doesn't appear to be something easily achieved.

So far I've achieved it, to a certain extent, with ObjectAda and GNAT/GPL. The code for the ObjectAda implementation is below. I'll post the GNAT/GPL stuff in the next couple of days, God willing.

BO_DLib.adb, BO_D.adb and BO_D.ads are all based, albeit rather loosely, on sample files in winapi\samples\petzold\ch19\edrlib\

First up, BO_DLib.adb



Next, the spec file, BO_D.ads

There are six routines:
  • procedure Bob1 calls dobox to show a messagebox.
  • function Bob2 returns a long value, 1.
  • function Bob3 receives a long and adds 21 to it.
  • procedure Bob4 receives a long pointer to a string and passes it to dobox for display.
    I can pass Unicode to it and have it rendered appropriately.
  • function Bob5 receives a long pointer to a string and returns a long being the length of the string.
  • function Bob6 receives a long pointer to a string and catenates a string to it.
    "Danger, Will Robinson!" ... this is not how to do it and VB complains bitterly.
Okay, there are seven routines, but dobox isn't exported. It takes a pointer to a wide string and passes it to Win32.Winuser.MessageBoxW. I got dobox from a sample file as well.



And, finally, BO_D.adb, where the definitions given in BO_D are fleshed out.



Now the VB code. Take note of a few things:
  • I declared the functions and procedures as DLL_Stdcall in BO_D.ads so the routines come in decorated, thus the use of Alias in the Declare line. I used Microsoft's Dependency Walker to discover to what extent the names had been mangled.
  • A reference to SCRRUN.DLL was added to the project, making possible the use of the FileSystemObject.
  • Bob6 barges past the limit set for the string by VB, so things get a bit unstable. I'm still working through how to pass strings back.


By the way, if you think my code sucks, say so. I'm a total newb when it comes to Ada. Critiques are always welcome. King Solomon said, "The wise person accepts instructions." and also "Better is open rebuke than hidden love."


© Copyright Bruce M. Axtens., 2007

Tuesday, October 23, 2007

[Protium] Splitting

Here's a short script for splitting a file. The file in this case is the perl language data file from the PLEAC website. pleac_perl.data contains sections marked with "# ^^PLEAC^^_" followed by a number. The section applies until the next section is marked. The script splits each section out of pleac_perl.data into pleac_perl_number.p. I'm working through these files and re-expressing the intent of the perl code in Protium.

The code may be described as follows:
  1. Define a work area, or alias, for the data file, calling it 'pleac'.
  2. Open the text file within that work area, using define-file-lit.
  3. Start a loop which iterates through an enumeration of the lines of data in the work area.
  4. Let a variable contain the data in the current line of the work area.
  5. Test whether the regular expression works for the current line.
  6. If it does work, let a variable contain the number found, ...
  7. ... turn off any output redirection, ...
  8. ... and redirect output to the file 'pleac_perl_' + the number found (in the same directory as the script).
  9. End of the if.
  10. Output the contents of the line.
  11. End of the iteration.
Simple ... and way powerful!

© Copyright Bruce M. Axtens, 2007

Saturday, September 08, 2007

[Protium] 'Assert' as a User-Defined Syllable (UDS)

From time to time, during development, it helps to have an assert. That is, a means of checking whether you got the answer you were expecting, but without having to write lots of repetitive code in the process. To that end, therefore, I've come up with a UDS, an user defined syllable, which implements the concept (and demonstrates other Protium functionality as well.)

For the sake of clarity, I've put each syllable, or "opcode", in title case. This is not something that must be done; Protium cares not what case or mix of cases the instructions are in.
A UDS is 'defined', thus the DEF at the beginning. An UDS has 3 parameters: the syllable itself, then the kind of UDS (more about that later), and then the Protium code which is processed each time the syllable is used. In this case, the syllable is ASR, the type is '__Transformer' and the code starts with <@ SAO> (more about SAO later, too).

Parameters may be passed to UDSes, and retrieved using PAR. In this case, the variable lhs is given the value of the first parameter, and the variable rhs the value of the second.

Next comes the test which forms the basis of an assert: does what is contained in lhs equal what is contained in rhs? The fourth line's opcodes implement this test: if not exact-match variable variable literal, with the arguments lhs, rhs and then another Protium instruction which is only evaluated if the test for exact-match fails.

If lhs does not match rhs, an EKM (Expand Macro Key And Memory) of the literal string "Assertion error: '&lhs;' <> '&rhs;'" is performed. lhs and rhs are bracketed by ampersand and comma, with the result that these symbols are replaced with the values of the variables themselves. The result is stored in the RES (the result) of the UDS, which is handed back to the calling code. Next comes a block wrapped in IGN. This is an artefact from the development of ASR. Code inside an IGN is ignored, that is, not executed. IGNs are predominantly used for documentation but can just as easily be used to isolate parts of the code.
Here are two invocations of the ASR syllable. The first generates nothing because the actioned RMD, the reverse-mid, actually does convert "Once a jolly swagman camped by a billabong" into "Once a jolly squatter camped by a billabong". The second invocation gives the error message because there's no way that that reverse-mid is going to be able to produce "all your base are belong to us".

Now SAO, aside from being the name of an Arnott's biscuit, also stands for "Suppress All Output". Usually text outside the <@> and </@> of a Protium instruction is echoed to the relevant transput (read input-output device). SAO suppresses that echoing. This explains why you don't see 'lhs=' and 'rhs=' each time ASR is invoked. SAO also suppresses everything output by SAY.

Regarding __Transformer, every syllable opcode belongs to a particular group of syllables and each group has certain specific behaviours. Other groups include __Modifier, __Alternator, __Evaluator and __Locator. Read the friendly manual.

Finally, a word about testing. It was the developer's original design to separate testing from branching, and it was due to pressure from the Protium user community which forced the merging of the two into the form seen in most other programming languages. According to the original design, the test and branch code should have looked like this:
Both ways of doing it work. I'm starting to come round to the idea that the original design is the better one, especially seeing that Protium supports ternary logic (true, false, unknown). More about that some other time.

This article can also be found at
Isotopes of Hydrogen on the Protium Blue Forum.

© Copyright Bruce M. Axtens, 2007

Friday, August 31, 2007

[Protium] Templating

Finally, after much talk, here's some action on the Protium front. This the first posting in the 'Isotopes of Hydrogen' series, on the subject of Templating. IoH is housed at the Protium Blue Forum.

If you don't want to go through the process of forum registration, the article is reproduced below.

We're implementing a SOAP interface to Google's AdWords. There are a number of services and subroutines. The following code was developed to speed up the implementation by taking the service and subroutines names and turning them into VB6 subs.
First there's the definition of template. Note that some parts of the template are Visual BASIC and some are something else: an ampersand, a word and a semicolon. These will be replaced with the text in the following list.
params contains, as a first item, the name of the service. After it are all the routines germane to that service. I got these by copying and pasting from Google's AdWords API website.
This bit takes the variable params, and converts it to a list, splitting on newlines. CND means 'construct delimited'. The list is called L (really original, I know.)
Next we iterate by enumeration of the L list. Here we see one of the special qualifiers that can be used with iteration, INI, that only fires on the first pass through the iteration and is ignored otherwise. In this case, its 'payload' is to define a macro where Service contains the current (in this case, the first) element of the L list.

ONG means 'ongoing' and fires on the second and subsequent iterations. The payload is in two parts. The first is to define another macro, Function, with the value of the current element of L. The second is to evaluate template, using EKM, substituting &Service; and &Function; with the values stored in the Service and Function macros.

By using INI, Service gets set only once. ONG ensures that Function will never contain the name of the service, and always contain the current name of the function.

An abbreviated sample of the output is below. There are 11 services and over 40 subs in total. Granted, there's still quite a bit of work to make these subs useful, but a lot of the hack work has been done by the computer, which is what it's there for.
© Copyright Bruce M. Axtens, 2007

Monday, May 07, 2007

[Visual Basic 6] Boost again, but as a binary

As nice as the VBScript version of BOOST is, some people prefer a compiled binary. So, here's the VB6 version.

But first, credit where credit is due:
*
Ultimate Packer for eXecutables which compresses binaries;
*
Euphoria programming language website for the SETSUBSYS tool which I use to turn a GUI applications into a console ones;
*
Experts Exchange for their ParseCommandLineValue function; and
*
vb.mvps.org for their sample on how to make console applications

Okay, now to the code. The algorithm is very similar to the VBScript project, but there are some new things.

First the constants:


Here are two functions vital to making the application function appropriately in a command line environment. The first discovers the handle for StdOut. The second writes to a file handle, in this case the handle for StdOut.

After the function declarations is a user-defined wrapper. Interesting how the output of the WriteFile function is transmitted to the return value of the wrapper (the last argument in the call is the name of the wrapper function -- I'd never seen that before.)


This is the SetPriority function pulled straight out of the VBScript project. Notice I haven't even been polite enough to VB6 to specify sProcess As String and nPriority As Integer. I haven't typed any of the variables local to the function either. It doesn't matter: VB6 types them all as Variant and takes care of my carelessness (and I have put them in since.)


Next comes the Experts Exchange code for parsing the command line.


Now the Main. For ease of access to the relevant values for the SetPriority function, I've used a Collection. I could have used VBScript's Dictionary (by adding a reference to SCRRUN.DLL in the Projects menu) but the Collection works well enough.


Now we parse the commandline and output a message about syntax if things aren't correctly specified there.


Assuming that the commandline is okay, we then attempt to figure out the runlevel value from the user-supplied specification, and show an appropriate error if it doesn't make sense.


And, finally, where it is all made to happen. If everything's set up right and there is in fact a process running that matches what's stored in sProcess, then it gets boosted and the user is informed. If there's no match, the message says that the process wasn't boosted.


Having compiled the code to an .EXE, I used the setsubsys tool to change the binary from a GUI app to a console app


I also compressed it using UPX,
taking a 24576 byte application and leaving me with an 8192 byte one.

If anyone's interested in downloading the BOOST binary (which now contains a KILL_PROCESS 'level'), please leave a comment to that effect and I'll put up a download link.

By the way, if you think my code sucks, say so. Critiques are always welcome. King Solomon said, "The wise person accepts instructions." and also "Better is open rebuke than hidden love."


Friday, March 16, 2007

[VBScript] Boost - changing process priority using WMI

I have little sh script on my iBook which changes the priority of a given process so that the OS services it more frequently, giving the impression of faster execution. Below is a re-implementation in VBScript of a similar tool for Windows. First a few constants and the arrays that handle the commandline options.
Next, the real meat of this tool: the Windows Management Interface (WMI) call which takes a string and a numeric defining the process name and the priority level.
Next a few less inspiring routines: IIF (available in VB but not in VBScript), ArrayOffset, and HelpText.
Finally the main routine, which uses Named and Unnamed Arguments to handle command line parameters. The name of the process is pulled out of the command line using an Unnamed Argument, and the text representation of the priority is pulled out using a Named Argument ("L"). If the priority is acceptable the name and priority are passed to the SetPriority routine.
A further refinement of this tool might be to provide for one other possibility for /L: 'KILL' or 'TERMINATE'. By way of comparison here's the original sh script.