<?xml version="1.0" encoding="iso-8859-1" ?>
<rss version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <channel>
  <title>Christof Wollenhaupt</title>
  <link>http://www.foxpert.com/knowlbits.htm</link>
  <description>My notes on Development, the Universe and Everything</description>
  <generator></generator>
  <item>
<title><![CDATA[
Implementing SmartCopy
]]></title>
<link>http://www.foxpert.com/knowlbits_200910_2.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
">
<p>
The following program implements sort of a smart copy in Visual FoxPro. When something is selected, the selected
text is copied. Otherwise the entire current line. So far, only Ctrl+C is implemented.
</p><pre>
*==========================================================
* Implements SmartCopy. When nothing is highlighted, the
* entire line is copied.
*==========================================================

  *--------------------------------------------------------
  * Remove existing keyboard short cut
  *--------------------------------------------------------
  Release Bar _med_copy of _medit
  DEFINE BAR _med_copy OF _medit PROMPT "\&lt;Copy" ;
    After _med_cut ;
    PICTRES _med_copy ;
    MESSAGE "Copies the selection onto the Clipboard"

  *--------------------------------------------------------
  * Invisible popup to capture short cut key.
  *--------------------------------------------------------
  Local lcFile
  lcFile = Sys(16)
  Define Popup SmartCopy
  Define Bar 1 of SmartCopy prompt "Copy" Key Ctrl+C
  On Selection Bar 1 of SmartCopy ;
    do HandleCopy in "&amp;lcFile"


*==========================================================
* Copies the entire line if nothing is selected, default
* behavior otherwise.
*==========================================================
Procedure HandleCopy

  *--------------------------------------------------------
  * Check if we need to execute the default behavior
  *--------------------------------------------------------
  Local llDefault
  _Cliptext = ""
  Sys(1500,"_med_copy","_medit")
  Doevents
  llDefault = not Empty(_Cliptext)

  *--------------------------------------------------------
  * Make sure, FoxTools.Fll is loaded.
  *--------------------------------------------------------
  If not "FOXTOOLS.FLL" $ Upper(Set("Library"))
    Set Library to (Home()+"FoxTools.Fll") Additive
  Endif

  *--------------------------------------------------------
  * Find current window handle
  *--------------------------------------------------------
  Local lnWHandle, laEnv[25]
  If not m.llDefault
    lnWHandle = _WOnTop()
    If m.lnWHandle &lt;= 0
      llDefault = .T.
    Else
      Try
        _EdGetEnv( m.lnWHandle, @laEnv )
        llDefault = (laEnv[25] &lt; 0)
      Catch
        llDefault = .T.
      EndTry
    EndIf
  EndIf

  *--------------------------------------------------------
  * Get the current line content
  *--------------------------------------------------------
  Local lnCurPos, lnLineNo, lnStart, lnEnd
  If not m.llDefault
    lnCurPos = _EdGetPos( m.lnWHandle )
    lnLineNo = _EdGetLNum( m.lnWHandle, m.lnCurPos )
    lnStart = _EdGetLPos( m.lnWHandle, m.lnLineNo )
    lnEnd = _EdGetLPos( m.lnWHandle, m.lnLineNo+1 )
    If m.lnStart &lt; m.lnEnd
      lnEnd = m.lnEnd - 1
      _Cliptext = _EdGetStr(m.lnWHandle,m.lnStart,m.lnEnd)
    Endif
    _EdSetPos(m.lnWHandle, m.lnCurPos)
  EndIf

