<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
     <channel>
         <title>Rick Strahl's FoxPro and Web Connection Web Log </title>
         <link>http://www.west-wind.com/wconnect/weblog/</link>
         <description>Life, Surf, Code and everything in between</description>
         <language>en-us</language>
         <ttl>1440</ttl>       <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/RickStrahlsFoxproAndWebConnectionWebLog" /><feedburner:info uri="rickstrahlsfoxproandwebconnectionweblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>20.906999</geo:lat><geo:long>-156.382029</geo:long><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/RickStrahlsFoxproAndWebConnectionWebLog" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare href="http://www.wikio.com/subscribe?url=http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Ffeeds.feedburner.com%2FRickStrahlsFoxproAndWebConnectionWebLog" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><item>
			<title>Root Path Support with ~ in Web Connection Response Output</title>
			<pubDate>Sat, 12 May 2012 22:44:55 GMT</pubDate>
			<guid isPermaLink="false">886_20120512</guid>
			<link>http://feedproxy.google.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~3/wLrKDpocnxQ/ShowEntry.blog</link>
			<dc:creator>Rick Strahl</dc:creator>
			<comments>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=886#Feedback</comments>
			<slash:comments>0</slash:comments>
			<description>&lt;p&gt;Here's a little not so well known tip that's useful if you're using &lt;a href="http://www.west-wind.com/webconnection/" target="_blank"&gt;Web Connection&lt;/a&gt;: When output is rendered, the output automatically expand URLs that use the ~/path syntax, expanding any URLs found to fully application relative URLs on the page. &lt;/p&gt;  &lt;p&gt;What it does is that you can write URLs like this (assuming a virtual directory of &lt;em&gt;wconnect&lt;/em&gt;):&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&amp;lt;a href=&amp;quot;&lt;font color="#c0504d"&gt;~/WebControls/Helloworld.wcsx&lt;/font&gt;&amp;quot;&amp;gt;Hello World&amp;lt;/a&amp;gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;and expand that URL out to:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&amp;lt;a href=&amp;quot;&lt;font color="#c0504d"&gt;/wconnect/WebControls/Helloworld.wcsx&lt;/font&gt;&amp;quot;&amp;gt;HelloWorld&amp;lt;/a&amp;gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;~/ paths basically say: Fix up the ~ to mean the base path of my Web Application. This allows you to create application rooted URLs consistently regardless of which virtual directory or root folder the URL is called from.&amp;#160; This different than relative paths which depend on the current location of the page that is loaded in the browser - the path generated is a Web server root relative path that was generated by the server based on the active application's path.&lt;/p&gt;  &lt;p&gt;This means if your app runs in a virtual directory called &lt;em&gt;wconnect &lt;/em&gt;the root path resolves to &lt;em&gt;/wconnect &lt;/em&gt; (root folder/wconnect subfolder). If you're running in the root of the site, the root path resolves to &lt;em&gt;/.&lt;/em&gt; Why should this matter? If you're developing applications that target different environments the base path of the Application might change. For example, you might develop your application in a virtual directory for development, but deploy the live application into a root Web, or a virtual with different names. Using ~/ urls, no changes are required when the application is moved to the live server.&lt;/p&gt;  &lt;p&gt;Web Connection 5.0 also introduced a code based equivalent in Process.ResolveUrl():&lt;/p&gt;  &lt;pre class="csharpcode"&gt;lcUrl = Process.ResolveUrl(&lt;span class="str"&gt;&amp;quot;~/WebControls/HelloWorld.wcsx&amp;quot;&lt;/span&gt;)&lt;/pre&gt;

&lt;p&gt;which accomplishes the same thing for you in code so you can use this function for creating root relative paths from your code. This is especially useful for generic and reusable code which may not know where it is running from. The Web Control framework makes extensive use of ResolveUrl for any URL properties on which it always calls ResolveUrl(). ResolveUrl() ignores full path urls if passed and returns them as-is. Urls that contain ~/ in the path are translated. &lt;/p&gt;

&lt;p&gt;Note that this feature started out as a feature specific to the the Web Control Framework, but it since then has migrated into the core framework and the &lt;a href="http://www.west-wind.com/webconnection/docs/page=_1o80yq37z.htm" target="_blank"&gt;wwPageResponse&lt;/a&gt;/wwResponseString objects to post-process in all output generated through the Response object. This means it works for Web Control Framework Pages, raw Response.Write() output, templates and scripts etc. It's only applied to HTML output when the Content Type is set to text/html.&lt;/p&gt;

&lt;h3&gt;Url Pathing Options&lt;/h3&gt;

&lt;p&gt;Note that this ~/ pathing is different than &lt;em&gt;relative pathing&lt;/em&gt; using ../ or &lt;em&gt;rooted pathing&lt;/em&gt; which starts with a / on the root site. Rather the ~ syntax creates an application relative URL that is always the same regardless of where your app runs.&lt;/p&gt;

&lt;p&gt;Whenever possible when creating URLs in your applications both in markup and code you should choose paths in this order:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Relative Paths 
      &lt;br /&gt;&lt;/strong&gt;Use relative paths whenever possible because they're the most portable. Relative paths (../css/standard.css or css/standard.css) tend to be the most portable because as long as your resources are relatively stored to each other they will always work. Problems with this arise only if the resources are moved relative to each other which is probably rare. 

    &lt;br /&gt;&lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Virtual Paths 
      &lt;br /&gt;&lt;/strong&gt;Use application relative paths because they are portable per application. Virtual path specifiers (~/css/standard.css which expands to /wconnect/css/standard.css) are always rooted to the application's root folder. In Web Connection you specify this value in the server configuration via the cVirtualPath in wc.ini or web.config using the VirtualPath key. The great thing about ~/ paths are that there's no relative pathing involved if you don't know where your request might be running from. They are also super useful for Web Control Framework User Controls that might be dropped into pages running for many different subfolders.

    &lt;br /&gt;&lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Rooted Paths 
      &lt;br /&gt;&lt;/strong&gt;Never use hardcoded paths to site or even rooted Webs. You should NEVER EVER use hard coded URL paths to reference anything in your local site. While this will work in whatever environment you're working in it'll break as soon as you move the site. At that point you have lots of links to clean up and that's never a good idea. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both relative paths and virtual paths are adaptable and the big advantage of these are that they are portable. If you move the site or move to a different virtual folder you don't have to change anything (ok - you have to change the cVirtualPath config property, for ~/).&lt;/p&gt;

&lt;p&gt;Relative paths are native to HTML and are parsed as the page is loaded. ~/ paths are expanded on the server and if you're using the wwPageResponse class as your Response class in Web Connection (which is the default in Web Connection 5.0) then any embedded ~/ paths are automatically expanded for you.&lt;/p&gt;

&lt;h3&gt;How it works and What is Transformed&lt;/h3&gt;

&lt;p&gt;The ~/ parsing is implemented as a post-processing feature of the &lt;a href="http://www.west-wind.com/webconnection/docs/page=_1o80yq37z.htm" target="_blank"&gt;wwPageResponse&lt;/a&gt; and wwResponseString classes. Basically Web Connection by default renders all of its output into a string first before potentially rendering the output into other outputs. For example, when running in file based mode Web Connection's output goes into a temporary file, but Web Connection (5.0) first renders the output to a string before explicitly writing the output to a file later. This switch occurred in Web Connection 5.0 to allow more control over the HTTP output created - using a string allowed for header manipulation because the final output doesn't get written to IIS until the response is complete. This means you can now add headers and cookies even when output has already been written to the Response.&lt;/p&gt;

