If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

Tutorials

- !! Introduction To Programming Book !!
- A look at RoboScripter
- A Quick Course on UDFs
- ADSI
- All about Dynamic Dialogs 6.1
- All about Dynamic Dialogs 6.2
- Boolean Math and Boolean Algebra Refresher
- Control Manager - Windows Analysis
- Exit Codes in WinBatch
- How To Call Windows API Functions
- HTTP and WinInet - An Opus
- Named Pipes
- Pointers
- Printing
- Screen Coordinates Explained
- Service Scripts
- Template File Processing
- Trap Errors
- WIL Dialog - Menu Tutorial
- WinBatch Navigator
- Working With Web Pages

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

Basically WinBatch has nearly a thousand separate functions to do all kinds of useful work. But alas, WinBatch cannot cover every conceivable possibility. In that case, though, it is possible to write your own function, comprised of a bunch of WinBatch functions, and then use your new function just like one of other WinBatch functions.

To make this clearer, we'll start with a runnable example right away. If you copy and paste this code into WinBatch Studio you can try it now. (You will need the 2001 version of WinBatch to do this though.)

;;;;;;;;;;;;; Beginning of Example 1 - SQUARE ;;;;;;;;;;;;;;;; #DefineFunction Square(x) ans = x * x return(ans) #EndFunction a=5 b=Square(a) Message(a,b) a=17.55 b=Square(a) Message(a,b) ;;;;;;;;;;;;; End of Example 1 - SQAURE ;;;;;;;;;;;;;;;;;;;;;;

Example 1 may be under-commented a tad, but if you take the time to understand how it works, then you can use this powerful new feature.

Basically the function you make can be used just like other WinBatch functions in your code. Instead of a bunch of ugly code whenever you have to do some standard task, you can just use one of your pre-defined UDFs and be done with it.

The variable space inside a UDF is completely separate from the other variables used in your script (pure local variables to the programming gurus). Only the parameters passed in on the function call are seen, and only the value in the return statement gets passed back to your script. This allows you to write a UDF once, and use it anywhere without worrying about stomping on variables already used by a script someplace.

So. What's going on here.

**#DefineFunction** and **#EndFunction** are the keywords indicating
the beginning and end of the UDF.

**Square** is the name of the function. Function names must begin
with a letter, can contain letters, numbers, and underscores,
and can be up to 30 characters long.

**x** is a variable name representing the variable passed to the
function. UDFs may have zero to sixteen parameters passed in.

At that point the UDF code executes pretty much like normal WinBatch code.

A new form of the **return** statement has been introduced to
allow the UDF to return a value. This simply sets the return
value of the function and is your way of getting the UDF
results back into your main script.

Admittedly, Example 1 does not save you a lot of time or lines of code. But it was a good starting example of a bare-bones UDF. You can define a whole bunch (hundreds?) of UDFs in a script if you wish.

Right triangles are the kind where one of the angles is exactly 90 degrees, making a perfect corner. The hypotenuse is the side opposite the 90 degree angle.

e.g.

For a right triangle with sides of 3 feet and 4 feet, the
sums of the squares of the sides would be

(3*3) + (4*4) or 25, being the square of the hypotenuse.

Thus the square root of 25 is 5, and the length of the hypotenuse is 5 feet.

So this is a UDF that, given two sides, will compute the hypotenuse of a right triangle.

;;;;;;;;;;;;; Beginning of Example 2 - PYTHAGOREAN ;;;;;;;;;;; #DefineFunction Pythagorean(a,b) SumOfSquares = (a*a) + (b*b) ans = Sqrt(SumOfSquares) return(ans) #EndFunction side1=3 side2=4 hypot=Pythagorean(side1,side2) Message("Results",strcat(side1,@crlf,side2,@crlf,hypot)) side1=1 side2=2 hypot=Pythagorean(side1,side2) Message("Results",strcat(side1,@crlf,side2,@crlf,hypot)) side1=31.7 side2=42.5 hypot=Pythagorean(side1,side2) Message("Results",strcat(side1,@crlf,side2,@crlf,hypot)) ;;;;;;;;;;;;; End of Example 2 - PYTHAGOREAN ;;;;;;;;;;;;;;;;;

In Example 2, note that a function called "Pythagorean" is defined and it accepts two parameters. It performs the required math operations and returns the result.

Nice little function.

Please note that yours truly was sorely tempted to include one of a number of *just dreadful* puns based on this theorem. Sanity prevailed, temptation overcome, and none of the dreadful puns appear.

True. The previous examples were designed to get you familiar with the concept of UDFs and the passing of information into and out of UDFs.

For the third example, we'll work with a somewhat more useful function. The CapFirstLetter function below is designed to accept a string. It will alter the capitalization of the string so that the first letter is capitalized and the rest are lower case. This function may be handy when marching through a list of names some of which may have improper capitalization.

This example even has comments. Will wonders never cease?