EndProc
</pre>
</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Wed, 28 Oct 2009 00:42:30</pubDate>
</item>
<item>
<title><![CDATA[
Locking done quickly
]]></title>
<link>http://www.foxpert.com/knowlbits_200910_1.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
">
<div style="border-width:thin; border-style:solid; margin-top: 20px; padding: 5px; border-color: gray; background-color: lightyellow" >
<p style="margin-top: 0px;"><b>UPDATE</b></p>
<p>
Joel Leach <a href="http://twitter.com/joel_leach">pointed out on Twitter</a> that the following code accomplishes the same even though Visual FoxPro's documentation states that SET REPROCESS TO 0 SECONDS is an invalid statement:
</p><pre>
LOCAL llLock
SET REPROCESS TO 0 SECONDS
llLock = RLOCK()
UNLOCK
</pre><p>
I'll leave the article on here since the low level approach might be useful for something else, too.
</div>
</p><p>
The only possible approach for finding out whether you can lock a record is to actually lock it. Aside from editing records there can be various reasons why you need to lock records. For instance, one application I'm working on, uses locks in a table to validate the number of seats that the application is licensed to. Every instance tries to find an unlocked record, then locks the record and updates it with some more details. If there's no unlocked record, the user ran out of licenses. Another module determines all locked records and displays all recorded information. This allows administrators and supporters to find out who is still in the application.
</p><p>
A straight forward approach would be to scan through the table, lock each record and continue until RLOCK() returns .T. Problems arise when the number of work stations and licenses grows. The first record is way more likely to be locked than the last one. Hence, the more users are logged on the longer it takes to launch the application for new users.
</p><p>
One approach I implemented in the past to get around this is to check for random record numbers instead of scanning through the table. Just generate a random number between 1 and RECCOUNT(). Navigate to the record, attempt to lock it, repeat with a new record. Probably you want to limit the number of attempts to something like two or three times the total number of records before exiting the application. This approach distributes locked records equally in the table. It's still slow, though.
</p><p>
Visual FoxPro never tries to lock a record just once (let me know if you disagree with this statement). Instead Visual FoxPro uses the value of SET REPROCESS TO for a number of attempts. There are various options such as locking for a number of seconds, a number of attempts or eternally until the user cancels out. In the end, though, it all boils down to Visual FoxPro repeatedly trying to lock the record until a termination condition is met.
</p><p>
SYS(3051) controls the interval between attempts. Possible values for this function are limited, though. The interval can be anything between 100 ms and one second. The default is 333 ms meaning that a value of 3 for SET REPROCESS makes the app wait up to one second before RLOCK() returns .F.
</p><p>
If you want to check a huge number of records, you want to minimize this time. The fastest possible setting in Visual FoxPro is
</p><pre>
SET REPROCESS TO 1
SYS(3051,100)
</pre><p>
When you attempt to lock a record that is already locked, you will know after 100 ms, more or less. Sufficient when all you want is to save a record, way to slow if you need to check 100 records to find an unlocked one. Even with this fast configuration, Visual FoxPro still performs two attempts to lock the record. One that fails right away putting VFP into a wait state. The second one occurs after the specified interval.
</p><p>
When I needed to process potentially more than 100 records recently, this approach was unusable. Therefore I searched my blog for a solution and came across the description of <a href="http://www.foxpert.com/knowlbits_200707_2.htm">how locking works</a> in Visual FoxPro.
</p><p>
Obviously, the problem in Visual FoxPro is not the attempt to lock the record, but the interval between the two attempts that you can't make shorter than 100 ms. Therefore my solution works on the API level to only make a single locking attempt. Either it fails, or doesn't. Calculating the locking position is fairly easy to do. It's 0x7FFFFFFE-Recno(). For the LockFile function you need a handle to the DBF file. Lacking an easy way of obtaining a file handle to a table opened by VFP, I opted for the API solution of opening the file a second time in shared mode. Having said this the code is really straight forward.
</p><pre>
*==========================================================
* Attempts to lock a record exactly once. If the record
* cannot be locked for whatever reason, .F. is returned.
* The record does not remain locked.
*
* There's no guarantee that a subsequent RLOCK() command
* works. It might fail even when isLocked() returns .T.
* when another machine locked the record in the meantime.
* It might had worked, if you tried to lock the record as
* the other machine released the lock already.
*
* This method is for code that needs to quickly scan a
* larger number of records to find a locked or unlocked
* one, for instance, when you need to clean certain
* records, or when you use locked records in a license
* tables to limit the number of instances.
*==========================================================
Procedure LockingPossible()

  *--------------------------------------------------------
  * If this instance has locked the record, we return
  * immediately.
  *--------------------------------------------------------
  If IsRLocked()
    Return .T.
  EndIf

  *--------------------------------------------------------
  * We can't check exclusively opened files. But then there
  * shouldn't be a problem obtaining a lock.
  *--------------------------------------------------------
  If IsExclusive()
    Return .T.
  EndIf

  *--------------------------------------------------------
  * API declarations
  *
  * source: http://www.news2news.com
  *--------------------------------------------------------
  DECLARE INTEGER LockFile IN kernel32;
      INTEGER hFile, INTEGER dwFileOffsetLow,;
      INTEGER dwFileOffsetHigh,;
      INTEGER nNumberOfBytesToLockLow,;
      INTEGER nNumberOfBytesToLockHigh
  DECLARE INTEGER OpenFile IN kernel32;
      STRING   lpFileName,;
      STRING @ lpReOpenBuff,;
      INTEGER  wStyle
  DECLARE INTEGER CloseHandle IN kernel32;
      INTEGER hObject

  *--------------------------------------------------------
  * Open the table a second time and attempt to lock the
  * record using low level access.
  *--------------------------------------------------------
  Local lcBuffer, lnFile, llLock
  #DEFINE GENERIC_READ 0x80000000
  llLock = .F.
  lcBuffer = Replicate(Chr(0), 250)
  lnFile = OpenFile(Dbf(), @lcBuffer, GENERIC_READ)
  If m.lnFile > 0
    If LockFile(m.lnFile, 0x7FFFFFFE-Recno(), 0, 1, 0) <> 0
      llLock = .T.
    EndIf
    CloseHandle(m.lnFile)
  EndIf

Return m.llLock
</pre>
</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Tue, 27 Oct 2009 10:22:56</pubDate>
</item>
<item>
<title><![CDATA[
Visual FoxPro crashes after installing hot fix or service pack 2
]]></title>
<link>http://www.foxpert.com/knowlbits_200909_1.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
"><p>
This is an error report that increasingly comes up lately. Visual FoxPro applications load two files when you run the EXE or instantiate a COM server: VFP9R.DLL and VFP9Rxxx.DLL. The first is the actual runtime library; the second file is a localized resource file. This file contains all localized strings such as menus, error messages, dialogs, names for months and week days, and so forth. There are multiple versions of this file. VFP9RENU.DLL is the English version, VFP9RDEU.DLL the German version, and so on. Which file Visual FoxPro loads depends:
<p></p>
If you have specified a particular version using the -L command line switch, this is the library that VFP loads.
<p></p>
Otherwise Visual FoxPro uses the regional settings of the operating system to load the correct runtime.
<p></p>
If the corresponding file cannot be found, Visual FoxPro always reverts to VFP9RENU.DLL, the English version.
<p></p>
These files are searched for in the current directory and the Windows path. That means, if you have one of these files in your System directory, Visual FoxPro might very well find and use this file. A crash happens when there's a version mismatch. The RTM version of VFP9R.DLL needs the RTM version of VFP9RENU.DLL, the SP1 version needs the SP1 version, and the SP2 version needs the corresponding SP2 file.
<p></p>
One scenario that causes a crash is having a SP1 VFP9Rxxx.DLL somewhere in the path and then installing the hotfix. If the resource file hasn't been replaced, too, Visual FoxPro will crash. This is more likely to happen outside English speaking countries, because SP1 and SP2 do contain localized versions, but the hot fix does not: There's only a VFP9RENU.DLL embedded into the MSM file. Before you can install the hotfix you should install SP2 to make sure that all runtime files are up-to-date.
<p></p>
If you or your clients experience crashes after installing the new version, search the entire hard disk to see if there are any older VFP9R*.DLL files around. Make sure to search hidden folders, as well.
<p></p>
In my tests the version difference between SP2 and the hotfix does not seem to inhibit the same behavior. That is, the hotfix version of VFP9R.DLL works with the VFP9RDEU.DLL version of service pack 2.
</p>
</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Tue, 15 Sep 2009 11:04:30</pubDate>
</item>
<item>
<title><![CDATA[Installing Windows 7 on VMware Server 2.0.1
]]></title>
<link>http://www.foxpert.com/knowlbits_200908_4.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
"><p>
VMware Server does not yet support Windows 7, but that doesn't mean you have to wait for a new release. When creating a new virtual machine, pick either Windows Vista 32 bit or Windows Vista 64 bit instead. Downloading the ISO file from MSDN Subscriber Download, placing this file in one of the data stores and mounting the image into the virtual CD drive is the easiest way to get the setup running.
</p><p>
Windows starts the installation right after powering on the virtual machine. The remaining steps are pretty self-explanatory. When you are prompted to enter a key, you can skip this step. It's easier to enter the key later in Windows 7 when you have access to the MSDN Key list and simply can copy and paste the key.
</p><p>
After Windows 7 started, the first change should be to disable the mouse pointer shadow in Start > Control Panel > Mouse.
</p><p>
The next step is usually to install VMware tools. At least with Windows 7 in the 64 bit version clicking on the link in VI Web Access to activate the VMware Tools image only results in an error message: The operating system is not supported. You can activate the image manually, though. On the server that hosts VMware Server open C:\Program Files (x86)\VMware\VMware Server and copy the Windows.iso file into your data store. Then use VI Web Access to mount this ISO image.
</p><p>
Inside Windows 7 open the CD drive and run Setup64.EXE. Following the steps and rebooting the system enables VMware tools with the known benefits such as having better mouse support.
</p>