&lt;p&gt;In Web Connection 5.0 the wwPageResponse class handles all primary output, and the ~/ processing is hooked up in the Render method like this:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;*** Fix up ~/ paths with UrlBasePath&lt;/span&gt;
&lt;span class="kwrd"&gt;IF&lt;/span&gt; &lt;span class="kwrd"&gt;THIS&lt;/span&gt;.contentType = &lt;span class="str"&gt;&amp;quot;text/html&amp;quot;&lt;/span&gt; AND &lt;span class="kwrd"&gt;VARTYPE&lt;/span&gt;(Process) = &lt;span class="str"&gt;&amp;quot;O&amp;quot;&lt;/span&gt;
   lcBasePath = Process.cUrlBasePath
   &lt;span class="kwrd"&gt;IF&lt;/span&gt; !&lt;span class="kwrd"&gt;EMPTY&lt;/span&gt;(lcBasePath)
      &lt;span class="kwrd"&gt;this&lt;/span&gt;.cOutput = &lt;span class="kwrd"&gt;STRTRAN&lt;/span&gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt;.cOutput,&lt;span class="str"&gt;[=&amp;quot;~/]&lt;/span&gt;,&lt;span class="str"&gt;[=&amp;quot;]&lt;/span&gt; + lcBasePath)
      &lt;span class="kwrd"&gt;this&lt;/span&gt;.cOutput = &lt;span class="kwrd"&gt;STRTRAN&lt;/span&gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt;.cOutput,&lt;span class="str"&gt;[url(~/]&lt;/span&gt;,&lt;span class="str"&gt;[url(]&lt;/span&gt; + lcBasePath)
   &lt;span class="kwrd"&gt;ENDIF&lt;/span&gt;
&lt;span class="kwrd"&gt;ENDIF&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The code first makes sure we're dealing with HTML content only and then looks to translates any embedded URL expressions in attributes (the first STRTRAN) and in CSS styles (the second url() based syntax).&lt;/p&gt;

&lt;p&gt;Based on this Web Connection will expand:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;~/webcontrols/helloworld.wcsx&amp;quot;&amp;gt;&lt;/span&gt;Hello World&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;/wconnect/webcontrols/Helloworld.wwd&amp;quot;&amp;gt;&lt;/span&gt;Hello World&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Notice thought that this will produce different results:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;~/webcontrols/helloworld.wcsx&amp;quot;&amp;gt;&lt;/span&gt;~/webcontrols/HelloWorld.wcsx&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;which produces:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;/wconnect/webcontrols/helloworld.wcsx&amp;quot;&amp;gt;&lt;/span&gt;~/webcontrols/HelloWorld.wcsx&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Note that the second ~/ tag wasn't expanded because it's not defined inside of an attribute - the plain string just stays as designed. If you want that sort of thing to work you have to use &amp;lt;%= Process.ResolveUrl() %&amp;gt; instead:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;~/webcontrols/helloworld.wcsx&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background: yellow"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;= &lt;/span&gt;Process.ResolveUrl(&amp;quot;~/webcontrols/HelloWorld.wcsx&amp;quot;) &lt;span style="background: yellow"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;You can also expand paths in css tags like the following:&lt;/p&gt;

&lt;pre class="code"&gt;    &lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;style&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &lt;/span&gt;&lt;span style="color: maroon"&gt;.salesitem
        &lt;/span&gt;{
            &lt;span style="color: red"&gt;padding&lt;/span&gt;: &lt;span style="color: blue"&gt;10px&lt;/span&gt;;
            &lt;span style="color: red"&gt;padding-right&lt;/span&gt;: &lt;span style="color: blue"&gt;30px&lt;/span&gt;;
           &lt;strong&gt; &lt;span style="color: red"&gt;background-image&lt;/span&gt;: &lt;span style="color: blue"&gt;url(~/css/images/pin.gif)&lt;/span&gt;;&lt;/strong&gt;
        }
    &lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;style&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;

&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;which expands out to:&lt;/p&gt;

&lt;pre class="code"&gt;    &lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;style&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &lt;/span&gt;&lt;span style="color: maroon"&gt;.salesitem
        &lt;/span&gt;{
            &lt;span style="color: red"&gt;padding&lt;/span&gt;: &lt;span style="color: blue"&gt;10px&lt;/span&gt;;
            &lt;span style="color: red"&gt;padding-right&lt;/span&gt;: &lt;span style="color: blue"&gt;30px&lt;/span&gt;;
            &lt;span style="color: red"&gt;background-image&lt;/span&gt;: &lt;span style="color: blue"&gt;url(/wconnect/css/images/pin.gif)&lt;/span&gt;;
        }
    &lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;style&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;

&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;It also works for inline styles:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;style&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;&lt;/span&gt;&lt;span style="color: red"&gt;background-image&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;strong&gt;url(~/css/images/help.gif)&lt;/strong&gt;&amp;quot; &lt;br /&gt;   &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;~/webcontrols/Helloworld.wwd&amp;quot;&amp;gt;&lt;/span&gt;Hello World&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;which transforms into:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;style&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;&lt;/span&gt;&lt;span style="color: red"&gt;background-image&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;strong&gt;url(/wconnect/css/images/help.gif&lt;/strong&gt;)&amp;quot; &lt;br /&gt;   &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;/wconnect/webcontrols/Helloworld.wwd&amp;quot;&amp;gt;&lt;/span&gt;Hello World example&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;h3&gt;Configuration&lt;/h3&gt;

&lt;p&gt;This feature is mostly transparent - there's nothing you have to set up or configure to make the render parse these values. There are two requirements though:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Make sure you're using wwPageResponse or the wwResponseString class for Response rendering &lt;/li&gt;

  &lt;li&gt;Make sure the VirtualPath property is set in web.config or wc.ini &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;wwPageResponse&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;wwPageResponse is Web Connection 5.0's default response class and unless you've explicitly overridden it this is the class used. If you're using an older version of Web Connection or you have an old application that was migrated to Web Connection 5.0 you might want to check and potentially switch to this class.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;cResponseClass = &lt;span class="str"&gt;&amp;quot;wwPageResponse&amp;quot;   &amp;amp;&amp;amp; wwPageResponse40 for 4.x compatibility&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;in your Process class property definitions header.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VirtualPath Configuration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Process.ResolvePath and Process.cBaseUrl retrieve the application's base path from the VirtualPath setting in the YourApplication.ini file. Specifically it comes out of the process class configuration section. For example, here's the wwDemo configuration section:&lt;/p&gt;

&lt;pre class="code"&gt;[Wwdemo]
Datapath=C:\WWAPPS\WC3\wwDemo\
Htmlpagepath=c:\westwind\wconnect\
&lt;strong&gt;Virtualpath=/wconnect/&lt;/strong&gt;&lt;/pre&gt;

&lt;p&gt;The VirtualPath key specifies the virtual path that is used. Note that this path is used for various other things as well so you should always set this in your applications. Web Connection's configuration Wizard automatically sets this but if you manually copy applications always make sure to set these values explicitly.&lt;/p&gt;

&lt;h3&gt;Summary&lt;/h3&gt;

&lt;p&gt;If you haven't used this feature before - take advantage of it. As small as this feature is, it's very useful and greatly simplifies creation of cleaner and consistent URLs in your application. The post parsing mechanism is totally transparent - you don't have to do anything to make this work. No changes are required other than making sure that the application's INI file is set.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/k0PExXAxn2iRS0o_wZITcYnQd0A/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/k0PExXAxn2iRS0o_wZITcYnQd0A/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/k0PExXAxn2iRS0o_wZITcYnQd0A/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/k0PExXAxn2iRS0o_wZITcYnQd0A/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=wLrKDpocnxQ:GwUNHELhtjA:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=wLrKDpocnxQ:GwUNHELhtjA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=wLrKDpocnxQ:GwUNHELhtjA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=wLrKDpocnxQ:GwUNHELhtjA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=wLrKDpocnxQ:GwUNHELhtjA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=wLrKDpocnxQ:GwUNHELhtjA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=wLrKDpocnxQ:GwUNHELhtjA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=wLrKDpocnxQ:GwUNHELhtjA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=wLrKDpocnxQ:GwUNHELhtjA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=wLrKDpocnxQ:GwUNHELhtjA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~4/wLrKDpocnxQ" height="1" width="1"/&gt;</description>
     <feedburner:origLink>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=886</feedburner:origLink></item>
     <item>
			<title>Global Values in Web Connection</title>
			<pubDate>Fri, 24 Feb 2012 06:04:00 GMT</pubDate>
			<guid isPermaLink="false">885_20120223</guid>
			<link>http://feedproxy.google.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~3/aO1fUoPE34w/ShowEntry.blog</link>
			<dc:creator>Rick Strahl</dc:creator>
			<comments>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=885#Feedback</comments>
			<slash:comments>1</slash:comments>
			<description>&lt;p&gt;Here's a question that comes up quite frequently about Web Connection: &lt;em&gt;How do I create and manage global variables effectively in a Web Connection application?&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Web Connection is somewhat unique in terms of Web back end solutions in that it actually has a dedicated server component and so has some 'state' - server state - that persists between individual requests. There are a number of ways that you can store 'global' data in a Web Connection instance:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;PUBLIC variables &lt;/li&gt;    &lt;li&gt;Properties on the wwServer instance &lt;/li&gt;    &lt;li&gt;The wwServer::oGlobals Property &lt;/li&gt;    &lt;li&gt;The wwServer::oResources Dictionary &lt;/li&gt;    &lt;li&gt;The wwServer::oCache Dictionary &lt;!--EndFragment--&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;But before we delve into the details of each of these mechanism it's important to understand what 'global' means in the context of a Web Connection application.&lt;/p&gt;  &lt;h3&gt;Global scope in Web Connection&lt;/h3&gt;  &lt;p&gt;Every Web Connection application starts out with one or more server instances that stick around as long as the instance is running. An instance is always tied to a specific EXE or DLL: The FoxPro IDE in development mode, a standalone FoxPro EXE when running in deployed file mode, or as COM EXE or DLL in COM mode.&lt;/p&gt;  &lt;p&gt; In file mode this means the instance is running sitting on a READ EVENTS loop, in COM mode it means the COM instance instantiated by the client IS the actual server instance. In COM mode (both ISAPI and .NET and EXE or DLL modes) Web Connection runs on a maintained pool of instances that are managed so these instances actually stay alive as long as the server instance is live.&lt;/p&gt;  &lt;p&gt;The important point here is that each EXE or DLL loaded instance it's its own silo of data that is separate from another instance. So while you can create global data using any of the mechanisms used in the list above, they are global only within the context of the current instance. Each Web Connection server has its own instance of global data - there's no in memory sharing between instances. The only way you can share data between instances is to store data to a database, disk or some other inter-process communication mechanism.&lt;/p&gt;  &lt;p&gt;That said, it's still quite useful to have global data in an application. Global data is good for resources that are expensive to load up repeatedly. For instance SQL Server connections are slow to connect each time, but very fast once open and already connected so it makes sense to store a SQL connection globally so it can be used across multiple requests. Other objects like COM components or any sort of cached memory based data also qualifies.&lt;/p&gt;  &lt;h3&gt;How Web Connection Instances are loaded&lt;/h3&gt;  &lt;p&gt;Web Connection instances are tied directly to a wwServer instance. In File Mode an instance of your wwServer subclass is created in the startup code in YourAppMain.prg which looks like this:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;   &lt;span class="rem"&gt;*** Load the Web Connection class libraries&lt;/span&gt;
   &lt;span class="kwrd"&gt;DO&lt;/span&gt; WCONNECT
 
   &lt;span class="rem"&gt;*** Load the server - wc3DemoServer class below&lt;/span&gt;
   goWCServer = &lt;span class="kwrd"&gt;CREATE&lt;/span&gt;(&lt;span class="str"&gt;&amp;quot;wcDemoServer&amp;quot;&lt;/span&gt;)
 
   &lt;span class="kwrd"&gt;IF&lt;/span&gt; !goWCServer.lDebugMode
         &lt;span class="kwrd"&gt;SET&lt;/span&gt; &lt;span class="kwrd"&gt;DEBUG&lt;/span&gt; &lt;span class="kwrd"&gt;OFF&lt;/span&gt;
         &lt;span class="kwrd"&gt;SET&lt;/span&gt; &lt;span class="kwrd"&gt;STATUS&lt;/span&gt; &lt;span class="kwrd"&gt;BAR&lt;/span&gt; &lt;span class="kwrd"&gt;OFF&lt;/span&gt;
         &lt;span class="kwrd"&gt;SET&lt;/span&gt; DEVELOP &lt;span class="kwrd"&gt;OFF&lt;/span&gt;
         &lt;span class="kwrd"&gt;SET&lt;/span&gt; &lt;span class="kwrd"&gt;RESOURCE&lt;/span&gt; &lt;span class="kwrd"&gt;OFF&lt;/span&gt;
         &lt;span class="kwrd"&gt;SET&lt;/span&gt; &lt;span class="kwrd"&gt;SYSMENU&lt;/span&gt; &lt;span class="kwrd"&gt;OFF&lt;/span&gt;
   &lt;span class="kwrd"&gt;ENDIF&lt;/span&gt;
 
                   
   &lt;span class="kwrd"&gt;IF&lt;/span&gt; &lt;span class="kwrd"&gt;TYPE&lt;/span&gt;(&lt;span class="str"&gt;&amp;quot;goWCServer&amp;quot;&lt;/span&gt;)#&lt;span class="str"&gt;&amp;quot;O&amp;quot;&lt;/span&gt;
      =&lt;span class="kwrd"&gt;MessageBox&lt;/span&gt;(&lt;span class="str"&gt;&amp;quot;Unable to load Web Connection Server&amp;quot;&lt;/span&gt;,;
         MB_ICONEXCLAMATION,&lt;span class="str"&gt;&amp;quot;Web Connection Error&amp;quot;&lt;/span&gt;)
      &lt;span class="kwrd"&gt;RETURN&lt;/span&gt;
   &lt;span class="kwrd"&gt;ENDIF&lt;/span&gt;
   
   &lt;span class="rem"&gt;*** Make the server live - Show puts the server online and in polling mode&lt;/span&gt;
   &lt;span class="kwrd"&gt;READ&lt;/span&gt; &lt;span class="kwrd"&gt;EVENTS&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The instance is created which loads the server instance and the server form (if enabled) and then pops into a READ EVENTS which keeps the server alive.&lt;/p&gt;

&lt;p&gt;In COM Mode the startup code goes away and the server instance is directly created via COM:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;loServer = &lt;span class="kwrd"&gt;CREATEOBJECT&lt;/span&gt;(&lt;span class="str"&gt;&amp;quot;wcDemo.wcDemoServer&amp;quot;&lt;/span&gt;)&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;loServer2 = &lt;span class="kwrd"&gt;CREATEOBJECT&lt;/span&gt;(&lt;span class="str"&gt;&amp;quot;wcDemo.wcDemoServer&amp;quot;&lt;/span&gt;)&lt;/pre&gt;

&lt;p&gt;The server can be started as an EXE or a DLL, but the behavior is the same. If I create multiple instances like above I can set properties on each and they are treated independently. Any PUBLIC data in each of these servers too are completely independent of each other. &lt;/p&gt;

&lt;h3&gt;Don't treat Global data like you do in Desktop Application&lt;/h3&gt;

&lt;p&gt;A common misconception for newbies to Web development is that you can use PUBLIC variables or even global cursor to persist data on a per user basis. Unlike desktop applications, which are typically tied to a specific user, Web applications serve requests for many users. Each Web Connection instance isn't tied to a specific user so anytime a request comes in it can come from any user that's using the system. If multiple instances are running the same user may not even come back the same instance in two consecutive requests.&lt;/p&gt;

&lt;p&gt;In short, global data for user data storage - both memory or using temporary cursors - in Web applications is a terrible idea in most cases. The exception is if you decide on some useful naming scheme to do but even then persistence across requests should be avoided whenever possible.&lt;/p&gt;

&lt;p&gt;Global scope then is only really useful for storing things that truly are application wide and preferably should only be used for things that really require it. Typically this means slow to load operations (like SQL connection loading for example) or pre-loading of data structures that can then be more easily reused later.&lt;/p&gt;

&lt;h3&gt;Storing Global Data in Web Connection&lt;/h3&gt;

&lt;p&gt;Let's look at the different approaches available from least desirable to more desirable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PUBLIC: Avoid whenever possible!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In desktop applications PUBLIC variables are an easy (if frowned upon) mechanism for storing global data and this mechanism still works in Web Connection. However, due to the possibility of scope naming conflicts and the inability to effectively manage PUBLIC variables it's not a good idea to use them.&lt;/p&gt;

&lt;p&gt;That said, some of Web Connection's internals actually use PUBLIC vars. Some library functions create global cached instances of objects that can be reused using PUBLIC. These objects use PUBLIC because they are generic and can be used outside of Web Connection (for example GetwwDotNetBridge() or GetwwRegEx()). Each of these functions create PUBLIC instances with __ prefixes to minimize naming conflicts and are used to cache resources that are expensive to create.&lt;/p&gt;

&lt;p&gt;In general application development (outside of libraries) I otherwise can't see any good reason to use PUBLIC variables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Properties on the Web Connection wwServer Instance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A Web Connection server instance is defined by its wwServer subclass implementation. This is the server class and the class that persists through the lifetime of the server instance. It has state and remains active through potentially many requests until it is shut down through the Web Connection administration interface or by IIS when you restart the Web Server or otherwise recycle an Application Pool.&lt;/p&gt;

&lt;p&gt;A server class definition looks like this:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;**************************************************************&lt;/span&gt;
&lt;span class="rem"&gt;****          YOUR SERVER CLASS DEFINITION                 ***&lt;/span&gt;
&lt;span class="rem"&gt;**************************************************************&lt;/span&gt;
&lt;span class="kwrd"&gt;DEFINE&lt;/span&gt; &lt;span class="kwrd"&gt;CLASS&lt;/span&gt; wcDemoServer AS WWC_SERVER OLEPUBLIC
&lt;span class="rem"&gt;*************************************************************&lt;/span&gt;&amp;#160; &lt;br /&gt;&lt;br /&gt;oMyProperty = .&lt;span class="kwrd"&gt;NULL&lt;/span&gt;.
â€¦&lt;/pre&gt;

&lt;p&gt;and you can create any number of custom properties on your server instance.&lt;/p&gt;

&lt;p&gt;The server is always available either via a global variable called &lt;em&gt;goWCServer&lt;/em&gt;, or via the &lt;em&gt;Process.oServer&lt;/em&gt; or simple &lt;em&gt;Server&lt;/em&gt; variables inside of actual request processing in a wwProcess request or Web Control Framework page . If you create a custom property on wwServer and you want to access it in a process class or Web Control page you can always use:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;Server.oMyProperty.DoSomeThing()&lt;/pre&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;font color="#0000ff"&gt;this&lt;/font&gt;.oServer.oMyProperty.DoSomeThing()&lt;/pre&gt;

&lt;p&gt;Using wwServer instance properties works and reasonably clean, but if you are running in COM mode, anytime you add a property to your class the ClassIds change for your COM server. This means you have to re-register your COM object on the server, which is a bit of a pain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;wwServer.oGlobal &lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In order to avoid the COM re-registering issue you can use the &lt;a href="http://www.west-wind.com/webconnection/docs?page=_3fu0m6aiy.htm" target="_blank"&gt;wwServer.oGlobal&lt;/a&gt; property and dynamically add properties at runtime. This object is merely an instance of a CUSTOM class attached to wwServer for the sole purpose of allowing you to hang new objects off it. To use it in code you can simply do:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;this&lt;/span&gt;.oGlobal.&lt;span class="kwrd"&gt;AddProperty&lt;/span&gt;(&lt;span class="str"&gt;&amp;quot;oMyProperty&amp;quot;&lt;/span&gt;,&lt;span class="kwrd"&gt;CREATEOBJECT&lt;/span&gt;(&lt;span class="str"&gt;&amp;quot;MyObject&amp;quot;&lt;/span&gt;))&lt;/pre&gt;

&lt;p&gt;This adds a property to the oGlobal instance which you can then use anywhere in your application:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;this&lt;/span&gt;.oGlobal.oMyProperty.DoSomething()&lt;/pre&gt;

&lt;p&gt;There's nothing magical about this of course - it uses only VFP's native dynamic language features of runtime type extension. It does however sidestep the COM registration issue.&lt;/p&gt;

&lt;p&gt;If you'd rather not use the .AddProperty() method at runtime and instead use a separate object that defines properties explicitly you can do that simply by assigning the oGlobal instance at runtime in OnInit() or OnLoad() of the server event.&lt;/p&gt;

&lt;p&gt;For example, here I create a custom MyGlobalsContainerClass instance and assign it to wwServer.oGlobal and then use the custom class' configuration property later in code:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;FUNCTION&lt;/span&gt; OnLoad()
 
&lt;span class="kwrd"&gt;this&lt;/span&gt;.oGlobal = &lt;span class="kwrd"&gt;CREATEOBJECT&lt;/span&gt;(&lt;span class="str"&gt;&amp;quot;MyGlobalsContainerClass&amp;quot;&lt;/span&gt;)
&lt;span class="kwrd"&gt;this&lt;/span&gt;.oGlobal.Configuration  = &lt;span class="kwrd"&gt;CREATEOBJECT&lt;/span&gt;(&lt;span class="str"&gt;&amp;quot;StoreConfig&amp;quot;&lt;/span&gt;) 
 
&lt;span class="kwrd"&gt;ENDFUNC&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Note wwServer.oGlobal was introduced in Web Connection 5.62. In version prior you can simply add an .oGlobals property to your server class:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;DEFINE&lt;/span&gt; &lt;span class="kwrd"&gt;CLASS&lt;/span&gt; wcDemoServer AS WWC_SERVER OLEPUBLIC&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;strong&gt;oGlobal = &lt;span class="kwrd"&gt;null&lt;/span&gt;
&lt;/strong&gt;&amp;#160; &lt;span class="kwrd"&gt;FUNCTION&lt;/span&gt; OnInit()
&lt;strong&gt;&lt;span class="kwrd"&gt;this&lt;/span&gt;.oGlobal = &lt;span class="kwrd"&gt;CREATEOBJECT&lt;/span&gt;(&lt;span class="str"&gt;&amp;quot;Custom&amp;quot;&lt;/span&gt;)&lt;/strong&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;strong&gt;â€¦&lt;/strong&gt;
&lt;span class="kwrd"&gt;ENDFUNC&lt;/span&gt;
â€¦&amp;#160;&amp;#160; &lt;span class="kwrd"&gt;ENDFUNC&lt;/span&gt;&lt;/pre&gt;



&lt;p&gt;which is pretty much all that Web Connection does internally in the later versions.&lt;/p&gt;

&lt;p&gt;Note that you can also add properties directly to the server object. wwServer derives from RELATION so it doesn't have an .AddProperty() method but you can use the ADDPROPERTY() function:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;ADDPROPERTY&lt;/span&gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt;,&lt;span class="str"&gt;&amp;quot;oMyProperty&amp;quot;&lt;/span&gt;,&lt;span class="kwrd"&gt;CREATEOBJECT&lt;/span&gt;(&lt;span class="str"&gt;&amp;quot;MyObject&amp;quot;&lt;/span&gt;))
&lt;span class="kwrd"&gt;this&lt;/span&gt;.oMyProperty.DoSomething()&lt;/pre&gt;

&lt;p&gt;Although this works just as well as the previous example maybe with slightly simpler syntax for the resulting object, I prefer using the oGlobal object instead as it is clearer what's happening. Both dynamic adds avoid COM object re-registration, though, so the choice is purely a preference.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;wwServer.oResources&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;wwServer also has an &lt;a href="http://www.west-wind.com/webconnection/docs?page=_3fu0me96s.htm" target="_blank"&gt;wwServer.oResources&lt;/a&gt; dictionary of type &lt;a href="http://west-wind.com/webconnection/docs/?page=_1o11fbxpb.htm" target="_blank"&gt;wwNameValueCollection&lt;/a&gt;. Basically this is a memory based dictionary that can hold any kind of variable including objects. So rather than actually adding properties to a class you can add and access these global values using a simple dictionary type syntax. &lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;this&lt;/span&gt;.oResources.&lt;span class="kwrd"&gt;Add&lt;/span&gt;(&lt;span class="str"&gt;&amp;quot;MyProperty&amp;quot;&lt;/span&gt;,&lt;span class="kwrd"&gt;CREATEOBJECT&lt;/span&gt;(&lt;span class="str"&gt;&amp;quot;MyObject&amp;quot;&lt;/span&gt;)&lt;/pre&gt;

&lt;p&gt;To use the resource entry you can then this from within Web Connection code.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;loMyObject = Server.oResources.Item(&lt;span class="str"&gt;&amp;quot;MyProperty&amp;quot;&lt;/span&gt;)
loMyObject.DoSomething()&lt;/pre&gt;

&lt;p&gt;The retrieval and usage syntax requires an intermediary since FoxPro doesn't allow for executing methods of return values directly, but otherwise the behavior is very similar to the approach using custom properties. The thing that's nice about the dictionary is that your object structure doesn't change at all and you can easily iterate over all items in the resource dictionary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;wwServer.oCache Global Caching&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On a somewhat related but not directly relevant note there's also the wwServer::oCache object. This &lt;a href="http://www.west-wind.com/webconnection/docs?page=_1190uuswk.htm" target="_blank"&gt;wwCache&lt;/a&gt; object allows storing string values for a specified expiration time. It stores data in a cursor or - optionally - in a fixed table that can be accessed by multiple instances. wwCache is limited to string values. Although the class is meant for caching you can effectively hijack it as a long term object store by setting a very long timeout for the cache expiry. If you use a fixed filename the cache persists to a table that can in fact work across instances and can survive an instance shutdown and startup. &lt;/p&gt;

&lt;p&gt;To add an item to the cache from the server class:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;this&lt;/span&gt;.oCache.AddItem(&lt;span class="str"&gt;&amp;quot;RssFeedOutput&amp;quot;&lt;/span&gt;,lcRssFeedOutput,9999999)&lt;/pre&gt;

&lt;p&gt;and to read it back in a process class:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;Server.oCache.GetItem(&amp;quot;RssFeedOutput)&lt;/pre&gt;

&lt;p&gt;Cache is interesting, but it's somewhat limited in that it works only with strings unlike all the previous mechanisms which can store values and objects. Still it might be useful for some scenarios that require global data/state to be persisted and it is the only option that allows multiple instances to share data from within the framework.&lt;/p&gt;

&lt;h3&gt;Summary&lt;/h3&gt;

&lt;p&gt;There are a number of ways to store global variables in Web Connection which is somewhat unique for Web based environments. But just because you can doesn't mean that you should. Always be very clear about why you need to store data or objects globally and think long and hard about it. Global data consumes resources on the server and it's resources that always stay loaded. If you really need those resources frequently then it makes sense to have it stored globally. But if these resources are rarely used or they are not expensive to load up in the first place it might be easier and more maintainable to simply create them as needed.&lt;/p&gt;

&lt;p&gt;There's little reason to use PUBLIC variables in Web Connection applications. Take advantage of the provided global stores from object properties hanging off the wwServer instance to the wwServer.oResources dictionary or if you're dealing with strings possibly the wwServer.oCache object. Lots of options abound. &lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/RxYmuVs3FL3k-FI964sEcP2LsFQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/RxYmuVs3FL3k-FI964sEcP2LsFQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/RxYmuVs3FL3k-FI964sEcP2LsFQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/RxYmuVs3FL3k-FI964sEcP2LsFQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=aO1fUoPE34w:L10GMATqAGs:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=aO1fUoPE34w:L10GMATqAGs:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=aO1fUoPE34w:L10GMATqAGs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=aO1fUoPE34w:L10GMATqAGs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=aO1fUoPE34w:L10GMATqAGs:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=aO1fUoPE34w:L10GMATqAGs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=aO1fUoPE34w:L10GMATqAGs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=aO1fUoPE34w:L10GMATqAGs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=aO1fUoPE34w:L10GMATqAGs:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=aO1fUoPE34w:L10GMATqAGs:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~4/aO1fUoPE34w" height="1" width="1"/&gt;</description>
     <feedburner:origLink>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=885</feedburner:origLink></item>
     <item>
			<title>Creating Gravatar Web Image Avatars in FoxPro</title>
			<pubDate>Thu, 2 Feb 2012 22:52:27 GMT</pubDate>
			<guid isPermaLink="false">884_20120202</guid>
			<link>http://feedproxy.google.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~3/LtWtXJ0fCkM/ShowEntry.blog</link>
			<dc:creator>Rick Strahl</dc:creator>
			<comments>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=884#Feedback</comments>
			<slash:comments>2</slash:comments>
			<description>&lt;p&gt;&lt;a href="http://gravatar.com/" target="_blank"&gt;Gravatar.com&lt;/a&gt; is a great and very popular Web service based way to associate an image with user accounts that are based on email addresses. It's easy to use and can provide a nice touch of personalization with very little effort to just about any Web application that uses email addresses for users. This post shows how you can use Gravatar from within your FoxPro based applications.&lt;/p&gt;  &lt;p&gt;I recently restyled my &lt;a href="http://www.west-wind.com/wwThreads/" target="_blank"&gt;West Wind Message Board support site&lt;/a&gt; and one of things that I think makes the messages look a little more interesting and personal is having an avatar - an image - associated with users. But rather than asking users to upload images and storing them on my servers, I opted to use Gravatar which is a Web based service that can be used in many applications and is supported by a large number of popular Web sites already. Ultimately it's a better choice for users who only have to sign up once to associate an email address with a Gravatar to be used on many sites.&lt;/p&gt;  &lt;p&gt;Here's what the Gravatar image looks like on a message board message:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.west-wind.com/wconnect/weblog/imageContent/2012/Windows-Live-Writer/Gravatar-Images-in-FoxPro_B5AC/Gravatar_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Gravatar" border="0" alt="Gravatar" src="http://www.west-wind.com/wconnect/weblog/imageContent/2012/Windows-Live-Writer/Gravatar-Images-in-FoxPro_B5AC/Gravatar_thumb.png" width="359" height="256" /&gt;&lt;/a&gt;&amp;#160; &lt;br /&gt;The Gravatar service&amp;#160; simply returns an an image for a given email address and some other parameters that are encoded and point at the Gravatar.com site. As a developer you configure Gravatar by creating a URL and embedding that URL into an &amp;lt;img&amp;gt; control's &lt;em&gt;src&lt;/em&gt; attribute.&lt;/p&gt;  &lt;p&gt;Above you can see the image that is associated with my Email address. The cool thing about Gravatar - if they have a Gravatar account already - is that once users have provided an email address they don't have to do anything else to associate their gravatar image with your application. If they have a gravatar configured the image is shown. If not, a default image is shown.&lt;/p&gt;  &lt;p&gt;If an email address is sent to Gravatar that doesn't exist you can either provide another URL to an alternate image (some sort of default that's appropriate for your app) or you can let Gravatar serve it's default icon which looks like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.west-wind.com/wconnect/weblog/imageContent/2012/Windows-Live-Writer/Gravatar-Images-in-FoxPro_B5AC/GravatarDefault_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="GravatarDefault" border="0" alt="GravatarDefault" src="http://www.west-wind.com/wconnect/weblog/imageContent/2012/Windows-Live-Writer/Gravatar-Images-in-FoxPro_B5AC/GravatarDefault_thumb.png" width="378" height="249" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;How it works&lt;/h3&gt;  &lt;p&gt;The Gravatar service works by calling a URL on their site and providing a few known parameters. An URL to retrieve an email address looks something like this:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://www.gravatar.com/avatar/d6ec6092141a8649fe9d81527569a4c0?s=80&amp;amp;r=r" href="http://www.gravatar.com/avatar/a4ec5092141a8649fe9d81527569a4c0?s=80&amp;amp;r=r"&gt;http://www.gravatar.com/avatar/a4ec5092141a8649fe9d81527569a4c0?s=80&amp;amp;r=r&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;In an image control:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;img &lt;/span&gt;&lt;span style="color: red"&gt;src&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;&lt;a title="http://www.gravatar.com/avatar/d6ec6092141a8649fe9d81527569a4c0?s=80&amp;amp;r=r" href="http://www.gravatar.com/avatar/a4ec5092141a8649fe9d81527569a4c0?s=80&amp;amp;r=r"&gt;http://www.gravatar.com/avatar/a4ec5092141a8649fe9d81527569a4c0?s=80&amp;amp;r=&lt;/a&gt;&amp;quot; &lt;br /&gt;&lt;/span&gt;&lt;span style="color: red"&gt;     class=&amp;quot;gravatar&amp;quot;&lt;/span&gt;&lt;span style="color: blue"&gt; &lt;br /&gt;     &lt;/span&gt;&lt;span style="color: red"&gt;alt&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;Gratar Image based on email address&amp;quot; /&amp;gt;
&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;The components you need to send to get a Gravatar image are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The Email Address encoded with an MD5 Hash&lt;/li&gt;

  &lt;li&gt;An image size&lt;/li&gt;

  &lt;li&gt;A default image if the email address is not registered with &lt;/li&gt;

  &lt;li&gt;A rating for the image (g, pg, r, x)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've created a small reusable function that helps create Gravatar images in FoxPro. Using the function you can do:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: black"&gt;? &lt;/span&gt;&lt;span style="color: black"&gt;GravatarLink&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;rstrahl@west-wind.com&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;80&lt;/span&gt;&lt;span style="color: black"&gt;) 
? &lt;/span&gt;&lt;span style="color: black"&gt;GravatarLink&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;invalid@west-wind.com&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;60&lt;/span&gt;&lt;span style="color: black"&gt;,,&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Here's the code for the GravatarLink function:&lt;/p&gt;

&lt;pre class="code"&gt;************************************************************************
*  GravatarLink
****************************************
***  Function: Creates an image URL for a given email address
***            that is registered with Gravatar.com.
***
***            Gravatar is a very popular avatar service that
***            requires only an email address to share a picture.
***            Used on many web sites so once you sign up your
***            picture will be used on many sites.
***    Assume: 
***      Pass: lcEmail - Email Address
***            lnSize - Image Size (square) 60-80 is usually good
***            lcDefaultImage - Url to an image if no match is found
***                             for email. Empty shows Gravatar's default
***            lcRating - g, pg, r, x   (Default: pg)
***    Return: URL to the Gravatar image
************************************************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;GravatarLink&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcEmail&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;lnSize&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;lcDefaultImage&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;lcRating&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;LOCAL &lt;/span&gt;&lt;span style="color: black"&gt;lcDefaultImage

&lt;/span&gt;&lt;span style="color: blue"&gt;IF EMPTY&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lnSize&lt;/span&gt;&lt;span style="color: black"&gt;)
   &lt;/span&gt;&lt;span style="color: black"&gt;lnSize &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;80
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF

IF &lt;/span&gt;&lt;span style="color: black"&gt;!&lt;/span&gt;&lt;span style="color: blue"&gt;EMPTY&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcEmail&lt;/span&gt;&lt;span style="color: black"&gt;)
    &lt;/span&gt;&lt;span style="color: black"&gt;lcHash &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;LOWER&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;STRCONV&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;HashMd5&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcEmail&lt;/span&gt;&lt;span style="color: black"&gt;),&lt;/span&gt;&lt;span style="color: black"&gt;15&lt;/span&gt;&lt;span style="color: black"&gt;))
&lt;/span&gt;&lt;span style="color: blue"&gt;ELSE
  &lt;/span&gt;&lt;span style="color: black"&gt;lcHash &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;quot;
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF
IF EMPTY&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcDefaultImage&lt;/span&gt;&lt;span style="color: black"&gt;)
   &lt;/span&gt;*** Gravatar default image displays
   &lt;span style="color: black"&gt;lcDefaultImage &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;quot;
&lt;/span&gt;&lt;span style="color: blue"&gt;ELSE
   &lt;/span&gt;&lt;span style="color: black"&gt;lcDefaultImage &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;amp;d=&amp;quot; &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;UrlEncode&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcDefaultImage&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF   
IF EMPTY&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcRating&lt;/span&gt;&lt;span style="color: black"&gt;)
   &lt;/span&gt;&lt;span style="color: black"&gt;lcRating &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;pg&amp;quot;
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF   

&lt;/span&gt;&lt;span style="color: black"&gt;lcUrl &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;http://www.gravatar.com/avatar/&amp;quot; &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;lcHash &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;?&amp;quot; &lt;/span&gt;&lt;span style="color: black"&gt;+;
       &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;s=&amp;quot; &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: blue"&gt;TRANSFORM&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lnSize&lt;/span&gt;&lt;span style="color: black"&gt;) +;
       &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;amp;r=&amp;quot; &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;lcRating &lt;/span&gt;&lt;span style="color: black"&gt;+;
       &lt;/span&gt;&lt;span style="color: black"&gt;lcDefaultImage

&lt;/span&gt;&lt;span style="color: blue"&gt;RETURN &lt;/span&gt;&lt;span style="color: black"&gt;lcUrl
&lt;/span&gt;* GravatarLink&lt;/pre&gt;



&lt;p&gt;The code is pretty straight forward - it basically builds up a URL as a string and adds the components provided by the parameters. The trickiest part of this is the MD5 encoding of the Email address. The MD5 hash creates a binary value which is then turned into a HexBinary string with STRCONV().&lt;/p&gt;

&lt;p&gt;In order to encode the email address as an MD5 hash I use the following routine &lt;a href="http://fox.wikis.com/wc.dll?fox~vfpmd5hashfunction" target="_blank"&gt;based on the content from the FoxPro Wiki&lt;/a&gt; a long while back:&lt;/p&gt;

&lt;pre class="code"&gt;************************************************************************
* wwAPI :: HashMD5
****************************************
***  Function: retrieved from the FoxWiki
***            &lt;span style="color: black"&gt;http://fox.wikis.com/wc.dll?fox~vfpmd5hashfunction
&lt;/span&gt;***    Assume: Self standing function - not part of wwAPI class
***      Pass: Data to encrypt
***    Return: 
************************************************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;HashMD5&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;tcData&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** #include &amp;quot;c:\program files\microsoft visual foxpro 8\ffc\wincrypt.h&amp;quot;
&lt;span style="color: black"&gt;#&lt;/span&gt;&lt;span style="color: blue"&gt;DEFINE &lt;/span&gt;&lt;span style="color: black"&gt;dnPROV_RSA_FULL           &lt;/span&gt;&lt;span style="color: black"&gt;1
&lt;/span&gt;&lt;span style="color: black"&gt;#&lt;/span&gt;&lt;span style="color: blue"&gt;DEFINE &lt;/span&gt;&lt;span style="color: black"&gt;dnCRYPT_VERIFYCONTEXT     &lt;/span&gt;&lt;span style="color: black"&gt;0xF0000000

&lt;/span&gt;&lt;span style="color: black"&gt;#&lt;/span&gt;&lt;span style="color: blue"&gt;DEFINE &lt;/span&gt;&lt;span style="color: black"&gt;dnALG_CLASS_HASH         &lt;/span&gt;&lt;span style="color: blue"&gt;BITLSHIFT&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;4&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;13&lt;/span&gt;&lt;span style="color: black"&gt;)
#&lt;/span&gt;&lt;span style="color: blue"&gt;DEFINE &lt;/span&gt;&lt;span style="color: black"&gt;dnALG_TYPE_ANY          &lt;/span&gt;&lt;span style="color: black"&gt;0
&lt;/span&gt;&lt;span style="color: black"&gt;#&lt;/span&gt;&lt;span style="color: blue"&gt;DEFINE &lt;/span&gt;&lt;span style="color: black"&gt;dnALG_SID_MD5           &lt;/span&gt;&lt;span style="color: black"&gt;3
&lt;/span&gt;&lt;span style="color: black"&gt;#&lt;/span&gt;&lt;span style="color: blue"&gt;DEFINE &lt;/span&gt;&lt;span style="color: black"&gt;dnCALG_MD5        &lt;/span&gt;&lt;span style="color: blue"&gt;BITOR&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;BITOR&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;dnALG_CLASS_HASH&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;dnALG_TYPE_ANY&lt;/span&gt;&lt;span style="color: black"&gt;),&lt;/span&gt;&lt;span style="color: black"&gt;dnALG_SID_MD5&lt;/span&gt;&lt;span style="color: black"&gt;)