;;;;;;;;;;;;; Beginning of Example 3 - CAPFIRSTLETTER ;;;;;;;; ; Define the CapFirstLetter function ; It takes one "parameter" which we will call ; word #DefineFunction CapFirstLetter(word) ;Get the length of the passed string len=StrLen(word) ;if length is zero, just return the null string if len==0 then return(word) ;if length is one, just uppercase it and ;return the result if len==1 then return(StrUpper(word)) ;if there is more than one character, ;split the first off from the rest ;uppercase the first character and ;lowercase the rest. firstchar=StrUpper(StrSub(word,1,1)) restofword=StrLower(StrSub(word,2,-1)) ;glue the word back together word=strcat(firstchar,restofword) ;return the new word return(word) #EndFunction ;Just by adding the above code to a script, ;you have a new function, CapFirstLetter ;Here are some examples of its use a="tom" b=CapFirstLetter(a) ; returns Tom Message(a,b) a="sALLY" b=CapFirstLetter(a) ; returns Sally Message(a,b) a="pOrCuPiNe" b=CapFirstLetter(a) ; returns Porcupine Message(a,b) a="i" b=CapFirstLetter(a) ; returns I Message(a,b) a="123" b=CapFirstLetter(a) ; returns 123 Message(a,b) a="123e20" b=CapFirstLetter(a) ; returns 123e20 Message(a,b) a="" b=CapFirstLetter(a) Message("A null string",b) ;returns a null string a="FRED" b=CapFirstLetter(a) ; returns Fred Message(a,b) ;that's all folks ;;;;;;;;;;;;; End of Example 3 - CAPFIRSTLETTER ;;;;;;;;;;;;;;

What with the commented source code and the previous explanations it is hoped that readers may be able to sort Example 3 out for themselves.

In computer science classes that dwell on this topic (snore) the archetypal example is the factorial calculation.

Basically a factorial of a number is that number multiplied by all the numbers smaller than itself.

Thus

Factorial(5) is equal to 5 * 4 * 3 * 2 * 1

and simply by definition,

Factorial(1) is equal to 1

Now it is true a simple FOR LOOP can easily do this calculation (and that would be...)

a=5 ans=1 for x = 1 to a ans = ans * x next Message(a,ans)

But the point is that the nature of factorial calculations makes an excellent introduction to recursion. The main trick in recursion is to transform the problem into a smaller version of itself. In factorial calculations it goes something like this...

Factorial(5) is equal to 5 * Factorial(4) Factorial(4) is equal to 4 * Factorial(3) Factorial(3) is equal to 3 * Factorial(2) Factorial(2) is equal to 2 * Factorial(1) Factorial(1) is equal to 1 Thus Factorial(2) is equal to 2*1 or 2 Thus Factorial(3) is equal to 3*2 or 6 Thus Factorial(4) is equal to 4*6 or 24 Thus Factorial(5) is equal to 5*24 or 120

In this case, in attempting to compute Factorial(5) is it noted that Factorial(5) is the same as 5*Factorial(4).

This is a smaller version of the same problem. So the Factorial routine simply calls itself again to compute the smaller problem.

And so on.

;;;;;;;;;;;;;; Beginning of Example 4 - FACTORIAL ;;;;;;;;;;;; #DefineFunction Factorial(x) ;Ooop WinBatch cannot go more than 100 levels deep ;and Factorials do not like negative numbers ;so check for errors Terminate(x>100,"Error","Number too large") ;And Factorial does not like negative numbers Terminate(x<1, "Error","number too small") ;If factorial of 1 is desired return 1 ;that the only answer we *know* if x == 1 then return(1) ;Otherwise return x * factorial(x-1) ;which does the "recursion" ans = x * Factorial(x-1) ;Add 0.0 to force the answer to ;floating point mode as we can quickly get ;into big numbers ans = ans + 0.0 ;return the result return( ans) #EndFunction a=5 b=Factorial(a) Message(a,b) a=10 b=Factorial(a) Message(a,b) a=15 b=Factorial(a) Message(a,b) ;;;;;;;;;;;;;; End of Example 4 - FACTORIAL ;;;;;;;;;;;;;;;;;;

So this is basic recursion. All well and good. The Factorial UDF calls itself to compute a smaller case of the problem. Eventually the smaller problems are solved and the deep nested UDFs begin returning and the final answer is computed.

Although perhaps interesting (snore) academically, this is really not very useful in normal scripting. However this same technique may be used elsewhere, such as in working through directories on a hard drive or plugging away at some set of registry keys. The next example will show working with a file system...

In this example, a recursive UDF will be used to traverse a directory tree to compute the total size of all files found.

Please note that for this particular case, WinBatch offers a built in function - DirSize - that can do this computation faster, but for many other operations, such as Xcopy and Deltree, UDFs may be used. In fact UDFs for XCopy and DelTree already exist in our UDF Function library (see next section for a how to find our UDF Library).