</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Wed, 19 Aug 2009 12:00:42</pubDate>
</item>
<item>
<title><![CDATA[Object reference counters in VFP
]]></title>
<link>http://www.foxpert.com/knowlbits_200908_3.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
"><p>
Visual FoxPro maintains a reference counter for every object. Whenever a reference to an object is stored in a variable or property, the reference counter is incremented by one. When the same property or variable is filled with a different value, or when it goes of scope, Visual FoxPro decrements the counter by one. Visual FoxPro releases the object once the counter reaches zero.
</p><p>
The Visual FoxPro API provides two functions to manage this reference counter from C++ libraries: <a href=" http://msdn.microsoft.com/en-us/library/z1t8fxz0%28VS.80%29.aspx">_ObjectReference</a> and <a href=" http://msdn.microsoft.com/en-us/library/b67ybx6z%28VS.80%29.aspx">_ObjectRelease</a>. To make them available to Visual FoxPro developers, I wrote a small FoxPro library called <a href=" http://www.foxpert.com/download/OBJREF.FLL">ObjRef.FLL</a>.
</p><p>
The syntax is very simple. If you want to increment the object reference counter, you call the IncrementRef() function passing the object as the only parameter. The following sample creates a form and stores the reference in a local variable. Normally, the form would be released as soon as the code finishes. That is, you would see the form flash very briefly. With the call to IncrementRef you basically create a dangling reference to the form letting the form stay around even after the code returns:
</p><pre>
* Create a form with just a local reference
Local loForm
loForm = CreateObject("Form")
loForm.Show()

* Create artificial dangling reference
Set Library To ObjRef.FLL
IncrementRef(loForm)
</pre><p>
Similarly you can force an object to release by decrementing the reference counter. Even so the method hasn't finished yet, the form is gone:
</p><pre>
* Create a form
Local loForm
loForm = CreateObject("Form")
loForm.Show()

* Release form
Set Library To ObjRef.FLL
DecrementRef(m.loForm)
Wait window
</pre><p>
Playing around with object reference counters isn't something you should normally do. Visual FoxPro doesn't expect this and in some cases might respond erratically. When you, for instance, execute the following code and then type in the Command Window, Visual FoxPro either crashes or brings up error messages.
</p><pre>
Set Library To ObjRef.FLL
DecrementRef(_Screen)
</pre>
</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Fri, 14 Aug 2009 19:37:30</pubDate>
</item>
<item>
<title><![CDATA[
VMWare Server installation notes
]]></title>
<link>http://www.foxpert.com/knowlbits_200908_2.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
"><p>
After using VMWare for various purposes for many, many years now, I've moved my development environment to virtual machines two years ago. These are mostly Windows XP and Windows Vista clients with around 1 GB of RAM. I stored and executed them on my main development laptop. While using the laptop provided various advantages one disadvantage became more and more prevalent: Notebook hard drives simply can't deal very well with multiple requests at the same time.
</p><p>
Running a single virtual machine never really put too muchstress on my notebook. There was plenty of RAM (3.5 GB) and I didn't use the host OS that much when working in a virtual machine. Running two virtual machines maxed out available RAM, but was still manageable when. and that's a big when. only one of the two machines accessed the hard disk.
</p><p>
Suspending one machine, a virus scan, Windows swapping memory, Lookout indexing Outlook: Whenever the hard disks where spinning performance went downhill.
</p><p>
At the same time one advantage of using a notebook diminishes. Three years ago basically being able to take the office with me was a big plus. Since then connectivity has more and more become a commodity. Fast internet access (we used to call it high-speed internet not long ago) is available in more and more places. Fast mobile internet access such as UMTS has become downright cheep with unlimited data transfer for less than 50 Euros/Dollars a month.
</p><p>
Therefore I moved some of my development machines onto a new server and use a combination of VMWare Remote Client and Windows Remote Desktop to connect from the laptop to the server. The following are a few notes I took during the installation.
</p><p>
The mouse pointer can be a source of frustration if you move to a remote server. By default Windows displays a tiny shadow beneath the pointer.  There's no doubt that this increases the <i>discoverability experience</i> of the mouse pointer. It seems, though, that drawing a mouse pointer with a shadow is significantly different from drawing one without shadow.
</p><p>
If the mouse pointer jumps around and there is a delay between moving the mouse and updating the mouse pointer, pointer shadows are most likely activated. Go to Control Panel > Mouse > Pointers and uncheck the "Enable pointer shadow" option. Sometimes this isn't sufficient and additionally you need to change the scheme to "Windows Default (System scheme)".
</p><p>
Installing VMWare server automatically adds VMWare to the list of exception in the Windows Firewall. Windows 2008 and later support multiple profiles, one each for public, private and domain access. It seems that VMWare only enables the public profile. If you server is connected to a private network, you can't access VMWare  VI Web Access to configure the virtual machines.
</p><p>
To change this, open Server Manager.If Server Manager doesn't come automatically when you log onto the server, right click Computer in the Start menu and choose Manage.  Expand the node Configuration > Windows Firewall with Advanced Security > Inbound Rules. Locate the "VMWare Hostd" and "VMWare Authd" rules. Open the properties dialog for each rule and on the Advanced page check the "All profiles" checkbox, or pick profiles individually.
</p><p>
Choosing the right client is difficult. I switched back between VMWare Remote Client and Windows Terminal Services. In between these I even experimented with using VMWare Workstation instead of VMWare Server on the server. Each of these has advantages and disadvantages:
</p><p>
<b>VMWare Workstation</b>
</p><p>
On the pro side: The network can be connected and disconnected right from the client. It also much easier to boot Windows into safe mode since the virtual machine appears immediately with the BIOS screen. Of course, VMWare Workstation also has more features and better hardware support.
</p><p>
There is one disadvantages of using VMWare, though. You always have to use Remote Desktop to connect to the server before you can run VMWare Workstation. Unfortunately, you cannot have WMWare Workstation and VMWare Server installed on the same computer.
</p><p>
<b>VMWare Remote Client</b>
</p><p>
Remote Client has a quite simplified interface. You can control the power for the virtual machine (reset, stop and suspend). Additionally you can disconnect CD drives, floppy disks and the audio device.  USB devices connected to the client computer appear in a list, but the connect option is grayed out. The same applies to the Network symbol.
</p><p>
As my friend Peter Steinke pointed out to me, the easiest way to connect to a virtual machine with the Remote Client is by creating a desktop short cut to the virtual machine from within the web interface (it's the last option in the list of machine's action). There's no need to use the web interface every time you want to access a virtual machine.
</p><p>
The remote client has a few advantages. If you connect to a virtual machine that is powered off, it will automatically power on. That means you can minimize the number of machines that running on the server without having to use the web interface to start them manually.
</p><p>
The VMWare Remote Client also provides direct access to the CD drive on the client. If you want to burn a CD inside a virtual machine, you can use the CD writer on your client machine instead of having to put the CDs into the server CD drive. Nonetheless you need a good network connection, since otherwise you get errors when burning the CD.
</p><p>
The catch with this feature is that it only works when you launch the Remote Client as a local administrator on your client machine. If you have a desktop short cut, you can right click and pick the "Run as administrator" option. If you use the web interface to launch the Console, you have to run the browser as an administrator first. As a regular user you merely get the following error message when you attempt to connect the CD drive:
</p><p>
Failed to connect device to remote :<br>
Could not connect to "D:". It is being used by another virtual machine or some other program.
</p><p>
Whenever you change the windows size of the Remote Client, the screen size in the virtual machine is adjusted accordingly. So you never get scrollbars and always see everything on the screen.
</p><p>
Sound is a disadvantage for the Remote client. With VMWare Server you can only connect audio devices that physically exist. If the server doesn't have audio (and why should a real server have audio?), you won't be able to forward audio to the client machine.
</p><p>
Logging onto the client is more annoying that with the other two options because you have to enter the user name and password every single time. The user name and password are supposed to be configurable with the -u and -p command line arguments in the shortcut. But I never could get those to work. No matter what I entered for the user name (user, .\user, server\user, user@server, user@127.0.0.1, .\\user, server\\user, and a variety of combinations), I always ended up with the error message:
</p><p>
Error opening the remote virtual machine servername:5000\8: <br>
 Login failed due to a bad username or password.