#&lt;/span&gt;&lt;span style="color: blue"&gt;DEFINE &lt;/span&gt;&lt;span style="color: black"&gt;dnHP_HASHVAL              &lt;/span&gt;&lt;span style="color: black"&gt;0x0002  &lt;/span&gt;&amp;amp;&amp;amp; Hash value

&lt;span style="color: blue"&gt;LOCAL &lt;/span&gt;&lt;span style="color: black"&gt;lnStatus&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;lnErr&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;lhProv&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;lhHashObject&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;lnDataSize&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;lcHashValue&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;lnHashSize
lhProv &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0
&lt;/span&gt;&lt;span style="color: black"&gt;lhHashObject &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0
&lt;/span&gt;&lt;span style="color: black"&gt;lnDataSize &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;LEN&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;tcData&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;lcHashValue &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;REPLICATE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;CHR&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;0&lt;/span&gt;&lt;span style="color: black"&gt;), &lt;/span&gt;&lt;span style="color: black"&gt;16&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;lnHashSize &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;LEN&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcHashValue&lt;/span&gt;&lt;span style="color: black"&gt;)


&lt;/span&gt;&lt;span style="color: blue"&gt;DECLARE INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;GetLastError &lt;/span&gt;&lt;span style="color: black"&gt;;
   &lt;/span&gt;&lt;span style="color: blue"&gt;IN &lt;/span&gt;&lt;span style="color: black"&gt;win32api &lt;/span&gt;&lt;span style="color: blue"&gt;AS &lt;/span&gt;&lt;span style="color: black"&gt;GetLastError

&lt;/span&gt;&lt;span style="color: blue"&gt;DECLARE INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;CryptAcquireContextA &lt;/span&gt;&lt;span style="color: black"&gt;;
   &lt;/span&gt;&lt;span style="color: blue"&gt;IN &lt;/span&gt;&lt;span style="color: black"&gt;WIN32API &lt;/span&gt;&lt;span style="color: blue"&gt;AS &lt;/span&gt;&lt;span style="color: black"&gt;CryptAcquireContext &lt;/span&gt;&lt;span style="color: black"&gt;;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;@&lt;/span&gt;&lt;span style="color: black"&gt;lhProvHandle&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;STRING &lt;/span&gt;&lt;span style="color: black"&gt;cContainer&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;STRING &lt;/span&gt;&lt;span style="color: black"&gt;cProvider&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;nProvType&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;nFlags

&lt;/span&gt;* load a crypto provider
&lt;span style="color: black"&gt;lnStatus &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;CryptAcquireContext&lt;/span&gt;&lt;span style="color: black"&gt;(@&lt;/span&gt;&lt;span style="color: black"&gt;lhProv&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;0&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;0&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;dnPROV_RSA_FULL&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;dnCRYPT_VERIFYCONTEXT&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;IF &lt;/span&gt;&lt;span style="color: black"&gt;lnStatus &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0
   &lt;/span&gt;&lt;span style="color: blue"&gt;THROW &lt;/span&gt;&lt;span style="color: black"&gt;GetLastError&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF

DECLARE INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;CryptCreateHash &lt;/span&gt;&lt;span style="color: black"&gt;;
   &lt;/span&gt;&lt;span style="color: blue"&gt;IN &lt;/span&gt;&lt;span style="color: black"&gt;WIN32API &lt;/span&gt;&lt;span style="color: blue"&gt;AS &lt;/span&gt;&lt;span style="color: black"&gt;CryptCreateHash &lt;/span&gt;&lt;span style="color: black"&gt;;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;hProviderHandle&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;nALG_ID&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;hKeyhandle&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;nFlags&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;@&lt;/span&gt;&lt;span style="color: black"&gt;hCryptHashHandle

&lt;/span&gt;* create a hash object that uses MD5 algorithm
&lt;span style="color: black"&gt;lnStatus &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;CryptCreateHash&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lhProv&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;dnCALG_MD5&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;0&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;0&lt;/span&gt;&lt;span style="color: black"&gt;, @&lt;/span&gt;&lt;span style="color: black"&gt;lhHashObject&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;IF &lt;/span&gt;&lt;span style="color: black"&gt;lnStatus &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0
   &lt;/span&gt;&lt;span style="color: blue"&gt;THROW &lt;/span&gt;&lt;span style="color: black"&gt;GetLastError&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF

DECLARE INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;CryptHashData &lt;/span&gt;&lt;span style="color: black"&gt;;
   &lt;/span&gt;&lt;span style="color: blue"&gt;IN &lt;/span&gt;&lt;span style="color: black"&gt;WIN32API &lt;/span&gt;&lt;span style="color: blue"&gt;AS &lt;/span&gt;&lt;span style="color: black"&gt;CryptHashData &lt;/span&gt;&lt;span style="color: black"&gt;;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;hHashHandle&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;STRING &lt;/span&gt;&lt;span style="color: black"&gt;@&lt;/span&gt;&lt;span style="color: black"&gt;cData&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;nDataLen&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;nFlags

&lt;/span&gt;* add the input data to the hash object
&lt;span style="color: black"&gt;lnStatus &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;CryptHashData&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lhHashObject&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;tcData&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;lnDataSize&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;0&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;IF &lt;/span&gt;&lt;span style="color: black"&gt;lnStatus &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0
   &lt;/span&gt;&lt;span style="color: blue"&gt;THROW &lt;/span&gt;&lt;span style="color: black"&gt;GetLastError&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF


DECLARE INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;CryptGetHashParam &lt;/span&gt;&lt;span style="color: black"&gt;;
   &lt;/span&gt;&lt;span style="color: blue"&gt;IN &lt;/span&gt;&lt;span style="color: black"&gt;WIN32API &lt;/span&gt;&lt;span style="color: blue"&gt;AS &lt;/span&gt;&lt;span style="color: black"&gt;CryptGetHashParam &lt;/span&gt;&lt;span style="color: black"&gt;;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;hHashHandle&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;nParam&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;STRING &lt;/span&gt;&lt;span style="color: black"&gt;@&lt;/span&gt;&lt;span style="color: black"&gt;cHashValue&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;@&lt;/span&gt;&lt;span style="color: black"&gt;nHashSize&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;nFlags

&lt;/span&gt;* retrieve the hash value, if caller did not provide enough storage (16 bytes for MD5)
* this will fail with dnERROR_MORE_DATA and lnHashSize will contain needed storage size
&lt;span style="color: black"&gt;lnStatus &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;CryptGetHashParam&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lhHashObject&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;dnHP_HASHVAL&lt;/span&gt;&lt;span style="color: black"&gt;, @&lt;/span&gt;&lt;span style="color: black"&gt;lcHashValue&lt;/span&gt;&lt;span style="color: black"&gt;, @&lt;/span&gt;&lt;span style="color: black"&gt;lnHashSize&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;0&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;IF &lt;/span&gt;&lt;span style="color: black"&gt;lnStatus &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0
   &lt;/span&gt;&lt;span style="color: blue"&gt;THROW &lt;/span&gt;&lt;span style="color: black"&gt;GetLastError&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF


DECLARE INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;CryptDestroyHash &lt;/span&gt;&lt;span style="color: black"&gt;;
   &lt;/span&gt;&lt;span style="color: blue"&gt;IN &lt;/span&gt;&lt;span style="color: black"&gt;WIN32API &lt;/span&gt;&lt;span style="color: blue"&gt;AS &lt;/span&gt;&lt;span style="color: black"&gt;CryptDestroyHash&lt;/span&gt;&lt;span style="color: black"&gt;;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;hKeyHandle

&lt;/span&gt;*** free the hash object
&lt;span style="color: black"&gt;lnStatus &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;CryptDestroyHash&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lhHashObject&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;IF &lt;/span&gt;&lt;span style="color: black"&gt;lnStatus &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0
   &lt;/span&gt;&lt;span style="color: blue"&gt;THROW &lt;/span&gt;&lt;span style="color: black"&gt;GetLastError&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF


DECLARE INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;CryptReleaseContext &lt;/span&gt;&lt;span style="color: black"&gt;;
   &lt;/span&gt;&lt;span style="color: blue"&gt;IN &lt;/span&gt;&lt;span style="color: black"&gt;WIN32API &lt;/span&gt;&lt;span style="color: blue"&gt;AS &lt;/span&gt;&lt;span style="color: black"&gt;CryptReleaseContext &lt;/span&gt;&lt;span style="color: black"&gt;;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;hProvHandle&lt;/span&gt;&lt;span style="color: black"&gt;, ;
   &lt;/span&gt;&lt;span style="color: blue"&gt;INTEGER &lt;/span&gt;&lt;span style="color: black"&gt;nReserved

&lt;/span&gt;*** release the crypto provider
&lt;span style="color: black"&gt;lnStatus &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;CryptReleaseContext&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lhProv&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;0&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;IF &lt;/span&gt;&lt;span style="color: black"&gt;lnStatus &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0
   &lt;/span&gt;&lt;span style="color: blue"&gt;THROW &lt;/span&gt;&lt;span style="color: black"&gt;GetLastError&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF

RETURN &lt;/span&gt;&lt;span style="color: black"&gt;lcHashValue
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;* HashMD5&lt;/pre&gt;

&lt;p&gt;With this function in place it's now a snap to embed Gravatar images into HTML based applications. In a Web Connection (or any other template/script based environment that uses Fox code) you can now simply do:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;img &lt;/span&gt;&lt;span style="color: red"&gt;src&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;&lt;/span&gt;&lt;span style="background: yellow"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;= &lt;/span&gt;GravatarLink(poUser.Email,80,,&amp;quot;pg&amp;quot;) &lt;span style="background: yellow"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;gravatar&amp;quot; /&amp;gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;And you're off to the races.&lt;/p&gt;

&lt;h3&gt;On the West Wind MessageBoard&lt;/h3&gt;

&lt;p&gt;If you're a user of the &lt;a href="http://www.west-wind.com/wwThreads/" target="_blank"&gt;West Wind Message Board&lt;/a&gt; I recommend you head over to Gravatar.com and hook up your Avatar image if you are interested in showing an image for any of your messages. Go ahead post a message, and see your Gravatar pop up. Once you have a Gravatar you may find that a lot of sites where you participate also already use Gravatar images so this will be useful in a lot of places beyond just the message board or your own applications.&lt;/p&gt;

&lt;p&gt;GravatarLink() is now also part of the wwUtils library in &lt;a href="http://west-wind.com/webconnection/" target="_blank"&gt;Web Connection&lt;/a&gt; and the &lt;a href="http://www.west-wind.com/WestwindClientTools.aspx"&gt;West Wind Client Tools&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/CFHYewNOffS4PgwHyVvJ8zzX23k/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/CFHYewNOffS4PgwHyVvJ8zzX23k/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/CFHYewNOffS4PgwHyVvJ8zzX23k/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/CFHYewNOffS4PgwHyVvJ8zzX23k/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=LtWtXJ0fCkM:9h0Jt00w9Ho:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=LtWtXJ0fCkM:9h0Jt00w9Ho:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=LtWtXJ0fCkM:9h0Jt00w9Ho:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=LtWtXJ0fCkM:9h0Jt00w9Ho:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=LtWtXJ0fCkM:9h0Jt00w9Ho:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=LtWtXJ0fCkM:9h0Jt00w9Ho:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=LtWtXJ0fCkM:9h0Jt00w9Ho:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=LtWtXJ0fCkM:9h0Jt00w9Ho:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=LtWtXJ0fCkM:9h0Jt00w9Ho:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=LtWtXJ0fCkM:9h0Jt00w9Ho:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~4/LtWtXJ0fCkM" height="1" width="1"/&gt;</description>
     <feedburner:origLink>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=884</feedburner:origLink></item>
     <item>
			<title>Transparent Bitmaps on Buttons and other Controls</title>
			<pubDate>Thu, 26 Jan 2012 22:19:19 GMT</pubDate>
			<guid isPermaLink="false">883_20120126</guid>
			<link>http://feedproxy.google.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~3/BDquaeASlbM/ShowEntry.blog</link>
			<dc:creator>Rick Strahl</dc:creator>
			<comments>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=883#Feedback</comments>
			<slash:comments>1</slash:comments>
			<description>&lt;p&gt;Overlayed bitmaps in FoxPro have always been a royal pain, but in order to make a UI that looks clean, getting some sort of transparency to work with FoxPro controls is pretty important. Although FoxPro supports most common image formats including GIF and PNG that support transparency, the transparency isn't supported everywhere within the product.&lt;/p&gt;  &lt;p&gt;Specifically the FoxPro Image control supports transparency of the various transparent image formats. If you load up an image control with a GIF or PNG file, the transparency is preserved and the image displays correctly.&lt;/p&gt;  &lt;p&gt;However, displaying transparent images on other controls that have a Picture property, unfortunately doesn't work as smoothly. Specifically, here's an example of what I've been struggling with, which is buttons with associated icons:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.west-wind.com/wconnect/weblog/imageContent/2012/Windows-Live-Writer/Transparent-Bitmaps-on-Buttons-and-other_C435/ataleoftwobuttons%5B6%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="ataleoftwobuttons[6]" border="0" alt="ataleoftwobuttons[6]" src="http://www.west-wind.com/wconnect/weblog/imageContent/2012/Windows-Live-Writer/Transparent-Bitmaps-on-Buttons-and-other_C435/ataleoftwobuttons%5B6%5D_thumb.png" width="325" height="51" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;The first button doesn't show transparency and looks terrible, while the second button properly shows transparency and appears like it should using one of the approaches mentioned below. Similar situation arises with other controls that have picture properties like OptionButton, Checkboxes. ComboBoxes and Listboxes as well, although it's less of a problem there because the background of lists tend to be white. As a matter of fact all container controls have a picture property and the same rules apply. &lt;/p&gt;  &lt;p&gt;By default only the Image control supports transparency properly for all GDI+ image formats.&lt;/p&gt;  &lt;p&gt;The good news is that with a bit of trickery you can get FoxPro to render transparent images. The bad news is that there are tradeoffs and extra work required to make it work properly.&lt;/p&gt;  &lt;h3&gt;Old School Transparency Support: BMP Image&lt;/h3&gt;  &lt;p&gt;GDI+ image support for non-BMP images is actually a relatively new feature in FoxPro. GDI+ support for graphics was introduced with Visual FoxPro 8. Prior to version 8 only BMP images were directly supported in the product and there are a couple of mechanisms used for handling transparency with BMPs.&lt;/p&gt;  &lt;p&gt;The most reliable way to get transparency in FoxPro involves &lt;a href="http://msdn.microsoft.com/en-us/library/2zw22dd5(v=vs.80).aspx" target="_blank"&gt;using BMP files and a matching BMP Mask file&lt;/a&gt;. The mask file basically holds black dots for each of the pixels that should display and white content for anything that should be transparent. As you might imagine creating MASK files is a pain and adds clutter to your image management - anytime the image changes the mask has to be changed too and keeping things in sync is terrible. To me this has always been a non-starter.&lt;/p&gt;  &lt;p&gt;You can also get transparency support with only BMP images. By default BMP images display white pixels as transparent, so as long as you can easily represent your transparent content as white it's easy to do. This is not always so cut and dried however because the image 'content' may also contain white pixels. In this case you can fill the white pixels with a slightly off white color like RGB(254,254,254). &lt;/p&gt;  &lt;p&gt;Both of these approaches are painful but they are very reliable. Once you got your image set up it always works without fail. But both approaches require that you at the very least convert them to BMP format and potentially tweak your images for transparency or by creating a mask.&lt;/p&gt;  &lt;h3&gt;Resource Loading in FoxPro&lt;/h3&gt;  &lt;p&gt;There's another approach that works in most situations because of a quirk in FoxPro that I just found out about last week. FoxPro loads images as resources and you can trick FoxPro by loading images with transparency by first loading them into an Image control which as mentioned earlier does support transparency. The trick is that you have to load the image into the image control BEFORE it gets loaded into a picture property of another control. The quirk is that FoxPro caches image data once loaded from a path, so loading it into an image control first caches the transparent image which then gets loaded in subsequent loads that reference the same disk image (or compiled in image resource).&lt;/p&gt;  &lt;p&gt;The image control has to only be loaded up and the control can then be released. The key is that this 'pre-load' has to happen BEFORE you load the same image into other controls. The image control doesn't need to stick around, so I use a small function that I only need to pass a file path to, create the Image control and set the picture property:&lt;/p&gt;  &lt;pre class="code"&gt;************************************************************************
*  LoadImageResource
****************************************
***  Function: Pre-load an image file so transparency is respected
***    Assume:
***      Pass:
***    Return:
************************************************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;LoadImageResource&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcFile&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;LOCAL &lt;/span&gt;&lt;span style="color: black"&gt;loImg &lt;/span&gt;&lt;span style="color: blue"&gt;as Image
&lt;/span&gt;&lt;span style="color: black"&gt;loImg &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;CREATEOBJECT&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;Image&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;loImg&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: blue"&gt;Picture &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;FULLPATH&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;bmps\search_small.png&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   LoadImageResource&lt;/pre&gt;

&lt;p&gt;When the function exits the Image control is released, but since the image was effectively loaded into the control the image is now cached inside of VFP's image cache. Now when you load an image that has been called with the function into a Picture property of another control like a button it will display GIF and PNG transparency properly.&lt;/p&gt;

&lt;p&gt;In an application I tend to have quite a few image resources I need to load up, so centralize one place when I do all the image pre-loading during startup. I create a function that I call from the application's startup, typically right after I display a startup splash screen.&lt;/p&gt;

&lt;p&gt;The method is simply a conglomeration of LoadImageResource() calls:&lt;/p&gt;

&lt;pre class="code"&gt;************************************************************************
*  LoadImageResources
****************************************
***  Function: Method is used to load up transparent images into
***            UI. This method should be called on startup
***    Assume:
***      Pass:
***    Return:
************************************************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;LoadImageResources&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;LOCAL &lt;/span&gt;&lt;span style="color: black"&gt;loImg &lt;/span&gt;&lt;span style="color: blue"&gt;as Image

&lt;/span&gt;&lt;span style="color: black"&gt;LoadImageResource&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;bmps\search_small.png&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;LoadImageResource&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;bmps\zipfile.gif&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;â€¦
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   LoadPictureResources&lt;/pre&gt;

&lt;p&gt;This is a simple approach that works fine and allows using PNG and GIF images with transparency on buttons and other controls.&lt;/p&gt;

&lt;h3&gt;Caveats with Preloading&lt;/h3&gt;

&lt;p&gt;In some instances however you can still end up with non-transparent resources. Basically FoxPro caches resources internally, but there are several ways that resources can get un-cached. Explicitly, if your code calls the CLEAR RESOURCES command anywhere, resources will get released and you'll lose any cached resources at that point. If you go back to a form with a transparent image on a control the image will display again with opaque background. Note that CLEAR RESOURCES is not affected by commands like CLEAR ALL or RELEASE ALL.&lt;/p&gt;

&lt;p&gt;Implicitly, FoxPro can on certain occasions also unload its image resources internally when memory is really low. This should be very rare but it's possible and I have seen occasions when this does occur. But it's really rare so it's probably OK to ignore that possibility. If you're concerned about this scenario you can either have some code that calls LoadImageResources() or something like it during certain key application points that fire occasionally to explicitly force reloading of the images, or you can load resources as needed everytime a given form is fired up. This will ensure that resources are always fresh, but keep in mind that this causes some extra overhead.&lt;/p&gt;

&lt;h3&gt;Summary&lt;/h3&gt;

&lt;p&gt;I sure wish this was easier to accomplish or more obvious. For the longest time I didn't even know this hack of image pre-loading. The safest solution is to use BMP files, but it's definitely way more convenient to use Web ready files like PNGs or GIFs that support transparency both for designing the icons and re-using them across applications and platforms (Web/Desktop as I do).&lt;/p&gt;

&lt;p&gt;Having to pre-load resources for transparent images in this fashion is a big hassle as opposed just loading up image resources directly. And worse it's an ugly hack that's impossible to discover on your own. I found a vague reference to this on a &lt;a href="http://www.tek-tips.com/viewthread.cfm?qid=1425832" target="_blank"&gt;message board message&lt;/a&gt; somewhere so it's even hard to search for. Hopefully this blog entry will help clarfiy the subject a little better, even if it's just for me to remember in the future. &lt;/p&gt;

&lt;p&gt;What really sucks about this problem is the fact that it DOES works with preloaded image resources. This seems to suggest that transparency actually works on controls but there's a small implementation detail in Visual FoxPro that prevents this from working all the time. It seems this would have been such a minor thing for the Fox team to fix and get working out of the box if the resources to do so had been there. But alas, we're stuck with a few minor and undiscoverable hacks. I take a hack over it not working at all which was what I thought until a week ago. &lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="http://weblogs.foxite.com/vfpimaging/archive/category/187.aspx" target="_blank"&gt;Cesar Chalom&lt;/a&gt;, &lt;a href="http://weblogs.foxite.com/joel_leach/" target="_blank"&gt;Joel Leach&lt;/a&gt;, &lt;a href="http://drfairday.blogspot.com/" target="_blank"&gt;Dragan Nedeljkovich&lt;/a&gt; for providing some ideas for this post and &lt;a href="http://www.tek-tips.com/viewthread.cfm?qid=1425832" target="_blank"&gt;Mike Lewis&lt;/a&gt; for providing the inspiration to look further into this and getting me to a working solution in &lt;a href="http://west-wind.com/wwhelp" target="_blank"&gt;Html Help Builder&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/d6cY5rq0mA1oP0MnX90RQD7QJq8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/d6cY5rq0mA1oP0MnX90RQD7QJq8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/d6cY5rq0mA1oP0MnX90RQD7QJq8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/d6cY5rq0mA1oP0MnX90RQD7QJq8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=BDquaeASlbM:4TSl_KvOQAw:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=BDquaeASlbM:4TSl_KvOQAw:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=BDquaeASlbM:4TSl_KvOQAw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=BDquaeASlbM:4TSl_KvOQAw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=BDquaeASlbM:4TSl_KvOQAw:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=BDquaeASlbM:4TSl_KvOQAw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=BDquaeASlbM:4TSl_KvOQAw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=BDquaeASlbM:4TSl_KvOQAw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=BDquaeASlbM:4TSl_KvOQAw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=BDquaeASlbM:4TSl_KvOQAw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~4/BDquaeASlbM" height="1" width="1"/&gt;</description>
     <feedburner:origLink>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=883</feedburner:origLink></item>
     <item>
			<title>How to work around Visual FoxPro's 16 Megabyte String Limit</title>
			<pubDate>Thu, 19 Jan 2012 10:56:39 GMT</pubDate>
			<guid isPermaLink="false">882_20120119</guid>
			<link>http://feedproxy.google.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~3/JXtaFmxZZaU/ShowEntry.blog</link>
			<dc:creator>Rick Strahl</dc:creator>
			<comments>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=882#Feedback</comments>
			<slash:comments>4</slash:comments>
			<description>&lt;p&gt;If you take a look at the Visual FoxPro documentation and the System Limits you find that FoxPro's string length limit is somewhere around ~16mb. The following is from the &lt;a href="http://msdn.microsoft.com/en-us/library/3kfd3hw9(v=vs.80).aspx" target="_blank"&gt;FoxPro Documentation&lt;/a&gt;:&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Maximum # of characters per character string or memory variable: 16,777,184&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Now 16mb seems like a lot of data, but in certain environments like Web applications it's not uncommon to send or receive data larger than 16 megs. In fact, last week I got a message from a user of our &lt;a href="http://www.west-wind.com/WestwindClientTools.aspx" target="_blank"&gt;Client Tools&lt;/a&gt; lamenting the fact that the HTTP Upload functionality does not allow for uploads larger than 16 megs. One of his applications is trying to occasionally upload rather huge files to a server using our &lt;a href="http://www.west-wind.com/webconnection/docs?page=_0rs0twgr6.htm" target="_blank"&gt;wwHttp class&lt;/a&gt;. At the time I did not have a good solution for him due to the 16meg limit.&lt;/p&gt;  &lt;h3&gt;What does the 16meg Limit really mean?&lt;/h3&gt;  &lt;p&gt;The FoxPro documentation actually is not quite accurate! You can actually get strings &lt;strong&gt;much&lt;/strong&gt; larger than 16megs into FoxPro. For example you can load up a huge file like the Office 2010 download from MSDN like this:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: black"&gt;lcFile &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;FILETOSTR&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;e:\downloads\en_office_professional_plus_2010_x86_515486.exe&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;)
? &lt;/span&gt;&lt;span style="color: blue"&gt;LEN&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcFile&lt;/span&gt;&lt;span style="color: black"&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The size of this string: 681,876,016 bytes or 681megs! Ok that's a little extreme :-) but to my surprise that worked just fine; you can load up a really huge string in VFP if you need to. But when you get over 16megs the behavior of strings changes and you can't do all the things you normally do with strings.&lt;/p&gt;

&lt;p&gt;Other operations do not work for example, the following which creates an 18meg string &lt;strong&gt;fails&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: black"&gt;lcString &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;REPLICATE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;1234567890&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;1800000&lt;/span&gt;&lt;span style="color: black"&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;with &lt;em&gt;&amp;quot;String is too long to fit&amp;quot;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;However the following which creates a 25 meg string &lt;strong&gt;does work&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: black"&gt;lcString &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;REPLICATE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;1234567890&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;1500000&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;lcString &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;lcString &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: blue"&gt;REPLICATE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;1234567890&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;1000000&lt;/span&gt;&lt;span style="color: black"&gt;)
? &lt;/span&gt;&lt;span style="color: blue"&gt;LEN&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcString&lt;/span&gt;&lt;span style="color: black"&gt;)  &amp;amp;&amp;amp; 25,000,000&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The following is almost identical except it copies the longer string to another string which &lt;strong&gt;does not work&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: black"&gt;lcString &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;REPLICATE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;1234567890&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;1500000&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;&lt;strong&gt;lcNewString&lt;/strong&gt; &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;lcString &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: blue"&gt;REPLICATE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;1234567890&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;1000000&lt;/span&gt;&lt;span style="color: black"&gt;) &lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;And that my friends is the real sticking point with large strings. You can create them, but once they get bigger than 16megs you can no longer assign them to a new variable. That might sound easy to avoid but it's actually tough to do. If you pass string to methods it's very likely that they are actually copied into temporary variables or added to another variable in a simulated buffer, and that is typically where large strings fail.&lt;/p&gt;

