General discussion

Locked

The SPS Weblog

By craig ·
Tags: Off Topic
blog root

This conversation is currently closed to new comments.

94 total posts (Page 2 of 10)   Prev   01 | 02 | 03 | 04 | 05   Next
| Thread display: Collapse - | Expand +

All Comments

Collapse -

ATOM and VFP

by craig In reply to The SPS Weblog

<p>
I wanted to do RSS 2.0 first given that it has the most momentum at the moment, but
that's hardly the only accepted syndication format. Here's the formats and the players
involved (consider it the abridged, highlights-only history of syndication by
yours truly)....
</p>
<ul>
<li>
RSS 0.9 : Netscape/Dan Libby (considered obsolete and too complex by most - <a href="http://www.w3.org/RDF/">RDF</a> specification
based - Netscape dropped out of the game about the time the simplified version 0.**
was proposed, big mistake - RSS stands for “<em>RDF Site Summary</em>&rdquo<br>
</li>
<li>
RSS 0.** : Netscape/Dan Libby (never got off the ground - it is argued
by some that this didn't even constitute a version... but it's documented, but it
is analogous to Visual FoxPro version 4... you hear about people who have the beta,
but never really seen it.)<br>
</li>
<li>
RSS 0.** : <a href="http://rss.userland.com/">UserLand Software</a>/Dave Winer (officially
obsoleted by RSS 2.0 - UserLand picks up the ball and runs with it - RSS stands for
“<em>Rich Site Summary“</em&gt<br>
</li>
<li>
RSS 0.92 : UserLand Software (officially obsoleted by RSS 2.0)<br>
</li>
<li>
RSS 0.93 : UserLand Software (officially obsoleted by RSS 2.0)<br>
</li>
<li>
RSS 0.94 : UserLand Software (officially obsoleted by RSS 2.0)<br>
</li>
<li>
RSS 1.0 : <a href="http://groups.yahoo.com/group/rss-dev/">RSS-DEV Working Group</a> (Active
- not from 0.94 as you may think, it is actually considered a branch from 0.90 and
RDF specification based - not affiliated with UserLand Software - RSS stands for “<em>RDF
Site Summary</em>&ldquo<br>
</li>
<li>
RSS 2.0 : UserLand Software (Active - next generation taking over where 0.94 left
off - RSS stands for “<em>Really Simple Syndication</em>&ldquo<br>
</li>
<li>
<a href="http://www.atomenabled.org/">ATOM</a> 0.1-1.0 IETF Atom Publishing Format
and Protocol (atompub) Working Group. (Active - entirely seperate from all previous
efforts, IETF didn't come into the picture until ATOM 0.3, has a very good chance
of becoming the internet standard for syndication. Note: UserLand/Dave Winer offered
to merge with ATOM in 2004, ATOM has so far declined the offer. Work on the specification
is on-going and affectionately referred to as the <a href="http://www.intertwingly.net/wiki/pie/FrontPage">ATOM
Project</a&gt</li>
</ul>
<p>
My blog offers RSS 2.0 and ATOM 0.2 syndication, so here's the code to grab ATOM into
Visual FoxPro tables via a schema and the XMLAdapter (I need to dig into the ATOM
1.0 specification before I can do a more thorough job, but this is a good start)...
</p>
<p>
<table cellspacing=5 cellpadding=5 width="90%" align=center border=1>
<tbody>
<tr>
<td>
<p>
<font face="Courier New" size=2>LOCAL loXMLAdapter, loBrowser, lcXSD, lcATOMContent,
lcXMLHeader, lcXMLFooter</font>
</p>
<p>
<font face="Courier New" size=2>lcXMLHeader = GetHeader()<br>
lcXSD = VFPATOMSchema()
<br>
*!* Atom .02 feed, need to dig into 1.0 specification </font><a href="font">http://ietfreport.isoc.org/idref/draft-ietf-atompub-format/"><font face="Courier New" size=2>http://ietfreport.isoc.org/idref/draft-ietf-atompub-format/</font></a>
<br>
<font face="Courier New" size=2>lcATOMContent = RetrieveATOM("</font><a href="/SPSBlog/SyndicationServiceExperimental.asmx/GetAtom"><font face="Courier New" size=2>http://www.sweetpotatosoftware.com/SPSBlog/SyndicationServiceExperimental.asmx/GetAtom</font></a><font face="Courier New" size=2>")<br>
lcXMLFooter = GetFooter()</font>
</p>
<p>
<font face="Courier New" size=2>oXMLAdapter = NEWOBJECT('XMLAdapter')</font>
</p>
<p>
<font face="Courier New" size=2>oXMLAdapter.LOADXML(lcXMLHeader + lcXSD+ lcATOMContent
+ lcXMLFooter)</font>
</p>
<p>
<font face="Courier New" size=2>CLOSE DATABASES ALL<br>
oXMLAdapter.TABLES(1).TOCURSOR && Generator<br>
oXMLAdapter.TABLES(2).TOCURSOR && Author<br>
oXMLAdapter.TABLES(3).ToCursor && Entry<br>
oXMLAdapter.TABLES(4).ToCursor && Feed<br>
SET</font>
</p>
<p>
<font face="Courier New" size=2>*****************************<br>
FUNCTION GetHeader()<br>
*****************************<br>
 LOCAL lcHeader<br>
 TEXT TO lcHeader NOSHOW<br>
<?xml version="1.0" encoding="utf-8" ?><br>
<VFPDataSet><br>
 ENDTEXT<br>
 RETURN lcHeader<br>
ENDFUNC</font>
</p>
<p>
<font face="Courier New" size=2>*****************************<br>
FUNCTION GetFooter()<br>
*****************************<br>
 LOCAL lcFooter<br>
 TEXT TO lcFooter NOSHOW<br>
</VFPDataSet><br>
 ENDTEXT<br>
 RETURN lcFooter<br>
ENDFUNC</font>
</p>
<p>
<font face="Courier New" size=2>*****************************<br>
FUNCTION VFPATOMSchema()<br>
*****************************<br>
 LOCAL lcXML<br>
*!* Use bare minimum abbreviated notation to show all that is necessary<br>
TEXT TO lcXML NOSHOW<br>
<xsd:schema xmlns:tns="</font><a href="font">http://purl.org/atom/ns"><font face="Courier New" size=2>http://purl.org/atom/ns</font></a><font face="Courier New" size=2>#"
attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="</font><a href="font">http://purl.org/atom/ns"><font face="Courier New" size=2>http://purl.org/atom/ns</font></a><font face="Courier New" size=2>#"
xmlns:xsd="</font><a href="font">http://www.w3.org/2001/XMLSchema"><font face="Courier New" size=2>http://www.w3.org/2001/XMLSchema</font></a><font face="Courier New" size=2>"><br>
  <xsd:import namespace="</font><a href="font">http://www.w3.org/XML/1998/namespace"><font face="Courier New" size=2>http://www.w3.org/XML/1998/namespace</font></a><font face="Courier New" size=2>"
/><br>
  <xsd:element name="feed"><br>
    <xsd:complexType><br>
      <xsd:sequence><br>
        <xsd:element name="title" type="xsd:string"
/><br>
        <xsd:element name="link" type="xsd:string"
/><br>
        <xsd:element name="modified" type="xsd:dateTime"
/><br>
        <xsd:element name="tagline" type="xsd:string"
/><br>
        <xsd:element name="generator"><br>
          <xsd:complexType><br>
            <xsd:simpleContent><br>
              <xsd:extension
base="xsd:string"><br>
               
<xsd:attribute name="name" type="xsd:string" use="required" /><br>
              </xsd:extension><br>
            </xsd:simpleContent><br>
          </xsd:complexType><br>
        </xsd:element><br>
        <xsd:element name="author"><br>
          <xsd:complexType><br>
            <xsd:sequence><br>
              <xsd:element
name="name" type="xsd:string" /><br>
            </xsd:sequence><br>
          </xsd:complexType><br>
        </xsd:element><br>
        <xsd:element maxOccurs="unbounded" name="entry"><br>
          <xsd:complexType><br>
            <xsd:sequence><br>
              <xsd:element
name="title" type="xsd:string" /><br>
              <xsd:element
name="link" type="xsd:string" /><br>
              <xsd:element
name="id" type="xsd:string" /><br>
              <xsd:element
name="issued" type="xsd:dateTime" /><br>
              <xsd:element
name="modified" type="xsd:dateTime" /><br>
              <xsd:element
name="created" type="xsd:dateTime" /><br>
              <xsd:element
name="content" type="xsd:string" /><br>
            </xsd:sequence><br>
          </xsd:complexType><br>
        </xsd:element><br>
      </xsd:sequence><br>
      <xsd:attribute name="version" type="xsd:decimal"
use="required" /><br>
    </xsd:complexType><br>
  </xsd:element><br>
</xsd:schema><br>
ENDTEXT<br>
 RETURN lcXML<br>
ENDFUNC</font>
</p>
<p>
<font face="Courier New" size=2>*****************************<br>
FUNCTION RetrieveATOM(tcURL)<br>
*****************************<br>
 #DEFINE INTERNET_OPEN_TYPE_PRECONFIG 0<br>
 #DEFINE SYNCHRONOUS 0<br>
 #DEFINE INTERNET_FLAG_RELOAD 2147483648</font>
</p>
<p>
<font face="Courier New" size=2> DECLARE INTEGER InternetOpen IN WININET STRING
Agent, ;<br>
  INTEGER AccessType, STRING ProxyName, ;<br>
  STRING ProxyBypass, INTEGER Flags</font>
</p>
<p>
<font face="Courier New" size=2> DECLARE INTEGER InternetOpenUrl IN WININET ;<br>
  INTEGER hInternetSession, STRING Url, STRING Header, ;<br>
  INTEGER HeaderLength, INTEGER Flags, INTEGER Context</font>
</p>
<p>
<font face="Courier New" size=2> DECLARE INTEGER InternetReadFile IN WININET
INTEGER file, ;<br>
  STRING @Buffer, INTEGER NumberOfBytesToRead, INTEGER @BytesRead</font>
</p>
<p>
<font face="Courier New" size=2> DECLARE SHORT InternetCloseHandle IN WININET
INTEGER hInst</font>
</p>
<p>
<font face="Courier New" size=2> LOCAL lcAgent, lhInternetSession, lhFile, llOK,
lnReturn, lcReadBuffer, lnBytesRead, lcRetVal</font>
</p>
<p>
<font face="Courier New" size=2> lcAgent = "VFP ATOM 0.2 Reader"<br>
 lhInternetSession = InternetOpen(lcAgent, INTERNET_OPEN_TYPE_PRECONFIG, "",
"", SYNCHRONOUS)</font>
</p>
<p>
<font face="Courier New" size=2> IF lhInternetSession = 0<br>
  ? "Problem Encountered: Internet session cannot be established"<br>
 ELSE<br>
  lhFile = InternetOpenUrl( lhInternetSession, tcURL, '', 0, INTERNET_FLAG_RELOAD,
0)<br>
  IF lhFile = 0<br>
   ? "Problem Encountered: URL cannot be opened"<br>
  ELSE<br>
   lcRetVal = ""<br>
   llOK = .T.<br>
   <br>
   DO WHILE llOK<br>
    lcReadBuffer = SPACE(1500)<br>
    lnBytesRead = 0<br>
    lnReturn = InternetReadFile(lhFile, @lcReadBuffer, LEN(lcReadBuffer),
@lnBytesRead)<br>
    IF (lnBytesRead > 0)<br>
     lcRetVal = lcRetVal + LEFT(lcReadBuffer, lnBytesRead)<br>
    ENDIF<br>
    llOK = (lnReturn = 1 AND lnBytesRead > 0)<br>
   ENDDO<br>
   <br>
   InternetCloseHandle(lhFile)<br>
   InternetCloseHandle(lhInternetSession)<br>
   lcRetVal = SUBSTR(lcRetVal, ATC("<feed", lcRetVal))<br>
   <br>
   RETURN LEFT(lcRetVal, ATC("</feed>", lcRetVal) + 9)<br>
  ENDIF<br>
 ENDIF<br>
 RETURN ""<br>
ENDFUNC</font>
</p>
</td>
</tr>
</tbody>
</table>
</p>
<br>
<hr>
This weblog is sponsored by <a href="http://www.sweetpotatosoftware.com">SweetPotato
Software, Inc.</a><p><div class="blogdisclaim"><a href="http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,92040996-d3bd-414c-a798-c99ddee86d3c.aspx">This post originally appeared on an external website</a></div>

Collapse -

RSS 2.0 and VFP (revisited)

by craig In reply to The SPS Weblog

<p>
OK, I've tried a number of different ways to get around handling additional elements
that aren't in the RSS 2.0 specification (such as trackback:ping, wfw:rssComments,
slash:comments, etc. - basically anything using QName).  First, I started with
the way you are supposed to do it, referencing and importing namespaces, creating
seperate xsd schemas and the using the ref attribute... that didn't work. So
then I started hacking the document by adding the namespace to the elements of the
XML on the fly, that didn't work either.
</p>
<p>
I've created a paired down version of my earlier schema (for testing purposes) that
will grab the RSS 2.0 feed from the SPS Blog, but the hack is atrocious (look at the
UndeclaredNamespace procedure). No matter what I try, I can't get MSXML4 and the XMLAdapter
to behave and bring in those elements (with their content) without the hack.
Anyone got any ideas, or better yet, solutions? I hope I'm missing something
here and that it isn't a problem with MSXML4 with no workaround.
</p>
<p>
<table cellspacing=5 cellpadding=5 width="90%" align=center border=1>
<tbody>
<tr>
<td>
<p>
<font face="Courier New" size=2>LOCAL loXMLAdapter, loBrowser, lcXSD, lcRSSContent,
lcXMLHeader, lcXMLFooter</font>
</p>
<p>
<font face="Courier New" size=2>lcXMLHeader = GetHeader()<br>
lcXSD = VFPRSS2Schema()<br>
lcRSSContent = RetrieveRSS("</font><a href="/SPSBlog/SyndicationService.asmx/GetRss"><font face="Courier New" size=2>http://www.sweetpotatosoftware.com/SPSBlog/SyndicationService.asmx/GetRss</font></a><font face="Courier New" size=2>")<br>
UndeclaredNamespace(@lcRSSContent)<br>
lcXMLFooter = GetFooter()</font>
</p>
<p>
<font face="Courier New" size=2>oXMLAdapter = NEWOBJECT('XMLAdapter')</font>
</p>
<p>
<font face="Courier New" size=2>oXMLAdapter.LOADXML(lcXMLHeader + lcXSD+ lcRSSContent
+ lcXMLFooter)</font>
</p>
<p>
<font face="Courier New" size=2>CLOSE DATABASES ALL<br>
oXMLAdapter.TABLES(1).TOCURSOR && Item<br>
oXMLAdapter.TABLES(2).TOCURSOR && Channel<br>
oXMLAdapter.TABLES(3).TOCURSOR && Rss<br>
SET</font>
</p>
<p>
<font face="Courier New" size=2>*****************************<br>
FUNCTION GetHeader()<br>
*****************************<br>
 LOCAL lcHeader<br>
 TEXT TO lcHeader NOSHOW<br>
<?xml version="1.0" encoding="utf-8" ?><br>
<VFPDataSet><br>
 ENDTEXT<br>
 RETURN lcHeader<br>
ENDFUNC</font>
</p>
<p>
<font face="Courier New" size=2>*****************************<br>
FUNCTION GetFooter()<br>
*****************************<br>
 LOCAL lcFooter<br>
 TEXT TO lcFooter NOSHOW<br>
</VFPDataSet><br>
 ENDTEXT<br>
 RETURN lcFooter<br>
ENDFUNC</font>
</p>
<p>
<font face="Courier New" size=2>*****************************<br>
PROCEDURE UndeclaredNamespace(tcRSSContent)<br>
*****************************<br>
   *!* Workaround for MSXML4 - This needs to be worked on still, I can't
seem to get these elements even if<br>
   *!* I split up the schemas and use imports and ref in element tag<br>
   *!* However, this workaround at least ensures that it doesn't **** up
with "Undeclared Namespace Prefix" error<br>
   *!* while still retrieving the contents. I hate hacks like this, especially
in this case because these elements aren't
<br>
   *!* part of the specification, but are on many blogs including mine.<br>
   *!* Anyone got a better fix or know how to do this right?<br>
   tcRSSContent = STRTRAN(tcRSSContent, "trackback:ping", [trackbackping],
-1, -1, 1)<br>
   tcRSSContent = STRTRAN(tcRSSContent, "pingback:server", [pingbackserver],
-1, -1, 1)<br>
   tcRSSContent = STRTRAN(tcRSSContent, "pingback:target", [pingbacktarget],
-1, -1, 1)<br>
   tcRSSContent = STRTRAN(tcRSSContent, "wfw:commentRSS", [wfwcommentRss],
-1, -1, 1)<br>
   tcRSSContent = STRTRAN(tcRSSContent, "wfw:comment", [wfwcomment], -1,
-1, 1)<br>
   tcRSSContent = STRTRAN(tcRSSContent, "slash:comment>", [slashcomments],
-1, -1, 1)<br>
ENDPROC</font>
</p>
<p>
<font face="Courier New" size=2>*****************************<br>
FUNCTION VFPRSS2Schema()<br>
*****************************<br>
 LOCAL lcXML<br>
 TEXT TO lcXML NOSHOW<br>
<xsd:schema xmlns:xsd="</font><a href="font">http://www.w3.org/2001/XMLSchema"><font face="Courier New" size=2>http://www.w3.org/2001/XMLSchema</font></a><font face="Courier New" size=2>"<br>
   xmlns:xsi="</font><a href="font">http://www.w3.org/2001/XMLSchema-instance"><font face="Courier New" size=2>http://www.w3.org/2001/XMLSchema-instance</font></a><font face="Courier New" size=2>"
<br>
   xmlns:trackback="</font><a href="font">http://madskills.com/public/xml/rss/module/trackback/"><font face="Courier New" size=2>http://madskills.com/public/xml/rss/module/trackback/</font></a><font face="Courier New" size=2>"<br>
   xmlns:wfw="</font><a href="font">http://wellformedweb.org/CommentAPI/"><font face="Courier New" size=2>http://wellformedweb.org/CommentAPI/</font></a><font face="Courier New" size=2>"<br>
   xmlns:slash="</font><a href="font">http://purl.org/rss/1.0/modules/slash/"><font face="Courier New" size=2>http://purl.org/rss/1.0/modules/slash/</font></a><font face="Courier New" size=2>"<br>
   xmlns:pingback="</font><a href="font">http://madskills.com/public/xml/rss/module/pingback/"><font face="Courier New" size=2>http://madskills.com/public/xml/rss/module/pingback/</font></a><font face="Courier New" size=2>"<br>
  attributeFormDefault="qualified" elementFormDefault="qualified" br>
  <xsd:element name="rss"><br>
    <xsd:complexType><br>
      <xsd:sequence><br>
        <xsd:element name="channel"><br>
          <xsd:complexType><br>
            <xsd:sequence><br>
              <xsd:element
name="title" type="xsd:string" /><br>
              <xsd:element
name="link" type="xsd:string" /><br>
              <xsd:element
name="description" type="xsd:string" /><br>
              <xsd:element
name="copyright" type="xsd:string" /><br>
              <xsd:element
name="lastBuildDate" type="xsd:string" /><br>
              <xsd:element
name="generator" type="xsd:string" /><br>
              <xsd:element
name="managingEditor" type="xsd:string" /><br>
              <xsd:element
name="webMaster" type="xsd:string" /><br>
              <xsd:element
name="item"><br>
               
<xsd:complexType><br>
                 
<xsd:sequence><br>
                    
<xsd:element name="trackbackping" type="xsd:string" maxOccurs="unbounded" /><br>
                    
<xsd:element name="pingserver" type="xsd:string" /><br>
                   
<xsd:element name="pingtarget" type="xsd:string" /><br>
                   
<xsd:element name="wfwcomment" type="xsd:string" /><br>
                   
<xsd:element name="wfwcommentRss" type="xsd:string" /><br>
                   
<xsd:element name="slashcomments" type="xsd:string" /><br>
                   
<xsd:element name="title" type="xsd:string" /><br>
                   
<xsd:element name="guid" type="xsd:string" /><br>
                   
<xsd:element name="link" type="xsd:string" /><br>
                   
<xsd:element name="pubDate" type="xsd:string" /><br>
                   
<xsd:element name="description" type="xsd:string" /><br>
                   
<xsd:element name="comments" type="xsd:string" /><br>
                   
<xsd:element name="category" type="xsd:string" /><br>
                 
</xsd:sequence><br>
               
</xsd:complexType><br>
              </xsd:element><br>
            </xsd:sequence><br>
          </xsd:complexType><br>
        </xsd:element><br>
      </xsd:sequence><br>
      <xsd:attribute name="version" type="xsd:decimal"
use="required" /><br>
    </xsd:complexType><br>
  </xsd:element><br>
</xsd:schema><br>
ENDTEXT<br>
 RETURN lcXML<br>
ENDFUNC</font>
</p>
<p>
<font face="Courier New" size=2>*****************************<br>
FUNCTION RetrieveRSS(tcURL)<br>
*****************************<br>
 #DEFINE INTERNET_OPEN_TYPE_PRECONFIG 0<br>
 #DEFINE SYNCHRONOUS 0<br>
 #DEFINE INTERNET_FLAG_RELOAD 2147483648</font>
</p>
<p>
<font face="Courier New" size=2> DECLARE INTEGER InternetOpen IN WININET STRING
Agent, ;<br>
  INTEGER AccessType, STRING ProxyName, ;<br>
  STRING ProxyBypass, INTEGER Flags</font>
</p>
<p>
<font face="Courier New" size=2> DECLARE INTEGER InternetOpenUrl IN WININET ;<br>
  INTEGER hInternetSession, STRING Url, STRING Header, ;<br>
  INTEGER HeaderLength, INTEGER Flags, INTEGER Context</font>
</p>
<p>
<font face="Courier New" size=2> DECLARE INTEGER InternetReadFile IN WININET
INTEGER file, ;<br>
  STRING @Buffer, INTEGER NumberOfBytesToRead, INTEGER @BytesRead</font>
</p>
<p>
<font face="Courier New" size=2> DECLARE SHORT InternetCloseHandle IN WININET
INTEGER hInst</font>
</p>
<p>
<font face="Courier New" size=2> LOCAL lcAgent, lhInternetSession, lhFile, llOK,
lnReturn, lcReadBuffer, lnBytesRead, lcRetVal</font>
</p>
<p>
<font face="Courier New" size=2> lcAgent = "VFP RSS 2.0 Reader"<br>
 lhInternetSession = InternetOpen(lcAgent, INTERNET_OPEN_TYPE_PRECONFIG, "",
"", SYNCHRONOUS)</font>
</p>
<p>
<font face="Courier New" size=2> IF lhInternetSession = 0<br>
  ? "Problem Encountered: Internet session cannot be established"<br>
 ELSE<br>
  lhFile = InternetOpenUrl( lhInternetSession, tcURL, '', 0, INTERNET_FLAG_RELOAD,
0)<br>
  IF lhFile = 0<br>
   ? "Problem Encountered: URL cannot be opened"<br>
  ELSE<br>
   lcRetVal = ""<br>
   llOK = .T.<br>
   <br>
   DO WHILE llOK<br>
    lcReadBuffer = SPACE(1500)<br>
    lnBytesRead = 0<br>
    lnReturn = InternetReadFile(lhFile, @lcReadBuffer, LEN(lcReadBuffer),
@lnBytesRead)<br>
    IF (lnBytesRead > 0)<br>
     lcRetVal = lcRetVal + LEFT(lcReadBuffer, lnBytesRead)<br>
    ENDIF<br>
    llOK = (lnReturn = 1 AND lnBytesRead > 0)<br>
   ENDDO<br>
   <br>
   InternetCloseHandle(lhFile)<br>
   InternetCloseHandle(lhInternetSession)<br>
   lcRetVal = SUBSTR(lcRetVal, ATC("<rss", lcRetVal))<br>
   <br>
   RETURN LEFT(lcRetVal, ATC("</rss>", lcRetVal) + 9)<br>
  ENDIF<br>
 ENDIF<br>
 RETURN ""<br>
ENDFUNC</font>
</p>
</td>
</tr>
</tbody>
</table>
</p>
<br>
<hr>
This weblog is sponsored by <a href="http://www.sweetpotatosoftware.com">SweetPotato
Software, Inc.</a><p><div class="blogdisclaim"><a href="http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,9ef75db5-f3ec-4ab4-b43b-8134ef0af070.aspx">This post originally appeared on an external website</a></div>

Collapse -

Visual FoxPro Community Action

by craig In reply to The SPS Weblog

<p>
<strong>A Call to Action<br>
</strong>While bemoaning its state, speculating as to an uncertain future or
even impending doom, whining about the lack of product marketing from Microsoft, tearing
down the IDE, and focusing, to the point of exhaustion, on the deficiencies
in the product known as Visual FoxPro might improve a developer's mental health for
the moment (letting off steam can be a good thing), it does little to address the
problems at hand. I am infinitely surprised at the tendency of otherwise solution
oriented, brilliant individuals to waste their time on a myriad of ineffectual
methods when it comes to pushing Visual FoxPro forward and beyond. I am equally surprised to
see so much in-depth problem analysis result in little more than “so much in-depth
problem analysis“.
</p>
<p>
<strong>To Be Clear<br>
</strong>Now, just so we're clear... I'm not saying that there isn't a basis for some
of the fears or complaints surrounding/leveled against Visual FoxPro. Neither
am I saying that one should not voice their disapproval when real-world problems exist
and criticism is warranted. My contention is merely that, once the problems have been
suitably identified, one could/should do more than throw words at them. This is especially
true when it comes to Visual FoxPro.
</p>
<p>
<strong>What Can Be Done<br>
</strong>These problems beg the question, “What can be done?”. Not long
after the question is spoken, the defeatists throw their hands up in the air and answer,
“Nothing!”. This answer is usually followed by some identification
of the parties directly responsible for the developer's inability to do anything;
more often than not, Microsoft is included in the list. However, the reaction to this
question is quite different in the minds of scores of other Visual FoxPro developers.
Visions begin to whirl around in the ether, slowly solidifying into concrete ideas
of what could/should be. This mindset, coupled with an enterprising, can-do spirit,
is directly responsible for more than a few of the solutions to problems past, and
it is my firm contention that the future of Visual FoxPro has a lot more to do with
the Visual FoxPro Community's action, or lack thereof, than anything the folks in
Redmond may be up to. So, here is my list of solutions, that are either being done
or could be done.
</p>
<p>
<strong>Marketing:<br>
</strong>Harness all the energy that is currently going into pointing out the deficiencies
in this area (for the 1 millionth time), and direct it into more weblogs and websites
with good Visual FoxPro related content. If you don't have a weblog, but have
some insights, code, or Visual FoxPro related solutions you'd like to share...
get one. Start blogging about the advantages of Visual FoxPro and solutions created
with it. There are countless places on the internet to sign-up for, and start, your
very own weblog for free. Here are a few resources:<br>
<a href="http://weblogs.foxite.com/">http://weblogs.foxite.com/</a><a href="/a>">http://weblogs.foxite.com/ericdendoop/archive/2005/03/18/151.aspx"></a>
<br>
<a href="http://www.blogger.com/start">http://www.blogger.com/start</a>
<br>
<a href="http://www.myblogsite.com/index.shtml">http://www.myblogsite.com/index.shtml</a>
</p>
<p>
If you already have a webserver and would like to create your own blog, then give <a href="http://wiki.shahine.com/default.aspx/DasBlog/Home%20Page.html">dasBlog</a> or <a href="http://www.gotdotnet.com/Workspaces/Workspace.aspx?id=e99fccb3-1a8c-42b5-90ee-348f6b77c407">.Text </a>a
look. This blog runs on the dasBlog engine, and many of the blogs listed in my Blogroll
are using .Text. (Blogroll is over there ----&gt
</p>
<p>
Also, there are some really good forums/boards on the internet that you should consider
becoming an active member of. These forums/boards spread the good word and help countless
Visual FoxPro developers across the globe. One of the best kinds of marketing for
a product is support, and the Visual FoxPro Community supports its product like no
other. Here are a few forums I recommend:<br>
<a href="http://www.universalthread.com">www.universalthread.com</a>
<br>
<a href="http://www.tek-tips.com">www.tek-tips.com</a>
<br>
<a href="http://fox.wikis.com">http://fox.wikis.com</a>
<br>
<a href="http://www.foxite.com">www.foxite.com</a>
<br>
<a href="http://forums.microsoft.com/msdn/ShowForum.aspx?ForumID=60">http://forums.microsoft.com/msdn/ShowForum.aspx?ForumID=60</a>
<br>
<a href="http://community.compuserve.com/n/pfx/forum.aspx?webtag=ws-msdevapps">http://community.compuserve.com/n/pfx/forum.aspx?webtag=ws-msdevapps</a>
</p>
<p>
Have you created a great Visual FoxPro 9 application? Then write a case study on it,
and have it included on the Microsoft site for all to see. There have been <a href="http://blogs.msdn.com/klevy/archive/2005/05/19/420005.aspx">repeated
calls for Visual FoxPro case studies</a> by Ken Levy and other members of the Visual
FoxPro Community. I had the pleasure of editing one recently, and it was
a rewarding experience.<br>
<br>
If you're a decent writer, then crank out some articles for the industry rags
(such as <a href="http://www.pinpub.com/ME2/Audiences/Default.asp">FoxTalk 2.0</a> and <a href="http://foxproadvisor.com/">FoxPro
Advisor</a&gt or write a book.<br>
<br>
The action of creating, supporting, and ultimately cultivating Visual FoxPro internet
resources has a direct impact on the visibility of Visual FoxPro and its perceived
value. Unfortunately, the same cannot be said for the countless campaigns and posts
cajoling or criticizing Microsoft.
</p>
<p>
<strong>Language Improvements:<br>
</strong>Submit ideas to one of the many Visual FoxPro wish lists that are certainly
seen by the MS Fox Team. Here is one such list: <a href="http://fox.wikis.com/wc.dll?Wiki~VFPVersion10WishList">http://fox.wikis.com/wc.dll?Wiki~VFPVersion10WishList</a>.<br>
<br>
If you have a penchant for C/C++, then create an FLL containing the new functions
and thrust it into the Public Domain for use by Visual FoxPro developers everywhere.
If you don't have any ideas on what might make a good FLL function for Visual Foxpro,
check the wish lists.<br>
<br>
If all else fails, then create ingenious Visual FoxPro functions and procedures in
Visual FoxPro that can be reused by developers in their applications. All of these
actions have had and will continue to have a direct, positive impact on Visual FoxPro.
</p>
<p>
<strong>Integrated Design Environment Improvements:</strong>
<br>
Create Visual FoxPro components that increase developer production and otherwise add
value to the Visual FoxPro IDE. There is an immense amount of untapped potential in
this area. More than a few of the components we use every day in Visual FoxPro are
the result of hardworking Visual FoxPro developers that lived and breathed this solution.
For a few examples see the following: <a href="http://fox.wikis.com/wc.dll?Wiki~VFPComponentAuthors">http://fox.wikis.com/wc.dll?Wiki~VFPComponentAuthors</a>.<br>
<br>
On a personal note, after having read about Craig Berntson's idea for a <a href="http://www.craigberntson.com/archives/2005_06_15_archive.asp#111886889776829310">Solution
Manager</a>, I've been giving this idea a lot of thought. I think something like
the Solution Explorer in VS would serve Visual FoxPro developers well. Envision, for
starters, the ability to access multiple projects with heirarchical drill-downs
for programs/forms/classes, and having multiple design windows and program
files open in seperate tabs, and the ability to expand/collapse function and procedure
calls while editing them.<br>
<br>
However, I digress. The point is, that the action of creating Visual FoxPro components
for Visual FoxPro has a direct impact on the IDE and increases Visual FoxPro's overall
usefulness.
</p>
<p>
<strong>Improved Interop, Integration and Extensibility<br>
</strong>The MS Fox Team announced that <a href="http://msdn.microsoft.com/vfoxpro/roadmap/">Sedna</a> will
be highly focused on this area. But, this is no reason to rest on our laurels
until 2007. Toss around ideas and make suggestions for Sedna on the <a href="http://www.universalthread.com">Universal
Thread</a> in the Sedna category. The Microsoft Fox Team has committed to monitoring
that category and if only a couple great ideas from there get implemented, it
will have been well worth it.
</p>
<p>
Create code and solutions that developers can use with .NET, Microsoft products such
as Office, and even ways in which Visual FoxPro can consume and publish XML. These
are all really big areas of interest to programmers the world over, and showing that
Visual FoxPro is an excellent choice for these types of solutions is an action that
will reap untold benefits for the product as a whole. Visual FoxPro is more than capable,
and this is a huge, virtually untapped area.<br>
<br>
This action results in Visual FoxPro being seen and used as a development environment
for solutions well outside the box. An increase in features and abilities garnered
from outside sources is always a good thing. What is Visual FoxPro good for? A lot
more than one might expect.
</p>
<p>
<strong>Improve Visual FoxPro Applications<br>
</strong>Visual FoxPro is given a black-eye daily by poorly thought out and implemented
solutions, applications that look like they are from the early 1990's, and convoluted
code that performs sub-standard. If you're going to develop in Visual FoxPro, then
do the language proud. Learn how to code and develop applications in an efficient
and professional manner, avail yourself of the improvements in each successive version
of Visual Foxpro, and take advantage of proven development/coding methodologies. While
you're at it, you might try a little spit and polish on those user interfaces.<br>
<br>
If you're still having a hard time adjusting from the world of FP to the world of
VFP, or if you've recently come over from another language, then buy a few books and
make heavy use of the aforementioned online resources related to Visual FoxPro. Remember,
the @Say is dead and there's no excuse for creating yet another dated looking
switch-board application running on spaghetti code that accesses a horribly denormalized
database.<br>
<br>
This action not only does Visual Foxpro a favor, but your customers as well.
</p>
<p>
<strong>Purchase or Upgrade to Visual FoxPro 9<br>
</strong>A no brainer. Unless you are strictly prohibited due to finances or job restrictions,
you need to upgrade to Visual FoxPro 9 as soon as feasibly possible. There's no greater
argument you can make to Microsoft for continued Visual FoxPro support than a few
of your hard earned dollars spent on this worthwhile product. Sign a petition, post
as many pleas to, or disparaging remarks about, Microsoft as you want, but in
the end, only this action ensures that Microsoft will extend the Visual FoxPro Roadmap
come 2007.
</p>
<p>
<strong>Anything Else that Actually Makes a Difference<br>
</strong>Here's where I admit that I don't have all the answers, but I know someone,
somewhere does. If you've got an idea that could improve Visual FoxPro, then you owe
it to yourself, the product, and the Visual FoxPro Community to take your best shot.
If the bulk of the Visual FoxPro Community members can move towards a state of Action
instead of the FUD (Fear, Uncertainty, and Doubt) Reaction, Visual FoxPro and
the developers that rely on it (not to mention the customers that depend on it) will
prosper. As a community, we can do more in 1 year than Microsoft could do in 10 to
improve the state of our beloved product. That's my two cents anyways.<br>
</p>
<p>
UPDATE: 07-27-2005 Fixed grammatical errors and improved some sentence structure
that was bothering me
</p>
<br>
<hr>
This weblog is sponsored by <a href="http://www.sweetpotatosoftware.com">SweetPotato
Software, Inc.</a><p><div class="blogdisclaim"><a href="http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,45bf2281-88a7-4d42-a75d-8fe7e87ae734.aspx">This post originally appeared on an external website</a></div>

Collapse -

Craig Bailey and VFP Solution Explorer

by craig In reply to The SPS Weblog

<p>
If you're like me and didn't have a clue that something called the “VFP Solution
Explorer” was being worked on, check out <a href="http://craigbailey.blogspot.com/2005/07/vfp-solution-explorer.html">Craig
Bailey's most recent blog entry</a>. I downloaded the <a href="http://www.svfpug.com.au/assets/2005Jul/SolutionExplorer/Solution%20Explorer%20Project.ppt">presentation</a>,
and I can't say enough good things about what I saw and read. If the “VFP Solution
Explorer” and it's lofty goals are carried out in a timely fashion, then I suspect
that a great many of us could be ditching Visual FoxPro's project manager in the not
too distant future.
</p>
<p>
This is exactly the kind of project that I was speaking of in <a href="/SPSBlog/PermaLink,guid,45bf2281-88a7-4d42-a75d-8fe7e87ae734.aspx">my
last post</a>. I hope that Scott Scovell and Craig Bailey make the release sooner
rather than later, because I suspect there are plenty of experienced Visual FoxPro
developers, I can think of at least one right now, that would be willing to contribute
to this worthwhile goal/project.
</p>
<p>
To Scott Scovell and Craig Bailey, I say, “Keep up the good work and be sure
to give me another heads up when you've released the beta. I'll take an alpha if you
decide to reconsider.”
</p>
<br>
<hr>
This weblog is sponsored by <a href="http://www.sweetpotatosoftware.com">SweetPotato
Software, Inc.</a><p><div class="blogdisclaim"><a href="http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,ccd9c592-0273-420a-af7e-0b43a0a6bf05.aspx">This post originally appeared on an external website</a></div>

Collapse -

Spelling Checker and VFP

by craig In reply to The SPS Weblog

<p>
Checking the spelling in a given string, such as the text in a control, is something
that a lot of Visual FoxPro applications can use. There are many ways to accomplish
this.  Some Visual FoxPro developers use Microsoft Word similar to the way I
did in <a href="http://www.tek-tips.com/faqs.cfm?fid=4258">my FAQ about it</a>. Others
shell out between $250-500 in order to purchase a third-party tool or control that
will get the job done. And some, just do without.
</p>
<p>
<strong>Making a Contribution<br>
</strong>Well, a couple days ago I was looking for a way to put <a href="/SPSBlog/PermaLink,guid,45bf2281-88a7-4d42-a75d-8fe7e87ae734.aspx">my
recent blog</a> about the Visual FoxPro Community into action at this end, and I decided
to try my hand at creating a class with the ability to easily add spelling checks
to Visual FoxPro applications. Here are some of the important steps I took, followed
by a screen capture of spelling checker I created in Visual FoxPro and a
couple of links, so you can download a copy of the project (all source code included),
some runnable examples, and even an alternate dictionary table.
</p>
<p>
<strong>Step 1:<br>
</strong>Find a way to recognize a misspelling. Obviously I needed a dictionary. Luckily
there are plenty of open source dictionaries out there, and I soon I had compiled
a dictionary table of 144,238 words. The words came from <a href="http://wordlist.sourceforge.net">Kevin
Atkinson's Spell Checking Oriented Word Lists</a> (SCOWL). I took English and American
words up to level 70. Level 80 and 95 words are mostly obscure (scrabble players only),
removed possessive words and duplicates, and gave it a few final tweaks. 140,000+
words is a nice size dictionary for any spelling checker.
</p>
<p>
<strong>Step 2:<br>
</strong>Give the user some choices of possible matches. Here again I was lucky in
that I've worked on a number of sounds-like algorithms for Visual FoxPro in the past
(including: <a href="http://fox.wikis.com/wc.dll?Wiki~ImproveSoundex">Improved Soundex</a>, <a href="http://fox.wikis.com/wc.dll?Wiki~MetaphoneImplementation-SoundexAlternative">Metaphone</a>,
and <a href="http://fox.wikis.com/wc.dll?Wiki~DoubleMetaphone-SoundexAlternative">Double
Metaphone</a&gt. In this case, because I was dealing with English words the Improved
Soundex was all that was needed, and it is the fastest of the alternatives so that
was a Win-Win. However, this only handled misspellings that sound like the actual
spelling, if I ran into “thwrw” because the user's finger had slipped
to the “w” instead of the “e”, the Improved Soundex algorithm
wasn't going to do me much good.
</p>
<p>
Well, it just so happened that I had run into a posting of a class method for
computing the <a href="http://fox.wikis.com/wc.dll?Wiki~LevenshteinAlgorithm">Levenshtein
Distance in Visual FoxPro</a> and I had rewritten it (see the bottom of the page I
linked). The <a href="http://en.wikipedia.org/wiki/Levenshtein_distance">Levenshtein
Distance</a> is an excellent indicator of how closely matched two words are even though
they don't sound the same.<br>
<br>
<strong>Step 3:<br>
</strong>With the first two hurdles overcome, it was time to figure out what kind
of design I would go for. I decided on doing the entire thing with classes and in
such a way that new user interfaces could be created and hooked up. Now, bear in mind
that this is just my first stab at it and less than two days have gone by, but I think
you'll see some things you like if you care enough to dig into it.
</p>
<p>
Before I go any further let me say that I have not put the error handling into it
yet. That will go in next. I find with projects of this size (and when there is a
high potential for me to be changing my mind while coding) that it is easiest to put
the error handling in once the design has stabilized. So please, no flames about the
lack of any error handling... it's on the way. Or, better yet, since it will be a
couple of days before I can get back to this, how about you throw in some really nice
Try...Catch...Finally commands in it and shoot it back to me? LOL.<br>
<br>
The guts of the spelling checker is in the spellcheck class in spellcheck.vcx and
my first stab at an interface is the splchkdialog class in spellcheck.vcx.  Other
than that the class library just holds a bunch of subclasses of the Visual FoxPro
base classes. I want to encapsulate the logic even further, so interfaces are a complete
snap to create and the spellcheck class is a black box engine (but it's still pretty
decent as it sits now).<br>
<br>
<strong>Step 4:</strong>
<br>
Return a list of suggestions for the user to pick from as replacements for a given
misspelling really fast. I had to figure out a way to tweak the returned suggestion
list that would handle the size of the dictionary table. I decided on an SQL
select statement because of its flexibility and speed when optimized. Then I defined
the criteria for the SQL where clause. I also ordered the elements in the Where
clause so that the criteria that would weed out the most entries came first and the
most resource intensive operations (such as the Levenshtein Distance) would come last.
</p>
<p>
This still wasn't fast enough, so I created another field in the dictionary table
to hold the Improved Soundex codes for the words and indexed it. And created an index
on the LEN(ALLTRIM()) of the word as well. This dramatically improved the speed and
after a few more tweaks I had a workable SQL for returning the results. See the getsuggestions
method of the spellcheck class.
</p>
<p>
<strong>Step 5:</strong>
<br>
Logically order the results returned to the user. Alphabetical returns are anything
but logical when returning suggestions for a spellchecker. I decided to add a weight
field to the suggestions curosr and base it on different aspects of the
matches between the word in question and the words in the dictionary table. In
this case, I went with lower weights meaning better the matches. The weight made
an excellent field to base the Order by clause on as well. The top 10 results
were finally being returned in a logical order. To see the way the weight is figured,
look in the figureweight method of the spellcheck class.<br>
<br>
<strong>Step 6:<br>
</strong>Test, tweak, test fix... drink more coffee and Red Bull energy drink... Test,
tweak, test, fix. And finally, create two examples, write a README.txt, zip it all
up, take a couple screen shots, and write this blog. The download link is provided
below (look on the right-hand side), full source included, don't forget to read the
README.txt.<br>
<br>
<strong>Visual FoxPro Spelling Checker<br>
<table cellspacing=0 cellpadding=0 width="100%" border=1>
<tbody>
<tr>
<td>
<img height=687 src="/SPSBlog/content/binary/screenshot.gif" width=363 border=0></td>
<td>
<p>
<font size=2> <a href="/files/spellcheck.zip">Download VFP Spelling Checker</a> </font><font size=1>(2MB
approx.)</font>
</p>
</td>
</tr>
</tbody>
</table>
</strong>
</p>
UPDATES: 07-31-2005 Created a new dictionary table based on the SCOWL so that copyright
and redistribution rights were sure (removed previous two dictionaries). Optimized
some code, fixed a couple of bugs, worked in the new dictionary and edited this blog
entry to apply to the new dictionary table.<br>
<hr>
This weblog is sponsored by <a href="http://www.sweetpotatosoftware.com">SweetPotato
Software, Inc.</a><p><div class="blogdisclaim"><a href="http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,8800bdb9-a9c2-484f-942f-6a08947d903a.aspx">This post originally appeared on an external website</a></div>

Collapse -

New Visual FoxPro Information Available

by craig In reply to The SPS Weblog

<p>
A couple of recent blog entries, a letter from the Editor concerning Visual FoxPro,
and a fairly hard-hitting interview... is today Christmas?
</p>
<p>
First, I owe thanks to <a href="http://www.bloglines.com/blog/AlexFeldstein?id=470">Alex
Feldstein's Blog</a> for a heads up that Ken Levy's <a href="http://msdn.microsoft.com/vfoxpro/letters/">August
2005 - Letter from the Editor</a> for Visual FoxPro has been published.
</p>
<p>
Then reading a <a href="http://talkingfox.blogspot.com/2005/08/sedna-and-future-of-visual-foxpro.html">recent
blog entry by David Stevenson</a>, I found that he had done a an <a href="http://foxcentral.net/microsoft/VFPDevCon2005_Interview_AlanGriver_KenLevy.htm">interview
with Microsoft's Alan Griver and Ken Levy</a>. Nicely done Dave, and thanks for making
it available to the Visual FoxPro Community.
</p>
<p>
It's on days like today that I marvel at the way blogs have changed the way in which
I receive information. The quantity, quality, and timeliness of that information can't
be beat. If you haven't done so yet, you owe it to yourself to get a decent news aggregator
(there are plenty of free ones available - I use and recommend <a href="http://www.synop.com/Products/SauceReader/">Sauce
Reader</a&gt. Then, if you are as interested in Visual FoxPro related content
as I am, subscribe to this blog and all of the blogs in my Blogroll (over there
---&gt.  It really will open up a whole new world for you.<br>
</p>
<br>
<hr>
This weblog is sponsored by <a href="http://www.sweetpotatosoftware.com">SweetPotato
Software, Inc.</a><p><div class="blogdisclaim"><a href="http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,54b7558d-0502-4152-a21d-3e92949f7787.aspx">This post originally appeared on an external website</a></div>

Collapse -

FoxTalk 2.0 GDI+ Article Available Online

by craig In reply to The SPS Weblog

<p>
Well, the <a href="http://www.pinpub.com/ME2/Audiences/dirmod.asp?sid=&nm=&type=Publishing&mod=Publications%3A%3AArticle&mid=8F3A7027421841978F18BE895F87F7**&AudID=301888DF3BCF483382FC8A1382F3050B&tier=4&id=43FF99C3289346189B14EAEA14573F3C">first
article in my GDI+ series</a> for <a href="http://www.pinpub.com/ME2/Audiences/Default.asp">FoxTalk
2.0</a> is available online for free today. Thanks to FoxTalk 2.0 for everything they've
done for me and the rest of the Visual FoxPro Community, especially David Stevenson
my editor at FoxTalk 2.0. He put in a lot of hard work to make this article possible
(as I am sure he has done for all the FoxTalk 2.0 articles).
</p>
<p>
This first article will take the reader through the basics of drawing on Visual FoxPro
forms with GDI+ using double-buffering and other techniques that make GDI+ more useable
for Visual FoxPro developers. It'll show you how to surmount many of the inherent
problems developers encounter when rendering graphics on Visual FoxPro forms using
GDI+.
</p>
<p>
Stay tuned for the next articles in the series where I'll build from this first article
and delve even further into GDI+ and it's many uses in Visual FoxPro.
</p>
<br>
<hr>
This weblog is sponsored by <a href="http://www.sweetpotatosoftware.com">SweetPotato
Software, Inc.</a><p><div class="blogdisclaim"><a href="http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,1e3a72fe-ffba-43fe-97bf-d0856a435750.aspx">This post originally appeared on an external website</a></div>

Collapse -

The SPS Blog Updated

by craig In reply to The SPS Weblog

<p>
As my younger brother Daniel was reading my weblog tonight, he messaged me and told
me that the "poker spam comments on your weblog are bogus". One of the online casinos
had obviously thought that my blog might make a good place to advertise. So, I've
taken this opportunity to not only clean up the spam, but also update to the <a href="https://sourceforge.net/project/showfiles.php?group_id=127624">latest
stable version</a> of dasBlog (version 1.7.5016.2) since I was going to be in here
messing around anyways.
</p>
<p>
The upgrade was fairly painless. I followed (to the letter) the instructions given,
ran the upgrader command line utility, copied the relevant pieces over the top of
my old version and ran headlong into a known issue with the titleList macro. A quick
Google search and a single line edit in the source made quick work of this problem.
Total time to upgrade 15 minutes... not bad, especially considering that I've customized
a few different areas of my blog. I haven't been through it end-to-end, but on quick
review everything appears to be working correctly.
</p>
<p>
As for the spammers, while they can still post manually (there's always a way for
the determined) there are new security features and blacklists to help prevent
as much as possible. And now, rather than having to edit the xml files (that make
up the content of this blog) to remove comments, I can now delete any spam comments
directly using the administrative functions (an obvious must for any serious
blog engine). All in all it appears to be a pretty good release.
</p>
<p>
I noticed that another new feature I could turn on is permalinks that use
the title of the blog entry instead of a guid. However, with the number of blogs and
websites pointing to different entries on this blog already, I think I will stay with
the guids, even if they are considered a little long in the tooth by some.
</p>
<p>
So, a big thank you to both my brother Daniel (for pointing out the spam) and the
development community surrounding dasBlog (for another good release). I
have something to say to the spammers as well, but decorum prevents me.
</p>
<br>
<hr>
This weblog is sponsored by <a href="http://www.sweetpotatosoftware.com">SweetPotato
Software, Inc.</a><p><div class="blogdisclaim"><a href="http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,93398858-cf28-46b0-8d3b-7cb542254847.aspx">This post originally appeared on an external website</a></div>

Collapse -

BindEvent on Steroids

by craig In reply to The SPS Weblog

<p>
The ability for BindEvent to hook into windows message events in Visual FoxPro 9 is
great. It is no doubt wrapping the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/windowclasses/windowclassreference/windowclassfunctions/setwindowlong.asp">SetWindowLong</a> API
function somewhere in the source and facilitates the magic by <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/windowprocedures/usingwindowprocedures.asp">subclassing
the target window</a>. My hat goes off to the Fox Team for coming up with this. But,
what if you want to modify a messagebox before it appears (such as change the button
captions and centering it with the form that called it) or what if you want to create
a Global Keyboard Hook? Basically, what if, as a Visual FoxPro developer, you want
to take advantage of the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/setwindowshookex.asp">SetWindowsHookEx</a> API
function and all the doors it opens up? Maybe I'm missing something, but BindEvent
doesn't seem to be able to do this.
</p>
<p>
I've got some ideas on things that I want Visual FoxPro to do long before Sedna gets
here, and some of these ideas require that I am able to use the SetWindowsHookEx. So,
today I decided to figure out how we (the Visual FoxPro Community) could do this.
</p>
<p>
To start this show, here's an FLL I've created using Visual C++ 7.0, that gives
us two more functions for Visual FoxPro. BindEventEX and UnBindEventEx. <a href="http://www.sweetpotatosoftware.com/files/vfpex.zip">Download
the vfpex.fll here</a>. These functions will give you indirect access to SetWindowsHookEx
for your Visual FoxPro applications/code. There is more to be done, but this is a
good start for now.
</p>
<p>
Then, below are a couple of "cut-n-paste into a prg file and execute" examples
I worked up in Visual FoxPro that use the vfpex.fll.
</p>
<p>
***************************************************<br>
*!* MODIFY MESSAGEBOX EXAMPLE<br>
*!*<br>
*!* Requires: vfpex.fll<br>
***************************************************<br>
PUBLIC oform1
</p>
<p>
oform1=NEWOBJECT("form1")<br>
oform1.Show<br>
RETURN
</p>
<p>
DEFINE CLASS form1 AS form<br>
 Top = 0<br>
 Left = 0<br>
 Height = 259<br>
 Width = 373<br>
 DoCreate = .T.<br>
 Caption = "Using the New BindEventsEx - MessageBox Modification"<br>
 WindowType = 1<br>
 Name = "Form1"
</p>
<p>
 ADD OBJECT command1 AS commandbutton WITH ;<br>
  Top = 216, ;<br>
  Left = 144, ;<br>
  Height = 27, ;<br>
  Width = 132, ;<br>
  Caption = "R\<un Example", ;<br>
  Name = "Command1"
</p>
<p>
 ADD OBJECT command2 AS commandbutton WITH ;<br>
  Top = 216, ;<br>
  Left = 276, ;<br>
  Height = 27, ;<br>
  Width = 84, ;<br>
  Caption = "E\<xit", ;<br>
  Name = "Command2"
</p>
<p>
 PROCEDURE wineventhandler<br>
  #DEFINE IDOK   1<br>
  #DEFINE IDCANCEL  2<br>
  #DEFINE IDABORT  3<br>
  #DEFINE IDRETRY  4<br>
  #DEFINE IDIGNORE  5<br>
  #DEFINE IDYES   6<br>
  #DEFINE IDNO   7<br>
  #DEFINE IDCLOSE  8<br>
  #DEFINE IDHELP   9<br>
  #DEFINE IDTRYAGAIN 10<br>
  #DEFINE IDCONTINUE 11<br>
  #DEFINE IDPROMPT 65535
</p>
<p>
  IF nCode == 5<br>
   SetWindowText(wParam, "VFP - WH_CBT HOOK") && Title<br>
   SetDlgItemText(wParam, IDPROMPT, "Visual FoxPro BindEventEx Example")
&& Message<br>
   SetDlgItemText(wParam, IDABORT, "VFP Rocks!") && First Button
Caption<br>
   SetDlgItemText(wParam, IDRETRY, "Always Has") && Second
Button Caption<br>
   SetDlgItemText(wParam, IDIGNORE, "Always Will") && Third
Button Caption
</p>
<p>
   Thisform.CenterMessageBox(wParam)
</p>
<p>
   CallNextHookEx(hHook, nCode, wParam, LPARAM) && all 4 variables
exist<br>
   UnBindEventEx()<br>
   SET LIBRARY TO<br>
  ELSE<br>
   CallNextHookEx(hHook, nCode, wParam, LPARAM) && all 4 variables
created by FLL<br>
  ENDIF
</p>
<p>
  RELEASE nCode, wParam, LPARAM, hHook<br>
 ENDPROC
</p>
<p>
 PROCEDURE buf2dword<br>
  LPARAMETERS tcBuffer<br>
  RETURN Asc(SUBSTR(tcBuffer, 1,1)) + ;
<br>
       Asc(SUBSTR(tcBuffer, 2,1)) * 2^8 +;
<br>
       Asc(SUBSTR(tcBuffer, 3,1)) * 2^16 +;
<br>
       Asc(SUBSTR(tcBuffer, 4,1)) * 2^24<br>
 ENDPROC
</p>
<p>
 PROCEDURE centermessagebox<br>
  LPARAMETERS tnwParam
</p>
<p>
  LOCAL lcBuffer, lnMsgLeft, lnMsgTop, lnMsgRight, lnMsgBottom, lnMsgWidth,
lnMsgHeight
</p>
<p>
  lcBuffer = REPLI(CHR(0), 2^4)
</p>
<p>
  =GetWindowRect(tnwParam, @lcBuffer)
</p>
<p>
  lnMsgLeft = THISFORM.buf2dword(SUBSTR(lcBuffer, 1, 4))<br>
  lnMsgTop = THISFORM.buf2dword(SUBSTR(lcBuffer, 5, 4))<br>
  lnMsgRight = THISFORM.buf2dword(SUBSTR(lcBuffer, 9, 4))<br>
  lnMsgBottom = THISFORM.buf2dword(SUBSTR(lcBuffer, 13, 4))<br>
  lnMsgWidth = lnMsgRight - lnMsgLeft<br>
  lnMsgHeight = lnMsgBottom - lnMsgTop<br>
  lnMsgLeft = THISFORM.LEFT + (THISFORM.WIDTH - lnMsgWidth) / 2<br>
  lnMsgTop = _screen.Top + THISFORM.TOP + (THISFORM.HEIGHT - lnMsgHeight)
/ 2
</p>
<p>
  MoveWindow(tnwParam, lnMsgLeft, lnMsgTop, lnMsgWidth, lnMsgHeight, .T.)<br>
 ENDPROC
</p>
<p>
 PROCEDURE Load<br>
  DECLARE INTEGER SetDlgItemText IN user32;<br>
   LONG hDlg,;<br>
   LONG nIDDlgItem,;<br>
   STRING lpString
</p>
<p>
  DECLARE INTEGER SetWindowText IN user32;<br>
   LONG HWND,;<br>
   STRING  lpString
</p>
<p>
  DECLARE LONG CallNextHookEx IN user32;<br>
   LONG, LONG, LONG, LONG
</p>
<p>
  DECLARE INTEGER MoveWindow IN user32;<br>
   INTEGER HWND,;<br>
   INTEGER X,;<br>
   INTEGER Y,;<br>
   INTEGER nWidth,;<br>
   INTEGER nHeight,;<br>
   INTEGER bRepaint
</p>
<p>
  DECLARE SHORT GetWindowRect IN user32 INTEGER HWND, STRING @ lpRect<br>
 ENDPROC<br>
 <br>
 PROCEDURE command1.Click<br>
  *!* Some of the various Windows Hook constants<br>
  #define WH_MSGFILTER -1<br>
  #define WH_JOURNALRECORD 0<br>
  #define WH_JOURNALPLAYBACK 1<br>
  #define WH_KEYBOARD 2<br>
  #define WH_GETMESSAGE 3<br>
  #define WH_CALLWNDPROC 4<br>
  #define WH_CBT 5 && the one used here<br>
  #define WH_SYSMSGFILTER 6<br>
  #define WH_MOUSE 7<br>
  #define WH_HARDWARE 8<br>
  #define WH_DEBUG 9<br>
  #define WH_SHELL 10<br>
  #define WH_FOREGROUNDIDLE 11<br>
  #define WH_CALLWNDPROCRET 12<br>
  #define WH_KEYBOARD_LL 13<br>
  #define WH_MOUSE_LL 14<br>
  <br>
  *!* Set library so BindEventEx and UnBindEventEx can be used<br>
  *!* in VFP<br>
  SET LIBRARY TO (LOCFILE(ADDBS(JUSTPATH(SYS(16))) + "vfpex.fll"))<br>
  *!* You must have a Named reference to the form or object<br>
  *!* as thisform or this cannot be used with BindEventEx<br>
  BindEventEx('oform1.wineventhandler()', WH_CBT) && SetWindowsHookEx<br>
  *!* This messagebox will be modified before it is shown<br>
  MESSAGEBOX(" ", 2, "") && Just A Blank Messagebox with Abort,
Retry, Ignore buttons<br>
 ENDPROC
</p>
<p>
 PROCEDURE command2.Click<br>
  Thisform.Release()<br>
 ENDPROC
</p>
<p>
ENDDEFINE
</p>
<p>
***************************************************<br>
*!* GLOBAL KEYBOARD HOOK EXAMPLE<br>
*!*<br>
*!* Requires: vfpex.fll<br>
***************************************************<br>
PUBLIC oform1
</p>
<p>
oform1=NEWOBJECT("form1")<br>
oform1.Show<br>
RETURN
</p>
<p>
DEFINE CLASS form1 AS form
</p>
<p>
 Top = 0<br>
 Left = 1<br>
 Height = 256<br>
 Width = 454<br>
 DoCreate = .T.<br>
 Caption = "Using the New BindEventsEx - Global Keyboard Hook"<br>
 Name = "form1"
</p>
<p>
 ADD OBJECT command1 AS commandbutton WITH ;<br>
  Top = 216, ;<br>
  Left = 311, ;<br>
  Height = 27, ;<br>
  Width = 132, ;<br>
  Caption = "R\<un Example", ;<br>
  Name = "Command1"
</p>
<p>
 ADD OBJECT edit1 AS editbox WITH ;<br>
  Height = 193, ;<br>
  Left = 11, ;<br>
  ReadOnly = .T., ;<br>
  Top = 12, ;<br>
  Width = 432, ;<br>
  Name = "Edit1"
</p>
<p>
 PROCEDURE wineventhandler<br>
  LOCAL HookStruct<br>
  *!* Real basic example, just to show it's possible<br>
  IF wParam = 256 && keydown<br>
   HookStruct = REPLICATE(CHR(0), 20)<br>
   CopyMemory(@Hookstruct, lParam, 20)<br>
   thisform.edit1.value = thisform.edit1.value + Chr(thisform.buf2dword(Hookstruct))<br>
  ENDIF<br>
  CallNextHookEx(hHook, nCode, wParam, lParam) && all 4 variables
created by FLL<br>
  RELEASE nCode, wParam, LPARAM, hHook<br>
 ENDPROC
</p>
<p>
 PROCEDURE buf2dword<br>
  LPARAMETERS tcBuffer<br>
  RETURN Asc(SUBSTR(tcBuffer, 1,1)) + ;
<br>
       Asc(SUBSTR(tcBuffer, 2,1)) * 2^8 +;
<br>
       Asc(SUBSTR(tcBuffer, 3,1)) * 2^16 +;
<br>
       Asc(SUBSTR(tcBuffer, 4,1)) * 2^24<br>
 ENDPROC
</p>
<p>
 PROCEDURE Load         
<br>
  DECLARE LONG CallNextHookEx IN user32;<br>
   LONG, LONG, LONG, LONG
</p>
<p>
  DECLARE RtlMoveMemory IN kernel32 As CopyMemory;
<br>
      STRING  @ Destination,;
<br>
      INTEGER   Source,;
<br>
      INTEGER   nLength 
</p>
<p>
  SET LIBRARY TO (LOCFILE("vfpex.fll", "FLL"))<br>
 ENDPROC
</p>
<p>
 PROCEDURE Destroy<br>
  *!* Unhook when form is destroyed<br>
  UnBindEventEx()<br>
  SET LIBRARY TO<br>
 ENDPROC
</p>
<p>
 PROCEDURE command1.Click<br>
  #define WH_MSGFILTER -1<br>
  #define WH_JOURNALRECORD 0<br>
  #define WH_JOURNALPLAYBACK 1<br>
  #define WH_KEYBOARD 2<br>
  #define WH_GETMESSAGE 3<br>
  #define WH_CALLWNDPROC 4<br>
  #define WH_CBT 5<br>
  #define WH_SYSMSGFILTER 6<br>
  #define WH_MOUSE 7<br>
  #define WH_HARDWARE 8<br>
  #define WH_DEBUG 9<br>
  #define WH_SHELL 10<br>
  #define WH_FOREGROUNDIDLE 11<br>
  #define WH_CALLWNDPROCRET 12<br>
  #define WH_KEYBOARD_LL 13 && this is the one used<br>
  #define WH_MOUSE_LL 14
</p>
<p>
  this.Enabled = .F.<br>
  WAIT "Go type in another application - your keystrokes will be recorded"
WINDOW TIMEOUT 2<br>
  *!* You must have a Named reference to the form or object<br>
  *!* as thisform or this cannot be used with BindEventEx<br>
  BINDEVENTEX('oform1.wineventhandler()', WH_KEYBOARD_LL) && SetWindowsHookEx<br>
 ENDPROC
</p>
<p>
ENDDEFINE
</p>
<br>
<hr>
This weblog is sponsored by <a href="http://www.sweetpotatosoftware.com">SweetPotato
Software, Inc.</a><p><div class="blogdisclaim"><a href="http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,f7644db8-b155-4d43-8216-4cfde233edb7.aspx">This post originally appeared on an external website</a></div>

Collapse -

New ReportPreview App for Visual FoxPro

by craig In reply to The SPS Weblog

<p>
<font face=Arial>The ReportPreview.app is a pretty good general preview application
for Visual FoxPro 9. The look of it mimics the report preview screen we had prior
to Visual FoxPro 9 and it provides much of the same functionality as well as some
new features available in Visual FoxPro 9 thrown in for good measure. However, some
Visual FoxPro developers are having problems with certain aspects of it.</font>
</p>
<p>
<font face=Arial>Running ReportPreview.app as a modal preview (report form command) in
a TopLevel form application will cause the print preview toolbar to stop responding.
That's because the ReportPreview.app brings the preview form up in a modal state and
toolbars are not accessible when a modal form is active. For the most part, this is
as it should be and is in-line with Microsoft Windows conventions. The answer is to
include the NOWAIT clause in the report form command or you can modify the ReportPreview.pjx
to force it into a modeless state when this situation occurs. Easy enough right? Well,
the problem with this approach is it usually defeats the very thing that the developer
is attempting to do... mainly, bring up a modal preview window in a TopLevel application
(I want the preview window to come up, then I want to wait until the user has released
the preview window before continuing with my code execution).</font>
</p>
<p>
<font face=Arial>If you haven't run into the aforementioned problem you can reproduce
it by opening up the Taskpane in Visual FoxPro and go to the Solutions Samples
area. Then expand the "New in Visual FoxPro 9.0" node and look for the "The typical
multiple detail band report" sample. Over on the right-hand side of the sample there
is a little report and magnifying glass button that says "Click here to view the code"
in its tooltip, click that button. Next modify the ShowWindow property of the
form that pops up (ShowWindow = 2 - As Top-Level Form). Close the form and save your
changes, then run the sample. You'll notice that the toolbar does not respond to user
events. To close the sample you'll have to close the report from the "X" in the top
right corner of the preview window.</font>
</p>
<p>
<font face=Arial>Another thing about the ReportPreview.app is that it looks a little
antiquated to me. I may be the only one that feels this way, but I suspect not. Now,
before the flames start... I'm not saying that I don't think the MS Fox Team didn't
do a good job. I'm all for having them just give us access and allow us, as seasoned
Visual FoxPro developers, develop the rest. I don't want them wasting time mocking
up Visual FoxPro forms and applications that I can create myself. I feel like we are
all well served by them opening the guts of Visual FoxPro up to us as developers,
give a basic example of the new feature's use, and then let us do the rest.</font>
</p>
<p>
<font face=Arial>So, last night I decided to rip into the ReportPreview.pjx and see
what I could do. I made an exact copy of the entire Report Preview project folder
from XSource and then began modifying it. Basically keeping the stuff I liked, deleting
the stuff I didn't, and modifying the rest. The result was a ReportPreviewEx.app that
can be used in lieu of the ReportPreview.app. To use it you'll need to set the _reportpreview
system variable to the new application:</font>
</p>
<font color=#0000ff>
<p>
<font face=Arial>_reportpreview </font>
</font><font face=Arial color=#000000>= "reportpreviewex.app"</font>>
<p>
<font face=Arial color=#000000>This will cause Visual FoxPro to use the new print
preview application. To try it out run one of the report samples in the Solutions
Samples area of the Taskpane underneath the "New in Visual FoxPro 9.0" node. The names
of the samples are "A multiple detail band report used for calculations" and "The
typical multiple detail band report".</font>
</p>
<p>
<font face=Arial color=#000000>This new application doesn't suffer from some of the
drawbacks the ReportPreview.app does. For instance, instead of toolbar, I placed the
buttons and such directly on the frxpreviewform class. This fixes the problem with
modal previews in a TopLevel application and is more in-line with print preview windows
such as the one in Internet Explorer.</font>
</p>
<p>
<font face=Arial color=#000000>I ran into more than a few issues while creating
this, but almost all of them have been resolved successfully. However, one issue that
is still plaguing me is the way the MS Fox Team failed to implement double-buffering
correctly when rendering emf content in an image control. Emf file format is perfect
for reports because meta-files scale better than anything else on the planet. But,
when you are running the print preview you are going to see a slight flicker. Regrettably
the MS Fox Team has not opened up the internal painting routines to us, so I am unable
to insert the proper code that should be used when Visual FoxPro is repainting the
image controls. That having been said, I added a property to the frxpreviewform form
class of the frxpreview.vcx that allows you to try out all the other formats and their
results. The property is "outputimagetype" and has the following possible values:
tiff, bmp, png, jpeg, gif, emf. If you want to try another format that doesn't have
the flicker and still has perhaps acceptable quality, change the property to "png".
The drawback to this format is that it looks blurry at large zoom levels and Visual
FoxPro turns into a bit of a performance hog with its internal painting routines.</font>
</p>
<p>
<font face=Arial color=#000000>I posted a comment on <a href="http://blogs.msdn.com/calvin_hsia/archive/2005/08/09/449347.aspx">Calvin
Hsia's blog</a> recently asking him to pull the curtain back further on the internal
painting routines for Visual FoxPro, and I've asked other members of the Fox Team
in the past to please give us a little insight into this so we can address issues
such as this effectively and help Microsoft out a little at the same time. Regrettably,
they have ignored me so far. I wish that their new goal of transparency extended towards
the Visual FoxPro core as well. I understand that they have trade secrets/intellectual
property rights to consider, but I think they could use some help in this particular
area.</font>
</p>
<p>
<font face=Arial color=#000000>Now some of you are no doubt thinking, why didn't Craig
just use the outputpage method of the Report Listener class to render to a canvas
object (shape or container control). The reason is that Visual FoxPro will paint right
over the top of anything that gets in the way of the canvas object. So, if you have
a bunch of canvas objects inside a container and you are allowing the canvas objects
to be slid around inside the container so that portions of them are outside the dimensions
of the visible container (left = -150 or top = -200 or whatever), the Report Listener
doesn't respect the container's borders, so it starts rendering the report right over
the top of other form elements. So, the answer is to use an image control and temporary
off-screen bitmaps assigned to their picture property. Why not a container (it has
a picture property)? Well with the image control I pick up a little more overhead,
but it gives me some really good additional functionality for free (such as the stretch
property that makes zooming in and out on print preview a breeze from a coding standpoint).
There's more to this whole sorted saga, but I think you get the general idea.</font>
</p>
<p>
<font face=Arial color=#000000>So, here's a screen capture of the new print preveiw,
a link to download the ReportPreviewEx.app, and an additional link to download
the entire source -- <font color=#ff0000>IMPORTANT NOTE:</font> I've just looked through
the redist.txt that comes with Visual FoxPro and I cannot find anywhere that certain
elements of the ReportPreview.pjx are on the allowable list - I will email Microsoft
for clarification - until I hear back from them, I have removed the source code link.</font>
</p>
<p>
<font face=Arial color=#000000><a href="http://www.sweetpotatosoftware.com/files/reportpreviewexapp.zip">Download
ReportPreviewEx Application</a> (approx. 47 KB)</font>
</p>
<p>
<img alt="ReportPreviewEx Application Screen Capture" hspace=0 src="http://www.sweetpotatosoftware.com/images/reportpreviewex.gif" align=baseline border=0>
</p>
<br>
<hr>
This weblog is sponsored by <a href="http://www.sweetpotatosoftware.com">SweetPotato
Software, Inc.</a><p><div class="blogdisclaim"><a href="http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,26acb331-c0fa-4e67-bd06-bb7569e2a3a3.aspx">This post originally appeared on an external website</a></div>

Back to After Hours Forum
94 total posts (Page 2 of 10)   Prev   01 | 02 | 03 | 04 | 05   Next

Related Discussions

Related Forums