</p><p>
<b>Remote Desktop</b>
</p><p>
Connecting to a virtual machine with the Remote Desktop client provides the closest experience to the native desktop experience. When the client and the guest operating system are both Windows Vista or Windows 7 and the client computer is Aero compatible, you even get the Aero interface on the remote virtual machine including glass effects and three dimensional task switching.
</p><p>
Microsoft's Remote Desktop is also the only possibility to get audio from the remote machine onto the local machine. The play back quality is way below what you have with local access from VMWare Workstation or natively, but at least there is audio. Recording isn't possible, though.
</p><p>
One drawback of Remote Desktop is that you can't connect or disconnect any of the hardware. VMWare Tools provide access to some of these features from within the virtual machine, but it's far from being as convenient as in VMWare Workstation or Remote Client. You also don't have access to the power options. To suspend the machine you need to access the web interface from the client. The same is true for machines that are powered off. You first have to power on through the web interface before you can connect to a virtual machine.
</p><p>
There's no way to boot into safe mode or make any BIOS changes through Remote Desktop. The virtual machine must be working and properly configured for Remote Desktop to work. For anything else you need VMWare's Remote Client and the web interface (when using VMWare Server) or the VMWare Workstation interface (when using Workstation on the server).
</p><p>
<b>Conclusion</b>
</p><p>
Right now it seems the best approach to use VMWare Remote Client and Remote Desktop together. Remote Client is used for maintenance tasks, everything that requires access to local devices and to start up the virtual machine if it's not running. Day-to-day jobs are done in Remote Desktop.
</p>
</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Thu, 6 Aug 2009 16:38:32</pubDate>
</item>
<item>
<title><![CDATA[
Changing the TCP ports for VMWare Server 2
]]></title>
<link>http://www.foxpert.com/knowlbits_200908_1.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
"><p>
<a href="http://www.vmware.com/products/server/">VMWare Server 2</a> has significant changes user interface-wise compared to the first version of the free VMWare Server product. The previous version (which itself is the successor of GSX server) provided access to the server and virtual machines through the VMWare Server Console. The Server Console could be replaced by Virtual Center 1.4, provided you had a license.
</p><p>
For the current release VMWare decided to replace these two tools with VMWare Infrastructure Web Access, the web client used in ESX server and VMWare Infrastructure 3.x. While the new interface offers additional features, it has received some bad critics due to its slowness and it's additional resource requirements on the server.  On my server this adds up to 128 MB RAM.
</p><p>
Web-based software needs a web server to run on. VI Web Access is written in Java and runs on top of Apache Tomcat. VI Web Access increases the product complexity by a magnitude compared to Server Console. This wasn't really an issue when VI Web Access was part of VMWare Infrastructure. This product is usually deployed by dedicated administrators.
</p><p>
VMWare Server 2, on the other hand, targets the average small business user and even non-business usage. The number of postings on the web shows that web based software can be very difficult to manage when you can't even connect to the web application.
</p><p>
During the installation VMWare Server 2 prompts for two TCP ports. Port 8222 is used for http traffic, port 8333 for https traffic. In many Windows applications you can change the port after the installation as a matter of typing a new value into the options dialog. If you hoped the same would be true for VMWare Server 2, you'll be disappointed.
</p><p>
A number of web sites suggest that the only way to change the port is to uninstall VMWare server, scrub the hard disk and clean the registry from any trace of the product. Then reinstall with the correct ports. There is an easier solution, though.
</p><p>
While you still can't change the port in a single place, you only need to change the ports in a few files. For the reminder I assume you are running Windows Server 2008. For other operating systems you need to change the paths accordingly. I assume that you want to change the ports to 5000 (from 8333) for https and 5001 (from 8222) for http transmissions.
</p><p>
The tools you need are a file explorer (Windows Explorer will work) and a text editor (Notepad would be sufficient). First open
</p><pre>
C:\Users\All Users\VMware\VMware Server\hostd\proxy.xml
</pre><p>
Change the ports in the bolded values. These are right at the beginning of the file:
</p><pre>
&lt;ConfigRoot&gt;
  &lt;httpPort&gt;<b>5001</b>&lt;/httpPort&gt;
  &lt;httpsPort&gt;<b>5000</b>&lt;/httpsPort&gt;
  &lt;EndpointList&gt;