&lt;p&gt;So what can we learn from this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Doesn't Work:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Assigning a massive FoxPro string to another string fails &lt;/li&gt;

  &lt;li&gt;Some FoxPro commands like REPLICATE() can't create output larger than 16 megs &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Works:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Assigning a massive string from a file &lt;strong&gt;using FileToString() &lt;/strong&gt;works &lt;/li&gt;

  &lt;li&gt;Adding to the &lt;strong&gt;same large string&lt;/strong&gt; (lcOutput = lcOutput + &amp;quot; more text&amp;quot;) works and the string can grow &lt;/li&gt;

  &lt;li&gt;Calling methods that manipulate string work as long as the same string is assigned &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are some limitations but knowing that if you work with a single string instance that can grow large is actually good news. What this means is that if you're careful with how you use strings in FoxPro you can fairly easily get around the 16 meg string limit. &lt;/p&gt;

&lt;p&gt;This actually worked well for me in the wwHttp class and the POST issue for larger than 16meg &lt;strong&gt;files but not string&lt;/strong&gt;. Internally wwHttp uses a cPostBuffer property to hold the POST data. The failure was occuring in the send code which would copy the string to a temporary string and get the size, then pass that to the WinInet APIs. The fix for this was fairly easy: Rather than creating the temporary variables (which were redundant anyway) I simply used the class property directly throughout the code without any hand off and voila, now wwHttp supports POSTs for greater than 16 megs. &lt;/p&gt;

&lt;p&gt;The code I use is kinda ugly because it's doing lots of string concatenation to build up the Post buffer. Something along these lines like this excerpt from wwHttp::AddPostKey:&lt;/p&gt;

&lt;pre class="code"&gt;************************************************************************
* wwHTTP :: AddPostKey
*********************************
***  Function: Adds POST variables to the HTTP request
***    Assume: depends on nHTTPPostMode setting
***      Pass: 
***    Return:
************************************************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;AddPostKey&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;tcKey&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;tcValue&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;llFileName&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;LOCAL &lt;/span&gt;&lt;span style="color: black"&gt;lcOldAlias
tcKey&lt;/span&gt;&lt;span style="color: black"&gt;=&lt;/span&gt;&lt;span style="color: blue"&gt;IIF&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;VARTYPE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;tcKey&lt;/span&gt;&lt;span style="color: black"&gt;)=&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;C&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;tcKey&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;tcValue&lt;/span&gt;&lt;span style="color: black"&gt;=&lt;/span&gt;&lt;span style="color: blue"&gt;IIF&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;VARTYPE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;tcValue&lt;/span&gt;&lt;span style="color: black"&gt;)=&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;C&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;tcValue&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;)


&lt;/span&gt;&lt;span style="color: blue"&gt;IF &lt;/span&gt;&lt;span style="color: black"&gt;tcKey&lt;/span&gt;&lt;span style="color: black"&gt;=&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;RESET&amp;quot; &lt;/span&gt;&lt;span style="color: black"&gt;OR &lt;/span&gt;&lt;span style="color: blue"&gt;PCOUNT&lt;/span&gt;&lt;span style="color: black"&gt;() = &lt;/span&gt;&lt;span style="color: black"&gt;0
   &lt;/span&gt;&lt;span style="color: blue"&gt;THIS&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;quot;
   &lt;/span&gt;&lt;span style="color: blue"&gt;RETURN
ENDIF

&lt;/span&gt;*** If we post a raw buffer swap parms
&lt;span style="color: blue"&gt;IF PCOUNT&lt;/span&gt;&lt;span style="color: black"&gt;() &amp;lt; &lt;/span&gt;&lt;span style="color: black"&gt;2
   &lt;/span&gt;&lt;span style="color: black"&gt;tcValue &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;tcKey
   tcKey &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;quot;
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF

IF &lt;/span&gt;&lt;span style="color: black"&gt;!&lt;/span&gt;&lt;span style="color: blue"&gt;EMPTY&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;tcKey&lt;/span&gt;&lt;span style="color: black"&gt;)
   &lt;/span&gt;&lt;span style="color: blue"&gt;DO CASE
    &lt;/span&gt;*** Url Encoded
    &lt;span style="color: blue"&gt;CASE THIS&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nhttppostmode &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;1         
         &lt;/span&gt;&lt;span style="color: blue"&gt;THIS&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: blue"&gt;IIF&lt;/span&gt;&lt;span style="color: black"&gt;(!&lt;/span&gt;&lt;span style="color: blue"&gt;EMPTY&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer&lt;/span&gt;&lt;span style="color: black"&gt;),&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;amp;&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;) + ;
                            &lt;/span&gt;&lt;span style="color: black"&gt;tcKey &lt;/span&gt;&lt;span style="color: black"&gt;+&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;=&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;URLEncode&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;tcValue&lt;/span&gt;&lt;span style="color: black"&gt;) 
      &lt;/span&gt;*** Multi-part formvars and file
    &lt;span style="color: blue"&gt;CASE this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nHttpPostMode &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;2
      &lt;/span&gt;*** Check for File Flag -  HTTP File Upload - Second parm is filename
      &lt;span style="color: blue"&gt;IF &lt;/span&gt;&lt;span style="color: black"&gt;llFileName
           &lt;/span&gt;&lt;span style="color: blue"&gt;THIS&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;THIS&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;--&amp;quot; &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;MULTIPART_BOUNDARY &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;CRLF &lt;/span&gt;&lt;span style="color: black"&gt;+ ;
            &lt;/span&gt;&lt;span style="color: teal"&gt;[Content-Disposition: form-data; name=&amp;quot;]&lt;/span&gt;&lt;span style="color: black"&gt;+&lt;/span&gt;&lt;span style="color: black"&gt;tcKey&lt;/span&gt;&lt;span style="color: black"&gt;+&lt;/span&gt;&lt;span style="color: teal"&gt;[&amp;quot;; filename=&amp;quot;] &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: blue"&gt;JUSTFNAME&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;tcValue&lt;/span&gt;&lt;span style="color: black"&gt;) + &lt;/span&gt;&lt;span style="color: teal"&gt;[&amp;quot;]&lt;/span&gt;&lt;span style="color: black"&gt;+&lt;/span&gt;&lt;span style="color: black"&gt;CRLF&lt;/span&gt;&lt;span style="color: black"&gt;+&lt;/span&gt;&lt;span style="color: black"&gt;CRLF
         &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: blue"&gt;FILETOSTR&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;FULLPATH&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;tcValue&lt;/span&gt;&lt;span style="color: black"&gt;))
         &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;CRLF
      &lt;/span&gt;&lt;span style="color: blue"&gt;ELSE
           this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;+&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;--&amp;quot; &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;MULTIPART_BOUNDARY &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;CRLF &lt;/span&gt;&lt;span style="color: black"&gt;+ ;
            &lt;/span&gt;&lt;span style="color: teal"&gt;[Content-Disposition: form-data; name=&amp;quot;]&lt;/span&gt;&lt;span style="color: black"&gt;+&lt;/span&gt;&lt;span style="color: black"&gt;tcKey&lt;/span&gt;&lt;span style="color: black"&gt;+&lt;/span&gt;&lt;span style="color: teal"&gt;[&amp;quot;]&lt;/span&gt;&lt;span style="color: black"&gt;+&lt;/span&gt;&lt;span style="color: black"&gt;CRLF&lt;/span&gt;&lt;span style="color: black"&gt;+&lt;/span&gt;&lt;span style="color: black"&gt;CRLF
         &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;tcValue
      &lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF
   ENDCASE
ELSE
   &lt;/span&gt;*** If there's no Key post the raw buffer
   &lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;+&lt;/span&gt;&lt;span style="color: black"&gt;tcValue
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF

ENDFUNC&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;AddPostKey can accept either a string value or a filename to load from. The file loading works by accepting the filename and then directly loading the file from within the function:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: blue"&gt;FILETOSTR&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;FULLPATH&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;tcValue&lt;/span&gt;&lt;span style="color: black"&gt;))&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This works fine because the file is directly loaded up into the buffer with no intermediate string variable.&lt;/p&gt;

&lt;p&gt;You cannot however pass a string that is greater than 16 megs into this function because the code that adds the key basically does this with the tcValue parameter:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostBuffer &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;tcValue&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;which is assigning the larger than 16 meg string (tcValue in this case) to another variable and as discussed earlier that fails with &amp;quot;String too long to fit&amp;quot;. Using a string to buffer your output to build up a larger string, there's no workaround for adding a larger than 16 meg string to another variable or buffer using variables. So my code now works with files loaded from disk, but not string parameters&lt;/p&gt;

&lt;p&gt;Good but not good enough!&lt;/p&gt;

&lt;h3&gt;Files for Large Buffers&lt;/h3&gt;

&lt;p&gt;Based on the earlier examples I showed we know that we can easily load up massive content from a file. Thus FILETOSTR() offers an easy way to serve large files. Knowing that it's possible to build stream like class that allows you to accumulate string content in a file and then later retrieve it. To do this I created a wwFileStream class. Using the class looks like this:&lt;/p&gt;

&lt;pre class="code"&gt;*** Load library
&lt;span style="color: blue"&gt;DO &lt;/span&gt;&lt;span style="color: black"&gt;wwapi

&lt;/span&gt;*** Create 20 meg string
&lt;span style="color: black"&gt;lcString &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;REPLICATE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;1234567890&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;1500000&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;lcString &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;lcString &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: blue"&gt;REPLICATE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;1234567890&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;500000&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** Create a stream
&lt;span style="color: black"&gt;loStream &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;CREATEOBJECT&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;wwFileStream&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** Write the 20meg  string
&lt;span style="color: black"&gt;loStream&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Write&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcString&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** Add some more string data
&lt;span style="color: black"&gt;loStream&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;WriteLine&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;...added content&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** Now write a 16meg+ to the buffer as well
&lt;span style="color: black"&gt;loStream&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;WriteFile&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;e:\downloads\ActiveReports3_5100158.zip&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** Works
&lt;span style="color: black"&gt;lcLongString &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;loStream&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;ToString&lt;/span&gt;&lt;span style="color: black"&gt;()

&lt;/span&gt;*** 55+ megs
&lt;span style="color: black"&gt;? &lt;/span&gt;&lt;span style="color: black"&gt;loStream&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nLength
&lt;/span&gt;&lt;span style="color: black"&gt;? &lt;/span&gt;&lt;span style="color: blue"&gt;LEN&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcLongString&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** Clear the file (auto when released)
&lt;span style="color: black"&gt;loStream&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Dispose&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Using this mechanism you can build up very large strings from files or strings regardless of what the size of the string is.&lt;/p&gt;

&lt;h3&gt;How wwFileStream works&lt;/h3&gt;

&lt;p&gt;Internally wwFileStream opens a low level file and tracks the handle. Each Write() operation does an FWRITE() to disk and the handle is released when the class goes out of scope. &lt;/p&gt;

&lt;p&gt;The class implementation is pretty straight forward:&lt;/p&gt;

&lt;p style="line-height: 13pt; margin: 0in 0in 10pt; mso-layout-grid-align: none" class="MsoNormal"&gt;&lt;span style="line-height: 12pt; font-family: ; color: "&gt;&lt;font color="#008000" face="Courier New"&gt;&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;

&lt;pre class="code"&gt;*************************************************************
&lt;span style="color: blue"&gt;DEFINE CLASS &lt;/span&gt;&lt;span style="color: black"&gt;wwFileStream &lt;/span&gt;&lt;span style="color: blue"&gt;AS Custom
&lt;/span&gt;*************************************************************
*: Author: Rick Strahl
*:         (c) West Wind Technologies, 2012
*:Contact: &lt;span style="color: black"&gt;http://www.west-wind.com
&lt;/span&gt;*:Created: 01/04/2012
*************************************************************
&lt;span style="color: blue"&gt;
&lt;/span&gt;&lt;span style="color: black"&gt;nHandle &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0
&lt;/span&gt;&lt;span style="color: black"&gt;cFileName &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;quot; 
&lt;/span&gt;&lt;span style="color: black"&gt;nLength &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0


&lt;/span&gt;************************************************************************
*  Init
****************************************
&lt;span style="color: blue"&gt;FUNCTION Init&lt;/span&gt;&lt;span style="color: black"&gt;()

&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cFileName &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;SYS&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;2023&lt;/span&gt;&lt;span style="color: black"&gt;)  + &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;\&amp;quot; &lt;/span&gt;&lt;span style="color: black"&gt;+  &lt;/span&gt;&lt;span style="color: blue"&gt;SYS&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;2015&lt;/span&gt;&lt;span style="color: black"&gt;) + &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;.txt&amp;quot;
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nHandle &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;FCREATE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cFileName&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nLength &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0

&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   Init

************************************************************************
*  Destroy
****************************************
&lt;span style="color: blue"&gt;FUNCTION Destroy&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Dispose&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   Destroy

************************************************************************
*  Dispose
****************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;Dispose&lt;/span&gt;&lt;span style="color: black"&gt;()

&lt;/span&gt;&lt;span style="color: blue"&gt;IF THIS&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nHandle &lt;/span&gt;&lt;span style="color: black"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color: black"&gt;0
   &lt;/span&gt;&lt;span style="color: blue"&gt;TRY
   FCLOSE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nHandle&lt;/span&gt;&lt;span style="color: black"&gt;)
   &lt;/span&gt;&lt;span style="color: blue"&gt;DELETE FILE &lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cFileName&lt;/span&gt;&lt;span style="color: black"&gt;)
   &lt;/span&gt;&lt;span style="color: blue"&gt;CATCH
   ENDTRY
ENDIF
this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nLength &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   Destroy

************************************************************************
*  Write
****************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;Write&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcContent&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;THIS&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nLength &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;THIS&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nLength &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: blue"&gt;LEN&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcContent&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;FWRITE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nHandle&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;lcContent&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   Write

************************************************************************
*  WriteLine
****************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;WriteLine&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcContent&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Write&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcContent&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Write&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;CHR&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;13&lt;/span&gt;&lt;span style="color: black"&gt;) + &lt;/span&gt;&lt;span style="color: blue"&gt;CHR&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;10&lt;/span&gt;&lt;span style="color: black"&gt;))
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   WriteLine

************************************************************************
*  WriteFile
****************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;WriteFile&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcFileName&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;lcFileName &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;FULLPATH&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcFileName&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Write&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;FILETOSTR&lt;/span&gt;&lt;span style="color: black"&gt;( &lt;/span&gt;&lt;span style="color: black"&gt;lcFileName &lt;/span&gt;&lt;span style="color: black"&gt;))
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   WriteFile

************************************************************************
*  ToString()
****************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;ToString&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;LOCAL &lt;/span&gt;&lt;span style="color: black"&gt;lcOutput

&lt;/span&gt;&lt;span style="color: blue"&gt;FCLOSE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nHandle&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;lcOutput &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;FILETOSTR&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cFileName&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** Reopen the file
&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nHandle &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;FOPEN&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cFileName&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;1&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;FSEEK&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nHandle&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;0&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;2&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;&lt;span style="color: blue"&gt;RETURN &lt;/span&gt;&lt;span style="color: black"&gt;lcOutput
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   ToString()


************************************************************************
*  Clear
****************************************
&lt;span style="color: blue"&gt;FUNCTION Clear&lt;/span&gt;&lt;span style="color: black"&gt;()

&lt;/span&gt;&lt;span style="color: blue"&gt;THIS&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Dispose&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;THIS&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: blue"&gt;Init&lt;/span&gt;&lt;span style="color: black"&gt;()

&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   Clear

&lt;span style="color: blue"&gt;ENDDEFINE
&lt;/span&gt;*EOC wwFileStream &lt;/pre&gt;


&lt;p style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none" class="MsoNormal"&gt;&lt;span style="line-height: 12pt; font-family: ; color: "&gt;The code is fairly self explanatory. The class creates a file in the temp folder and saves the handle. Any write operation then uses the file handle to FWRITE() either a string or the output from FILETOSTR(). ToString() can be called to retrieve the file, which closes the file, reads it then reopens it and points to the end. When the class is released the handle is closed and the handle released.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style="line-height: 12pt; font-family: ; color: "&gt;Using this class makes it easy to create large strings and hold onto them. The additional advantage is that memory usage is kept low as strings are loaded up only briefly and then immediately written to file and can be released. So if you're dealing with very large strings a class like this is actually highly recommended. In fact Web Connection uses this same approach for file based application output.&lt;/span&gt;&lt;/p&gt;

&lt;h3&gt;A matching MemoryStream Class&lt;/h3&gt;

&lt;p&gt;While the FileStream class works, it does have some overhead compared to memory based operation especially when you're dealing with small amounts of data. In the wwHttp class for example, I would not want to create a new wwFileStream for each POST operation. 99% of POST ops are going to be light weight, so it makes sense to only use the wwFileStream class selectively.&lt;/p&gt;

&lt;p&gt;In order to do this I also created a wwMemoryStream class which has the same interface as wwFileStream and which uses a simple string property on the class to hold data. Since the classes have the same interface they are interchangable in use which makes them easily swappable.&lt;/p&gt;

&lt;p&gt;The code for wwMemoryStream looks like this:&lt;/p&gt;

&lt;p&gt;
  &lt;pre class="code"&gt;*************************************************************
&lt;span style="color: blue"&gt;DEFINE CLASS &lt;/span&gt;&lt;span style="color: black"&gt;wwMemoryStream &lt;/span&gt;&lt;span style="color: blue"&gt;AS Custom
&lt;/span&gt;*************************************************************
*: Author: Rick Strahl
*:         (c) West Wind Technologies, 2012
*:Contact: &lt;span style="color: black"&gt;http://www.west-wind.com
&lt;/span&gt;*:Created: 01/05/2012
*************************************************************
&lt;span style="color: blue"&gt;
&lt;/span&gt;&lt;span style="color: black"&gt;cOutput &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;quot;
&lt;/span&gt;&lt;span style="color: black"&gt;nLength &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0

&lt;/span&gt;************************************************************************
*  Destroy
****************************************
&lt;span style="color: blue"&gt;FUNCTION Destroy&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;THIS&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Dispose&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   Destroy

************************************************************************
*  Dispose
****************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;Dispose&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cOutput &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;quot;
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nLength &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   Dispose

************************************************************************
*  Clear
****************************************
&lt;span style="color: blue"&gt;FUNCTION Clear&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cOutput &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;quot;
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nLength &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;0
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   Clear

************************************************************************
*  Write
****************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;Write&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcContent&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nLength &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;nLength &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: blue"&gt;LEN&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcContent&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cOutput &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cOutput &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;lcContent
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   Write

************************************************************************
*  WriteLine
****************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;WriteLine&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcContent&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Write&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcContent&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Write&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;CRLF&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   WriteLine

************************************************************************
*  WriteFile
****************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;WriteFile&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcFileName&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Write&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;FILETOSTR&lt;/span&gt;&lt;span style="color: black"&gt;( &lt;/span&gt;&lt;span style="color: blue"&gt;FULLPATH&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcFileName&lt;/span&gt;&lt;span style="color: black"&gt;) ))
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   WriteFile

************************************************************************
*  ToString()
****************************************
&lt;span style="color: blue"&gt;FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;ToString&lt;/span&gt;&lt;span style="color: black"&gt;()
&lt;/span&gt;&lt;span style="color: blue"&gt;RETURN this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cOutput
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDFUNC
&lt;/span&gt;*   ToString()

&lt;span style="color: blue"&gt;ENDDEFINE
&lt;/span&gt;*EOC wwMemoryStream &lt;/pre&gt;
  It's now a cinch to create my class depending on the need. &lt;/p&gt;

&lt;p&gt;In wwHttp I use wwMemoryStream by default since it addresses the 99% scenario. I added two properties to wwHttp: oPostStream and cPostStreamClass. The class is set to wwMemoryStream which is the default and can be overridden. Then internally when the time comes to create an instance of the stream class I use:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;IF VARTYPE&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;oPostStream&lt;/span&gt;&lt;span style="color: black"&gt;) != &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;O&amp;quot;
   &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;oPostStream &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;CREATEOBJECT&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostStreamClass&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This way the user can easily chose which of the streams to use simply by specifying:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: black"&gt;loHttp&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cPostStreamClass &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;wwFileStream&amp;quot;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;What's also nice about this approach is that the mechanism becomes extensible. If you want to store POST vars in another storage format you can simply create another subclass that implements the same methods and now can store your post variables in an INI file or in structured storage etc. Unlikely scenario for POST data, but very useful for other potential data storage scenarios.&lt;/p&gt;

