[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Windows API



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.3500" name=GENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY bgColor=#ffffff>
<DIV><FONT size=2>Ton:</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT size=2>I could not open the attached file.&nbsp; I got a message that 
it was not a gif file (using Paint Shop Pro).</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT size=2>Can you resend It?</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT size=2>Thanks</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT size=2>Lionel Issen</FONT></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-List</A> </DIV>
  <DIV style="FONT: 10pt arial"><B>Sent:</B> Thursday, September 16, 1999 10:13 
  PM</DIV>
  <DIV style="FONT: 10pt arial"><B>Subject:</B> Re: Windows API</DIV>
  <DIV><BR></DIV>
  <DIV><FONT size=2>A re-post (previous did not make it to&nbsp;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>&nbsp;</DIV>
  <DIV>&nbsp;</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>&nbsp;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>&nbsp;</DIV>
    <DIV><FONT size=2>Also click the "show toc"-icon below to go to the MSDN 
    Library (eg a&nbsp;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>&nbsp;</DIV></FONT>
    <DIV><FONT size=2>And&nbsp;naturaly there is more:</FONT></DIV>
    <DIV><FONT size=2><A 
    href="http://search.microsoft.com/us/results.asp?SName=Developer+Sites&amp;SPath=http://msdn.microsoft.com&amp;SCatalog=Developer&amp;IntCat=11&amp;Boolean=PHRASE&amp;Nq=TRUE&amp;qu=WIN32API&amp;submit1=search";>http://search.microsoft.com/us/results.asp?SName=Developer+Sites&amp;SPath=http://msdn.microsoft.com&amp;SCatalog=Developer&amp;IntCat=11&amp;Boolean=PHRASE&amp;Nq=TRUE&amp;qu=WIN32API&amp;submit1=search</A></FONT></DIV>
    <DIV><FONT size=2>(note: the lines above were&nbsp;split but should be 
    copied+pasted in full as&nbsp;it is also one(1)&nbsp;full website's 
    address)</FONT></DIV>
    <DIV>&nbsp;</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>&nbsp;</DIV>
    <DIV>&nbsp;</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 &lt;<A 
    href="mailto:metastock@xxxxxxxxxxxxx";>metastock@xxxxxxxxxxxxx</A>&gt;</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>&gt; Thanks for your email. Sorry but I don't know how to 
    do that.<BR>&gt; <BR>&gt; There is a whole section of advanced Excel VBA 
    programming using Windows API<BR>&gt; (Application Programming Interface) 
    that is covered in the WROX programmers<BR>&gt; reference book. Usually, 
    that kind of access to the Windows platform and<BR>&gt; ".dll's" is used by 
    C and C+ programmers.<BR>&gt; <BR>&gt; Where Windows API programming is of 
    interest is when you want to take over<BR>&gt; the entire Excel interface 
    and create your own icon's etc.<BR>&gt; <BR>&gt; As I mentioned earlier, you 
    can make Excel look less and less like Excel and<BR>&gt; more like your own 
    program using VBA and VBA access to Windows API.<BR>&gt; <BR>&gt; Using 
    Windows API, as far as I know, is not only complicated but "risky"<BR>&gt; 
    because of the lack of error messages and difficulty figuring out what 
    went<BR>&gt; wrong when things don't work correctly.<BR>&gt; <BR>&gt; 
    Personally, I'm going to leave all of that to the C and C+ 
    programmers.<BR>&gt; "Plain" VBA is complicated enough for an untrained and 
    "clueless" programmer<BR>&gt; such as myself.<BR>&gt; <BR>&gt; Maybe Guy or 
    Ton can post some general info about Windows API and the MSDN<BR>&gt; 
    library files.<BR>&gt; <BR>&gt; There's suppose to be a "win32api.txt" file 
    that has all of the declarations<BR>&gt; for the core windows functions 
    written in VBA notation. I don't know where<BR>&gt; it is or how to find it. 
    Maybe Guy uses it in his programming.<BR>&gt; <BR>&gt; Best regards<BR>&gt; 
    <BR>&gt; Walter<BR>&gt;&nbsp;<BR><!--TOOLBAR_START--><!--TOOLBAR_EXEMPT--><!--TOOLBAR_END--><!--SYNC_START-->
    <SCRIPT language=JavaScript src="/library/synch.js"></SCRIPT>
    </FONT></DIV>
    <DIV><FONT size=2>&nbsp;<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&#8212;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&#8212;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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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&#8212;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() &lt;&gt; 27 &amp;&amp; allow ESC
 REPORT FORM &amp;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 &amp;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></BLOCKQUOTE></BODY></HTML>
</x-html>From ???@??? Fri Sep 17 12:21:41 1999
Return-Path: <majordom@xxxxxxxxxxxxxxxxxx>
Received: from listserv.equis.com (listserv.equis.com [204.246.137.2])
	by purebytes.com (8.8.7/8.8.7) with ESMTP id MAA16997
	for <neal@xxxxxxxxxxxxx>; Fri, 17 Sep 1999 12:13:36 -0700
Received: (from majordom@xxxxxxxxx)
	by listserv.equis.com (8.8.7/8.8.7) id CAA26035
	for metastock-outgoing; Sat, 18 Sep 1999 02:16:52 -0600
X-Authentication-Warning: listserv.equis.com: majordom set sender to owner-metastock@xxxxxxxxxxxxx using -f
Received: from freeze.metastock.com (freeze.metastock.com [204.246.137.5])
	by listserv.equis.com (8.8.7/8.8.7) with ESMTP id CAA26031
	for <metastock@xxxxxxxxxxxxxxxxxx>; Sat, 18 Sep 1999 02:16:49 -0600
Received: from mars.superlink.net (root@xxxxxxxxxxxxxxxxxx [209.236.128.133])
	by freeze.metastock.com (8.8.5/8.8.5) with ESMTP id LAA04303
	for <metastock@xxxxxxxxxxxxx>; Fri, 17 Sep 1999 11:59:48 -0600 (MDT)
Received: from superlink.com (209.236.135.47.dialup.superlink.net [209.236.135.47])
	by mars.superlink.net (8.9.3/8.9.3) with ESMTP id NAA13269
	for <metastock@xxxxxxxxxxxxx>; Fri, 17 Sep 1999 13:46:00 -0400 (EDT)
Message-ID: <37E27DE0.11B4967A@xxxxxxxxxxxxx>
Date: Fri, 17 Sep 1999 13:44:01 -0400
From: Vitaly Larichev <vitaly@xxxxxxxxxxxxx>
X-Mailer: Mozilla 4.61 [en] (Win98; U)
X-Accept-Language: en
MIME-Version: 1.0
To: metastock@xxxxxxxxxxxxx
Subject: Re: Installation hangover
References: <001301be0a89$cc30cc60$51662599@xxxx> <37DA943D.82A2C25E@xxxxxxxxxxxxx>
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Sender: owner-metastock@xxxxxxxxxxxxx
Precedence: bulk
Reply-To: metastock@xxxxxxxxxxxxx
Status:   

Seems I am working in a self-service mode - answering my own questions posted earlier :-) .

Lately, after installing MS 6.52 I've got too large fonts in Data Window and Title Bars of Inner
Windows, and too thick Title Bars themselves. This was the problem I struggled with last few days.

Since I've got no response to my question, it's quite probable that all other listers don't experience
these troubles or don't care, and this post with answers might be just a nuisance for many of you.
Well ... having finished with apologies, let me explain how you can change settings to fix this stuff,
or adjust if you wish.

To change fonts and the thickness of Title Bars, go to Control Panel/Display icon, choose Appearance
tab. Then click on "Palette Title" in "Item" menu. There choose Palette Title's size, font's type and
size. Mind different fonts has different smallest sizes which in turn determines smallest Bars'
thickness available. As for the font size in Data Window, I cannot pinpoint how I managed to make it
smaller. Perhaps, my monkeying with all those settings gave MS 6.52 a shake it needed to set the font
size right. Otherwise, cannot explain why with the same Control Panel settings MS 5.11 and 6.52 looked
different.

Cheers, Vitaly



Vitaly Larichev wrote:

> Hello everybody,
>
> Just installed MS 6.52 in the place of warm, fuzzy 5.11 <g>. It's fine. One thing I cannot figure
> out is how to change font size in Data Window. It's too large now, so that some values are cut off
> from the front: Volume for AT&T may read 3,567,000 instead of 13,567,000. Also it makes me scroll
> down too far if a chart is crowded with indicators.
>
> Another big problem is again too large font size in Title Bars of Inner Windows. It seems as if it
> also makes the bars so thick that they take out a good portion of screen real estate for a layout
> with 9 inner windows.
>
> Somehow in 5.11 I had all this small enough to like it.
>
> Thanks for any advice.
>
> Cheers, Vitaly.