</pre><p>
Next open
</p><pre>
C:\Program Files (x86)\VMware\VMware Server\tomcat\
webapps\ui\jslib-1.0.122589\modules\
com.vmware.webaccess.app_1.0.0\WebAccess.properties
</pre><p>
At the end of the file you find the following part. Change the port in the bolded line:
</p><pre>
new Object({
   login_url: "http://localhost:<b>5001</b>/sdk",
   login_show_webservice_url: "false",
   login_name: "",
   login_password: ""
});
</pre><p>
If you miss this file, you get to the login prompt, but entering a user name and password results in an error message. To update the link to the server page open
</p><pre>
C:\Program Files (x86)\VMware\VMware Server\serverui.url
</pre><p>
Change the file like this (there are just two lines in there):
</p><pre>
[InternetShortcut]
URL=https://MyServer:<b>5000</b>/ui/
</pre><p>
Finally, you need to update the location of the client plugin. Open
</p><pre>
C:\Program Files (x86)\VMware\VMware Server\hostd\
docroot\client\clients.xml
</pre><p>
Then change the port number in the following line
</p><pre>
&lt;downloadUrl&gt;https://*:<b>5000</b>/client/VMware-viclient.exe&lt;/downloadUrl&gt;
</pre><p>
Those are all changes you need to make. They won't take effect until you restart VMWare server, or more precisely, the services that make up VMWare Server.
</p><p>
In the Start menu right click Computer and pick the "Manage" option. Navigate to the Services node (Configuration > Services on Windows 2008). Sort the list by name and restart all services whose name start with "VMWare" to be on the safe side. Now you should be able to connect to the web interface by typing the following URL into your browser:
</p><p>
<a href="https://MyServer:5000"> https://MyServer:5000</a>
</p><p>
replace "MyServer" with the computer name or IP address of your VMWare Server host machine. If you access your virtual machines through Terminal Services, VNC, or other clients, you're done now. Use the web interface to configure, start, stop, and suspend virtual machines.
</p><p>
Should you rely on the VMWare Remote Console, though, you need to know that while 8333 and 8222 are the only ports that you can configure during the setup, they aren't the only ones that VMWare uses. The Remote Console uses by default port 902 to communicate with the server.
</p><p>
Initially the Remote Console connects to the server using the https port. After authenticating the web server provides the client with details on how to connect to the console. To change these connection information, open the following file on the server:
</p><pre>
C:\Users\All Users\VMware\VMware Server\config.ini
</pre><p>
The first line is a new one that you won't find in your file. In the INI files you can specify the port the server is listening on and the port that the client uses. Both can be different if there's a firewall that translates the port:
</p><pre>
<b>authd.port = "5002"</b>
authd.client.port = "<b>5002</b>"
</pre><p>
I personally prefer the remote console to use a port adjacent to the Tomcat ports. I can then open up the firewall with a single port range rule instead of using multiple rules. The fewer rules the better usually.
</p><p>
Before the new settings take effect, you have to restart the "VMWare Authorization Service", or VMAuthdService for short.
</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Thu, 6 Aug 2009 14:31:26</pubDate>
</item>
<item>
<title><![CDATA[
Have a date, or two, but never half
]]></title>
<link>http://www.foxpert.com/knowlbits_200907_2.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
"><p>
Date is one of those data types that is very unique to FoxPro, or at least, not that common in other programming languages. Most other languages have some sort of datetime data type that combines a date with the time during that day.
</p><p>
FoxPro isn't that much different from other languages, as even FoxPro simulates the date data type. Internally, everything is just a datetime value. This can cause a bit of confusion with date operations. Consider the following code snippet:
</p><pre>
ld1 = DATE()
ld2 = DATE()+0.25
? ld1
? ld2
? ld1 = ld2
</pre><p>
If you look at the screen output, both date values seem to be equal. Yet, the equals to operator returns .F. ld2 has an invisible time portion of "06:00" which you would only see when you cast the date into a datetime value:
</p><pre>
? Dtot(m.ld2)
</pre><p>
To make this more confusing: When you store ld2 in a date field and read it back, the time portion is lost and suddenly ld2 equals ld1. Of course, you won't write code that adds 0.25 to a date value intentionally. In real code this bug creeps up in a more evil way. Consider you are calculating the end date of a process. This might involve fractions if the duration is something like 3 days at 80% capacity. So you might end up with:
</p><pre>
? Date()+0.9999999
</pre><p>
which still prints the current day. If you store this value in a table, your process finishes one day early. A similar problem is adding fractions repeatedly, because you need the end date of a process that consists of multiple steps with a finite but fractional duration.
</p><p>
If you perform date operations by adding values, make sure you use ROUND(nValue,0) for any numeric value. Or convert the date into a datetime variable.
</p>
</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Tue, 14 Jul 2009 07:21:10</pubDate>
</item>
<item>
<title><![CDATA[
Fatal error 0x8000FFFF when using a COM server
]]></title>
<link>http://www.foxpert.com/knowlbits_200907_1.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
"><p>
Our application needs to talk to quite a few other applications. Recently I replaced the existing DDE based interface with a COM based one. The vendor of the other application provides a COM server that controls their application and passes data back and forth. My first attempt in Visual FoxPro looked like this
</p><pre>
loClient = CREATEOBJECT("Acme.Client")
loClient.acmeConnect("App")
</pre><p>
The first line creates an instance of the COM server and works just fine. The second line, however, crashes with a COM exception 0x8000FFFF. As a VFP developer I don't take it for granted that COM objects just work. So I tried the same component in other environments. First in VB Script:
</p><pre>
Set o = CreateObject("Acme.Client")
msgbox o.acmeConnect("App")
</pre><p>
Same error here. But who uses VB Script, anyway? Next in C#:
</p><pre>
var x = new Acme3Client.Client();
var n = x.acmeConnect("App");
</pre><p>
Surprisingly, I got the same error. The control ships with a sample application written in C++ in which the COM server works. Unfortunately, the sample application is just a compiled EXE. So, next I tried this in C++ with ATL:
</p><pre>
int _tmain(int argc, _TCHAR* argv[])
{
  CoInitialize(NULL);
  using namespace Acme3Client;
  IClientPtr px("Acme.Client");
  px->acmeConnect("App");
  return 0;
}
</pre><p>
I wasn't willing to see yet another 0x8000FFFF exception, but my computer didn't ask me. As a last attempt I tried to use the COM server in an MFC application:
</p><pre>
CAcmeClient *p = new CAcmeClient();
p->acmeConnect(CString("App"));
</pre><p>
Finally, I got a different error message. MFC fired an assertion because a window handle was NULL. This lead to the solution: Contrary to what the documentation states, this COM server can only be used by adding it as an ActiveX control to the form. A better error message would have pointed me in the right direction much earlier.
</p>
</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Tue, 7 Jul 2009 13:46:22</pubDate>
</item>
<item>
<title><![CDATA[Unit tests to validate COM interfaces
]]></title>
<link>http://www.foxpert.com/knowlbits_200906_2.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
"><p>
Creating a COM server in VFP is easy, maybe too easy. Check the OLEPUBLIC checkbox or add the OLEPUBLIC keyword to the class definition and you are done. Building a DLL creates a COM server that you can pass to anyone who needs to interface with your application. Using a COM server in VFP is similar uneventful. Instantiate the COM server using the ProgId and call methods on the object, that's it.
</p><p>
The ease of creating a COM server comes at a high price. We VFP developer tend to not think about how our COM server is consumed. Unlike Visual FoxPro, which due too its use of late binding is very forgiving when consuming COM servers, this isn't true for most other environments, especially .NET.
</p><p>
A COM interface consists of a list of method pointers. Each method is accessed by its index number. When .NET imports a COM server, it internally creates a mapping which forwards any call of a named method to the corresponding index in the interface. As long as the interface doesn't change, life is good. Have an updated version of the COM server? Just copy it over the existing DLL or EXE.
</p><p>
Any interface change, however, requires a lot of work for the .NET developer. The COM server needs to be imported again. The InterOp library must be generated anew. Depending on how the COM server is used by the application, the entire application might need to be recompiled. The old COM server has to be unregistered; the new one to be distributed and registered.
</p><p>
That's quite a bit of work, but manageable if you tell your clients about the modified interface. Unfortunately VFP makes it way too easy to introduce interface changes accidentally.
</p><p>
How does VFP generate the interface for a COM server?
</p><p>
For every COM class, VFP loops through all public properties and methods and assigns id values. The first method or property in the PRG file is id 0, the second PEM becomes id 1, and so forth. In other words, the physical order determines the id value. This index is the same one that early binding languages use to call methods and access properties.
</p><p>
It's probably obvious now that there're at least two ways to alter the COM interface in a way which wouldn't have any impact on Visual FoxPro, at all: If you rearrange methods in your source code, the index numbers change. Secondly, any new property or method that you don't mark protected or hidden, is added to the interface, as well.
</p><p>
At least for me the second one is a major source for headache. Visual FoxPro uses an object based approach to protected members where almost any other OOP language uses a class based approach. This renders protected PEMs in Visual FoxPro basically useless, which is why I often don't bother making procedures protected. I do even less so with properties as protected properties in Visual FoxPro make it hard to debug code properly and therefore affect code quality negatively. But that's food for another controversy discussion..
</p><p>
After refactoring code and accidentally changing the interface, I took a defensive approach to make sure this won't happen again. I added a unit test similar to the following one for every COM class in my project. It doesn't detect changes to the order of PEMs, but it's sufficient to make sure I'm aware of interface changes to the COM server:
</p><pre>
Procedure Test_CheckInterface

  Local loBO
  loBO = CreateObject("MyCOM.Server")
  This.AssertTrue( "Error loading MyCOM.Server", ;
    Vartype(m.loBO)=="O" )

  Local laPem[1]
  This.AssertEquals( "Wrong number of PEMs", 4, ;
    AMembers(laPem, m.loBO, 3) )
  This.AssertEquals( "#1", "Method1", laPem[1,1] )
  This.AssertEquals( "#2", "Method2", laPem[2,1] )
  This.AssertEquals( "#3", "PEM1", laPem[3,1] )
  This.AssertEquals( "#4", "PEM1", laPem[4,1] )