&lt;p&gt;BTW, the wwFileStream class is also a fairly useful generic file output tool. If you ever need to write output to files it provides a real easy OO way to do so, cleaning up after itself when you close it. I've used classes like (wwResponseFile) for years in various applications that need to create file output. It's very useful in many situations.&lt;/p&gt;

&lt;h3&gt;Summary&lt;/h3&gt;

&lt;p&gt;Even though Visual FoxPro has a 16 meg string limit, you now have some tools in your arsenal to work around this limit and work with larger strings. While you can work with larger strings, keep in mind that once you go past 16 megs you can't assign that string to anything else. It also gets much harder (and slower) to string manipulation on that string once you're beyond VFP's legal limit.&lt;/p&gt;

&lt;p&gt;Still it's nice to know that the limit is not a final one and there are ways to work around it.&lt;/p&gt;

&lt;h3&gt;Resources&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href="http://west-wind.com/files/Demos/2012/wwStreams.zip" target="_blank"&gt;wwStreams.prg and Sample&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/A2n0K1kmeCr-L1N07xSuEoUN2qA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/A2n0K1kmeCr-L1N07xSuEoUN2qA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/A2n0K1kmeCr-L1N07xSuEoUN2qA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/A2n0K1kmeCr-L1N07xSuEoUN2qA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=JXtaFmxZZaU:IaBVSqiM13Y:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=JXtaFmxZZaU:IaBVSqiM13Y:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=JXtaFmxZZaU:IaBVSqiM13Y:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=JXtaFmxZZaU:IaBVSqiM13Y:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=JXtaFmxZZaU:IaBVSqiM13Y:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=JXtaFmxZZaU:IaBVSqiM13Y:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=JXtaFmxZZaU:IaBVSqiM13Y:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=JXtaFmxZZaU:IaBVSqiM13Y:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=JXtaFmxZZaU:IaBVSqiM13Y:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=JXtaFmxZZaU:IaBVSqiM13Y:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~4/JXtaFmxZZaU" height="1" width="1"/&gt;</description>
     <feedburner:origLink>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=882</feedburner:origLink></item>
     <item>
			<title>SetFocus() in Form Init() kills @K Select All Formatting on Textboxes</title>
			<pubDate>Wed, 4 Jan 2012 12:20:14 GMT</pubDate>
			<guid isPermaLink="false">881_20120104</guid>
			<link>http://feedproxy.google.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~3/wMepU-8LTxc/ShowEntry.blog</link>
			<dc:creator>Rick Strahl</dc:creator>
			<comments>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=881#Feedback</comments>
			<slash:comments>1</slash:comments>
			<description>&lt;p&gt;Ran into a little nit today in some code for Help Builder. I have a small dialog in my toolbox that I use to create HREF links. Basically this dialog captures a title, URL and either returns those values back or creates an anchor (&amp;lt;a&amp;gt;) HTML tag from it.&lt;/p&gt;  &lt;p&gt;The dialog looks like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.west-wind.com/wconnect/weblog/imageContent/2012/Windows-Live-Writer/SetFocus-kills-K-Select-All-Formatting-o_2AB4/HyperlinkDialog_2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="HyperlinkDialog" border="0" alt="HyperlinkDialog" src="http://www.west-wind.com/wconnect/weblog/imageContent/2012/Windows-Live-Writer/SetFocus-kills-K-Select-All-Formatting-o_2AB4/HyperlinkDialog_thumb.png" width="592" height="196" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Usually a user will be editing some help topic, then type some text like Visit our Support Site, highlight the selection of text and then pop into the dialog. Ideally I want to start out in the Web Link field and have the text highlighted.&lt;/p&gt;  &lt;p&gt;So in the designer I have thisform.txtUrl.Format = &amp;quot;K&amp;quot; which autoselects the text in both controls. Now this all works fine as long as I tab through the controls manually. However, my original code used the original TabOrder and tried to SetFocus to the URL like this in the Init of the form class:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;LPARAMETER &lt;/span&gt;&lt;span style="color: black"&gt;lcUrl&lt;/span&gt;&lt;span style="color: black"&gt;, &lt;/span&gt;&lt;span style="color: black"&gt;lcText

&lt;/span&gt;&lt;span style="color: blue"&gt;THIS&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cUrl &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;TRIM&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcUrl&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;THIS&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;cText &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;lcText

&lt;/span&gt;&lt;font color="#008080"&gt;*** Move focus to second field&lt;/font&gt;
&lt;span style="color: blue"&gt;IF &lt;/span&gt;&lt;span style="color: black"&gt;!&lt;/span&gt;&lt;span style="color: blue"&gt;EMPTY&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcText&lt;/span&gt;&lt;span style="color: black"&gt;)
   &lt;/span&gt;&lt;span style="color: blue"&gt;thisform&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;txtURL&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: blue"&gt;SetFocus&lt;/span&gt;&lt;span style="color: black"&gt;()
   &lt;/span&gt;&lt;font color="#008080"&gt;*KEYBOARD &amp;quot;{TAB}&amp;quot;&lt;/font&gt;
&lt;span style="color: blue"&gt;ENDIF&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This works fine for moving the focus - the control comes up with the focus set to txtUrl just fine. But unfortunately the @K auto-selection of the text is not happening. Using SetFocus() during the startup of the form simply fails. It only fails when using SetFocus() during startup in Init() or before the form is activated - if you call SetFocus() after activation the @K selection is properly respected.&lt;/p&gt;

&lt;h3&gt;Workarounds&lt;/h3&gt;

&lt;p&gt;Of course there's a simple and obvious workaround that probably would have been the better solution in the first place here. I can simply set the TabOrder to force the txtUrl field to be the first field accessed by the form and adjust the taborder accordingly with the txtTitle being the last in the taborder. &lt;/p&gt;

&lt;p&gt;If you really need dynamic focusing at runtime, you can move that code to a later time in the form's event cycle: Moving it to the Activate event works.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/TSRE8vvwz73E8RKHEyL0CC1wJUI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/TSRE8vvwz73E8RKHEyL0CC1wJUI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/TSRE8vvwz73E8RKHEyL0CC1wJUI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/TSRE8vvwz73E8RKHEyL0CC1wJUI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=wMepU-8LTxc:x_Ki1vom26E:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=wMepU-8LTxc:x_Ki1vom26E:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=wMepU-8LTxc:x_Ki1vom26E:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=wMepU-8LTxc:x_Ki1vom26E:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=wMepU-8LTxc:x_Ki1vom26E:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=wMepU-8LTxc:x_Ki1vom26E:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=wMepU-8LTxc:x_Ki1vom26E:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=wMepU-8LTxc:x_Ki1vom26E:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=wMepU-8LTxc:x_Ki1vom26E:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=wMepU-8LTxc:x_Ki1vom26E:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~4/wMepU-8LTxc" height="1" width="1"/&gt;</description>
     <feedburner:origLink>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=881</feedburner:origLink></item>
     <item>
			<title>ClassIDs in Visual FoxPro COM Projects</title>
			<pubDate>Sat, 26 Nov 2011 21:47:25 GMT</pubDate>
			<guid isPermaLink="false">880_20111126</guid>
			<link>http://feedproxy.google.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~3/Yuc_0hfSHSY/ShowEntry.blog</link>
			<dc:creator>Rick Strahl</dc:creator>
			<comments>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=880#Feedback</comments>
			<slash:comments>1</slash:comments>
			<description>&lt;p&gt;As you probably know Visual FoxPro projects can be compiled into COM servers. It's as easy as creating a new FoxPro class and marking it with the OLEPUBLIC keyword to allow it to be compiled into a COM Server.&lt;/p&gt;  &lt;p&gt;In a PRG file it's as easy as creating a class like this:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;DEFINE CLASS &lt;/span&gt;&lt;span style="color: black"&gt;SimpleClass &lt;/span&gt;&lt;span style="color: blue"&gt;as Session OLEPUBLIC

FUNCTION &lt;/span&gt;&lt;span style="color: black"&gt;HelloWorld&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcName&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;RETURN &lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;Hello &amp;quot; &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;lcName

&lt;/span&gt;&lt;span style="color: blue"&gt;ENDDEFINE&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Now add this class to a project called SimpleServer and compile the class either into an EXE (which becomes a DCOM out of process server) or a DLL (MTDLL or Regular DLL).&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;BUILD MTDLL &lt;/span&gt;&lt;span style="color: black"&gt;SimpleServer &lt;/span&gt;&lt;span style="color: blue"&gt;FROM &lt;/span&gt;&lt;span style="color: black"&gt;simpleserver&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;and voila you have a COM server that you can now instantiate from other environments or even from Visual FoxPro.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: black"&gt;o &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;CREATEOBJECTEX&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;SimpleServer.SimpleClass&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;? &lt;/span&gt;&lt;span style="color: black"&gt;o&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;HelloWorld&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;Rick&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The name of the COM server by default becomes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ProjectName.ClassName&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;so here the project is SimpleServer and the class is SimpleClass.&lt;/p&gt;

&lt;p&gt;Note I'm using CreateObjectEx here to force VFP to use the object as a COM object in VFP - in some situations VFP treats in process (DLL) FoxPro COM objects like Fox objects and CREATEOBJECTEX() ensures that the object is always loaded as a true COM object. Of course you can do something similar in VB classic, or .NET, Delphi, C++ etc. where use a FoxPro COM object makes a lot more sense than inside of FoxPro code where you could (and should if possible) use the object natively.&lt;/p&gt;

&lt;p&gt;When you use a DLL server as above the COM instance will be loaded into the host process - it's an InProcess component and it runs in the hosts environment. This means that the environment settings (Startup Path, memory setup, OS Paths etc) are all inherited from the host process inside of the DLL server. In effect the DLL server becomes part of the host process just like any other DLL loaded into it.&lt;/p&gt;

&lt;p&gt;To create an EXE server you can just compile the same code into an EXE:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;BUILD EXE &lt;/span&gt;&lt;span style="color: black"&gt;SimpleServer &lt;/span&gt;&lt;span style="color: blue"&gt;FROM &lt;/span&gt;&lt;span style="color: black"&gt;simpleserver&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Once you've compiled an EXE you can use the same code used previously to instantiate the server - nothing changes. However, now the server is an out of process server and runs in its own process - SimpleServer.exe if you look it up in Task Manager - that is completely separate from the host process. SimpleServer.exe gets instantiated by the Visual FoxPro runtime and it gets its own brand new environment and any interaction between the host application and your COM server occurs over an RPC Remoting interface that performs interprocess communication.&lt;/p&gt;

&lt;h3&gt;ClassIDs in Visual FoxPro&lt;/h3&gt;

&lt;p&gt;Typically you interact with COM objects via ProgIds like SimpleServer.SimpleClass, but internally all COM access is routed through unique GUID identifiers called ClassIDs. To find more info about COM servers you can use the COMCLASSINFO function in FoxPro. One of the options of COMCLASSINFO is option 4:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: black"&gt;o &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;CREATEOBJECT&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;&amp;quot;SimpleServer.SimpleClass&amp;quot;&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;? &lt;/span&gt;&lt;span style="color: blue"&gt;COMCLASSINFO&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;o&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;4&lt;/span&gt;&lt;span style="color: black"&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;which shows you the ClassId for the COM object which looks like this (but will be different if you were following along - GUIDs are unique):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;{6C552462-832E-432A-9059-351145E7090B}&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Visual FoxPro creates these unique CLASSIDs inside of the Project file. When you build your project VFP scans for any COM objects - those classes marked with OLEPUBLIC - and keeps track of them. The first time a given class is encountered VFP stores its GUID inside of the project file. Subsequent builds retrieve this GUID and reuse it for registration and creation of the type library and DllRegister/DllUnregister functions that compile into VFP.&lt;/p&gt;

&lt;p&gt;Specifically it stores this data - ProgId and ClassIds in the Reserved 2 field of the PJX header record. To demonstrate I added a second COM class (SimpleServerNo2) to the project and compiled. When I then open USE SimpleServer.pjx and BROWSE I can see the Reserved2 field which looks like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&amp;#160;&amp;#160; 4 103&amp;#160;&amp;#160; 4&amp;#160;&amp;#160; 2&amp;#160; 30c:\wwapps\wc3\SimpleServer.DLL&amp;#160; 12simpleserver&amp;#160; 12simpleserver&amp;#160; 25simpleserver Type Library&amp;#160;&amp;#160; 4 116&amp;#160; 38{F10346E2-C9D9-47F7-81D1-74059CC15C3C}&amp;#160;&amp;#160; 10&amp;#160; 24simpleserver.SimpleClass&amp;#160; 24simpleserver.SimpleClass&amp;#160;&amp;#160; 0&amp;#160; 11SimpleClass&amp;#160; 30c:\wwapps\wc3\simpleserver.prg&amp;#160;&amp;#160; 12&amp;#160; 38&lt;em&gt;{6C552462-832E-432A-9059-351145E7090B}&lt;/em&gt;&amp;#160; 38{3753AF24-8DCA-4D00-B59B-3CA256C07091}&amp;#160;&amp;#160; 10&amp;#160; 27simpleserver.SimpleClassNo2&amp;#160; 27simpleserver.SimpleClassNo2&amp;#160;&amp;#160; 0&amp;#160; 14SimpleClassNo2&amp;#160; 30c:\wwapps\wc3\simpleserver.prg&amp;#160;&amp;#160; 12&amp;#160; 38&lt;em&gt;{353EB458-7DDE-4987-8BC0-42AD9ECCB9E9}&lt;/em&gt;&amp;#160; 38{EDBC795C-62AB-42F6-863B-45708C680C72}&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What you see here is a &lt;strong&gt;fixed length format&lt;/strong&gt; record of project information. Most of this info comes from the Project Info dialog in FoxPro. But some information - namely the COM Server configuration additional 'records' are added to the Reserved2 field. I marked the ClassIds for the two COM servers in italic in the string above. Each COM server has both a CLASSID as well as an (IID) Interface ID which is the second classID you see following the ClassID.&lt;/p&gt;

&lt;p&gt;Why does this matter?&lt;/p&gt;

&lt;p&gt;If you corrupt a project in some way you CAN, if you're really desperate, fix things by going in here and fixing up the ProgIds or ClassIds to match known values. I've had many occasions where customers have copied around projects multiple times and have renamed classes without paying attention. Going into this field I've been able to 'save' the project and existing ClassIDs and ProgIds. Basically the COM objects are at the end&lt;/p&gt;

&lt;h3&gt;COM Information Corruption in FoxPro Projects&lt;/h3&gt;

&lt;p&gt;As a vendor who sells several FoxPro products that utilize COM to interact with other host environments I've seen many problems with FoxPro COM servers. One of the things I've seen a lot of is that COM CLASSIDs get corrupted.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Wrong Server loading&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;The most common reason for this corruption that I've seen comes from projects being copied. Since VFP stores COM information as part of the project file, copying the project (ie. COPY FILES SimpleServer.pj* to SimpleServer2.pj*) copies all the COM information as well. Sometimes this is what you want, other times not. If you want to make an exact copy of a project for testing or backup then project copying is totally fine. Just keep in mind that if you build the copied project it will share the same ProgIds and ClassIds as the original project and when you build this second project all COM references will point at this DLL.&lt;/p&gt;

&lt;p&gt;Often times, however, people copy projects because they want a new starting point for a new project. They copy the project and various files not realizing they are essentially copying the COM functionality as well. What ends up happening is that two different objects now exist in two separate projects that are registered with the same ClassIDs. The result of this is that one registration overwrites the other and if the two versions are not kept in sync unpredictable behavior ensues because you're never sure which type of object gets loaded.&lt;/p&gt;

&lt;p&gt;Moral of this story is: When you copy projects with COM objects for creation of a new project: Always create a new project and import all files from scratch. This ensures that each project gets their own set of CLASSIDs. &lt;/p&gt;

&lt;h3&gt;Which server is which?&lt;/h3&gt;

&lt;p&gt;When in doubt which server holds what COM object it's best to manually register projects. To be sure always register the component you're interested in manually with:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;regsvr32 SimpleServer.dll&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;or for an EXE:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SimpleServer.exe /regserver&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This always makes sure you get the right server loaded.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;ClassID Corruption&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;When VFP builds a project it checks the ClassID in the project and tries to find existing classids in the registry. VFP checks the validity of the entries in the registry and tries to update the registry with the latest build information. VFP is pretty smart about this and corruption of these IDs is very, very rare, but it does happen. Usually it happens when you have two projects where each was created on its own (ie. you didn't copy the projects). What happens in this scenario is that both projects reference the same ProgIds but different ClassIDs. In effect each project builds different registry entries. Aside from expected problems that each time the project is compiled in a different project it will end up pointing to a different binary on disk, this scenario can also cause corruption as VFP tries to update the registry. The error that comes up in this case is: &amp;quot;Invalid subscript reference&amp;quot; while trying to build the project when it's trying to register the COM server.&lt;/p&gt;

&lt;p&gt;The first thing to try in this case is to see if you can find an old copy of your COM binary&amp;#160; (DLL or EXE) and try to register it. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;regsvr32 simpleserver.dll&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;or for an EXE server:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SimpleServer.exe /regserver&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Re-registering might clean up the registry and point at the right locations for things to start working again. Once registered try loading the COM object. If that works, unload it and then try to rebuild your project, chances are good that now it will build.&lt;/p&gt;

&lt;p&gt;If that fails, you can try and fix your project using the Reserved2 field mentioned before. It's all text so you can change values in this field, but be really careful - the field data is fixed length, so any character you change needs to be replaced with another (ie. spaces are important!). You can fix ProgIDs and ClassIds and paths if necessary.&lt;/p&gt;

&lt;p&gt;If that fails another - more laborious option - is to clean the registry of your COM object. &lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Find all instances of your ProgId (s)&amp;#160; HKCR\simpleserver.SimpleClass&amp;#160; HKCR\simpleServer.SimpleClassNo2 &lt;/li&gt;

  &lt;li&gt;Find all instances of your TypeLib HKCR\TypeLib\{guid} &lt;/li&gt;

  &lt;li&gt;Find all instances of your servers executable name (ie. SimpleServer.dll) &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the case of my SimpleServer example I'd just search the registry for &amp;quot;SimpleServer&amp;quot;. Delete all the root entries that you find for matches (ie. walk them back up to the GUID entry or the ProgId entry). This will be the ProgId key in the root and the various ClassId entries in the All key. &lt;/p&gt;

&lt;p&gt;If your name is not clearly delineated you have to search more specifically on the ProgId and the ClassId to find all entries - both ways work, but the latter is more tedious.&lt;/p&gt;

&lt;p&gt;Once the registry is clean make sure you only compile the same COM objects from a single project OR if you need to have multiple projects with same COM objects, make 100% sure that the second project is a copy of the original project that contains all the same ClassID entries! &lt;/p&gt;

&lt;h3&gt;When in doubt: Create a new Project with a New Name&lt;/h3&gt;

&lt;p&gt;Your last resort option that should always work is to create a brand new project &lt;em&gt;with a new name&lt;/em&gt;. Don't copy it, just create a new project and give it a new name and then add all your project files back to the project. When you create a new project with a new name the ProgIds will change as will the ClassIds. Essentially creating a new project with a new name ensures that you're starting from scratch and it's almost guaranteed to work. The downside of course is that all your COM ProgIds change and any client code that's already using your COM objects has to change. &lt;/p&gt;

&lt;p&gt;I've had to do this in the past with a few projects that were corrupted and also ended up corrupting a customer's installations. Starting over was really the only option to make this all work out properly. However, when you're down to your last resort this is the most reliable solution to get to a known good starting point.&lt;/p&gt;

&lt;h3&gt;Not as bad as it sounds&lt;/h3&gt;

&lt;p&gt;If all this sounds scary, don't worry. A lot of what I'm describing here is really, really rare. But it does happen occasionally. If you are careful with copying projects then you are almost sure to never run into a problem. Just make sure you understand what happens when you copy a project that has existing COM objects in it. Safest route is to create a new project, with a new name and start fresh - this is guaranteed to avoid COM object corruption.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/LDz8gj4T3cCkGzZGlfnGKwetDq0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/LDz8gj4T3cCkGzZGlfnGKwetDq0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/LDz8gj4T3cCkGzZGlfnGKwetDq0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/LDz8gj4T3cCkGzZGlfnGKwetDq0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=Yuc_0hfSHSY:N_g6xUv5QJg:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=Yuc_0hfSHSY:N_g6xUv5QJg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=Yuc_0hfSHSY:N_g6xUv5QJg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=Yuc_0hfSHSY:N_g6xUv5QJg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=Yuc_0hfSHSY:N_g6xUv5QJg:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=Yuc_0hfSHSY:N_g6xUv5QJg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=Yuc_0hfSHSY:N_g6xUv5QJg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=Yuc_0hfSHSY:N_g6xUv5QJg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=Yuc_0hfSHSY:N_g6xUv5QJg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=Yuc_0hfSHSY:N_g6xUv5QJg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~4/Yuc_0hfSHSY" height="1" width="1"/&gt;</description>
     <feedburner:origLink>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=880</feedburner:origLink></item>
     <item>
			<title>Dropping in MetaWeblog Provider into my FoxPro Weblog</title>
			<pubDate>Mon, 21 Nov 2011 18:53:00 GMT</pubDate>
			<guid isPermaLink="false">879_20111121</guid>
			<link>http://feedproxy.google.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~3/-rZ0RS3Gaxk/ShowEntry.blog</link>
			<dc:creator>Rick Strahl</dc:creator>
			<comments>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=879#Feedback</comments>
			<slash:comments>0</slash:comments>
			<description>&lt;p&gt;For a while I've been slacking on my FoxPro blogging. Part of the reason has been that I'm spoiled - spoiled by using &lt;a href="http://explore.live.com/windows-live-writer" target="_blank"&gt;Windows Live Writer&lt;/a&gt; on my &lt;a href="http://www.west-wind.com/" target="_blank"&gt;main Weblog&lt;/a&gt; (where I post most of my .NET and general content). In case you're a blogger and you haven't used Live Writer, I urge you to RUN not walk over to the Windows Live site and download a copy. Seriously this will make your life much easier. With a couple of plug-ins - namely my &lt;a href="http://www.west-wind.com/weblog/posts/2011/Oct/13/SnagIt-Live-Writer-Plugin-Updated" target="_blank"&gt;SnagIt Screen Capture plug-in&lt;/a&gt; and the &lt;a href="http://plugins.live.com/writer/detail/paste-from-visual-studio" target="_blank"&gt;Paste from Visual Studio&lt;/a&gt; (which captures RTF colored text including with some limitations FoxPro code)&lt;/p&gt;  &lt;p&gt;My main site's Weblog runs a custom-built ASP.NET application that built years ago and I built a &lt;a href="http://xmlrpc.scripting.com/metaWeblogApi.html" target="_blank"&gt;MetawebLog API&lt;/a&gt; provider for it so it would work easily with Live Write (and other blogging tools). MetawebLog API is a standard format that can be used to post post information from the client to the server. The API is about 10 methods that implement things like retrieving blogs (for multi-blog hosts), retrieving recent posts, individual posts, deleting posts and of course allow you to post and update existing posts as well as handling binary/image uploads. One thing that's really painful about MetaWebLogAPI is that it's built using the Xml-RPC protocol which is an old and rarely used API. It would have been a lot easier if a generic SOAP or JSON API existed to do this. Alas, we're stuck with MetaWeblogAPI since that's what most editors suppport (as well as WordPress, Blogger and a few other specific formats).&lt;/p&gt;  &lt;p&gt;Anyway, I wrote some &lt;a href="http://www.west-wind.com/weblog/posts/2007/Mar/10/MetaWebLog-API-and-Blog-Writers" target="_blank"&gt;.NET code a long while back&lt;/a&gt; to implement MetaWebLog API in my main blog and that's been working great. However, working on my FoxPro blog which is written with FoxPro code and Web Connection, I've been suffering from feature envy. For the Fox blog I used to use Word and then pasted content into a rich edit box - yuk! Later on I finally got wise and I used Live Writer to write my posts for my main blog, and post the FoxPro entries as Drafts. I'd then pick up the raw HTML and paste it into the FoxPro blogs entry form. Yeah, that sucked too.&lt;/p&gt;  &lt;p&gt;So finally today I said - enough of this and sat down to create a provider to work against my Fox data in the FoxPro blog. Now I cheated a bit here - rather than using FoxPro and the Web Connection base code and reinvent XmlRpc and then build the MetaWeblog API ontop of it, I instead used my existing .NET MetawebLog base classes and recreated the final implementation talking to FoxPro data with OleDb. That's not something I like to do much - in fact I think this is the first ever application I've built for myself that uses OleDb against Fox data, but in the grand scheme of things this was simply the quickest way to go. It took me two hours to build the following implementation.&lt;/p&gt;  &lt;h3&gt;DotNet and FoxPro Data&amp;#160; &lt;/h3&gt;  &lt;p&gt;In the past I've gotten a lot of questions about how to access FoxPro data from .NET. Using FoxPro data from .NET is just about limited to using ADO.NET which in raw form is very verbose - much more so than FoxPro's concise Data Definition Language. A long while back I created a really basic Data Access Layer (DAL) that can be used with any SQL backend and it provides highlevel abstractions that make basic SQL commands single method calls which is a lot less verbose than low level ADO.NET code.&lt;/p&gt;  &lt;p&gt;For the following code I use the low level &lt;a href="http://www.west-wind.com:8080/svn/WestwindWebToolkit/trunk/Westwind.Utilities/Data/" target="_blank"&gt;SqlDataAccess helper class&lt;/a&gt; which is available as part of the &lt;a href="http://www.west-wind.com/WestwindWebToolkit/" target="_blank"&gt;West Wind Web Toolkit&lt;/a&gt; and the Westwind.Utilities .NET assembly. Using this class here's what a few data access commands look like:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;SqlDataAccess &lt;/span&gt;Data = 
    &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SqlDataAccess&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;ConfigurationManager&lt;/span&gt;.ConnectionStrings[&lt;span style="color: #a31515"&gt;&amp;quot;WebLogFox&amp;quot;&lt;/span&gt;].ConnectionString,
                      &lt;span style="color: #a31515"&gt;&amp;quot;System.Data.OleDb&amp;quot;&lt;/span&gt;);

