PureBytes Links
Trading Reference Links
|
<x-html><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META content="text/html; charset=iso-8859-1" http-equiv=Content-Type>
<META content="MSHTML 5.00.2614.3401" name=GENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY bgColor=#ffffff>
<DIV><FONT size=2>A re-post (previous did not make it to the
List).</FONT></DIV>
<DIV><BR>Regards,<BR>Ton Maas<BR><A
href="mailto:ms-irb@xxxxxxxxxxxxxxxx">ms-irb@xxxxxxxxxxxxxxxx</A><BR>Dismiss the
".nospam" bit (including the dot) when replying and<BR>note the new address
change. Also for my Homepage<BR><A
href="http://home.planet.nl/~anthmaas">http://home.planet.nl/~anthmaas</A></DIV>
<DIV> </DIV>
<DIV> </DIV>
<BLOCKQUOTE
style="BORDER-LEFT: #000000 2px solid; MARGIN-LEFT: 5px; MARGIN-RIGHT: 0px; PADDING-LEFT: 5px; PADDING-RIGHT: 0px">
<DIV style="FONT: 10pt arial">----- Original Message ----- </DIV>
<DIV
style="BACKGROUND: #e4e4e4; FONT: 10pt arial; font-color: black"><B>From:</B> A.J.
Maas </DIV>
<DIV style="FONT: 10pt arial"><B>To:</B> <A
href="mailto:metastock@xxxxxxxxxxxxx"
title=metastock@xxxxxxxxxxxxx>metastock@xxxxxxxxxxxxx</A> </DIV>
<DIV style="FONT: 10pt arial"><B>Sent:</B> zaterdag 11 september 1999
19:11</DIV>
<DIV style="FONT: 10pt arial"><B>Subject:</B> Re: Windows API</DIV>
<DIV><BR></DIV>
<DIV><FONT size=2>Windows API : This below can be found @ </FONT></DIV>
<DIV><FONT size=2><A
href="http://msdn.microsoft.com/library/periodic/period96/D1/FT0296.htm">http://msdn.microsoft.com/library/periodic/period96/D1/FT0296.htm</A></FONT></DIV>
<DIV> </DIV>
<DIV><FONT size=2>Also click the "show toc"-icon below to go to the MSDN
Library (eg a treasure for Windows developers</FONT></DIV>
<DIV><FONT size=2>and not to be mixed up with the Windows library files (eg
drivers + dll's + ocx's etc.).</FONT></DIV>
<DIV><FONT size=2> </DIV></FONT>
<DIV><FONT size=2>And naturaly there is more:</FONT></DIV>
<DIV><FONT size=2><A
href="http://search.microsoft.com/us/results.asp?SName=Developer+Sites&SPath=http://msdn.microsoft.com&SCatalog=Developer&IntCat=11&Boolean=PHRASE&Nq=TRUE&qu=WIN32API&submit1=search">http://search.microsoft.com/us/results.asp?SName=Developer+Sites&SPath=http://msdn.microsoft.com&SCatalog=Developer&IntCat=11&Boolean=PHRASE&Nq=TRUE&qu=WIN32API&submit1=search</A></FONT></DIV>
<DIV><FONT size=2>(note: the lines above were split but should be
copied+pasted in full as it is also one(1) full website's
address)</FONT></DIV>
<DIV> </DIV>
<DIV><FONT size=2>Regards,<BR>Ton Maas<BR><A
href="mailto:ms-irb@xxxxxxxxxxxxxxxx">ms-irb@xxxxxxxxxxxxxxxx</A><BR>Dismiss
the ".nospam" bit (including the dot) when replying and<BR>note the new
address change. Also for my Homepage<BR><A
href="http://home.planet.nl/~anthmaas">http://home.planet.nl/~anthmaas</A></FONT></DIV>
<DIV> </DIV>
<DIV> </DIV>
<DIV><FONT size=2>----- Original Message ----- </FONT>
<DIV><FONT size=2>From: Walter Lake</FONT></DIV>
<DIV><FONT size=2>To: Metastock bulletin board <<A
href="mailto:metastock@xxxxxxxxxxxxx">metastock@xxxxxxxxxxxxx</A>></FONT></DIV>
<DIV><FONT size=2>Sent: donderdag 9 september 1999 15:34</FONT></DIV>
<DIV><FONT size=2>Subject: Windows API</FONT></DIV></DIV>
<DIV><BR></DIV>
<DIV><FONT size=2>> Thanks for your email. Sorry but I don't know how to do
that.<BR>> <BR>> There is a whole section of advanced Excel VBA
programming using Windows API<BR>> (Application Programming Interface) that
is covered in the WROX programmers<BR>> reference book. Usually, that kind
of access to the Windows platform and<BR>> ".dll's" is used by C and C+
programmers.<BR>> <BR>> Where Windows API programming is of interest is
when you want to take over<BR>> the entire Excel interface and create your
own icon's etc.<BR>> <BR>> As I mentioned earlier, you can make Excel
look less and less like Excel and<BR>> more like your own program using VBA
and VBA access to Windows API.<BR>> <BR>> Using Windows API, as far as I
know, is not only complicated but "risky"<BR>> because of the lack of error
messages and difficulty figuring out what went<BR>> wrong when things don't
work correctly.<BR>> <BR>> Personally, I'm going to leave all of that to
the C and C+ programmers.<BR>> "Plain" VBA is complicated enough for an
untrained and "clueless" programmer<BR>> such as myself.<BR>> <BR>>
Maybe Guy or Ton can post some general info about Windows API and the
MSDN<BR>> library files.<BR>> <BR>> There's suppose to be a
"win32api.txt" file that has all of the declarations<BR>> for the core
windows functions written in VBA notation. I don't know where<BR>> it is or
how to find it. Maybe Guy uses it in his programming.<BR>> <BR>> Best
regards<BR>> <BR>> Walter<BR>> <BR><!--TOOLBAR_START--><!--TOOLBAR_EXEMPT--><!--TOOLBAR_END--><!--SYNC_START-->
<SCRIPT language=JavaScript src="/library/synch.js"></SCRIPT>
</FONT></DIV>
<DIV><FONT size=2> <A
href="http://msdn.microsoft.com/isapi/msdnlib.idc?theURL=/library/periodic/period96/d1/ft0296.htm"
target=_top><IMG border=0 height=17
src="mhtml:mid://00000220/!http://msdn.microsoft.com/library/images/msdn/art/mlibfram.gif"
width=75></A> <!--SYNC_END--></DIV>
<P><FONT face="Verdana, Arial, Helvetica" size=2>
<H1>Use the Windows API to Print to Multiple Print Queues</H1>
<P>Richard Aman</P>
<P><I>Richard Aman is director of software engineering at Loren Industries, a
jewelry manufacturing company with headquarters in Hollywood, Florida. Richard
has been developing business solutions in FoxBASE/FoxPro since 1988 and
regularly gives presentations at his local Fox User Group. CompuServe
73700,141.</I></P>
<P>This article originally appeared in the February 1996 issue of FoxTalk,
published by Pinnacle Publishing Inc., PO Box 888, Kent, WA 98035-0888;
800-788-1900; 206-251-1900; http://www.pinpub.com.</P>
<P>Windows provides a wealth of services for controlling network connections.
Richard Aman shows how to use these services in either FoxPro 2.x or Visual
FoxPro to easily send a report to any available output device. In the process,
you'll learn about Visual FoxPro's new variant of DECLARE, which allows you to
call external DLL routines as if they were native UDFs. You'll also learn how
to use several useful Windows API routines.</P>
<P>ONE of the more difficult application types I've implemented is an
automatic scheduler. A scheduler performs procedures at various scheduled and
unscheduled times throughout the day. The procedures must perform in
unattended mode and make decisions without user input. Along with
software-related decisions like branching and looping, the procedures must
make hardware decisions. For example, the software must decide which printer
to send output to, which network connection to use, when to reset the
software, and which users are logged on when.</P>
<P>When I implemented the scheduler in Windows, the main design decision was
how to allow the system to use different printers in different locations for
the various output reports—key in an order-entry and work progress-based
system like this one. I designed the system to make decisions based on orders
entered, and by the various stages of manufacture that pieces have
achieved.</P>
<H2>The Win.INI route</H2>
<P>To choose an output printer, I initially used sample code from the
Microsoft Developer's Network (MSDN) CD. That sample code had multiple
printers installed in Windows, then modified the WIN.INI file to change the
default printer. The method worked fine, although it had limitations. First,
it required that all printers to be used be installed in Windows—a problem if
you want to use the application on different machines. The second limitation
was that Windows has only a limited number of printer ports. Though it's
possible to have several printers assigned to the same port, keeping track of
them can get messy. The third limitation is that it takes time to modify
WIN.INI and notify running applications to update themselves with the
changes.</P>
<P>The method detailed on the MSDN CD used the Windows API functions
GetProfileString() and PutProfileString() to access WIN.INI. This made me
wonder what other functions for switching printers might be buried in the
Windows API. I started looking through the Microsoft Developer's Network CD
and the TechNet CD (both excellent resources) and the Windows API help file
that comes with Visual FoxPro Professional Edition for other approaches to
this problem.</P>
<H2>A better way</H2>
<P>That's when I came across the WNetGetConnection(), WNetAddConnection(), and
WNetCancelConnection() functions. These three Windows API functions combine to
give you almost unlimited programmatic control over the network connections
through an application. WNetGetConnection() returns the name of the network
connection that a local device is mapped to, or NULL if the device isn't
mapped on the network. WNetAddConnection() maps a local device to a network
connection if it's not already connected. And WNetCancelConnection()
disconnects a local device from a network connection. With these three
functions, I implemented multiple printer output through LPT1 alone. I also
found two other useful Windows API functions: WNetGetUser(), which returns the
user network login ID, and ExitWindows(), which can be used to restart Windows
from within FoxPro.</P>
<P>My automatic scheduler application scans the orders table at a recurring
interval for any new orders. When new orders are found, they're copied to
separate temporary tables for printing. Based on the type, orders can print at
one of three places in the plant. The print routine is passed through three
parameters, which tell the routine the name of the temporary table, the report
form to use, and where to send output. When the routine processes the print
location decision, it calls WNetGetConnection() to check whether LPT1 is
connected to a network print queue. If a current connection exists, it calls
WNetCancelConnection() to disconnect LPT1 from the current network print
queue. It then calls WNetAddConnection() to connect LPT1 to the proper network
print queue. (To prevent a connection error, you'll need to cancel the
existing connection before creating a new connection..)</P>
<H2>The basics</H2>
<P>Before I get to my sample code, I want to quickly cover some basic
requirements for using this method of printer control and for using any of the
Windows API functions (or functions in any Windows DLL).</P>
<P>If you're using FoxPro 2.6 for Windows, first load in the library file
FoxTools.fll, (supplied with FoxPro 2.6). This library file loads with the
command SET LIBRARY TO FoxTools. Once the library is loaded, your program has
access to a pair of functions called RegFn() and CallFn(). RegFn() is used to
register Windows API functions to FoxPro. CallFn() is used to call the
functions previously registered with RegFn(). In Visual FoxPro 3.0, the
DECLARE command replaces the need for FoxTools.fll and the RegFn() and
CallFn() routines . This new DECLARE command is also used to register Windows
API functions. Once the functions have been registered, they're called just
like the internal FoxPro functions. However, for backward compatibility,
FoxTools.fll, RegFn() and CallFn() can still be used in FoxPro 3.0. (Refer to
the Visual FoxPro 3.0 help file for more information on the DECLARE
command.)</P>
<P>If you're working in FoxPro 2.x and are new to FoxTools/RegFn/CallFn, you
can get details from "Use Microsoft Windows Services from FoxPro" by Robert W.
Lord (<I>FoxTalk</I>, March 1994). Back issues can be ordered at 800-788-1900.
In the meantime, here's a brief rundown of these commands and the new Visual
FoxPro replacements for them:</P>
<H3>Loading the FoxTools.fll library</H3>
<P>First, load the FoxTools.fll library for FoxPro 2.6:</P>
<P><BR></P><PRE><CODE><FONT face="Verdana, Arial, Helvetica" size=2> SET LIBRARY TO SYS(2004) + 'FoxTools.fll' ADDITIVE</FONT></CODE></PRE>
<P>This command line uses the FoxPro function SYS(2004) to get FoxPro's home
directory, which is where FoxTools.fll is installed during normal
installation. Also, use the ADDITIVE clause to add the library to any existing
loaded libraries; otherwise, FoxTools.fll will replace any existing loaded
libraries.</P>
<H3>Using RegFn()</H3>
<P>The FoxTools function RegFn() registers a Windows API function with FoxPro.
RegFn() takes three required parameters and one optional parameter. The first
parameter is the name of the Windows API function you want to register. The
second parameter is a string containing letter designations for the types of
parameters the Windows API function requires ( 'C' for character or string,
'I' for integer, and so forth). The third parameter is a letter designation
for the type of value the Windows API function will return to FoxPro. The
fourth and optional parameter is the name of the Windows DLL that contains the
function you want to register. If you don't include the DLL name, FoxPro
automatically looks in the standard Windows libraries (USER.EXE, KRNL386.EXE,
and GDI.EXE in Windows 3.x) to try to find the Windows API function. If the
function isn't found, an error code is returned. If the function is
successfully registered, a function handle is returned. That handle is then
used by CallFn() to access the Windows API function, as I describe later.</P>
<H3>Using CallFn()</H3>
<P>The FoxTools function CallFn() is used to access a Windows API function
from within FoxPro once it has been registered with RegFn(). The parameters
passed to CallFn() are the Windows API function handle returned by RegFn(),
and the parameters specified in the second parameter in RegFn() when the
Windows API function was registered. </P>
<H3>Using DECLARE in Visual FoxPro</H3>
<P>DECLARE is an enhanced command in Visual FoxPro 3.0. In addition to
defining arrays, the DECLARE command also removes the need for using FoxTools
to access the Windows API functions. DECLARE allows the application to
directly register Windows API functions with FoxPro. Once the functions are
registered, they can be called like any other FoxPro internal function. The
first parameter to the DECLARE command is the Windows API function return
type. The second parameter is the name of the function you're registering. The
third parameter is the DLL containing the Windows API function. The remainder
of the parameters are the parameter types that FoxPro will pass to the Windows
API function.</P>
<H2>The Windows API functions</H2>
<H3>WNetGetConnection()</H3>
<P>WNetGetConnection() is used to retrieve the network connection to which a
local device is mapped. The first parameter is a variable containing the name
of the local device you want to check. The second parameter is a variable
initialized to spaces ( I use 255 ) and will be supplied with the connection
name by WNetGetConnection(). The last parameter is a variable containing the
length of the second parameter ( in this case 255 ). All three parameters need
to be passed by reference. After initializing the variables, register the
function with FoxPro. This lets FoxPro know that the function will be passed
three parameters by reference, two strings and one integer, and the function
will return an integer. Ensure the second parameter buffer is empty before
calling this function, because an error won't clear the buffer and you might
get incorrect results.</P>
<P>Here's the syntax for setting up the WNetGetConnection call, first for
FoxPro 2.x, then for Visual FoxPro:</P>
<P><BR></P><PRE><CODE><FONT face="Verdana, Arial, Helvetica" size=2> * FoxPro 2.x
lnGetConn = RegFn('WNetGetConnection','@C@x@I','I')
* Visual FoxPro
DECLARE INTEGER WNetGetConnection IN win32api ;
STRING @, STRING @, INTEGER @</FONT></CODE></PRE>
<P>Call the function to return the current connection for the specified
device:</P>
<P><BR></P><PRE><CODE><FONT face="Verdana, Arial, Helvetica" size=2> * FoxPro 2.x
lnRetVal = CallFn(lnGetConn, @lcDeviceName, ;
@lcConnName, @lnBuffLen)
* Visual FoxPro
lnRetVal = WNetGetConnection(@lcDeviceName, ;
@lcConnName, @lnBuffLen)</FONT></CODE></PRE>
<P>After the call to WNetGetConnection(), the buffer lcConnName will either
contain the name of the network connection for the specified local device or
will be empty if no connection currently exists for the local device. It will
also be empty if an error occurred. Also, be sure to check the return value
for any error codes. The Windows API return codes for WNetGetConnection()
follow, as found in the Windows SDK:</P>
<P>0 The function was successful.</P>
<P>8 The system was out of memory.</P>
<P>50 The function was not supported.</P>
<P>59 An error occurred on the network.</P>
<P>87 The local device name parameter was not a valid local device.</P>
<P>234 The buffer was too small. ( The connection name is longer than </P>
<P>the allotted buffer length. )</P>
<P>487 The pointer was invalid.</P>
<P>2250 The local device name parameter was not a redirected local </P>
<P>device.</P>
<H3>WNetAddConnection()</H3>
<P>WNetAddConnection() is used to map a local device to a network connection.
The first parameter is the network connection to map the device to. The second
parameter is the password to use and should be a null string to use the
default password. Finally, the third parameter is the local device to map.
After initializing the variables, register the function with FoxPro. This lets
FoxPro know that the function will be passed three parameters as strings, and
will return one integer:</P>
<P><BR></P><PRE><CODE><FONT face="Verdana, Arial, Helvetica" size=2> * FoxPro 2.6
lnAddConn = RegFn('WNetAddConnection','CCC','I')
* Visual FoxPro
DECLARE INTEGER WNetAddConnection IN win32api ;
STRING, STRING, STRING</FONT></CODE></PRE>
<P>Call the function to map the local device to the network connection:</P>
<P><BR></P><PRE><CODE><FONT face="Verdana, Arial, Helvetica" size=2> * FoxPro 2.x
lnRetVal = CallFn(lnAddConn,'\\SERVER1\HP4','','LPT1:')
* Visual FoxPro
lnRetVal = WNetAddConnection('\\SERVER1\HP4','','LPT1:')</FONT></CODE></PRE>
<P>This function returns 0 if successful, or an error number for any error
that occurs while attempting to create the network connection. I've listed the
Windows API return codes for WNetAddConnection(), which follow, as found in
the Windows SDK.</P>
<TABLE border=0 cols=2>
<COLGROUP>
<COL vAlign=top width=68>
<COL vAlign=top width=226></COLGROUP>
<TBODY>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>0</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The
function was successful.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>5</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>A security
violation occurred.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>8</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The system
was out of memory.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>50</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The
function was not supported.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>59</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>An error
occurred on the network.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>67</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The network
resource name was invalid.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>85</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The local
device was already connected to a remote resource.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>86</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The
password was invalid.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>487</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The pointer
was invalid.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>1200</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The local
device name was invalid.</FONT></TD></TR></TBODY></TABLE>
<P><BR></P>
<H3>WNetCancelConnection()</H3>
<P>WNetCancelConnection() is used to remove a network connection mapping from
a local device. This is necessary because the WNetAddConnection() function
will return an error if the device that you are trying to map is already
mapped to a network connection. For this reason, I recommend checking the
network mapping for the local device before attempting to create a new
connection. Also, I recommend releasing any network mapping that exists first.
The first parameter is the local device to cancel the network connection to.
The second parameter tells Windows whether to close any open files, or simply
to return an error. The second parameter should be 0 to close open files
before disconnecting. After initializing the variables, register the function
with FoxPro. This lets FoxPro know that the function will be passed two
parameters, one string and one integer, and will return one integer.</P>
<P><BR></P><PRE><CODE><FONT face="Verdana, Arial, Helvetica" size=2> * FoxPro 2.6
lnCancelConn = RegFn('WNetCancelConnection','CI','I')
* Visual FoxPro
DECLARE INTEGER WNetCancelConnection IN win32api ;
STRING, INTEGER</FONT></CODE></PRE>
<P>Call the function to cancel the connection for the specified local
device:</P>
<P><BR></P><PRE><CODE><FONT face="Verdana, Arial, Helvetica" size=2> * FoxPro 2.6
lnRetVal = CallFn(lnCancelConn,'LPT1:',0)
* Visual FoxPro
lnRetVal = WNetCancelConnection('LPT1:',0)</FONT></CODE></PRE>
<P>This function returns 0 if successful, or it returns an error number for
any error that occurs while attempting to cancel the network connection.
Following are the Windows API return codes for WNetCancelConnection(), as
found in the Windows SDK:</P>
<TABLE border=0 cols=2>
<COLGROUP>
<COL vAlign=top width=72>
<COL vAlign=top width=243></COLGROUP>
<TBODY>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>0</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The
function was successful.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>8</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The system
was out of memory.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>50</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The
function was not supported.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>59</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>An error
occurred on the network.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>87</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The local
device name parameter was not a valid local device </FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2> </FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>or network
name. </FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>487</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The pointer
was invalid.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>2250</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The local
device name parameter was not a redirected local </FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2> </FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>device or
currently accessed network resource.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>2401</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>Files were
open and the fForce parameter was 0. </FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2> </FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The
connection was not canceled.</FONT></TD></TR></TBODY></TABLE>
<P><BR></P>
<H3>WNetGetUser()</H3>
<P>WNetGetUser() is used to return the network login ID of the machine the
application is running on. The first parameter is a variable containing the
local name to return the network login ID for. It should be NULL for the
current machine. The second parameter is a variable initialized to spaces (I
use 255 spaces) and will be filled in by WNetGetUser() with the network login
ID. The third parameter is the length of the second parameter. All three
parameters need to be passed in by reference in order for the function to
operate correctly. After initializing the variables, register the function
with FoxPro. This lets FoxPro know that the function will be passed two
parameters by reference, one string and one integer, and the function will
return one integer. Use NULL for the first parameter to get the current
sign-on name because if the user is signed on more than once, the system makes
a random choice of which login name to return:</P>
<P><BR></P><PRE><CODE><FONT face="Verdana, Arial, Helvetica" size=2> * FoxPro 2.x
lnGetUser = RegFn('WNetGetUser','@C@x@I','I')
* Visual FoxPro
DECLARE INTEGER WNetGetUser IN win32api ;
STRING @, STRING @, INTEGER @</FONT></CODE></PRE>
<P>Call the function to get the network login ID of the machine:</P>
<P><BR></P><PRE><CODE><FONT face="Verdana, Arial, Helvetica" size=2> * FoxPro 2.x
lnRetVal = CallFn(lnGetUser,@lcUserID,@lnBuffLen)
lnRetVal = WNetGetUser(@lcUserID,@lnBuffLen)</FONT></CODE></PRE>
<P>After the call to WNetGetUser(), the buffer lcUserID will contain either
the network login ID or will be empty if the machine isn't logged in to the
network. Also, check the return value for any error codes. Following are the
Windows API return codes for WNetGetUser(), as found in the Windows SDK:</P>
<TABLE border=0 cols=2>
<COLGROUP>
<COL vAlign=top width=59>
<COL vAlign=top width=297></COLGROUP>
<TBODY>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>8</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The
function could not allocate sufficient memory to </FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2> </FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>complete
its operation.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>50</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>This
function is not supported. </FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>59</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>A network
error occurred.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>234</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The buffer
was too small to hold the complete user name. </FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>487</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The pointer
is invalid.</FONT></TD></TR>
<TR>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica"
size=2>2202</FONT></TD>
<TD vAlign=top><FONT face="Verdana, Arial, Helvetica" size=2>The user is
not logged in; there is no current user name.
</FONT></TD></TR></TBODY></TABLE>
<P><BR></P>
<H3>ExitWindows() and ExitWindowsEx()</H3>
<P>ExitWindows() has two uses of interest, based on the first parameter passed
in. The first parameter is a flag to tell Windows to either reboot or exit.
The second parameter is reserved and should be 0. If you pass in a 67 to the
first parameter, Windows will close down any running applications and exit to
the DOS prompt. If you pass in a 66, Windows will close down any running
applications and restart Windows. (the function is called ExitWindowsEx() in
32-bit Windows; the first parameter should be 0 to restart Windows.) I use a
66 in the automatic scheduler application . After initializing the variables,
register the function with FoxPro. This lets FoxPro know that the function
will be passed two parameters, both integers, and the function will return one
integer:</P>
<P><BR></P><PRE><CODE><FONT face="Verdana, Arial, Helvetica" size=2> * FoxPro 2.x
lnExitWin = RegFn('ExitWindows','II','I')
* Visual FoxPro
DECLARE INTEGER ExitWindowsEx IN user32 ;
INTEGER, INTEGER</FONT></CODE></PRE>
<P>Call the function to restart Windows:</P>
<P><BR></P><PRE><CODE><FONT face="Verdana, Arial, Helvetica" size=2> * FoxPro 2.x
lnRetVal = CallFn(lnExitWin,66,0)
* Visual FoxPro
lnRetVal = ExitWindowsEx(0,0)</FONT></CODE></PRE>
<P>ExitWindows() and ExitWindowsEx() have only two return codes: 0 or FALSE if
an error occurred, and 1 or TRUE if the function call was successful. In this
use of ExitWindows() or ExitWindowsEx(), you probably need only check for a
failure return code, since a successful call would have restarted Windows and
FoxPro, meaning the return code value would have been released. But a check
for success might be important in other uses.</P>
<P>Why use ExitWindows() or ExitWindowsEx()? I use ExitWindows() because of a
"memory leak" in FoxPro for Windows 2.6, which my scheduler runs under. When
FoxPro generates a report, some of the memory used isn't released back to the
pool of free memory. Consequently, after a certain number of reports, FoxPro
can run out of memory. In my case, problems occur after approximately 75 work
production tickets, each with a bitmap of the item and several different
fonts. To prevent this, I set up FoxPro in the Windows StartUp group with a
command line call to the automatic scheduler. Then, every 15 minutes I call a
procedure called ResetWin (included on this month's Companion Disk), which
closes down FoxPro and restarts Windows. When Windows starts up, it runs
FoxPro from the StartUp group, which then restarts the automatic scheduler,
which picks up where it left off—but with refreshed memory. Everything runs
smoothly with this scheme in place.</P>
<P>Presumably, this memory leak has been fixed in Visual FoxPro, but you may
still want to use ExitWindowsEx() to automatically shut down or restart some
application types, perhaps at particular times of the day when demand is
minimal. It often helps to get a "clean slate" periodically for an automated
server application on a dedicated workstation, particularly if the application
has the potential of running unattended for days or weeks.</P>
<P>Listing 1 illustrates my basic method of printer control. Prior to this
procedure, the application will have selected the records to be printed, the
report form to use, and the network print queue destination, all of which are
passed in through parameters. I first initialize my variables and save the
current library setting. I then make sure the Foxtools library is loaded for
version 2.x. Next, I register the Windows API functions with FoxPro ( using
the DECLARE command for version 3.0 or the RegFn() for version 2.x ). Then I
check for and release any existing connection for LPT1: using
WNetGetConnection(). I then set LPT1: to the desired network print queue with
WNetAddConnection(). After all is set up properly, I loop through the source
table and generate a full-page form for each record (this allows other users
to insert print jobs between my frequent multi-page output). Finally, I make a
call to GetNetID() to see if I'm on the automatic scheduler. If so, I reset
LPT1: to a default network print queue. I then restore the previous library
setting and exit the routine.</P>
<P>The call to the GetNetID UDF deserves a little more explanation. GetNetID()
is included on this month's Companion Disk. It calls the Windows WNetGetUser()
function to return the network login ID of the machine the application is
running on. This can be used for a variety of things. In AutoPrnt, I check the
network ID with GetNetID() to see if the application print routine is running
on the automatic scheduler machine. If so, I re-map the printer back to the
default queue so normal output that doesn't need to be specifically redirected
can be printed on the central printer. </P>
<P><B>Listing 1. The AutoPrnt procedure.</B></P>
<P><BR></P><PRE><CODE><FONT face="Verdana, Arial, Helvetica" size=2> ********************************************************
* PROCEDURE AutoPrnt
********************************************************
* Author............: Richard L. Aman
*) Description.......: A scaled down version of the print
*) : engine for the automatic scheduler
* Calling Samples...: DO AutoPrnt WITH cSrcTable,
*) : cFormName, cPrinter
* Parameter List....: cSrcTable - table containing
*) : records to print
* : cFormName - name of form to use
* : cPrinter - report destination
PROCEDURE AutoPrnt
PARAMETERS cSrcTable, cFormName, cPrinter
*-- define variables
PRIVATE lcFormName, lcPrinter, lcReport, lcOldPrinter, ;
lcOldLibrary, lnAddConn, lnDelConn, lnGetConn, ;
lcDeviceName, lcConnName, lnBuffLen, ;
llVersion3, lcConnTo, lnRetVal
*-- init variables
lcFormName = cFormName
lcPrinter = cPrinter
lcReport = lcFormName
lcOldPrinter = ''
lcOldLibrary = SET('LIBRARY')
lcDeviceName = 'LPT1'
lcConnName = SPACE(254)
lnBuffLen = LEN(lcConnName)
llVersion3 = '3.0' $ VERSION()
lcConnTo = ''
lnRetVal = 0
*--ensure that foxtools library is loaded
IF NOT llVersion3
IF NOT 'FOXTOOLS' $ UPPER( lcOldLibrary )
SET LIBRARY TO SYS( 2004 ) + 'FOXTOOLS.FLL' ADDITIVE
ENDIF
ENDIF
*-- register the Windows API functions
IF llVersion3
DECLARE INTEGER WNetAddConnection IN win32API ;
STRING, STRING, STRING
DECLARE INTEGER WNetCancelConnection IN win32API ;
STRING, INTEGER
DECLARE INTEGER WNetGetConnection IN win32API ;
STRING @, STRING @, INTEGER @
ELSE
lnAddConn = RegFn('WNetAddConnection','CCC','I')
lnDelConn = RegFn('WNetCancelConnection','CI','I')
lnGetConn = RegFn('WNetGetConnection','@C@x@I','I')
ENDIF
*-- check for an existing connection
IF llVersion3
lnRetVal = WNetGetConnection(@lcDeviceName, ;
@lcConnName,@lnBuffLen)
ELSE
lnRetVal = CallFn(lnGetConn,@lcDeviceName, ;
@lcConnName,@lnBuffLen )
ENDIF
IF NOT EMPTY( lcConnName )
IF llVersion3
lnRetVal = WinNetCancelConnection('LPT1:',0)
ELSE
lnRetVal = CallFn(lnDelConn,'LPT1:',0)
ENDIF
ENDIF
*-- set the printer to the correct queue
DO CASE
CASE lcPrinter = 'MIS'
lcConnTo = '\\SERVER1\MIS'
CASE lcPrinter = 'QC'
lcConnTo = '\\SERVER1\HP4'
CASE lcPrinter = 'PRODUCTION'
lcConnTo = '\\SERVER2\PRODPRINT'
ENDCASE
IF llVersion3
lnRetVal = WNetAddConnection( lcConnTo, '','LPT1:')
ELSE
lnRetVal = CallFn(lnAddConn,lcConnTo,'','LPT1:')
ENDIF
*-- print the report for each record
GO TOP
SCAN WHILE LASTKEY() <> 27 && allow ESC
REPORT FORM &lcReport TO PRINTER NEXT 1 NOCONSOLE
ENDSCAN
*-- clean up and return
IF GetNetID() = 'SCHEDULE'
IF llVersion3
lnRetVal = WNetCancelConnection('LPT1:',0)
lnRetVal = WNetAddConnection('\\SERVER1\PRINTQ_0',;
'','LPT1:')
ELSE
lnRetVal = CallFn(lnDelConn,'LPT1:',0)
lnRetVal = CallFn(lnAddConn,'\\SERVER1\PRINTQ_0',;
'','LPT1:')
ENDIF
ENDIF
SET LIBRARY TO &lcOldLibrary
RETURN</FONT></CODE></PRE>
<H2>Things I learned the hard way about using Windows API functions </H2>
<P>If the function declaration calls for a value to be passed by reference,
you <I>must</I> use a variable and preface it with the "@" symbol. I thought
that for the buffer length, I could set a variable with the length of the
buffer, then just pass the variable, but not in this case. I still had to use
the "@" symbol.</P>
<P>If you're using the Visual FoxPro calling convention with the DECLARE
command, the Windows API function names are case-sensitive.</P>
<P>Always remember to check the return value for any error codes.
Unfortunately, I didn't have enough space in this article to go into detail
about handling errors, but at the very least you should determine what the
function returns when it's successful and test for that. Don't forge ahead in
your code just <I>assuming</I> that the API function executed
successfully.</P>
<H2>Conclusion</H2>
<P>FoxPro for Windows and Visual FoxPro provide a rich programming language
that allows the developer to create applications of amazing power and
complexity. However, even with all the commands included, there are still
times when a task either can't be accomplished with native FoxPro code, or the
overhead associated with the procedure written in native FoxPro causes too
great a performance hit. When you hit a brick wall in your development and
FoxPro just won't cooperate, take time to browse through the Windows API help
file (included with the Professional Edition of Visual FoxPro and other
Microsoft "visual" development products). You may find just what you need.</P>
<P>Having easy access to around 75 percent of the Windows API functions (the
rest require abstract data types such as C structures so you have to either be
very tricky or write C routines to access them), opens up a world of
possibilities for developers who do a little research. I hope these examples
help you, and let you build on what I've presented here. I look forward to
comments, questions or suggestions. </P>
<P align=center><A href="http://www.pinpub.com/foxtalk/"><IMG border=0
height=72
src="mhtml:mid://00000220/!http://msdn.microsoft.com/library/periodic/period96/D1/Pinnacle.gif"
width=216></A></P>
<P align=center><STRONG>To find out more about FoxTalk and Pinnacle
Publishing, visit their website at</STRONG> <BR><A
href="http://www.pinpub.com/foxtalk/"><STRONG>http://www.pinpub.com/foxtalk/</STRONG></A></P>
<P align=center><FONT face="Verdana, Arial, Helvetica" size=2>Note: This is
not a Microsoft Corporation website. <BR>Microsoft is not responsible for its
content.</FONT></P>
<P><I>This article is reproduced from the February 1996 issue of
</I>FoxTalk<I>. Copyright 1995, by Pinnacle Publishing, Inc., unless otherwise
noted. All rights are reserved. </I>FoxTalk<I> is an independently produced
publication of Pinnacle Publishing, Inc. No part of this article may be used
or reproduced in any fashion (except in brief quotations used in critical
articles and reviews) without prior consent of Pinnacle Publishing, Inc. To
contact Pinnacle Publishing, Inc., please call (800)788-1900 or
(206)251-1900.</I></P></FONT><A
href="http://msdn.microsoft.com/isapi/gomscom.asp?TARGET=/misc/cpyright.htm"
target=_top>© 1999 Microsoft Corporation. All rights reserved. Terms of
use</A></FONT></BLOCKQUOTE></BODY></HTML>
</x-html>Content-Type: image/gif;
name="mlibfram.gif"
Content-Location: http://msdn.microsoft.com/library/images/msdn/art/mlibfram.gif
Attachment Converted: "c:\eudora\attach\mlibfram.gif"
Content-Type: image/gif;
name="Pinnacle.gif"
Content-Location: http://msdn.microsoft.com/library/periodic/period96/D1/Pinnacle.gif
Attachment Converted: "c:\eudora\attach\Pinnacle.gif"
|