EndProc
</pre><p>
For every method there's one item in the array created by AMembers. Properties have two entries, one for the getter, and one for the setter. Since I added this unit tests, I made the same mistake several times. But I always spotted the problem before I even prepared the distribution set.
</p>
</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Tue, 30 Jun 2009 12:40:16</pubDate>
</item>
<item>
<title><![CDATA[Get rid of security warnings
]]></title>
<link>http://www.foxpert.com/knowlbits_200906_1.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
"><p>
When you download a file with Internet Explorer, the file is tagged as being downloaded from the internet. This has impact on a number of file types. When the file is an EXE and you execute it, you (or more specifically, your users) get a warning:
</p><p>
<b>The publisher could not be verified. Are you sure you want to run this software?</b>
</p><p>
If the file is a CHM help file, the content is never shown. Instead you only see a "Navigation cancelled" error page. For archives the tag is often mysteriously inherited when you extract files. In other words, while this warning might be helpful to prevent malicious code to execute, the system causes a lot of unnecessary support effort for smaller application makers.
</p><p>
Technically, the tag is just an NTFS stream named "Zone.Identifier". This file is actually an INI file specifying the network zone from which the file originates:
</p><pre>
[ZoneTransfer]
ZoneId=3
</pre><p>
Since NTFS streams are only supported on NTFS drives, copying the file to a FAT32 formatted USB stick and pack to the disk effectively removes the security tag. This is neither an obvious, nor a very understandable solution. To an average user this approach sounds much like the famous "if your car stops working get our and back in to fix it" approach.
</p><p>
It would be better to handle this within the application. Providing you have write access to the files, the following program removes the security warnings for all files that match the pattern you pass to it:
</p><pre>
*============================================================
* Removes the security warning for all files in a directory
* that match the pattern
*============================================================
LParameter tcPattern

  Local laDir[1], lnFile
  Declare Long DeleteFile in Win32Api String
  For lnFile=1 to ADir(laDir,m.tcPattern)
    DeleteFile( ;
      Addbs(FullPath(JustPath(m.tcPattern)))+;
      laDir[m.lnFile,1]+":Zone.Identifier" ;
  )
  EndFor