&lt;span style="color: #2b91af"&gt;DataTable &lt;/span&gt;table = Data.ExecuteTable(&lt;span style="color: #a31515"&gt;&amp;quot;TRecentEntries&amp;quot;&lt;/span&gt;,
            &lt;span style="color: #a31515"&gt;&amp;quot;select top 25 * from blog_entries order by entered desc&amp;quot;&lt;/span&gt;);

&lt;span style="color: green"&gt;// DataReaders are more efficient
&lt;/span&gt;&lt;span style="color: #2b91af"&gt;DbDataReader &lt;/span&gt;reader = Data.ExecuteReader(&lt;span style="color: #a31515"&gt;&amp;quot;select * from blog_entries where pk=?&amp;quot;&lt;/span&gt;,
                                         Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;,pk) );

&lt;span style="color: blue"&gt;int &lt;/span&gt;maxPk = (&lt;span style="color: blue"&gt;int&lt;/span&gt;)Data.ExecuteScalar(&lt;span style="color: #a31515"&gt;&amp;quot;select max(pk) from blog_Entries&amp;quot;&lt;/span&gt;);

&lt;span style="color: blue"&gt;int &lt;/span&gt;affected = Data.ExecuteNonQuery(&lt;span style="color: #a31515"&gt;&amp;quot;insert into blog_user (pk, username, password) values (?,?)&amp;quot;&lt;/span&gt;,
            Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;,&lt;span style="color: #a31515"&gt;&amp;quot;rick&amp;quot;&lt;/span&gt;),
            Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;,&lt;span style="color: #a31515"&gt;&amp;quot;sekrit&amp;quot;&lt;/span&gt;) );&lt;/pre&gt;

&lt;p&gt;
  &lt;br /&gt;As you can see, it's not too difficult to make database calls - it looks a lot like using SQL Passthrough in FoxPro code which is no accident. For down and dirty, quick data access this stuff is sweet and easy and I use it frequently for administrative task - like say posting blog entries to my site.&lt;/p&gt;

&lt;p&gt;Without much further ado (lower case! And the pun is intended) here's the code for my FoxPro based MetaWeblog implementation which puts the DAL above to use:&lt;/p&gt;

&lt;pre class="code"&gt;    &lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MetaWebLogApi &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;XmlRpcService&lt;/span&gt;, &lt;span style="color: #2b91af"&gt;IMetaWeblog
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;private const string &lt;/span&gt;STR_RickStrahl = &lt;span style="color: #a31515"&gt;&amp;quot;Rick Strahl&amp;quot;&lt;/span&gt;;
        &lt;span style="color: blue"&gt;private const string &lt;/span&gt;STR_WconnectweblogimageContent = &lt;span style="color: #a31515"&gt;&amp;quot;~/weblog/imageContent/&amp;quot;&lt;/span&gt;;
        &lt;span style="color: blue"&gt;private const string &lt;/span&gt;STR_WebLogName = &lt;span style="color: #a31515"&gt;&amp;quot;Rick Strahl's FoxPro and Web Connection Weblog&amp;quot;&lt;/span&gt;;

        &lt;span style="color: blue"&gt;private static string &lt;/span&gt;STR_WeblogBaseUrl =
                &lt;span style="color: #a31515"&gt;&amp;quot;http://&amp;quot; &lt;/span&gt;+ &lt;span style="color: #2b91af"&gt;HttpContext&lt;/span&gt;.Current.Request.ServerVariables[&lt;span style="color: #a31515"&gt;&amp;quot;server_name&amp;quot;&lt;/span&gt;] +
                &lt;span style="color: #a31515"&gt;&amp;quot;/wconnect/weblog/&amp;quot;&lt;/span&gt;;

        &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SqlDataAccess &lt;/span&gt;Data = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SqlDataAccess&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;ConfigurationManager&lt;/span&gt;.ConnectionStrings[&lt;span style="color: #a31515"&gt;&amp;quot;WebLogFox&amp;quot;&lt;/span&gt;].ConnectionString,
                                                      &lt;span style="color: #a31515"&gt;&amp;quot;System.Data.OleDb&amp;quot;&lt;/span&gt;);


        &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;
        /// &lt;/span&gt;&lt;span style="color: green"&gt;Validates the user and throws exception on failure which will throw
        &lt;/span&gt;&lt;span style="color: gray"&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;us out of any service method and return the error to the client.
        &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&amp;quot;Username&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
        /// &amp;lt;param name=&amp;quot;Password&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
        /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
        &lt;/span&gt;&lt;span style="color: blue"&gt;private bool &lt;/span&gt;ValidateUser(&lt;span style="color: blue"&gt;string &lt;/span&gt;Username, &lt;span style="color: blue"&gt;string &lt;/span&gt;Password)
        {
            &lt;span style="color: blue"&gt;object &lt;/span&gt;val = Data.ExecuteScalar(&lt;span style="color: #a31515"&gt;&amp;quot;select pk from weblogusersecurity where username==? and password=?&amp;quot;&lt;/span&gt;,
                                            Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;, Username),
                                            Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;, Password));

            &lt;span style="color: blue"&gt;if &lt;/span&gt;(val == &lt;span style="color: blue"&gt;null&lt;/span&gt;)
                &lt;span style="color: blue"&gt;return false&lt;/span&gt;;

            &lt;span style="color: blue"&gt;return true&lt;/span&gt;;
        }

        &lt;span style="color: blue"&gt;#region &lt;/span&gt;IMetaWeblog Members


        &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;CategoryInfo&lt;/span&gt;[] getCategories(&lt;span style="color: blue"&gt;object &lt;/span&gt;blogid, &lt;span style="color: blue"&gt;string &lt;/span&gt;username, &lt;span style="color: blue"&gt;string &lt;/span&gt;password)
        {           
            &lt;span style="color: blue"&gt;this&lt;/span&gt;.ValidateUser(username, password);

            &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;CategoryInfo&lt;/span&gt;&amp;gt; CategoryInfoList = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;CategoryInfo&lt;/span&gt;&amp;gt;();
            &lt;span style="color: #2b91af"&gt;CategoryInfo &lt;/span&gt;cat = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;CategoryInfo&lt;/span&gt;();
            cat.categoryid = &lt;span style="color: #a31515"&gt;&amp;quot;1&amp;quot; &lt;/span&gt;;
            cat.description = &lt;span style="color: #a31515"&gt;&amp;quot;FoxPro&amp;quot;&lt;/span&gt;;
            cat.title = &lt;span style="color: #a31515"&gt;&amp;quot;FoxPro&amp;quot;&lt;/span&gt;;            
            CategoryInfoList.Add(cat);
            
            &lt;span style="color: blue"&gt;return &lt;/span&gt;CategoryInfoList.ToArray();            
        }

        &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Post &lt;/span&gt;getPost(&lt;span style="color: blue"&gt;string &lt;/span&gt;postid, &lt;span style="color: blue"&gt;string &lt;/span&gt;username, &lt;span style="color: blue"&gt;string &lt;/span&gt;password)
        {
            &lt;span style="color: blue"&gt;this&lt;/span&gt;.ValidateUser(username, password);
            
            &lt;span style="color: blue"&gt;int &lt;/span&gt;Pk = 0;
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(!&lt;span style="color: blue"&gt;int&lt;/span&gt;.TryParse(postid,&lt;span style="color: blue"&gt;out &lt;/span&gt;Pk))
                &lt;span style="color: blue"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XmlRpcException&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Invalid PostId  passed&amp;quot;&lt;/span&gt;);


           &lt;span style="color: #2b91af"&gt;DbDataReader &lt;/span&gt;reader = Data.ExecuteReader(&lt;span style="color: #a31515"&gt;&amp;quot;select * from blog_entries where pk = &amp;quot; &lt;/span&gt;+ Pk.ToString());
           &lt;span style="color: blue"&gt;if &lt;/span&gt;(reader == &lt;span style="color: blue"&gt;null &lt;/span&gt;|| !reader.HasRows )
               &lt;span style="color: blue"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XmlRpcException&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;invalid Post - no matching post found for id: &amp;quot; &lt;/span&gt;+ Pk.ToString());


           &lt;span style="color: #2b91af"&gt;Post &lt;/span&gt;post = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Post&lt;/span&gt;();

           &lt;span style="color: blue"&gt;while &lt;/span&gt;(reader.Read())
           {
               post.title = (&lt;span style="color: blue"&gt;string&lt;/span&gt;)reader[&lt;span style="color: #a31515"&gt;&amp;quot;Title&amp;quot;&lt;/span&gt;];
               post.description = (&lt;span style="color: blue"&gt;string&lt;/span&gt;)reader[&lt;span style="color: #a31515"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;];
               post.postid = (&lt;span style="color: blue"&gt;int&lt;/span&gt;)reader[&lt;span style="color: #a31515"&gt;&amp;quot;Pk&amp;quot;&lt;/span&gt;];

               &lt;span style="color: green"&gt;// *** Move to business object
               &lt;/span&gt;post.permalink = STR_WeblogBaseUrl + &lt;span style="color: #a31515"&gt;&amp;quot;ShowPost.blog?id=&amp;quot; &lt;/span&gt;+ Pk.ToString();
               post.link = post.permalink;

               post.dateCreated = (&lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;)reader[&lt;span style="color: #a31515"&gt;&amp;quot;Entered&amp;quot;&lt;/span&gt;];
               post.categories = reader[&lt;span style="color: #a31515"&gt;&amp;quot;Categories&amp;quot;&lt;/span&gt;].ToString().Split(&lt;span style="color: #a31515"&gt;','&lt;/span&gt;);

               post.mt_keywords = &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
               post.mt_excerpt = (&lt;span style="color: blue"&gt;string&lt;/span&gt;)reader[&lt;span style="color: #a31515"&gt;&amp;quot;abstract&amp;quot;&lt;/span&gt;];
           }

            &lt;span style="color: blue"&gt;return &lt;/span&gt;post;
        }

        &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Post&lt;/span&gt;[] getRecentPosts(&lt;span style="color: blue"&gt;object &lt;/span&gt;blogid, &lt;span style="color: blue"&gt;string &lt;/span&gt;username, &lt;span style="color: blue"&gt;string &lt;/span&gt;password, &lt;span style="color: blue"&gt;int &lt;/span&gt;numberOfPosts)
        {
            &lt;span style="color: blue"&gt;this&lt;/span&gt;.ValidateUser(username, password);

            
            &lt;span style="color: #2b91af"&gt;DbDataReader &lt;/span&gt;reader = Data.ExecuteReader(&lt;span style="color: #a31515"&gt;&amp;quot;select TOP ? * from blog_Entries order by entered desc&amp;quot;&lt;/span&gt;,
                                                     Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;,numberOfPosts));

            &lt;span style="color: blue"&gt;if &lt;/span&gt;(reader == &lt;span style="color: blue"&gt;null &lt;/span&gt;|| !reader.HasRows)
                &lt;span style="color: blue"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XmlRpcException&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Error retrieving posts: &amp;quot; &lt;/span&gt;+ Data.ErrorMessage);
            
            &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Post&lt;/span&gt;&amp;gt; Posts = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Post&lt;/span&gt;&amp;gt;();

            &lt;span style="color: blue"&gt;while &lt;/span&gt;(reader.Read()) 
            {
                &lt;span style="color: #2b91af"&gt;Post &lt;/span&gt;post = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Post&lt;/span&gt;();

                post.description = reader[&lt;span style="color: #a31515"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;].ToString();
                post.title = reader[&lt;span style="color: #a31515"&gt;&amp;quot;title&amp;quot;&lt;/span&gt;].ToString();
                post.postid = (&lt;span style="color: blue"&gt;int&lt;/span&gt;)reader[&lt;span style="color: #a31515"&gt;&amp;quot;pk&amp;quot;&lt;/span&gt;];

                &lt;span style="color: green"&gt;// *** Move to business object
                &lt;/span&gt;post.permalink = STR_WeblogBaseUrl + &lt;span style="color: #a31515"&gt;&amp;quot;ShowPost.blog?id=&amp;quot; &lt;/span&gt;+ reader[&lt;span style="color: #a31515"&gt;&amp;quot;pk&amp;quot;&lt;/span&gt;].ToString();
                post.link = post.permalink;

                post.dateCreated = (&lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;) reader[&lt;span style="color: #a31515"&gt;&amp;quot;Entered&amp;quot;&lt;/span&gt;];
                &lt;span style="color: blue"&gt;string&lt;/span&gt;[] Categories = reader[&lt;span style="color: #a31515"&gt;&amp;quot;Categories&amp;quot;&lt;/span&gt;].ToString().Split(&lt;span style="color: blue"&gt;new char&lt;/span&gt;[1] {&lt;span style="color: #a31515"&gt;','&lt;/span&gt;},&lt;span style="color: #2b91af"&gt;StringSplitOptions&lt;/span&gt;.RemoveEmptyEntries);
                post.categories = Categories;

                Posts.Add(post);
            }

            &lt;span style="color: blue"&gt;return &lt;/span&gt;Posts.ToArray();
        }

        &lt;span style="color: blue"&gt;public bool &lt;/span&gt;editPost(&lt;span style="color: blue"&gt;string &lt;/span&gt;postid, &lt;span style="color: blue"&gt;string &lt;/span&gt;username, &lt;span style="color: blue"&gt;string &lt;/span&gt;password, &lt;span style="color: #2b91af"&gt;Post &lt;/span&gt;post, &lt;span style="color: blue"&gt;bool &lt;/span&gt;publish)
        {
            &lt;span style="color: blue"&gt;this&lt;/span&gt;.ValidateUser(username, password);

            &lt;span style="color: blue"&gt;int &lt;/span&gt;id = -1;
            &lt;span style="color: blue"&gt;int&lt;/span&gt;.TryParse(postid, &lt;span style="color: blue"&gt;out &lt;/span&gt;id);

            &lt;span style="color: blue"&gt;string &lt;/span&gt;sql =
            &lt;span style="color: #a31515"&gt;@&amp;quot;update blog_entries 
                set Title=?,
                body=?,
                abstract=?,
                active=?,
                categories=?,
                keywords=?
                where pk = ?&amp;quot;&lt;/span&gt;;

            &lt;span style="color: blue"&gt;string &lt;/span&gt;abstr = post.mt_excerpt;
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(&lt;span style="color: blue"&gt;string&lt;/span&gt;.IsNullOrEmpty(abstr))
                abstr = &lt;span style="color: #2b91af"&gt;StringUtils&lt;/span&gt;.HtmlAbstract(post.description, 200);  
            &lt;span style="color: blue"&gt;string &lt;/span&gt;kwrds = post.mt_keywords;
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(&lt;span style="color: blue"&gt;string&lt;/span&gt;.IsNullOrEmpty(kwrds))
                kwrds = &lt;span style="color: blue"&gt;string&lt;/span&gt;.Empty;
            &lt;span style="color: blue"&gt;string &lt;/span&gt;userid = post.userid;
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(&lt;span style="color: blue"&gt;string&lt;/span&gt;.IsNullOrEmpty(userid))
                userid = STR_RickStrahl;
            &lt;span style="color: blue"&gt;string &lt;/span&gt;cats = &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(post.categories != &lt;span style="color: blue"&gt;null &lt;/span&gt;|| post.categories.Length &amp;gt; 0)
            {
                &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;string &lt;/span&gt;cat &lt;span style="color: blue"&gt;in &lt;/span&gt;post.categories)
                    cats += cat + &lt;span style="color: #a31515"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;;
                cats.TrimEnd(&lt;span style="color: #a31515"&gt;','&lt;/span&gt;);
            }

            &lt;span style="color: blue"&gt;int &lt;/span&gt;res =
                Data.ExecuteNonQuery(sql,
                Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;, post.title),
                Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;, post.description),
                Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;, abstr),
                Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;, publish),
                Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;, cats),
                Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;, kwrds),
                Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;, id)
                );


            &lt;span style="color: blue"&gt;if &lt;/span&gt;(res == -1)
                &lt;span style="color: blue"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XmlRpcException&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Error inserting data: &amp;quot; &lt;/span&gt;+ Data.ErrorMessage);
            
            &lt;span style="color: blue"&gt;return true&lt;/span&gt;;
        }

        &lt;span style="color: blue"&gt;public string &lt;/span&gt;newPost(&lt;span style="color: blue"&gt;object &lt;/span&gt;blogid, &lt;span style="color: blue"&gt;string &lt;/span&gt;username, &lt;span style="color: blue"&gt;string &lt;/span&gt;password, &lt;span style="color: #2b91af"&gt;Post &lt;/span&gt;post, &lt;span style="color: blue"&gt;bool &lt;/span&gt;publish)
        {
            &lt;span style="color: blue"&gt;this&lt;/span&gt;.ValidateUser(username, password);


            &lt;span style="color: blue"&gt;int &lt;/span&gt;id = (&lt;span style="color: blue"&gt;int&lt;/span&gt;)Data.ExecuteScalar(&lt;span style="color: #a31515"&gt;&amp;quot;select max(pk) from blog_entries&amp;quot;&lt;/span&gt;);
            id++;                        

            &lt;span style="color: blue"&gt;string &lt;/span&gt;sql =
&lt;span style="color: #a31515"&gt;@&amp;quot;insert into blog_entries (pk,blogPk,Title, body, abstract, entered, updated, author,active,categories,keywords,feedback,url,BodyMode) 
         values (?,0,?,?,?,?,?,?,?,?,?,0,'',0)&amp;quot;&lt;/span&gt;;

            &lt;span style="color: blue"&gt;string &lt;/span&gt;abstr = post.mt_excerpt;
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(&lt;span style="color: blue"&gt;string&lt;/span&gt;.IsNullOrEmpty(abstr))
                abstr = &lt;span style="color: #2b91af"&gt;StringUtils&lt;/span&gt;.HtmlAbstract(post.description, 200);                
            &lt;span style="color: blue"&gt;string &lt;/span&gt;kwrds = post.mt_keywords;
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(&lt;span style="color: blue"&gt;string&lt;/span&gt;.IsNullOrEmpty(kwrds))
                kwrds = &lt;span style="color: blue"&gt;string&lt;/span&gt;.Empty;
            &lt;span style="color: blue"&gt;string &lt;/span&gt;userid = post.userid;
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(&lt;span style="color: blue"&gt;string&lt;/span&gt;.IsNullOrEmpty(userid))
                userid = STR_RickStrahl;
            &lt;span style="color: blue"&gt;string &lt;/span&gt;cats = &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(post.categories != &lt;span style="color: blue"&gt;null &lt;/span&gt;|| post.categories.Length &amp;gt; 0)
            {
                &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;string &lt;/span&gt;cat &lt;span style="color: blue"&gt;in &lt;/span&gt;post.categories)
                    cats += cat + &lt;span style="color: #a31515"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;;
                cats.TrimEnd(&lt;span style="color: #a31515"&gt;','&lt;/span&gt;);
            }



            &lt;span style="color: blue"&gt;int &lt;/span&gt;res = 
                Data.ExecuteNonQuery(sql,
                    Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;,id),                    
                    Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;,post.title),
                    Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;,post.description),
                    Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;,abstr),
                    Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;,post.dateCreated &amp;lt; &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;(2010,1,1) ? &lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;.Now : post.dateCreated),
                    Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;, &lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;.Now),
                    Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;,userid),
                    Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;,publish),
                    Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;,cats),
                    Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;,kwrds)
                    );

            &lt;span style="color: blue"&gt;if &lt;/span&gt;(res == -1)
                &lt;span style="color: blue"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XmlRpcException&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Error inserting data: &amp;quot; &lt;/span&gt;+ Data.ErrorMessage);
                        
            
            &lt;span style="color: blue"&gt;return &lt;/span&gt;id.ToString();
        
       }


        &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;mediaObjectInfo &lt;/span&gt;newMediaObject(&lt;span style="color: blue"&gt;object &lt;/span&gt;blogid, &lt;span style="color: blue"&gt;string &lt;/span&gt;username, &lt;span style="color: blue"&gt;string &lt;/span&gt;password, &lt;span style="color: #2b91af"&gt;mediaObject &lt;/span&gt;mediaobject)
        {
            &lt;span style="color: blue"&gt;this&lt;/span&gt;.ValidateUser(username,password);

            &lt;span style="color: blue"&gt;string &lt;/span&gt;relPath = STR_WconnectweblogimageContent + &lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;.Now.Year.ToString() + &lt;span style="color: #a31515"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;;

            &lt;span style="color: blue"&gt;string &lt;/span&gt;ImagePhysicalPath = &lt;span style="color: #2b91af"&gt;HttpContext&lt;/span&gt;.Current.Server.MapPath(relPath);

            &lt;span style="color: blue"&gt;if &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Directory&lt;/span&gt;.Exists(ImagePhysicalPath))
                &lt;span style="color: #2b91af"&gt;Directory&lt;/span&gt;.CreateDirectory(ImagePhysicalPath);
                
            &lt;span style="color: blue"&gt;string &lt;/span&gt;ImageWebPath = &lt;span style="color: #2b91af"&gt;WebUtils&lt;/span&gt;.ResolveServerUrl(relPath,&lt;span style="color: blue"&gt;false&lt;/span&gt;);

            &lt;span style="color: blue"&gt;if &lt;/span&gt;(mediaobject.bits != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
            {
                &lt;span style="color: #2b91af"&gt;MemoryStream &lt;/span&gt;ms = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MemoryStream&lt;/span&gt;(mediaobject.bits);
                &lt;span style="color: #2b91af"&gt;Bitmap &lt;/span&gt;bitmap = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Bitmap&lt;/span&gt;(ms);

                ImagePhysicalPath = ImagePhysicalPath + mediaobject.name;
                &lt;span style="color: blue"&gt;string &lt;/span&gt;PathOnly = &lt;span style="color: #2b91af"&gt;Path&lt;/span&gt;.GetDirectoryName(ImagePhysicalPath).Replace(&lt;span style="color: #a31515"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;,&lt;span style="color: #a31515"&gt;&amp;quot;\\&amp;quot;&lt;/span&gt;);
                &lt;span style="color: blue"&gt;if &lt;/span&gt;(!&lt;span style="color: #2b91af"&gt;Directory&lt;/span&gt;.Exists(PathOnly))
                    &lt;span style="color: #2b91af"&gt;Directory&lt;/span&gt;.CreateDirectory(PathOnly);

                bitmap.Save(ImagePhysicalPath);
            }

            &lt;span style="color: #2b91af"&gt;mediaObjectInfo &lt;/span&gt;mediaInfo = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;mediaObjectInfo&lt;/span&gt;();
            mediaInfo.url = ImageWebPath + mediaobject.name;                        
            &lt;span style="color: blue"&gt;return &lt;/span&gt;mediaInfo;
        }

        &lt;span style="color: blue"&gt;public bool &lt;/span&gt;deletePost(&lt;span style="color: blue"&gt;string &lt;/span&gt;appKey, &lt;span style="color: blue"&gt;string &lt;/span&gt;postid, &lt;span style="color: blue"&gt;string &lt;/span&gt;username, &lt;span style="color: blue"&gt;string &lt;/span&gt;password, &lt;span style="color: blue"&gt;bool &lt;/span&gt;publish)
        {
            &lt;span style="color: blue"&gt;this&lt;/span&gt;.ValidateUser(username, password);

            &lt;span style="color: blue"&gt;int &lt;/span&gt;postpk = -1;
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(!&lt;span style="color: blue"&gt;int&lt;/span&gt;.TryParse(postid, &lt;span style="color: blue"&gt;out &lt;/span&gt;postpk))
                &lt;span style="color: blue"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XmlRpcException&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Invalid Pk passed&amp;quot;&lt;/span&gt;);
            
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(Data.ExecuteNonQuery(&lt;span style="color: #a31515"&gt;&amp;quot;delete from entries where pk = ?&amp;quot;&lt;/span&gt;,
                                 Data.CreateParameter(&lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;, postpk)) &amp;gt; -1)
                &lt;span style="color: blue"&gt;return true&lt;/span&gt;;

            &lt;span style="color: blue"&gt;return false&lt;/span&gt;;            
        }

        &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;BlogInfo&lt;/span&gt;[] getUsersBlogs(&lt;span style="color: blue"&gt;string &lt;/span&gt;appKey, &lt;span style="color: blue"&gt;string &lt;/span&gt;username, &lt;span style="color: blue"&gt;string &lt;/span&gt;password)
        {
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(!&lt;span style="color: blue"&gt;this&lt;/span&gt;.ValidateUser(username, password))
                &lt;span style="color: blue"&gt;return null&lt;/span&gt;;

            &lt;span style="color: #2b91af"&gt;BlogInfo &lt;/span&gt;blog = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;BlogInfo&lt;/span&gt;();
            blog.blogid = &lt;span style="color: #a31515"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;;            
            blog.blogName = STR_WebLogName;
            blog.url = STR_WeblogBaseUrl;
            
            &lt;span style="color: blue"&gt;return new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;BlogInfo&lt;/span&gt;[1] { blog };
        }

        &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;wp_author&lt;/span&gt;[] wp_getAuthors(&lt;span style="color: blue"&gt;object &lt;/span&gt;blogId, &lt;span style="color: blue"&gt;string &lt;/span&gt;username, &lt;span style="color: blue"&gt;string &lt;/span&gt;password)
        {
            &lt;span style="color: blue"&gt;this&lt;/span&gt;.ValidateUser(username, password);                

            &lt;span style="color: #2b91af"&gt;wp_author &lt;/span&gt;author = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;wp_author&lt;/span&gt;();
            author.display_name = STR_RickStrahl;
            author.user_email = &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
            author.user_login = &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
            author.meta_value = &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;

            &lt;span style="color: blue"&gt;return new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;wp_author&lt;/span&gt;[1] { author };
        }
        &lt;span style="color: blue"&gt;#endregion
    &lt;/span&gt;}&lt;/pre&gt;