;;;;;;;;;;;;;; Beginning of Example 5 - GETDIRSIZE ;;;;;;;;;;; ;This file traverses the directory tree and computes 'the total size of all files on the C:\ drive. #DefineFunction GetDirSize(dir) ;Save original directory origdir=DirGet() ;Change to directory to inspect DirChange(dir) ;Display current directory for warm fuzzy feeling BoxText(DirGet()) ;Get total size of files in this directory ;and make sure it is a floating point number ;by adding 0.0 as it can get very large. total=FileSizeEx("*.*")+0.0 ;Get a list of subdirectories in this directory ;and count how many there are. dirlist=DirItemize("*.*") dircount=ItemCount(dirlist,@tab) ;For each subdirectory, call out GetDirSize UDF ;to determine its size. for xx=1 to dircount ;Pick off a subdirectory name thisdir=ItemExtract(xx,dirlist,@tab) ;Add size of that subdirectory to our running total total=total+GetDirSize(thisdir) next ;Change back to the directory we entered with DirChange(origdir) ;Return current value of total to caller. return total #EndFunction ;True start of program ;Allow system and hidden files to be counted IntControl(5,1,0,0,0) ;Open a Box to display warm fuzzy progress to user BoxOpen("File Size Inspector","Reading Initial Directories") ;Call our UDF to compute size of C: drive tot=GetDirSize("C:\") ; Convert to KB totKB = INT(tot/1024) ;Display Results Message("Total File Size of C:\", StrCat(totkb," KB")) Exit ;;;;;;;;;;;;;; End of Example 5 - GETDIRSIZE ;;;;;;;;;;;;;;;;;

In Example 5, the job of computing the size of the files in a directory is broken down on a directory by directory basis. The function, using the WinBatch FileSizeEx function, computes the size of the files in the current directory.

It then gets a list of all the subdirectories in the current directory and runs each of them, in turn, through the same GetDirSize UDF (recursively). Each subdirectory level down does the same.

Thus we take the previous code, drop in an AddComma UDF (written again by yours truly), make a minor modification to the previously existing code and, walla, there we have it.

;;;;;;;;;;;;;; Beginning of Example 6 - ADDCOMMAS ;;;;;;;;;;;; ;This file traverses the directory tree and computes the total ;size of all files on the C:\ drive. ;UDF AddCommas to format our final answer for display (only) #DefineFunction AddCommas(passednumstring) ; Grab everything to the left of the decimal (if any) intpart=ItemExtract(1,passednumstring, ".") ;Grab everything to the right of the decimal fractpart=ItemExtract(2,passednumstring,".") ;Compute how many comma separated groups we need groups= ((strlen(intpart)-1) / 3 ) +1 ;Initialize an answer variable to a null string answer="" ;Figure out what each group looks like ;and add each group to the answer variable with ;a comma for y=1 to groups if y==1 ptr=( (strlen(intpart)-1) mod 3 ) +1 answer=strsub(intpart,1, ptr ) ptr=ptr +1 else answer=strcat(answer, ",", strsub(intpart, ptr , 3)) ptr=ptr+3 endif next ;Now that we have the numbers to the left of the decimal ;point "comma-ized" properly, see if there is any ;fractional part to worry about. ;If there is a fractional part, glue it onto the end ;of he "comma-ized" number along with a decimal if fractpart!="" answer=strcat(answer,".",fractpart) endif ;Return the comma-ized answer return (answer) #EndFunction ;Define the function that does all the real work #DefineFunction GetDirSize(dir) ;Save original directory origdir=DirGet() ;Change to directory to inspect DirChange(dir) ;Display current directory for warm fuzzy feeling BoxText(DirGet()) ;Get total size of files in this directory ;and make sure it is a floating point number ;by adding 0.0 as it can get very large. total=FileSizeEx("*.*")+0.0 ;Get a list of subdirectories in this directory ;and count how many there are. dirlist=DirItemize("*.*") dircount=ItemCount(dirlist,@tab) ;For each subdirectory, call out GetDirSize UDF ;to determine its size. for xx=1 to dircount ;Pick off a subdirectory name thisdir=ItemExtract(xx,dirlist,@tab) ;Add size of that subdirectory to our running total total=total+GetDirSize(thisdir) next ;Change back to the directory we entered with DirChange(origdir) ;Return current value of total to caller. return total #EndFunction ;True start of program ;Allow system and hidden files to be counted IntControl(5,1,0,0,0) ;Open a Box to display warm fuzzy progress to user BoxOpen("File Size Inspector","Reading Initial Directories") ;Call our UDF to compute size of C: drive tot=GetDirSize("C:\") ; Convert to KB totKB = INT(tot/1024) ;Display Results totKB = AddCommas(totKB) Message("Total File Size of C:\", Strcat(totKB," KB")) Exit ;;;;;;;;;;;;;; End of Example 6 - ADDCOMMAS ;;;;;;;;;;;;;;;;;;

That, in a nutshell, is an introduction to UDFs. There is more documentation available in the manuals and help files.

If you have questions, you are encouraged to use our online WinBatch Technical Support Forum at http://forum.winbatch.com.

Article ID:W14984

File Created:2010:02:17:11:58:06

Last Updated:2015:07:22:08:52:07