</pre><p>
To fix your updated EXE and CHM files, you would use:
</p><pre>
RemSecurityWarning("*.CHM")
RemSecurityWarning("*.EXE")
</pre><p>
You can specify a directory if the current directory is not the right choice.
</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Thu, 6 Aug 2009 23:22:06</pubDate>
</item>
<item>
<title><![CDATA[RecordSource - bang.boom.gone
]]></title>
<link>http://www.foxpert.com/knowlbits_200905_1.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
"><p>
In Visual FoxPro every object belongs to a particular data session. Under normal circumstances this is the data session in which the object is created. The exception are objects that have an intrinsic data session, namely Form, FormSet, Toolbar, and Session. Instantiating these objects may create a new data session in which these objects are then built.
</p><p>
As objects must belong to only one data session, changing the data session inside a form method moves the entire form into the new data session. In my session "The Dark Side of Visual FoxPro" I explained that expressions are evaluated in the context of whatever data session is the current one. Expressions like ControlSources, and so forth might be evaluated at any time. This makes changing the data session risky, but not necessarily unfeasible.
</p><p>
The grid is unfortunately slightly more pro-active. Whenever the record source cursor disappears even for the fraction of a nanosecond, the grid responds immediately. Closing a cursor is an obvious way to hide a cursor. Creating a new cursor in the same work area isn't as obvious, but still understandable. In both cases the grid responds by removing all columns and the RecordSource. On the visual front the grid turns into a white rectangle with a thin black border.
</p><p>
Changing the data session isn't all that obvious. Nonetheless, moving the form - and along the grid - into a different data session constitutes a change in visibility of the cursor. Consequently, the grid updates itself and blanks out the RecordSources property and all ControlSources.
</p><p>
Contrary to closing the cursor in the current data session the column objects remain, only the binding information is gone. As a result the grid looks much like before. Except that there's no record shown. The only visible clue is that the deleted mark column on the left side of the grid is black for all records instead of cleared as it was before.
</p><p>
If this happens to you in a grid where you don't always expect data to be shown this can be a bug that is hard to discover and hard to nail down.  On a screen shot of your application, watch out for the deleted mark column.
</p>
</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Tue, 19 May 2009 09:43:48</pubDate>
</item>
<item>
<title><![CDATA[ON SAVE DAYLIGHT RECOMPILE
]]></title>
<link>http://www.foxpert.com/knowlbits_200904_1.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
"><p>
This year I lost another hour of my life. I suffered the switch to daylight saving time twice: The first time early March in Seattle in the USA, the second time the past weekend in Germany. Windows has come a long way to adjust to these changes automatically, other devices I own aren't as smart, unfortunately. But that's a different story.
</p><p>
So this week is the week of the great recompile! If you build your project for the first time this week, you might notice that Visual FoxPro recompiles most files even if you haven't checked the "Recompile all" checkbox and haven't touched them in years. Participation in the great recompile depends on your storage location, though.
</p><p>
On NTFS, the standard file format for Windows these days, all file time stamps are stored in UTC time. UTC means Universal Time Coordinates and is a modern way of saying Greenwich Mean Time. That is, if people save their files all around the world within the same 100 nanoseconds, the time stamp for these files is identical. The time zone doesn't have any impact at all on the value that is stored.
</p><p>
Applications that determine time stamps usually do not work on the raw UTC time structure. Instead they rely on an operating system function to convert the UTC time stamp with its wierd format into a regular time structure based on the local system time. During your day to day work this behavior is what you expect.
</p><p>
Strange things happen, though, when you change the timezone offset, either by changing the timezone or by switching to or from daylight saving time. If you create a file at 9:00AM in January and look at it's creation time in April you'll see that it has been created at 10:00AM. The time that's 9:00 in the winter is 10:00 in the summer (spring forward, fall back).
</p><p>
The time stamp always reflects the absolute time, not the local time when you created a file. This allows Windows to precisely determine the time elapsed since the last modificiation. It also puts all files into creation order, even if you are a frequent traveller that changes time zones every day.
</p><p>
How does this relate to Visual FoxPro, after all?
</p><p>
Visual FoxPro optimizes the compile process and, by default, only compiles files that have been changed. A form or a class libary need to be recompiled when either the file itself has been edited, or when an associated included file has changed. The latter forces Visual FoxPro to keep track of when the include file has last changed.
</p><p>
While a sensible approach would have been to recompile whenever the include file is newer than the form or the class library, this is not the approach that FoxPro takes. Microsoft decided to use a more fail-proof way and includes the time stamp of all dependent header files in the VCX in a binary format. As you can guess this time is stored in the local time format.
</p><p>
So, twice a year the timezone offset changes and the include file suddenly has a different last modified date. Visual FoxPro, recognizing that the form isn't en par with the include file, decides to recompile the form.
</p><p>
Now you know why daylight saving time wastes hours of recompile time in Visual FoxPro projects all around the world... twice a year.
</p>
</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Tue, 7 Apr 2009 22:58:32</pubDate>
</item>
<item>
<title><![CDATA[
Detecting idle users
]]></title>
<link>http://www.foxpert.com/knowlbits_200903_1.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
">
<p>
<b>Updated 2009-04Apr-10</b>
</p><p>
Many thanks to John L Veazey, Simon White, and Geof Shugar for pointing out that my original code turns the mouse pointer into an hour glass most of the time, and for mentioning some unneeded code lines. The updated version should not show this behaviour, at all. John also provided a different approach that I'll post shortly.
</p><p>
It's not too uncommon in business application development to face the requirement to log out users automatically after a period of time. Preventing access to the application by unauthorized users is frequently quoted as a reason for such a feature. This purpose, however, should better be handled on the corporate level. A policy that locks a computer after a certain period of time is more secure, more reliable and better way to prevent access.
</p><p>
Nonetheless, some users let applications run all night long. This is often facilitated by company policies that require the user to keep the computer running as backup and maintenance tasks are carried out during the night.
</p><p>
While an application that is connected to SQL server has little impact on SQL server's ability for maintenance issues, the same does not hold true for Visual FoxPro. Reindexing, packing, backing up, all requires exclusive access to the files.
</p><p>
Detecting activity used to be a tedious development issue. In most scenarios activity equals to moving the mouse and pressing keys. Up to VFP 8.0 the only solution was to insert code into the KeyPress and the MouseMove event of every single base class. Especially the KeyPress event does react differently when there's code in the event. Consequently, adding this feature at a later stage required a lot of testing. When third-party libraries or ActiveX controls had been used, this was even more difficult as they required special coding.
</p><p>
Visual FoxPro 9.0 introduced a great feature: BINDEVENT can bind to API messages. There are two ways to bind to messages. You can specify a single window and only receive messages that go to that specific window, or you can specify 0 as the window handle and automatically receive message for every FoxPro window.
</p><p>
The following program implements a timer that keeps track of the user activities. When the user has been idle for a specified number of minutes, the eventTimeout event is triggered. Here you can respond by logging the user out, shutting the application, or just giving a warning and increasing the timeout:
</p><pre>
*============================================================
* Detects user activity and fires an event after the
* specified period of inactivity.
*============================================================
Define Class InactivityTimer as Timer

  *----------------------------------------------------------
  * API constants
  *----------------------------------------------------------
  #define WM_KEYUP                        0x0101
  #define WM_SYSKEYUP                     0x0105
  #define WM_MOUSEMOVE                    0x0200
  #define GWL_WNDPROC         (-4)

  *----------------------------------------------------------
  * internal properties
  *----------------------------------------------------------
  nTimeOutInMinutes = 0
  tLastActivity = {/:}
  nOldProc = 0

  *----------------------------------------------------------
  * Timer configuration
  *----------------------------------------------------------
  Interval = 30000
  Enabled = .T.