&lt;p&gt;This code is based on &lt;a href="http://www.west-wind.com/weblog/posts/2007/Mar/10/MetaWebLog-API-and-Blog-Writers" target="_blank"&gt;my original post&lt;/a&gt; which includes the XmlRpc class and IMetaWeblogApi implementation. The nice thing about this is that the process of converting this code to run with FoxPro data was pretty easy. The ASP.NET blog uses more sophisticated business objects since the entire app is running in .NET. The FoxPro app also uses business objects running against FoxPro data, but those business objects are not easily accessible to .NET. I wanted to avoid COM Interop at all costs here so I chose to go the direct SQL route.&lt;/p&gt;

&lt;p&gt;I'm posting this here mainly because I've seen a lot of questions FoxPro about data choices. Here's an example that shows how to use a light abstraction layer around the ADO.NET API which goes a long way towards making it pretty easy to access FoxPro data with minimal fuss. You can use my data access layer (it's free for personal use and testing, and cheap for commercial use) or you can build something similar on your own.&lt;/p&gt;

&lt;p&gt;And hey -&amp;#160; if you've read this far you can see the fruits of this labor in code above: This post was posted to the blog using the metaweblog api client and Windows Live Writer. Feeling a little dÃ©jÃ  vu, when viewing this screen shot? :-)&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.west-wind.com/wconnect/weblog/imageContent/2011/Windows-Live-Writer/ef2d63d29879_1A31/LiveWriterEditing%5B10%5D_1.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="LiveWriterEditing[10]" border="0" alt="LiveWriterEditing[10]" src="http://www.west-wind.com/wconnect/weblog/imageContent/2011/Windows-Live-Writer/ef2d63d29879_1A31/LiveWriterEditing%5B10%5D_thumb_1.png" width="804" height="928" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Resources&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://www.west-wind.com/weblog/posts/2007/Mar/10/MetaWebLog-API-and-Blog-Writers" target="_blank"&gt;&lt;strong&gt;Original MetaWeblogAPI article&lt;/strong&gt;&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://www.west-wind.com/files/tools/misc/metaweblog.zip" target="_blank"&gt;&lt;strong&gt;Original base MetaWebLogAPI C# code download&lt;/strong&gt;&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://www.west-wind.com/WestwindWebToolkit/" target="_blank"&gt;&lt;strong&gt;West Wind Web Toolkit&lt;/strong&gt;&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://www.west-wind.com:8080/svn/WestwindWebToolkit/trunk/Westwind.Utilities/Data/" target="_blank"&gt;&lt;strong&gt;SqlDataAccess Source Code&lt;/strong&gt;&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://www.west-wind.com/WestwindWebToolkit/docs?page=_3c00lhq3f.htm" target="_blank"&gt;&lt;strong&gt;SqlDataAccess Documentation&lt;/strong&gt;&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ElovZqMrzDbd4VMZ2jt_wL0wFHM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ElovZqMrzDbd4VMZ2jt_wL0wFHM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ElovZqMrzDbd4VMZ2jt_wL0wFHM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ElovZqMrzDbd4VMZ2jt_wL0wFHM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=-rZ0RS3Gaxk:6tW17M85Hxw:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=-rZ0RS3Gaxk:6tW17M85Hxw:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=-rZ0RS3Gaxk:6tW17M85Hxw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=-rZ0RS3Gaxk:6tW17M85Hxw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=-rZ0RS3Gaxk:6tW17M85Hxw:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=-rZ0RS3Gaxk:6tW17M85Hxw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=-rZ0RS3Gaxk:6tW17M85Hxw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=-rZ0RS3Gaxk:6tW17M85Hxw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=-rZ0RS3Gaxk:6tW17M85Hxw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=-rZ0RS3Gaxk:6tW17M85Hxw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~4/-rZ0RS3Gaxk" height="1" width="1"/&gt;</description>
     <feedburner:origLink>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=879</feedburner:origLink></item>
     <item>
			<title>Doing .NET COM Interop with FoxPro? You need a .NET Disassembler</title>
			<pubDate>Fri, 18 Nov 2011 03:02:11 GMT</pubDate>
			<guid isPermaLink="false">878_20111117</guid>
			<link>http://feedproxy.google.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~3/slk5APwhmos/ShowEntry.blog</link>
			<dc:creator />
			<comments>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=878#Feedback</comments>
			<slash:comments>2</slash:comments>
			<description>&lt;p&gt;So you're doing a bunch of COM Interop with .NET. Whether you're using plain COM Interop or the richer functionality offered by &lt;a href="http://www.west-wind.com/webconnection/wwClient_docs?pag=_24n1cfw3a.htm" target="_blank"&gt;wwDotnetBridge&lt;/a&gt;, you probably already know that finding the approriate .NET type names is tedious. FoxPro code in either case must reference the full .NET typename which includes the namespace and class name.&lt;/p&gt;  &lt;p&gt;For example check out this code that loops through personal certificate store on the local machine using wwDotnetBridge. I've highlighted all the .NET type names used in this small snippet in bold:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;do &lt;/span&gt;&lt;span style="color: black"&gt;wwDotNetBridge
&lt;/span&gt;&lt;span style="color: blue"&gt;LOCAL &lt;/span&gt;&lt;span style="color: black"&gt;loBridge &lt;/span&gt;&lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: black"&gt;wwDotNetBridge
loBridge &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;CreateObject&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;"wwDotNetBridge"&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: teal"&gt;"V4"&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** Create an instance of 509Store
&lt;span style="color: black"&gt;loStore &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;loBridge&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;CreateInstance&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;"&lt;strong&gt;System.Security.Cryptography.X509Certificates.X509Store&lt;/strong&gt;"&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** Grab a static Enum value
&lt;span style="color: black"&gt;leReadOnly &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;loBridge&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;GetEnumvalue&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;"&lt;strong&gt;System.Security.Cryptography.X509Certificates.OpenFlags&lt;/strong&gt;"&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: teal"&gt;"ReadOnly"&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** Open the certificate store - results into loStore.Certificates
&lt;span style="color: black"&gt;loStore&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: blue"&gt;Open&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;leReadOnly&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** Collection of Certificates
&lt;span style="color: black"&gt;laCertificates &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;loStore&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Certificates

&lt;/span&gt;*** Collections don't work over regular COM Interop
*** so use indirect access
&lt;span style="color: black"&gt;lnCount &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;loBridge&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;GetProperty&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;laCertificates&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: teal"&gt;"Count"&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** Loop through Certificates
&lt;span style="color: blue"&gt;FOR &lt;/span&gt;&lt;span style="color: black"&gt;lnX &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;1 &lt;/span&gt;&lt;span style="color: blue"&gt;TO &lt;/span&gt;&lt;span style="color: black"&gt;lnCount &lt;/span&gt;&lt;span style="color: black"&gt;-&lt;/span&gt;&lt;span style="color: black"&gt;1
    &lt;/span&gt;*** Access collection item indirectly
    &lt;span style="color: blue"&gt;LOCAL &lt;/span&gt;&lt;span style="color: black"&gt;loCertificate &lt;/span&gt;&lt;span style="color: blue"&gt;as &lt;strong&gt;System&lt;/strong&gt;&lt;/span&gt;&lt;strong&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Security&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Cryptography&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;X509Certificates&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;/strong&gt;&lt;span style="color: black"&gt;&lt;strong&gt;X509Certificate2&lt;/strong&gt;    
    loCertificate &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;loBridge&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;GetPropertyEx&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;loStore&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: teal"&gt;"Certificates[" &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: blue"&gt;TRANSFORM&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lnX&lt;/span&gt;&lt;span style="color: black"&gt;) + &lt;/span&gt;&lt;span style="color: teal"&gt;"]"&lt;/span&gt;&lt;span style="color: black"&gt;)
    
    &lt;/span&gt;&lt;span style="color: blue"&gt;IF &lt;/span&gt;&lt;span style="color: black"&gt;!&lt;/span&gt;&lt;span style="color: blue"&gt;ISNULL&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;loCertificate&lt;/span&gt;&lt;span style="color: black"&gt;)
        ? &lt;/span&gt;&lt;span style="color: black"&gt;loCertificate&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;FriendlyName
        &lt;/span&gt;&lt;span style="color: black"&gt;? &lt;/span&gt;&lt;span style="color: black"&gt;loCertificate&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;SerialNumber
        &lt;/span&gt;&lt;span style="color: black"&gt;? &lt;/span&gt;&lt;span style="color: black"&gt;loBridge&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;GetPropertyEx&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;loCertificate&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: teal"&gt;"IssuerName.Name"&lt;/span&gt;&lt;span style="color: black"&gt;)
    &lt;/span&gt;&lt;span style="color: blue"&gt;ENDIF
ENDFOR

RETURN&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;How the heck do you figure out all those type names used in this code?&lt;/p&gt;

&lt;p&gt;Answer: You use a .NET disassembling tool that provides insight into a .NET assembly. Regardless of whether you're using a system component or custom .NET component of your own being able to look up exact type names is critical if you do .NET COM Interop.&lt;/p&gt;

&lt;h3&gt;.NET Reflector&lt;/h3&gt;

&lt;p&gt;My favorite tool to do this is &lt;a href="http://www.reflector.net/" target="_blank"&gt;Red Gate's .NET Reflector&lt;/a&gt;. .NET Reflector is free up to version 6.8 and a relatively cheap tool for all that it provides from version 7.0 forward. All the features described here work in 6.x although I'm using version 7.&lt;/p&gt;

&lt;p&gt;Using Reflector basically allows you to point at any DLL on disk and show all the contained types and resources that are available. It can also load assemblies from the GAC and by default it loads up a number of common .NET runtime components.&lt;/p&gt;

&lt;p&gt;Here's a view of Reflector with the X509Store class open and selected:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.west-wind.com/Weblog/images/200901/Windows-Live-Writer/Doi.NET-COM-Interop-with-FoxPro-You-need_E9F0/Reflector_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Reflector" alt="Reflector" src="http://www.west-wind.com/Weblog/images/200901/Windows-Live-Writer/Doi.NET-COM-Interop-with-FoxPro-You-need_E9F0/Reflector_thumb.png" height="829" width="1043" border="0"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Reflector provides a number of important pieces of information for Interop. It basically lets you browser the .NET component that you might want to access and call methods or access properties on. You can at a glance see what the component does and how you need to interact with it. &lt;/p&gt;

&lt;p&gt;The next important thing is that you can get the full class name for any type. Notice in the bottom left window it gives the name of the type, its definition and the fully qualified type name that includes the full namespace and class. THIS is the type name you generally need for the wwDotnetBridge CreateInstance call.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: black"&gt;loStore &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;loBridge&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;CreateInstance&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;"System.Security.Cryptography.X509Certificates.X509Store"&lt;/span&gt;&lt;span style="color: black"&gt;)&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;I can't stress how important this particular piece of information is because while you might know what the name of a particular .NET class is often it's not so easy to figure out what the full name is. This is especially true if you're loading a third party assembly that might not be well documented. .NET components frequently omit detailed full type information documentation because .NET developers are used to Intellisense and Visual Studio helping them inject assembly and namespace references into their code. As FoxPro developers doing interop we don't have that luxury so for us using a tool like Reflector is vitally important.&lt;/p&gt;

&lt;p&gt;Next you can also get detailed information about the methods that you call in .NET. Again this is vitally important as you have to ensure that you are passing the right parameters to .NET and that these types match the .NET signature. Type marshalling from FoxPro -&amp;gt; .NET doesn't always work as expected especially when dealing with numeric values (don't forget to use CAST()).&lt;/p&gt;

&lt;p&gt;For the method view we get the full parameter signature plus a disassembled view of the actual code:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.west-wind.com/Weblog/images/200901/Windows-Live-Writer/Doi.NET-COM-Interop-with-FoxPro-You-need_E9F0/Reflector2_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Reflector2" alt="Reflector2" src="http://www.west-wind.com/Weblog/images/200901/Windows-Live-Writer/Doi.NET-COM-Interop-with-FoxPro-You-need_E9F0/Reflector2_thumb.png" height="588" width="993" border="0"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The disassembled code is very useful for .NET developers at times. As Fox developers all we care about is the method signature though. We can see all the parameters that are passed and all complex types (like the OpenFlags Enum here) are linked, so you can click on the link and directly navigate to the Enum type:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.west-wind.com/Weblog/images/200901/Windows-Live-Writer/Doi.NET-COM-Interop-with-FoxPro-You-need_E9F0/Reflector3_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Reflector3" alt="Reflector3" src="http://www.west-wind.com/Weblog/images/200901/Windows-Live-Writer/Doi.NET-COM-Interop-with-FoxPro-You-need_E9F0/Reflector3_thumb.png" height="588" width="993" border="0"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Now what's cool here is that you get to see the actual typename as before and we can now use wwDotnetBridge's Enum functionality to create the enum value in FoxPro code:&lt;span style="color: black"&gt;&lt;/span&gt;

  &lt;/p&gt;&lt;p&gt;&lt;font face="Calibri"&gt;&lt;span style="color: black"&gt;
        &lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;pre class="code"&gt;&lt;font face="Calibri"&gt;&lt;span style="color: black"&gt;leReadOnly &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;loBridge&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;GetEnumvalue&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;"System.Security.Cryptography.X509Certificates.OpenFlags"&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: teal"&gt;"ReadOnly"&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;loStore&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: blue"&gt;Open&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;leReadOnly&lt;/span&gt;&lt;span style="color: black"&gt;)&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;font face="Calibri"&gt;
        &lt;/font&gt;&lt;font face="Calibri"&gt;&lt;/font&gt;&lt;p&gt;&lt;/p&gt;

  
  &lt;span style="color: black"&gt;&lt;/span&gt;&lt;font face="Calibri"&gt;&lt;/font&gt;You can see that I need the full type name here, and I can get that from the Name property in the window on the lower left.&lt;p&gt;&lt;/p&gt;

&lt;p&gt;However, there's actually an easier way: Since Reflector shows me the disassembled code it also shows me the Flag values for this particular enumeration. I can actually bypass the enumeration and just use the numeric value:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: black"&gt;loStore&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: blue"&gt;Open&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;0&lt;/span&gt;&lt;span style="color: black"&gt;) &lt;/span&gt;&amp;amp;&amp;amp; leReadOnly)&lt;/pre&gt;


&lt;p&gt;and it works just the same. Note that this will work as long the Enum is actually a flag value - not all enumerated values in .NET translate to a flag value so not all enums translated into numbers. You'll know because Reflector won't show the numbers if that's the case.&lt;/p&gt;

&lt;h3&gt;What's that Assembly Name from the GAC?&lt;/h3&gt;

&lt;p&gt;When loading assemblies with wwDotnetBridge from the GAC you need to specify a full assembly name rather than a filename. Actually you can use filename if you know the exact path in the GAC, but that's usually a rather long and obscure path. A better way to reference GAC components is via their full assembly name. For example earlier I needed to work with the .NET JavaScript serializer for long string serialization/deserialization. Here's a small code example that demon hat does this using wwDotNetBridge:&lt;/p&gt;

&lt;pre class="code"&gt;*** Load a GAC assembly (full .NET type name required)
&lt;span style="color: black"&gt;loBridge&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;LoadAssembly&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;"&lt;strong&gt;System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35&lt;/strong&gt;"&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** Load a private assembly from disk by full file name
* ? loBridge.LoadAssemblY("c:\apps\myapp\myappassembly.dll")

*** Create an instance of the JavaScript Serializer
&lt;span style="color: black"&gt;loSer &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;loBridge&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;CreateInstance&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;"System.Web.Script.Serialization.JavaScriptSerializer"&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;&lt;span style="color: black"&gt;lcValue &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;"Hello World\r\nHere's what I've got!"

&lt;/span&gt;*** Serialize string to JSON
&lt;span style="color: black"&gt;lcJson &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;loSer&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;serialize&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcValue&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;span style="color: black"&gt;? &lt;/span&gt;&lt;span style="color: black"&gt;lcJson

&lt;/span&gt;*** Create a .NET Type object for string
&lt;span style="color: black"&gt;loType &lt;/span&gt;&lt;span style="color: black"&gt;= &lt;/span&gt;&lt;span style="color: black"&gt;loBridge&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;GetType&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;"x"&lt;/span&gt;&lt;span style="color: black"&gt;)

&lt;/span&gt;*** Deserialize with the .NET type provided
&lt;span style="color: black"&gt;? &lt;/span&gt;&lt;span style="color: black"&gt;loSer&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;Deserialize&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;lcJson&lt;/span&gt;&lt;span style="color: black"&gt;,&lt;/span&gt;&lt;span style="color: black"&gt;loType&lt;/span&gt;&lt;span style="color: black"&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;span style="color: black"&gt;To find this assembly in Reflector from the GAC I can use File | Open Global Assembly Cache and then look at the assembly in the list view:&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.west-wind.com/Weblog/images/200901/Windows-Live-Writer/Doi.NET-COM-Interop-with-FoxPro-You-need_E9F0/Reflector4%5B4%5D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Reflector4[4]" alt="Reflector4[4]" src="http://www.west-wind.com/Weblog/images/200901/Windows-Live-Writer/Doi.NET-COM-Interop-with-FoxPro-You-need_E9F0/Reflector4%5B4%5D_thumb.png" height="352" width="600" border="0"&gt;&lt;/a&gt;

  &lt;br&gt;&lt;/p&gt;

&lt;p&gt;And now the strong assembly name shows up in the name property on the bottom which I can then use in my LoadAssembly call:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: black"&gt;loBridge&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;LoadAssembly&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;"System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"&lt;/span&gt;&lt;span style="color: black"&gt;)
&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;&amp;nbsp;&lt;/p&gt;



&lt;p&gt;Note with GAC components - especially those from Microsoft - the hardest part often is to figure which assembly components live in. When in doubt punch in a search into your favorite search engine and look at MSDN entries. As ineffectual as MSDN documentation often is, it does provide you with the necessary type information most of the time:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.west-wind.com/Weblog/images/200901/Windows-Live-Writer/Doi.NET-COM-Interop-with-FoxPro-You-need_E9F0/MsdnLookup_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="MsdnLookup" alt="MsdnLookup" src="http://www.west-wind.com/Weblog/images/200901/Windows-Live-Writer/Doi.NET-COM-Interop-with-FoxPro-You-need_E9F0/MsdnLookup_thumb.png" height="548" width="865" border="0"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;You get the two important pieces of information you need: The assembly the component lives in and the full namespace. Once you load the assembly you can easily look up the namespace and find the class in Reflector.&lt;/p&gt;

&lt;h3&gt;Reflector in the real World&lt;/h3&gt;

&lt;p&gt;I have a tool called &lt;a href="http://www.west-wind.com/wsdlgenerator/" target="_blank"&gt;West Wind Web Service Proxy Generator&lt;/a&gt;, which is a tool that creates Web Service clients from a WSDL document for Visual FoxPro applications. This tool works by looking at a WSDL document and create a .NET proxy class, and a FoxPro class that calls this .NET proxy class. In the process we end up with a 1-1 mapping of Web Service methods to FoxPro class methods.&lt;/p&gt;

&lt;p&gt;Web Services can get very complex and most of the time these Web Services include a slew of support types that make up the various message objects that are used to pass parameters to and from the Web Service. For example, if you look at the Amazon SOAP Web Services you'll find that there are hundreds of support objects! But even simpler services end up at least with a handful of objects. Since .NET imports the WSDL from the Web and dynamically generates these types as part of the import there is no explicit documentation for them. A tool like Reflector is a life saver to figure out what the service makes available.&lt;/p&gt;

&lt;p&gt;Here's an example:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.west-wind.com/Weblog/images/200901/Windows-Live-Writer/Doi.NET-COM-Interop-with-FoxPro-You-need_E9F0/WebService_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="WebService" alt="WebService" src="http://www.west-wind.com/Weblog/images/200901/Windows-Live-Writer/Doi.NET-COM-Interop-with-FoxPro-You-need_E9F0/WebService_thumb.png" height="650" width="948" border="0"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In this case there's one service class (at the bottom) and about a dozen message classes that are used as part of the requests. Figuring out the full type names for each of these types is not exactly obvious and finding out each of the object's properties isn't either. It's tremendously helpful to be able to look at Reflector and to look at the method I'm calling, following it to the message type that needs to be sent to get the object name and then be able to access each of the properties of each of these objects.&lt;/p&gt;

&lt;p&gt;It's invaluable.&lt;/p&gt;

&lt;h3&gt;Reflect on this!&lt;/h3&gt;

&lt;p&gt;Ok, so Reflector is very cool, but Reflector has kind of a checkered history and it's not the only game in town anymore. Reflector started out as an open source tool by Lutz Roeder who maintained it until version 4.0. Red Gate took over the product and although they promised to keep it free eventually started forcing people to upgrade to Version 7.0 with a nasty forced upgrade. I've been bitten by this as I've been linking Reflector as part of the &lt;a href="http://www.west-wind.com/wsdlgenerator/" target="_blank"&gt;West Wind Web Service Proxy Generator&lt;/a&gt;, so lots of people actually used Reflector in conjunction with this tool. When Reflector 7 came out Red Gate tried to force people to upgrade and when they didn't they actually removed the running copy of Reflector - it self-destructed and broke some of the links in my tool. Argh! I was pissed.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.red-gate.com/messageboard/viewtopic.php?t=13384" target="_blank"&gt;Red Gate recently reversed that last bit and now Version 6.8 can be used for free&lt;/a&gt; (if you can find a copy of V6) and it won't ask to upgrade or self destruct, but the catch is that you have to have an existing copy of Reflector 6 to upgrade first (Red Gate took down Reflector 6 from their servers).&lt;/p&gt;

&lt;p&gt;All that said I think that Reflector is a worthwhile tool to spend $35 on even if all you do is COM Interop. The latest version has a number of improvements you know you're running a tool that is kept up to date with the latest features and versions of the .NET runtime.&lt;/p&gt;

&lt;p&gt;You can grab an eval copy of Reflector from here:&lt;/p&gt;

&lt;p&gt;&lt;a title="http://www.reflector.net/" href="http://www.reflector.net/"&gt;http://www.reflector.net/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For what it's worth I use Reflector 7 and have upgraded because it's worth it and I have dependencies on it. I don't regret that, but I am pretty miffed at the way Red Gate handled this whole upgrade process.&lt;/p&gt;

&lt;h3&gt;Other Options&lt;/h3&gt;

&lt;p&gt;Because of the way that Red Gate blundered their marketing on the move to version 7.0 a lot of people were pissed off and a number of alternatives have sprung up, all of them free. Most of these provide similar functionality as Reflector does although the user interface might be slightly different (out of these JustDecompile is probably closest to Reflector).&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href="http://wiki.sharpdevelop.net/ILSpy.ashx" target="_blank"&gt;ILSpy&lt;/a&gt;

      &lt;br&gt;&lt;/strong&gt;Open source tool that provides all the basic functionality of Reflector, but the UI is a bit more low level. Little harder to find things. 

    &lt;br&gt;&lt;em&gt;(requires .NET 4.0)&lt;/em&gt;&lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;&lt;a href="http://www.telerik.com/products/decompiler.aspx" target="_blank"&gt;JustDecompile&lt;/a&gt;

      &lt;br&gt;&lt;/strong&gt;Telerik basically created a .NET Reflector clone using WPF. It's a nice and smooth application that provides the base features that .NET Reflector provides in a user interface that's very similar to Reflectors. 

    &lt;br&gt;&lt;em&gt;(requires .NET 4.0)&lt;/em&gt;&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://www.jetbrains.com/decompiler/" target="_blank"&gt;&lt;strong&gt;DotPeek&lt;/strong&gt;&lt;/a&gt;

    &lt;br&gt;JetBrains also has a tool that competes in this space. It's more techy and provides many additional .NET features that won't be so useful to Interop developers. But as the others it provides the necessary tools to figure out type names and method signatures reliably. 

    &lt;br&gt;&lt;em&gt;(requires .NET 4.0)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see all the alternate tools require .NET 4.0 while Reflector 6 and 7 still run on Version 2.0 which is nice as .NET 2.0 is widely pre-loaded while 4.0 is still trying to reach critical mass. Otherwise each of these tools should do the trick of helping you in your development.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/H0kAuLQY5wZTQfyJUx3iKd3r2jA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/H0kAuLQY5wZTQfyJUx3iKd3r2jA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/H0kAuLQY5wZTQfyJUx3iKd3r2jA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/H0kAuLQY5wZTQfyJUx3iKd3r2jA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=slk5APwhmos:5jx86f1Dlq8:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=slk5APwhmos:5jx86f1Dlq8:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=slk5APwhmos:5jx86f1Dlq8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=slk5APwhmos:5jx86f1Dlq8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=slk5APwhmos:5jx86f1Dlq8:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=slk5APwhmos:5jx86f1Dlq8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=slk5APwhmos:5jx86f1Dlq8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=slk5APwhmos:5jx86f1Dlq8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=slk5APwhmos:5jx86f1Dlq8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=slk5APwhmos:5jx86f1Dlq8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~4/slk5APwhmos" height="1" width="1"/&gt;</description>
     <feedburner:origLink>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=878</feedburner:origLink></item>
     <item>
			<title>Writing to the Windows Console from Visual FoxPro</title>
			<pubDate>Mon, 7 Nov 2011 08:21:11 GMT</pubDate>
			<guid isPermaLink="false">871_20111107</guid>
			<link>http://feedproxy.google.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~3/Ul5IWCBN16w/ShowEntry.blog</link>
			<dc:creator />
			<comments>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=871#Feedback</comments>
			<slash:comments>5</slash:comments>
			<description>&lt;p&gt;I'm starting this post with a disclaimer: This post doesn't have a full solution to the problem I was aiming to solve. However I'm posting it anyway to give some insights that might prove helpful to others and a partial solution that might address some limited scenarios that only need to generate display output to the console.&lt;/p&gt;  &lt;p&gt;Here's the issue: I have a Visual FoxPro application that is a desktop application - &lt;a href="http://www.west-wind.com/wwhelp" target="_blank"&gt;Html Help Builder&lt;/a&gt; - but that also has command line options for a variety of tasks. When the app starts with no parameters it just runs the desktop app. But if you pass in a few specific parameters it will crunch away at some options and then exit. Along the way it would be nice to provide a little information, especially if something goes wrong. Specifically the process I'm working on is for Help File build automation with command line - you tell &lt;a href="http://www.west-wind.com/wwhelp/" target="top"&gt;Html Help Builder&lt;/a&gt; to do a Help File compile and build - this process may take a little while and it be nice to provide some basic status information. For command line options that process is typically handled through Console output.&lt;/p&gt;  &lt;p&gt;Alas, FoxPro - or for that matter any Windows application - can't output to Console by default. Windows apps start enter a message loop and exit back to the command prompt, and then continue running. Is it possible to write to the Console anyway? Sort ofâ€¦&lt;/p&gt;  &lt;h3&gt;Getting output to the Console&lt;/h3&gt;  &lt;p&gt;After a bit of research I found a solution to create Console output via some C code in a DLL. Basically you can attach a console or create one for a process and then write to a console.&lt;/p&gt;  &lt;p&gt;The code to do this is:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;lt;windows.h&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;lt;stdio.h&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;lt;fcntl.h&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;lt;io.h&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;lt;iostream&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;lt;fstream&amp;gt;

&lt;/span&gt;BOOL WINAPI WriteToConsole(&lt;span style="color: blue"&gt;char &lt;/span&gt;*input)
{    
    BOOL bConsole = AttachConsole(ATTACH_PARENT_PROCESS) != FALSE;

    &lt;span style="color: blue"&gt;if &lt;/span&gt;(bConsole)
    {
        &lt;span style="color: blue"&gt;int &lt;/span&gt;fd = 0;
        &lt;span style="color: blue"&gt;long &lt;/span&gt;lStdOut;
        lStdOut = (&lt;span style="color: blue"&gt;long&lt;/span&gt;)GetStdHandle( STD_OUTPUT_HANDLE); &lt;span style="color: green"&gt;// STD_ERROR_HANDLE);
        &lt;/span&gt;fd = _open_osfhandle(lStdOut, _O_TEXT);
        &lt;span style="color: blue"&gt;if &lt;/span&gt;(fd &amp;gt; 0)
        {
            *stdout = *_fdopen(fd, &lt;span style="color: #a31515"&gt;"w"&lt;/span&gt;);
            setvbuf(stdout, NULL, _IONBF, 0 );
        }
    }

    printf(input);    
    FreeConsole();
    &lt;span style="color: blue"&gt;return &lt;/span&gt;TRUE;
}&lt;/pre&gt;

&lt;p&gt;I compiled this into wwIPStuff.dll (which includes a ton of other stuff used in our &lt;a href="http://www.west-wind.com/westwindclienttools.aspx" target="_blank"&gt;West Wind Client Tools&lt;/a&gt;) and I then created a small test program ConsoleOutput.prg in FoxPro that looks like this:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: black"&gt;#&lt;/span&gt;&lt;span style="color: blue"&gt;include &lt;/span&gt;&lt;span style="color: black"&gt;wconnect&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: black"&gt;h

&lt;/span&gt;&lt;span style="color: blue"&gt;DECLARE integer &lt;/span&gt;&lt;span style="color: black"&gt;WriteToConsole &lt;/span&gt;&lt;span style="color: blue"&gt;IN &lt;/span&gt;&lt;span style="color: black"&gt;wwipstuff&lt;/span&gt;&lt;span style="color: black"&gt;.&lt;/span&gt;&lt;span style="color: blue"&gt;dll &lt;/span&gt;&lt;span style="color: black"&gt;;
     &lt;/span&gt;&lt;span style="color: blue"&gt;string

&lt;/span&gt;&lt;span style="color: black"&gt;? &lt;/span&gt;&lt;span style="color: black"&gt;WriteToConsole&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: black"&gt;CRLF&lt;/span&gt;&lt;span style="color: black"&gt;)
? &lt;/span&gt;&lt;span style="color: black"&gt;WriteToConsole&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;"Hello from FoxPro" &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;CRLF&lt;/span&gt;&lt;span style="color: black"&gt;)

? &lt;/span&gt;&lt;span style="color: black"&gt;WriteToConsole&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;"More output" &lt;/span&gt;&lt;span style="color: black"&gt;+ &lt;/span&gt;&lt;span style="color: black"&gt;CRLF&lt;/span&gt;&lt;span style="color: black"&gt;)
? &lt;/span&gt;&lt;span style="color: black"&gt;WriteToConsole&lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;"And still some More output" &lt;/span&gt;&lt;span style="color: black"&gt;+&lt;/span&gt;&lt;span style="color: black"&gt;CRLF&lt;/span&gt;&lt;span style="color: black"&gt;)

? &lt;/span&gt;&lt;span style="color: teal"&gt;"Output from FoxPro Console"
&lt;/span&gt;&lt;span style="color: blue"&gt;WAIT window
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;I then add ConsoleOutput.prg to a project and compile this into an EXE:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BUILD EXE ConsoleOutput from ConsoleOutput&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;Good News, Bad News&lt;/h3&gt;

&lt;p&gt;To run this and get Console output to work you have to run the EXE from the Windows Command prompt. If you run from Explorer nothing is going to happen since there's no console active when an app is started from Explorer, the Run box or through code.&lt;/p&gt;

&lt;p&gt;So open a command window and run the code. What you'll end up with is something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.west-wind.com/Weblog/images/200901/Windows-Live-Writer/Writing-to-the-Windows-Console-from-Visu_E9E/FoxProWindowsConsole_2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="FoxProWindowsConsole" alt="FoxProWindowsConsole" src="http://www.west-wind.com/Weblog/images/200901/Windows-Live-Writer/Writing-to-the-Windows-Console-from-Visu_E9E/FoxProWindowsConsole_thumb.png" border="0" height="313" width="677"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;It's clearly working - output *is* written into the Windows console.&lt;/p&gt;

&lt;p&gt;But if you look closely, you'll notice that something funky is going on with the command prompt. Notice that there's an empty command prompt followed by console output, and then after the program is done executing the cursor remains in 'empty space' after the console output. &lt;/p&gt;

&lt;p&gt;The command prompt is actually active, so you can type any Console commands and it will work - there's just no prompt.&lt;/p&gt;

&lt;p&gt;Why is this happening? Unfortunately, this is how a Windows application is supposed to work. A Windows app like Visual FoxPro (WinMain() entry point) starts, loads up its Windows message loop and then is supposed to exit the console and return to the command prompt. The application runs, but it runs independently of the command prompt. A true Console application however (Main() entry point) runs synchronously until the main function completes at which point the application exits and returns to the command prompt.&lt;/p&gt;

&lt;p&gt;This is even more evident if you try to redirect output to a file. If you do:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;consoleoutput &amp;gt; consoleoutput.txt&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;you'll find that a 0 byte file consoleoutput.txt is created, but it's empty and no matter what you write to the console, the file will remain at 0 bytes, because the console redirection expires when the exe returns to the command prompt.&lt;/p&gt;

&lt;p&gt;The bad news is that although I've now managed to write to the Windows Console, the output it generates is not all that useful. Yes I can see the output in the console window (even though it looks rather funky because of the writing *after* the prompt), but the output can't be captured using all the common Windows mechanisms for redirecting the output.&lt;/p&gt;

&lt;p&gt;For example in &lt;a href="http://www.west-wind.com/wwhelp/" target="top"&gt;Html Help Builder&lt;/a&gt; and my compilation output, this is useless because what I need is a mechanism to capture the result from the compilation process so it can be integrated into a build process.&lt;/p&gt;

&lt;h3&gt;No Native FoxPro Solution&lt;/h3&gt;

&lt;p&gt;Unfortunately I think this is a problem that can't be solved using FoxPro code because of the way Windows GUI apps work. The immediate exit is not something that I think we can get around especially since the console exit occurs even before any FoxPro runs. I was thinking that maybe with some of Windows internal events you'd be able to hook into the message queue at startup, but even that won't work because by the time even the first line of Fox code runs it's too late.&lt;/p&gt;

&lt;h3&gt;Workaround: Create a front end Console Application&lt;/h3&gt;

&lt;p&gt;I did end up with a solution to the problem however, although it's a pretty roundabout way to get there:&lt;/p&gt;

&lt;p&gt;I ended up creating a .NET Console application that acts as a front end to the FoxPro app. The .NET app automates the &lt;a href="http://www.west-wind.com/wwhelp/" target="top"&gt;Html Help Builder&lt;/a&gt; COM object and then echos output back to the Console. Granted this is a bit more work, especially since the FoxPro app already had a command line interface, but it's a workable solution.&lt;/p&gt;

&lt;p&gt;Here's what the .NET Console App looks like:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;System;
&lt;span style="color: blue"&gt;using &lt;/span&gt;Westwind.wwHelp;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.IO;

&lt;span style="color: blue"&gt;namespace &lt;/span&gt;HelpBuilderConsole
{
    &lt;span style="color: blue"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HelpBuilderConsole
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;static void &lt;/span&gt;Main(&lt;span style="color: blue"&gt;string&lt;/span&gt;[] args)
        {

            &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"West Wind Html &lt;a href="http://www.west-wind.com/wwhelp/" target="top"&gt;Html Help Builder&lt;/a&gt; Console"&lt;/span&gt;);

            &lt;span style="color: blue"&gt;if &lt;/span&gt;(args == &lt;span style="color: blue"&gt;null &lt;/span&gt;|| args.Length == 0)
            {
                &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"\r\n* Available commands:"&lt;/span&gt;);
                &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"RESET"&lt;/span&gt;);
                &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"REINDEX \t\t[hbp Project FilePath]"&lt;/span&gt;);
                &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"BUILDPROJECT \t\t[hbp Project FilePath]"&lt;/span&gt;);
                &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"ASSEMBLYIMPORT \t\t[AssenblyFilePath] [NewOrExistingprojectFile]"&lt;/span&gt;); 

                OnExit();
                &lt;span style="color: blue"&gt;return&lt;/span&gt;;
            }

            &lt;span style="color: blue"&gt;string &lt;/span&gt;command = args[0].ToUpper();

            &lt;span style="color: blue"&gt;if &lt;/span&gt;(command == &lt;span style="color: #a31515"&gt;"BUILDPROJECT"&lt;/span&gt;)
                BuildProject(args);
            &lt;span style="color: blue"&gt;else if &lt;/span&gt;(command == &lt;span style="color: #a31515"&gt;"ASSEMBLYIMPORT"&lt;/span&gt;)
                AssemblyImport(args);
            &lt;span style="color: blue"&gt;else if &lt;/span&gt;(command == &lt;span style="color: #a31515"&gt;"RESET"&lt;/span&gt;)
                Reset(args);
            &lt;span style="color: blue"&gt;else if &lt;/span&gt;(command == &lt;span style="color: #a31515"&gt;"REINDEX"&lt;/span&gt;)
                Reindex(args);                
            
            OnExit();
            &lt;span style="color: blue"&gt;return&lt;/span&gt;;
        }

        &lt;span style="color: blue"&gt;static void &lt;/span&gt;OnExit()
        {
&lt;span style="color: blue"&gt;#if &lt;/span&gt;DEBUG
            &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.ReadLine();
&lt;span style="color: blue"&gt;#endif
        &lt;/span&gt;}

        &lt;span style="color: blue"&gt;static void  &lt;/span&gt;BuildProject(&lt;span style="color: blue"&gt;string&lt;/span&gt;[] args)
        {
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(args.Length &amp;lt; 2 || args[1] == &lt;span style="color: blue"&gt;null&lt;/span&gt;)
            {
                WriteError(3, &lt;span style="color: #a31515"&gt;"Invalid or missing Project Filename"&lt;/span&gt;);
                &lt;span style="color: blue"&gt;return&lt;/span&gt;;
            }

            &lt;span style="color: blue"&gt;string &lt;/span&gt;projFile = args[1];
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(!IsFile(projFile))
                &lt;span style="color: blue"&gt;return&lt;/span&gt;;

            
            &lt;span style="color: #2b91af"&gt;wwHelp &lt;/span&gt;help = &lt;span style="color: #2b91af"&gt;wwHelp&lt;/span&gt;.CreateInstance();
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(!help.Open(projFile))
            {
                WriteError(24, &lt;span style="color: #a31515"&gt;"Unable to open: " &lt;/span&gt;+ projFile + &lt;span style="color: #a31515"&gt;". " &lt;/span&gt;+ help.ErrorMsg);
                &lt;span style="color: blue"&gt;return&lt;/span&gt;;
            }

            &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"Building Html &lt;a href="http://www.west-wind.com/wwhelp/" target="top"&gt;Html Help Builder&lt;/a&gt; Project: " &lt;/span&gt;+ projFile);

            WriteProgress(&lt;span style="color: #a31515"&gt;"Generating HTML..."&lt;/span&gt;);
            help.GenerateHtml();
            WriteProgress(&lt;span style="color: #a31515"&gt;"Generating Index..."&lt;/span&gt;);
            help.GenerateIndex();
            WriteProgress(&lt;span style="color: #a31515"&gt;"Generating Toc..."&lt;/span&gt;);
            help.GenerateToc(0,&lt;span style="color: blue"&gt;true&lt;/span&gt;,&lt;span style="color: blue"&gt;null&lt;/span&gt;);
            WriteProgress(&lt;span style="color: #a31515"&gt;"Compiling Project..."&lt;/span&gt;);
            &lt;span style="color: blue"&gt;string &lt;/span&gt;result = help.CompileProject();
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(result == &lt;span style="color: blue"&gt;null &lt;/span&gt;|| help.Error)
            {
                WriteError(24, &lt;span style="color: #a31515"&gt;"Error compiling project: " &lt;/span&gt;+ help.ErrorMsg +  &lt;span style="color: #a31515"&gt;"\r\n\r\n" &lt;/span&gt;+ result);
                &lt;span style="color: blue"&gt;return&lt;/span&gt;;
            }

            WriteSuccess(&lt;span style="color: #a31515"&gt;"Project built.\r\n\r\n* Compiler Messages:\r\n" &lt;/span&gt;+ result);

            help.Release();
            help = &lt;span style="color: blue"&gt;null&lt;/span&gt;;
        }&lt;br&gt;}&lt;br&gt;... additional methods omitted &lt;/pre&gt;

&lt;p&gt;The wwHelp object used here is a wrapper around the Html &lt;a href="http://www.west-wind.com/wwhelp/" target="top"&gt;Html Help Builder&lt;/a&gt; COM object. &lt;a href="http://www.west-wind.com/wwhelp/" target="top"&gt;Html Help Builder&lt;/a&gt; includes a .NET API that provides the .NET wrapper around the COM object which makes short. With this code in place it's now easy to do:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HelpBuilderConsole.exe RESET&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HelpBuilderConsole.exe BUILDPROJECT "c:\HelpBuilder Projects\RazorHosting\RazorHosting.hbp" &amp;gt; BuildOutput.txt 
    &lt;br&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's not as clean as having the main wwHelp.exe app handle these tasks, but at least the required functionality is in place. It works and gets the job done.&lt;/p&gt;

&lt;p&gt;You can build your Console app in any language that can produce one - .NET is probably the easiest, but you can use C++ or Delphi or Java etc. Any environment that can produce a Console app will do.&lt;/p&gt;

&lt;h3&gt;Resources&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://www.west-wind.com/files/demos/2012/FoxProConsoleOutput.zip" target="_blank"&gt;&lt;strong&gt;ConsoleOutput Sample&lt;/strong&gt;&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/liqjBbCXag2wyOFaE57FL1vqyjo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/liqjBbCXag2wyOFaE57FL1vqyjo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/liqjBbCXag2wyOFaE57FL1vqyjo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/liqjBbCXag2wyOFaE57FL1vqyjo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=Ul5IWCBN16w:3y-7FPIbLdo:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=Ul5IWCBN16w:3y-7FPIbLdo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=Ul5IWCBN16w:3y-7FPIbLdo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=Ul5IWCBN16w:3y-7FPIbLdo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=Ul5IWCBN16w:3y-7FPIbLdo:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=Ul5IWCBN16w:3y-7FPIbLdo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=Ul5IWCBN16w:3y-7FPIbLdo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=Ul5IWCBN16w:3y-7FPIbLdo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?a=Ul5IWCBN16w:3y-7FPIbLdo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RickStrahlsFoxproAndWebConnectionWebLog?i=Ul5IWCBN16w:3y-7FPIbLdo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RickStrahlsFoxproAndWebConnectionWebLog/~4/Ul5IWCBN16w" height="1" width="1"/&gt;</description>
     <feedburner:origLink>http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=871</feedburner:origLink></item>
</channel>
</rss>