*------------------------------------------------------------
* Listen to API events when the form starts. You can pass
* the timeout as a parameter.
*------------------------------------------------------------
Procedure Init(tnTimeOutInMinutes)
    DECLARE integer GetWindowLong IN WIN32API ;
      integer hWnd, ;
      integer nIndex
    DECLARE integer CallWindowProc IN WIN32API ;
      integer lpPrevWndFunc, ;
      integer hWnd,integer Msg,;
      integer wParam,;
      integer lParam
    THIS.nOldProc=GetWindowLong(_VFP.HWnd,GWL_WNDPROC)
  If Vartype(m.tnTimeOutInMinutes) == "N"
    This.nTimeOutInMinutes = m.tnTimeOutInMinutes
  EndIf
  This.tLastActivity = Datetime()
  BindEvent(0,WM_KEYUP,This,"WndProc")
  BindEvent(0,WM_MOUSEMOVE,This,"WndProc")
EndProc

*------------------------------------------------------------
* Stop listening
*------------------------------------------------------------
Procedure Unload
  UnBindEvents(0,WM_KEYUP)
  UnBindEvents(0,WM_MOUSEMOVE)
EndProc

*------------------------------------------------------------
* Every event counts as activity
*------------------------------------------------------------
Procedure WndProc( ;
  hWnd as Long,Msg as Long,wParam as Long,lParam as Long )
  This.tLastActivity = Datetime()
_screen.Caption = Str(Val(_Screen.Caption)+1)
Return CallWindowProc(this.noldproc,hWnd,msg,wParam,lParam)

*------------------------------------------------------------
* Check last activity against time out
*------------------------------------------------------------
Procedure Timer
  Local ltFireEvent
  ltFireEvent = This.tLastActivity + 60*This.nTimeOutInMinutes
  If Datetime() > m.ltFireEvent
    This.eventTimeout()
  EndIf
EndProc

*------------------------------------------------------------
* Override this event or bind to it to respond to user
* inactivity. You can change the nTimeOutInMinutes to offer
* multiple stages of timeouts.
*------------------------------------------------------------
Procedure eventTimeout

EndDefine
</pre><p>
To use the timer you can either create a sub class or bind to the eventTimeout using BINDEVENTS(). In any case, the instance must be available while the application is running, whether that's as a global variable, as a property in an application object, or by any other mean. For trying this class you can run the following sample code
</p><pre>
Public goForm
goForm = CreateObject("InactivityDemo")

Define Class InactivityDemo as InactivityTimer
  Procedure Init
    DoDefault(1)
  Procedure eventTimeout
    MessageBox("Timeout!")
EndDefine
</pre><p>
If you run this code and then stop working in Visual FoxPro for between one and one and a half minutes, you get a message box every 30 seconds until you stop the demo with CLEAR ALL.
</p><p>
There are a few situations where the inactivity timer is not updated. Long running statements like SELECT or COPY TO commands don't trigger any event handler. Moving the mouse only in the header area isn't captured by VFP. I also suspect that activity inside an ActiveX control is not reliable detected, either.
</p>
</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Sat, 11 Apr 2009 08:25:30</pubDate>
</item>
<item>
<title><![CDATA[
How empty is an empty RecordSource?
]]></title>
<link>http://www.foxpert.com/knowlbits_200808_1.htm</link>
<description><![CDATA[<DIV class="fp-text" style="font-family:Verdana,Arial,Helvetica,sans-serif;
">
<p>
Can a record source be empty? Is empty the same as empty? Are all empty record sources equal, or are some more equal than others? Does a grid suffer it doesn't have a record source? Questions over questions...
</p><p>
...and not easy ones, for sure. The grid distinguishes <i>empty</i> as in having the default value and <i>empty</i> as in specifying an empty string as the record source value.
</p><p>
The second one means just that. The record source is unknown, empty, unspecified, unavailable. Not knowing what do the grid just stares blank at you, literally.
</p><p>
The first one, leaving the grid at the blank default value, though gives the grid the opportunity to show you how smart it is. It figures, you either forgot to specify a record source, or it's so blatantly obvious what record source you want the grid to use. Hence, it uses the cursor in the current work area by default.
</p><p>
If that's what you want, that's fine. However, if you create an index on the record source, specify filter, and assume you can use code like this
</p><pre>
IF NOT EMPTY(This.RecordSource)
  SET FILTER TO something IN (This.RecordSource)
ENDIF
</pre><p>
you are as mistaken as I am every once in a while when I stumble over this behaviour in Visual FoxPro. If you want an empty record source, use ="" for the property value in the form, otherwise specify a valid alias. But don't leave the property simply at its default value.
</p>
</DIV><STYLE>.fp-text
{
	font-size: 11pt;
	text-align: justify;
	line-height: 15pt;
	width: 600px;
	margin-left: auto;
	margin-right: auto;
	text-indent: 10px;
}

.fp-text pre
{
	border: 1px dashed black;
	padding: 6px;
	background-color: Beige;
	font-family:monospace;
	margin-left: 10px;
	margin-right: 10px;
	text-indent: 0px;
	line-height: 100%;
}

.fp-text,.fp-sidebar p
{
	margin-top: 6pt;
	margin-bottom: 6pt;
}

.fp-sidebar
{
	width: 200px;
	vertical-align: top;
	font-size: 11pt;
}

.fp-sidebar #search
{
	margin-top: 30px;
}


.fp-text h1
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
	padding: 0px;
	margin: 0px;
}

.fp-text span
{
	font-size: 9px;
	float: right;
	padding: 0px;
	margin: 0px;
	font-weight: normal;
	font-style: italic;
}

.fp-divider
{
	height: 32px;
}

.fp-text h2
{
	text-indent: 0px;
	font-size: 11pt;
	font-weight: bold;
}

</STYLE>]]></description>
<author>Christof Wollenhaupt</author>
<pubDate>Mon, 25 Aug 2008 11:13:44</pubDate>
</item>

 </channel>
</rss>
