<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" 
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Thinking more...-Visual FoxPro</title>
<link>http://blog.roodo.com/thinkingmore/archives/cat_82808.html</link>
<description>Just thinking more...&amp;nbsp;訂閱 RSS

var gaJsHost = ((&quot;https:&quot; == document.location.protocol) ? &quot;https://ssl.&quot; : &quot;http://www.&quot;);
document.write(unescape(&quot;%3Cscript src=&#039;&quot; + gaJsHost + &quot;google-analytics.com/ga.js&#039; type=&#039;text/javascript&#039;%3E%3C/script%3E&quot;));















  google.load(&quot;jquery&quot;, &quot;1.2&quot;);
  google.setOnLoadCallback( function() {
    try {
      var pageTracker = _gat._getTracker(&quot;UA-97150-7&quot;);
      pageTracker._trackPageview();
    }catch(err) {}
    $(&quot;pre &gt; br&quot;).each( function() { $(this).replaceWith( &quot;\n&quot; ); } );
    $(&quot;textarea &gt; br&quot;).each( function() { $(this).replaceWith( &quot;\n&quot; ); } );
    SyntaxHighlighter.config.ClipboardSwf = &#039;http://alexgorbatchev.com/pub/sh/2.0.296/scripts/clipboard.swf&#039;;
    SyntaxHighlighter.all();
    dp.SyntaxHighlighter.ClipboardSwf = &#039;http://alexgorbatchev.com/pub/sh/2.0.296/scripts/clipboard.swf&#039;;
    dp.SyntaxHighlighter.HighlightAll(&#039;code&#039;);
  } );

</description>
<language>zh-tw</language>
<generator>Roodo Blog System</generator>
<copyright>All Rights Reserved</copyright>
<atom:link href="http://blog.roodo.com/thinkingmore/archives/cat_82808.xml" rel="self" type="application/rss+xml" />
<item>
	<title>VFP 與 Regular Expression</title>
	<description><![CDATA[
			VFP 本身並不支援 Regular Expression，幸好，有人非常熱心，以 C/C++ 有名的 Boost library 為基礎，製作了給 VFP 用的 Regular Expression Library。
License 基本上是遵循 boost library 的 LGPL license，所以你可以直接使用 binary code (也就是 .fll)在商業用途上。

為甚麼要 Regular Expression？因為他可以很方便地以簡單的語法表示出一段文字的規則。
以文章裡面的範例來看，你會發現他真的好用～
*!* 驗證 email 信箱格式
lcExpression = "^([0-9a-zA-Z]+[-._+&])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}$"
?RegExp("john@isp.com",lcExpression)
?RegExp("john@.isp.com",lcExpression)

*!* 驗證金額
lcExpression = "^(\$)?(([1-9]\d{0,2}(\,\d{3})*)|([1-9]\d*)|(0))(\.\d{2})?$"
?RegExp("$1,244,311.81",lcExpression) && Match
?RegExp("$1,24,4311.81",lcExpression) && No Match

*!* 驗證電話號碼
lcExpression = "^[2-9]\d{2}-\d{3}-\d{4}$"
?RegExp("507-562-0020",lcExpression) && Match
?RegExp("507-56-0020",lcExpression) && No Match


基本規則說明可以直接參考洪朝貴先生發佈的文章。

參考資料：A Regular Expressions library for Visual FoxProReg Exp - Visual FoxPro Wiki一輩子受用的 Regular Expressions -- 兼談另類的電腦學習態度Programming with GNU Regex LibraryJserv's blog: Regex Programming 資源Boost.Regex: Perl Regular Expression Syntax

		]]>
	</description>
	<content:encoded><![CDATA[
			VFP 本身並不支援 Regular Expression，幸好，<a href="http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,91241006-595a-487d-ac06-d0fc1fc71632.aspx" title="A Regular Expressions library for Visual FoxPro">有人非常熱心，以 C/C++ 有名的 Boost library 為基礎，製作了給 VFP 用的 Regular Expression Library。</a><br />
License 基本上是遵循 boost library 的 LGPL license，所以你可以直接使用 binary code (也就是 .fll)在商業用途上。<br />
<br />
為甚麼要 Regular Expression？因為他可以很方便地以簡單的語法表示出一段文字的規則。<br />
以<a href="http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,91241006-595a-487d-ac06-d0fc1fc71632.aspx" title="A Regular Expressions library for Visual FoxPro">文章</a>裡面的範例來看，你會發現他真的好用～<br />
<blockquote>*!* 驗證 email 信箱格式<br />
lcExpression = "^([0-9a-zA-Z]+[-._+&])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}$"<br />
?RegExp("john@isp.com",lcExpression)<br />
?RegExp("john@.isp.com",lcExpression)<br />
<br />
*!* 驗證金額<br />
lcExpression = "^(\$)?(([1-9]\d{0,2}(\,\d{3})*)|([1-9]\d*)|(0))(\.\d{2})?$"<br />
?RegExp("$1,244,311.81",lcExpression) && Match<br />
?RegExp("$1,24,4311.81",lcExpression) && No Match<br />
<br />
*!* 驗證電話號碼<br />
lcExpression = "^[2-9]\d{2}-\d{3}-\d{4}$"<br />
?RegExp("507-562-0020",lcExpression) && Match<br />
?RegExp("507-56-0020",lcExpression) && No Match<br />
</blockquote><br />
<br />
基本規則說明可以直接參考<a href="http://www.cyut.edu.tw/~ckhung/b/gnu/regexp.php" title="一輩子受用的 Regular Expressions -- 兼談另類的電腦學習態度">洪朝貴先生發佈的文章</a>。<br />
<br />
參考資料：<ul><li><a href="http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,91241006-595a-487d-ac06-d0fc1fc71632.aspx" title="A Regular Expressions library for Visual FoxPro">A Regular Expressions library for Visual FoxPro</a></li><li><a href="http://wikis.com/wc.dll?Wiki~RegExp" title="Reg Exp - Visual FoxPro Wiki">Reg Exp - Visual FoxPro Wiki</a></li><li><a href="http://www.cyut.edu.tw/~ckhung/b/gnu/regexp.php" title="一輩子受用的 Regular Expressions -- 兼談另類的電腦學習態度">一輩子受用的 Regular Expressions -- 兼談另類的電腦學習態度</a></li><li><a href="http://phi.sinica.edu.tw/aspac/reports/96/96004/" title="Programming with GNU Regex Library">Programming with GNU Regex Library</a></li><li><a href="http://blog.linux.org.tw/~jserv/archives/001476.html" title="Jserv's blog: Regex Programming 資源">Jserv's blog: Regex Programming 資源</a></li><li><a href="http://www.boost.org/libs/regex/doc/syntax_perl.html" title="Boost.Regex: Perl Regular Expression Syntax">Boost.Regex: Perl Regular Expression Syntax</a></li></ul><br />

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/2231406.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/2231406.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Wed, 04 Oct 2006 12:25:09 +0800</pubDate>
</item>
<item>
	<title>How to detect device arrival?</title>
	<description><![CDATA[
			幫朋友找資料找到的,順道貼上來
我沒試過
不過我想應該是可以運行吧~~

以 VFP 或 VB 來說,是利用 sysinfo 這個 Active X control .
主要是攔截 DeviceArrival 這個 event

詳細的範例可以參考DeviceArrival Event Example

雖然他是 VB 的範例,不過看起來應該是很好改成 VFP 才是...

Private Sub SysInfo1_DeviceArrival(ByVal DeviceType As Long, ByVal DeviceID As Long, ByVal DeviceName As String, ByVal DeviceData As Long)
   Debug.Print "DeviceArrival"
   Debug.Print "devicetype " & DeviceType
   Debug.Print "DeviceID " & GetDrive(DeviceType, DeviceID)
   Debug.Print "DeviceName " & DeviceName
   Debug.Print "DeviceData " & DeviceData
End Sub

Private Function GetDrive(devType As Long, devID As Long) As String
   Select Case devType
   Case 0 To 1 ' returns null
      GetDrive = devID
      Exit Function
   Case 3 To 4 ' returns null
      GetDrive = devID
      Exit Function
   Case 2 ' logical drive.
      ' Create an array for the possible drive numbers returned by 
      ' deviceID
      Dim drives(25) ' A-Z
      Dim dvNum As Long ' Possible bit values.
      Dim i As Integer
      dvNum = 1
      drives(0) = 1
      ' Populate with bit values.
      For i = 1 To 25
         dvNum = dvNum * 2
         drives(i) = dvNum
      Next i
      For i = 0 To 25
         If drives(i) = devID Then
            GetDrive = "Drive: " & Chr(i + 65)
            Exit Function
         End If
      Next I
   Case Else   ' Other unexpected returns
      Debug.Print devType, devID
   End Select
 End Function

		]]>
	</description>
	<content:encoded><![CDATA[
			幫朋友找資料找到的,順道貼上來<br />
我沒試過<br />
不過我想應該是可以運行吧~~<br />
<br />
以 VFP 或 VB 來說,是利用 sysinfo 這個 Active X control .<br />
主要是攔截 DeviceArrival 這個 event<br />
<br />
詳細的範例可以參考<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinf98/html/vbevtdevicearrivaleventexamplex.asp" title="DeviceArrival Event Example">DeviceArrival Event Example</a><br />
<br />
雖然他是 VB 的範例,不過看起來應該是很好改成 VFP 才是...<br />
<br />
<blockquote>Private Sub SysInfo1_DeviceArrival(ByVal DeviceType As Long, ByVal DeviceID As Long, ByVal DeviceName As String, ByVal DeviceData As Long)<br />
   Debug.Print "DeviceArrival"<br />
   Debug.Print "devicetype " & DeviceType<br />
   Debug.Print "DeviceID " & GetDrive(DeviceType, DeviceID)<br />
   Debug.Print "DeviceName " & DeviceName<br />
   Debug.Print "DeviceData " & DeviceData<br />
End Sub<br />
<br />
Private Function GetDrive(devType As Long, devID As Long) As String<br />
   Select Case devType<br />
   Case 0 To 1 ' returns null<br />
      GetDrive = devID<br />
      Exit Function<br />
   Case 3 To 4 ' returns null<br />
      GetDrive = devID<br />
      Exit Function<br />
   Case 2 ' logical drive.<br />
      ' Create an array for the possible drive numbers returned by <br />
      ' deviceID<br />
      Dim drives(25) ' A-Z<br />
      Dim dvNum As Long ' Possible bit values.<br />
      Dim i As Integer<br />
      dvNum = 1<br />
      drives(0) = 1<br />
      ' Populate with bit values.<br />
      For i = 1 To 25<br />
         dvNum = dvNum * 2<br />
         drives(i) = dvNum<br />
      Next i<br />
      For i = 0 To 25<br />
         If drives(i) = devID Then<br />
            GetDrive = "Drive: " & Chr(i + 65)<br />
            Exit Function<br />
         End If<br />
      Next I<br />
   Case Else   ' Other unexpected returns<br />
      Debug.Print devType, devID<br />
   End Select<br />
 End Function<br />
</blockquote>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/554278.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/554278.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Tue, 26 Jul 2005 21:25:01 +0800</pubDate>
</item>
<item>
	<title>Hook operation / Hooks and anchor</title>
	<description><![CDATA[
			以前逛到的兩個 Pattern, 比較特別的是:
1.Pattern 名字沒聽過,
2.用 VFP 實作的~~

挺有趣的,網址在這裡:
Hook operation
Hooks and anchor

Hook operation 講的是一種包裝別人物件的方法,一般來說,都是利用繼承的方法來將對方的 control 包進去,然後再去作客製化的動作;這個 pattern 則是繼承以後,另外利用了一個 hook manager 去專門處理這個客製化的動作.所以才稱作 Hook(掛勾).

Hooks and anchar 則是前面 hook 的延伸,據我個人的理解,這就有點像是 c# 可以把很多 event 或 delegate 串起來一樣~不過我不是很確定啦~~

另外,上面文章所屬的網站還蠻多文章的,大部分是講如何用VFP去搞 Design Pattern 的,各位可以去看看~~

與各位分享~
		]]>
	</description>
	<content:encoded><![CDATA[
			以前逛到的兩個 Pattern, 比較特別的是:<br />
1.Pattern 名字沒聽過,<br />
2.用 VFP 實作的~~<br />
<br />
挺有趣的,網址在這裡:<br />
<a href="http://www.stevenblack.com/PTN-Hook%20Operations.asp">Hook operation</a><br />
<a href="http://stevenblack.com/HooksAndAnchorsDesignPattern.ASP">Hooks and anchor</a><br />
<br />
Hook operation 講的是一種包裝別人物件的方法,一般來說,都是利用繼承的方法來將對方的 control 包進去,然後再去作客製化的動作;這個 pattern 則是繼承以後,另外利用了一個 hook manager 去專門處理這個客製化的動作.所以才稱作 Hook(掛勾).<br />
<br />
Hooks and anchar 則是前面 hook 的延伸,據我個人的理解,這就有點像是 c# 可以把很多 event 或 delegate 串起來一樣~不過我不是很確定啦~~<br />
<br />
另外,上面文章所屬的<a href="http://www.stevenblack.com/SBC%20Publications.asp">網站</a>還蠻多文章的,大部分是講如何用VFP去搞 Design Pattern 的,各位可以去看看~~<br />
<br />
與各位分享~
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/554006.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/554006.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Sat, 27 Mar 2004 20:31:06 +0800</pubDate>
</item>
<item>
	<title>Builder pattern on VFP</title>
	<description><![CDATA[
			給予適當的建構資料,就可以得到我們所需要的物件.

詳細的說明可以參考後面所附的參考資料,那些資料就已經寫的很好了,我想我沒必要再畫蛇添足.

最初製作 SQL Builder class 的時候是想說,我只要給予它一些欄位和條件,他就會自動幫我產生 SQL 敘述,而不必再去考量 SQL 敘述是否正確啊...等等的問題.剛好想到 Builder pattern 其實很適合,所以就實做看看.

目前這個 class 已經蠻齊全了,不過有些地方可以再加強.
   1. Join 部分
   2. 資料型態轉換,作的不好~應該可以再更精簡,更可靠.
   3. 傳入 select - sql 敘述,就能產生 delete-sql, update-sql.
   4. ...

參考資料:
http://www.dotspace.idv.tw/Patterns/Jdon_Builder.htm
http://140.109.17.201/Jyemii/patternscolumn/articles/DesignPatternPart(2).htm
Design Pattern 中譯本 - 葉秉哲譯

範例程式:

* 主程式
LOCAL lc_sql
LOCAL lo_builder
lo_builder=CREATEOBJECT("csqlbuilder")
lo_builder.ADDCOLUMN("u_id")
lo_builder.ADDCOLUMN("u_name")
lo_builder.setTable("users")
lo_builder.addWhere("", "u_id", "=", "drury")
lo_builder.addOrderby( "u_id" )
lo_builder.addGroupby( "u_id" )
? "====="
? "select sql::"
?? lo_builder.getSelectSQL()
lo_builder.reconf()
lo_builder.addPair("u_id", "ellery")
lo_builder.addPair("u_name", "ellery")
lo_builder.setTable("users")
lo_builder.addWhere("", "u_id", "=", "drury")
? "====="
? "insert sql::" + lo_builder.getInsertSQL()
? "update sql::" + lo_builder.getUpdateSQL()
? "delete sql::" + lo_builder.getDeleteSQL()

*
* Builder pattern 類別實作
* 此類別適用環境: VFP 8.0
* 類別定義開始
*
DEFINE CLASS CSQLBuilder AS CUSTOM
&nbsp;&nbsp;ADD OBJECT PROTECTED m_pairs AS COLLECTION
&nbsp;&nbsp;ADD OBJECT PROTECTED m_where AS COLLECTION
&nbsp;&nbsp;ADD OBJECT PROTECTED m_groupby AS COLLECTION
&nbsp;&nbsp;ADD OBJECT PROTECTED m_orderby AS COLLECTION
&nbsp;&nbsp;ADD OBJECT PROTECTED m_keys as collection 
&nbsp;&nbsp;m_table = ""		&& the table
&nbsp;&nbsp;m_targettype=""	&& cursor, table
&nbsp;&nbsp;m_target=""		&& name

&nbsp;&nbsp;* Init
&nbsp;&nbsp;PROCEDURE INIT
&nbsp;&nbsp;ENDPROC

&nbsp;&nbsp;* Destroy
&nbsp;&nbsp;PROCEDURE DESTROY
&nbsp;&nbsp;ENDPROC

&nbsp;&nbsp;* Reconfigure
&nbsp;&nbsp;PROCEDURE reconf
&nbsp;&nbsp;&nbsp;&nbsp;* MSDN said: pass -1 will clear all items
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_pairs.REMOVE( -1 )
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_where.REMOVE( -1 )
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_groupby.REMOVE( -1 )
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_orderby.REMOVE( -1 )
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_table = ""
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_targettype=""
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_target=""
&nbsp;&nbsp;ENDPROC

&nbsp;&nbsp;* addColumns
&nbsp;&nbsp;PROCEDURE ADDCOLUMN( c_field AS STRING )
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_pairs.ADD( .NULL., c_field )
&nbsp;&nbsp;ENDPROC

&nbsp;&nbsp;PROCEDURE addWhere( c_logical AS STRING, c_field AS STRING, c_operator AS STRING, o_value AS OBJECT )
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_where.ADD( o_value, c_logical + c_field + c_operator )
&nbsp;&nbsp;ENDPROC

&nbsp;&nbsp;PROCEDURE addPair( c_field AS STRING, o_value AS OBJECT )
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_pairs.ADD( o_value, c_field )
&nbsp;&nbsp;ENDPROC

&nbsp;&nbsp;PROCEDURE addGroupby( c_field AS STRING )
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_groupby.ADD( .NULL., c_field )
&nbsp;&nbsp;ENDPROC

&nbsp;&nbsp;PROCEDURE addOrderby( c_field AS STRING )
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_orderby.ADD( .NULL., c_field )
&nbsp;&nbsp;ENDPROC

&nbsp;&nbsp;PROCEDURE addKey( c_field as String )
&nbsp;&nbsp;&nbsp;&nbsp;this.m_keys.add( .null., c_field )
&nbsp;&nbsp;ENDPROC
	
&nbsp;&nbsp;PROCEDURE addJoin
&nbsp;&nbsp;&nbsp;&nbsp;* todo: this is the most hard part.
&nbsp;&nbsp;ENDPROC

&nbsp;&nbsp;PROCEDURE setTable( c_table AS STRING )
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_table=c_table
&nbsp;&nbsp;ENDPROC

&nbsp;&nbsp;PROCEDURE setTarget( c_type AS STRING, c_target AS STRING )
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_targettype=c_type
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_target=c_string
&nbsp;&nbsp;ENDPROC

&nbsp;&nbsp;PROCEDURE getInsertSQL
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL i
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL lc_sql
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL lc_fields, lc_values, lc_type

&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=""
&nbsp;&nbsp;&nbsp;&nbsp;lc_values=""
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql="insert into " + THIS.m_table + " "
&nbsp;&nbsp;&nbsp;&nbsp;FOR i=1 TO THIS.m_pairs.COUNT
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=lc_fields+THIS.m_pairs.GETKEY(i)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF( i+1 
		]]>
	</description>
	<content:encoded><![CDATA[
			給予適當的建構資料,就可以得到我們所需要的物件.<br />
<br />
詳細的說明可以參考後面所附的參考資料,那些資料就已經寫的很好了,我想我沒必要再畫蛇添足.<br />
<br />
最初製作 SQL Builder class 的時候是想說,我只要給予它一些欄位和條件,他就會自動幫我產生 SQL 敘述,而不必再去考量 SQL 敘述是否正確啊...等等的問題.剛好想到 Builder pattern 其實很適合,所以就實做看看.<br />
<br />
目前這個 class 已經蠻齊全了,不過有些地方可以再加強.<br />
   1. Join 部分<br />
   2. 資料型態轉換,作的不好~應該可以再更精簡,更可靠.<br />
   3. 傳入 select - sql 敘述,就能產生 delete-sql, update-sql.<br />
   4. ...<br />
<br />
參考資料:<br />
<a href="http://www.dotspace.idv.tw/Patterns/Jdon_Builder.htm">http://www.dotspace.idv.tw/Patterns/Jdon_Builder.htm</a><br />
<a href="http://140.109.17.201/Jyemii/patternscolumn/articles/DesignPatternPart(2).htm">http://140.109.17.201/Jyemii/patternscolumn/articles/DesignPatternPart(2).htm</a><br />
Design Pattern 中譯本 - 葉秉哲譯<br />
<br />
範例程式:<br />
<blockquote><br />
* 主程式<br />
LOCAL lc_sql<br />
LOCAL lo_builder<br />
lo_builder=CREATEOBJECT("csqlbuilder")<br />
lo_builder.ADDCOLUMN("u_id")<br />
lo_builder.ADDCOLUMN("u_name")<br />
lo_builder.setTable("users")<br />
lo_builder.addWhere("", "u_id", "=", "drury")<br />
lo_builder.addOrderby( "u_id" )<br />
lo_builder.addGroupby( "u_id" )<br />
? "====="<br />
? "select sql::"<br />
?? lo_builder.getSelectSQL()<br />
lo_builder.reconf()<br />
lo_builder.addPair("u_id", "ellery")<br />
lo_builder.addPair("u_name", "ellery")<br />
lo_builder.setTable("users")<br />
lo_builder.addWhere("", "u_id", "=", "drury")<br />
? "====="<br />
? "insert sql::" + lo_builder.getInsertSQL()<br />
? "update sql::" + lo_builder.getUpdateSQL()<br />
? "delete sql::" + lo_builder.getDeleteSQL()<br />
<br />
*<br />
* Builder pattern 類別實作<br />
* 此類別適用環境: VFP 8.0<br />
* 類別定義開始<br />
*<br />
DEFINE CLASS CSQLBuilder AS CUSTOM<br />
&nbsp;&nbsp;ADD OBJECT PROTECTED m_pairs AS COLLECTION<br />
&nbsp;&nbsp;ADD OBJECT PROTECTED m_where AS COLLECTION<br />
&nbsp;&nbsp;ADD OBJECT PROTECTED m_groupby AS COLLECTION<br />
&nbsp;&nbsp;ADD OBJECT PROTECTED m_orderby AS COLLECTION<br />
&nbsp;&nbsp;ADD OBJECT PROTECTED m_keys as collection <br />
&nbsp;&nbsp;m_table = ""		&& the table<br />
&nbsp;&nbsp;m_targettype=""	&& cursor, table<br />
&nbsp;&nbsp;m_target=""		&& name<br />
<br />
&nbsp;&nbsp;* Init<br />
&nbsp;&nbsp;PROCEDURE INIT<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;* Destroy<br />
&nbsp;&nbsp;PROCEDURE DESTROY<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;* Reconfigure<br />
&nbsp;&nbsp;PROCEDURE reconf<br />
&nbsp;&nbsp;&nbsp;&nbsp;* MSDN said: pass -1 will clear all items<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_pairs.REMOVE( -1 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_where.REMOVE( -1 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_groupby.REMOVE( -1 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_orderby.REMOVE( -1 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_table = ""<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_targettype=""<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_target=""<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;* addColumns<br />
&nbsp;&nbsp;PROCEDURE ADDCOLUMN( c_field AS STRING )<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_pairs.ADD( .NULL., c_field )<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROCEDURE addWhere( c_logical AS STRING, c_field AS STRING, c_operator AS STRING, o_value AS OBJECT )<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_where.ADD( o_value, c_logical + c_field + c_operator )<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROCEDURE addPair( c_field AS STRING, o_value AS OBJECT )<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_pairs.ADD( o_value, c_field )<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROCEDURE addGroupby( c_field AS STRING )<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_groupby.ADD( .NULL., c_field )<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROCEDURE addOrderby( c_field AS STRING )<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_orderby.ADD( .NULL., c_field )<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROCEDURE addKey( c_field as String )<br />
&nbsp;&nbsp;&nbsp;&nbsp;this.m_keys.add( .null., c_field )<br />
&nbsp;&nbsp;ENDPROC<br />
	<br />
&nbsp;&nbsp;PROCEDURE addJoin<br />
&nbsp;&nbsp;&nbsp;&nbsp;* todo: this is the most hard part.<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROCEDURE setTable( c_table AS STRING )<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_table=c_table<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROCEDURE setTarget( c_type AS STRING, c_target AS STRING )<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_targettype=c_type<br />
&nbsp;&nbsp;&nbsp;&nbsp;THIS.m_target=c_string<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROCEDURE getInsertSQL<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL i<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL lc_sql<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL lc_fields, lc_values, lc_type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=""<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_values=""<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql="insert into " + THIS.m_table + " "<br />
&nbsp;&nbsp;&nbsp;&nbsp;FOR i=1 TO THIS.m_pairs.COUNT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=lc_fields+THIS.m_pairs.GETKEY(i)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF( i+1 <= THIS.m_pairs.COUNT )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=lc_fields+","<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_type=VARTYPE( THIS.m_pairs.ITEM(i) )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DO CASE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE lc_type="C"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_values=lc_values+ "'" + THIS.m_pairs.ITEM(i)+ "'"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE INLIST( lc_type, "N", "Y" )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_values=lc_values + ALLTRIM( STR(THIS.m_pairs.ITEM(i) ) )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE lc_type="D"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_values=lc_values + "{^" + DTOC( THIS.m_pairs.ITEM(i) ) + "}"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE lc_type="L"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_values=lc_values + IIF( THIS.m_pairs.ITEM(i), ".T.", ".F." )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE lc_type="X"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_values=lc_values + ".null."<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENDCASE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF( i+1 <= THIS.m_pairs.COUNT )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_values=lc_values+","<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
&nbsp;&nbsp;&nbsp;&nbsp;NEXT<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql + "(" + lc_fields + ") values (" + lc_values + ")"<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN lc_sql<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROTECTED PROCEDURE getWhereSQL<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL lc_sql<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;IF( THIS.m_where.COUNT >=1 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=" where "<br />
&nbsp;&nbsp;&nbsp;&nbsp;ELSE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=""<br />
&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
&nbsp;&nbsp;&nbsp;&nbsp;FOR i=1 TO THIS.m_where.COUNT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_type=VARTYPE( THIS.m_where.ITEM(i) )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DO CASE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE lc_type="C"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_value= "'" + THIS.m_where.ITEM(i)+ "'"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE INLIST( lc_type, "N", "Y" )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_value= ALLTRIM( STR(THIS.m_where.ITEM(i) ) )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE lc_type="D"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_value="{" + DTOC( THIS.m_where.ITEM(i) ) + "}"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE lc_type="L"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_value=IIF( THIS.m_where.ITEM(i), ".T.", ".F." )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE lc_type="X"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_value=".null."<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENDCASE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql + THIS.m_where.GETKEY(i) + lc_value<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF( i+1 <= THIS.m_where.COUNT )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql+","<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
&nbsp;&nbsp;&nbsp;&nbsp;NEXT<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN lc_sql<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROCEDURE getOnlyKey( o_collection AS COLLECTION )<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL i<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL lc_sql<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=""<br />
&nbsp;&nbsp;&nbsp;&nbsp;FOR i=1 TO o_collection.COUNT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql+o_collection.GETKEY(i)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF( i+1 <= o_collection.COUNT )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql+","<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
&nbsp;&nbsp;&nbsp;&nbsp;NEXT<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN lc_sql<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROCEDURE getOrderBySQL<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL lc_sql<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=THIS.getOnlyKey( THIS.m_orderby )<br />
&nbsp;&nbsp;&nbsp;&nbsp;IF( EMPTY(lc_sql) )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN lc_sql<br />
&nbsp;&nbsp;&nbsp;&nbsp;ELSE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN " order by " + lc_sql<br />
&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROCEDURE getGroupbySQL<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL lc_sql<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=THIS.getOnlyKey( THIS.m_groupby )<br />
&nbsp;&nbsp;&nbsp;&nbsp;IF( EMPTY(lc_sql) )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN lc_sql<br />
&nbsp;&nbsp;&nbsp;&nbsp;ELSE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN " group by " + lc_sql<br />
&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROCEDURE getSelectSQL<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL i<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL lc_sql, lc_where, lc_orderby, lc_groupby<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql="select "<br />
&nbsp;&nbsp;&nbsp;&nbsp;FOR i=1 TO THIS.m_pairs.COUNT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql+THIS.m_pairs.GETKEY(i)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF( i+1 <= THIS.m_pairs.COUNT )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql+","<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
&nbsp;&nbsp;&nbsp;&nbsp;NEXT<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql + " from " + THIS.m_table<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_where=THIS.getWhereSQL()<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql + lc_where<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_orderby=THIS.getOrderBySQL()<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql+lc_orderby<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_groupby=THIS.getGroupbySQL()<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql+lc_groupby<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN lc_sql<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROCEDURE getDeleteSQL<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL lc_sql<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL i<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL lc_value, lc_type, lc_where<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql="delete from " + THIS.m_table<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_where=THIS.getWhereSQL()<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql+lc_where<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN lc_sql<br />
&nbsp;&nbsp;ENDPROC<br />
<br />
&nbsp;&nbsp;PROCEDURE getUpdateSQL<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL i<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL lc_sql<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL lc_fields, lc_values, lc_type, lc_where<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=""<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_values=""<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql="update " + THIS.m_table + " set "<br />
&nbsp;&nbsp;&nbsp;&nbsp;FOR i=1 TO THIS.m_pairs.COUNT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql+THIS.m_pairs.GETKEY(i)+"="<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_type=VARTYPE( THIS.m_pairs.ITEM(i) )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DO CASE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE lc_type="C"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql + "'" + THIS.m_pairs.ITEM(i) + "'"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE INLIST( lc_type, "N", "Y" )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql + ALLTRIM( STR(THIS.m_pairs.ITEM(i) ) )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE lc_type="D"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql + "{^" + DTOC( THIS.m_pairs.ITEM(i) ) + "}"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE lc_type="L"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_values=lc_sql + IIF( THIS.m_pairs.ITEM(i), ".T.", ".F." )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CASE lc_type="X"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_values=lc_sql + ".null."<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENDCASE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF( i+1 <= THIS.m_pairs.COUNT )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql+","<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
&nbsp;&nbsp;&nbsp;&nbsp;NEXT<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;* handle where clause.<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_where=THIS.getWhereSQL()<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_sql=lc_sql+lc_where<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN lc_sql<br />
&nbsp;&nbsp;ENDPROC<br />
	<br />
&nbsp;&nbsp;PROCEDURE getKeyFieldList()<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL i<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL lc_fields<br />
&nbsp;&nbsp;&nbsp;&nbsp;IF( THIS.m_keys.COUNT >=1 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=""<br />
&nbsp;&nbsp;&nbsp;&nbsp;ELSE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN ""<br />
&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
&nbsp;&nbsp;&nbsp;&nbsp;FOR i=1 TO THIS.m_keys.COUNT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=lc_fields+this.m_keys.getKey(i)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF( i+1 <= THIS.m_keys.COUNT )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=lc_fields+","<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
&nbsp;&nbsp;&nbsp;&nbsp;NEXT<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN lc_fields<br />
&nbsp;&nbsp;ENDPROC<br />
	<br />
&nbsp;&nbsp;PROCEDURE getTable()<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN THIS.m_table<br />
&nbsp;&nbsp;ENDPROC<br />
	<br />
&nbsp;&nbsp;PROCEDURE getUpdatableFieldList()<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL i, lc_fields<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=""<br />
&nbsp;&nbsp;&nbsp;&nbsp;FOR i=1 TO THIS.m_pairs.COUNT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=lc_fields+THIS.m_pairs.GETKEY(i)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF( i+1 <= THIS.m_pairs.COUNT )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=lc_fields+","<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
&nbsp;&nbsp;&nbsp;&nbsp;NEXT<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN lc_fields<br />
&nbsp;&nbsp;ENDPROC<br />
	<br />
&nbsp;&nbsp;PROCEDURE getUpdateNameList()<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCAL i, lc_fields<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=""<br />
&nbsp;&nbsp;&nbsp;&nbsp;FOR i=1 TO THIS.m_pairs.COUNT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=lc_fields+THIS.m_pairs.GETKEY(i)+" "<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=lc_fields+this.m_table+"."+this.m_pairs.getkey(i)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF( i+1 <= THIS.m_pairs.COUNT )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lc_fields=lc_fields+","<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
&nbsp;&nbsp;&nbsp;&nbsp;NEXT<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN lc_fields<br />
&nbsp;&nbsp;ENDPROC<br />
ENDDEFINE<br />
* 類別定義結束<br />
</blockquote>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/554004.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/554004.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Tue, 16 Mar 2004 12:46:36 +0800</pubDate>
</item>
<item>
	<title>FontCharSet in VFP8</title>
	<description><![CDATA[
			剛剛用 VFP8 在做 form 的時候
發現 TextBox 的 property 裡面居然有個以前沒看過的傢伙: FontCharSet
翻了一下 Help, 原來他可以指定 font 的 charset (字元集)
換言之,只要變動 Fontname, fontcharset, 與內容(value or caption), 應該就可以達到 localization (l10n)的目的了.
		]]>
	</description>
	<content:encoded><![CDATA[
			剛剛用 VFP8 在做 form 的時候<br />
發現 TextBox 的 property 裡面居然有個以前沒看過的傢伙: FontCharSet<br />
翻了一下 Help, 原來他可以指定 font 的 charset (字元集)<br />
換言之,只要變動 Fontname, fontcharset, 與內容(value or caption), 應該就可以達到 localization (l10n)的目的了.
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553981.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553981.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Sun, 01 Feb 2004 20:59:08 +0800</pubDate>
</item>
<item>
	<title>base64 encode/decode</title>
	<description><![CDATA[
			忘記從哪兒節錄下來的了,在這裡向作者說聲抱歉,因為那時沒有記下出處.
如果有侵犯版權的話,請來信告訴我,我會拿掉.
兩個 function 是作 base64 encode/decode 的.

不過, VFP7 以後,微軟已經擴充了 STRCONV() 的功能,讓他也能作 base64 encode/decode.

用法如下:
? STRCONV("Hallo",13)  encodes to Base64
? STRCONV("SGFsbG8=",14) decodes from Base64

=====

FUNCTION Base64Encode(lcInput,loXML)
LOCAL loNode

IF VARTYPE(loXML) # "O"
   loXML = CREATEOBJECT("MSXML2.DOMDocument")
   loXML.Async = .F.
ENDIF

loXML.loadXML("&lt;node&gt;&lt;/node&gt;")
loNode = loXML.DocumentElement

loNode.dataType = "bin.base64"
loNode.nodeTypedValue =  CREATEBINARY(lcInput)

RETURN loNode.Text


FUNCTION Base64Decode(lcInput,loXML)
LOCAL lcDocument

IF VARTYPE(loXML) # "O"
   loXML = CREATEOBJECT("MSXML2.DomDocument")
   loXML.Async = .F.
ENDIF

lcDocument = [&lt;node xmlns:dt="urn:schemas-microsoft-com:datatypes"
dt:dt="bin.base64"&gt;] + lcInput + [&lt;/node&gt;]

loXML.loadXML(lcDocument)

RETURN  loXML.DocumentElement.nodeTypedValue
		]]>
	</description>
	<content:encoded><![CDATA[
			忘記從哪兒節錄下來的了,在這裡向作者說聲抱歉,因為那時沒有記下出處.<br />
如果有侵犯版權的話,請來信告訴我,我會拿掉.<br />
兩個 function 是作 base64 encode/decode 的.<br />
<br />
不過, VFP7 以後,微軟已經擴充了 STRCONV() 的功能,讓他也能作 base64 encode/decode.<br />
<br />
用法如下:<br />
? STRCONV("Hallo",13)  encodes to Base64<br />
? STRCONV("SGFsbG8=",14) decodes from Base64<br />
<br />
=====<br />
<br />
FUNCTION Base64Encode(lcInput,loXML)<br />
LOCAL loNode<br />
<br />
IF VARTYPE(loXML) # "O"<br />
   loXML = CREATEOBJECT("MSXML2.DOMDocument")<br />
   loXML.Async = .F.<br />
ENDIF<br />
<br />
loXML.loadXML("&lt;node&gt;&lt;/node&gt;")<br />
loNode = loXML.DocumentElement<br />
<br />
loNode.dataType = "bin.base64"<br />
loNode.nodeTypedValue =  CREATEBINARY(lcInput)<br />
<br />
RETURN loNode.Text<br />
<br />
<br />
FUNCTION Base64Decode(lcInput,loXML)<br />
LOCAL lcDocument<br />
<br />
IF VARTYPE(loXML) # "O"<br />
   loXML = CREATEOBJECT("MSXML2.DomDocument")<br />
   loXML.Async = .F.<br />
ENDIF<br />
<br />
lcDocument = [&lt;node xmlns:dt="urn:schemas-microsoft-com:datatypes"<br />
dt:dt="bin.base64"&gt;] + lcInput + [&lt;/node&gt;]<br />
<br />
loXML.loadXML(lcDocument)<br />
<br />
RETURN  loXML.DocumentElement.nodeTypedValue
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553966.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553966.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Mon, 19 Jan 2004 21:25:33 +0800</pubDate>
</item>
<item>
	<title>以 VFP 實作 Singleton Pattern</title>
	<description><![CDATA[
			Singleton,確保類別永遠只有一份實體

Singleton pattern, 簡言之,是一個確保類別永遠只有一份實體的範式(Pattern).
在什麼情況下,我們會用到這個 Pattern 呢??
比如,一台電腦裡在同一時間只能有一個視窗管理員在運行.

一般性的做法,是讓類別自行管理這個唯一個物件實體,讓他確保絕對無法生出第二個物件個體.

那麼在 VFP 裡面要如何實現呢??
讓我們來試試看,首先先定義出 CSingleton 這個Class
*
* Class Singleton
*
DEFINE CLASS CSingleton as Custom 
&nbsp;&nbsp;HIDDEN m_singleton
&nbsp;&nbsp;m_singleton=.NULL.
&nbsp;&nbsp;PROCEDURE getInstance
&nbsp;&nbsp;&nbsp;&nbsp;IF m_singleton==.NULL.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_singleton=CREATEOBJECT("CSingleton")
&nbsp;&nbsp;&nbsp;&nbsp;ENDIF
&nbsp;&nbsp;&nbsp;&nbsp;RETURN m_singleton
&nbsp;&nbsp;ENDPROC
&nbsp;&nbsp;PROCEDURE getClassName
&nbsp;&nbsp;&nbsp;&nbsp;return "I am Singleton Class"
&nbsp;&nbsp;ENDPROC
ENDDEFINE
我們將 m_singleton 隱藏起來,讓外界無法直接存取,並且提供 getInstance method,讓外界可以透過此 method 取得 m_singleton 這個 instance.
所以當我們需要這個類別的實體時,就可以這麼寫:
lo_object=CSingleton::getInstance()

嘿,等等,別的語言是可以這麼寫,VFP 允許我們這樣用嗎??
此外,我們也沒有辦法隱喻地將 m_instance 放到 heap,像別的語言可以用 static 表明 m_instance 要放到 heap 中,確保只會有一份實體.
VFP 必須要先為 CSingleton 類別產生實體,才能呼叫 getInstance()
也就是要先這樣子
local lo_class, lo_object
lo_class=createobject("CSingleton")
lo_object=lo_class.getInstance()
才能讓 lo_object 取得實體.


那這不就違反我們的本意了嗎??
當使用者呼叫了多次 createobject("CSingleton"), 等於是創建了好幾次 m_singleton,我們就無法讓 m_singleton 是系統中唯一的一個實體了.

那麼還有別的方法嗎??
嗯,用全域變數如何??
我們可以用全域變數搭配一個Function來使用.
所以就可以這麼寫
public m_instance
....
* 主程式
m_instance=.null.
...
* Function
function getInstance
&nbsp;&nbsp;if m_instance==.null.
&nbsp;&nbsp;&nbsp;&nbsp;m_instance=createobject("CSingleton")
&nbsp;&nbsp;endif
&nbsp;&nbsp;return m_instance
endfunc
...
* 要使用的時候
lo_object=getInstance()
? lo_object.getClassName()
...
這樣子總算是解決問題了,只要維持一個良好的撰寫習慣
就可以保證CSingleton的實體是唯一.
可是萬一後繼者不明白,直接去存取了全域變數 m_instance 的話,該怎麼辦呢??

嗯~~再換個方向來想
VFP 不是有個函數叫做 getobject() 嗎??
如果我們將類別轉為 OLEPUBLIC 之後,再使用 getobject() 去取得 instance,就可以取得唯一的實體來使用了.
這也不失為一個不錯的解法.

綜觀上面推論,或許還有其他的方法,是我沒有想到的.(我有想過用 fopen() 或 flock()...等等的)
但是就目前看來,在 VFP 裡面對 Singleton 並沒有一個完美的解法.
只有期待 VFP 未來能加入新的語言特性,讓我們能更靈活的運用了.

附錄: C++ 的解法
class CSingleton {
private:
&nbsp;&nbsp;static CSingleton* m_instance;
protected:	//保護起來,不讓 constructor 直接被叫用.
&nbsp;&nbsp;Singleton();
&nbsp;&nbsp;Singleton(const Singleton&amp;);
&nbsp;&nbsp;Singleton& operator= (const Singleton&amp;);
public:
&nbsp;&nbsp;CSingleton* getInstance(void) {
&nbsp;&nbsp;&nbsp;&nbsp;if( m_instance==NULL )
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_instance=new CSingleton();
&nbsp;&nbsp;&nbsp;&nbsp;return m_instance;
&nbsp;&nbsp;}
&nbsp;&nbsp;char* getClassName(void) {
&nbsp;&nbsp;&nbsp;&nbsp;return "Hello! Singleton Pattern!!\n";
&nbsp;&nbsp;}
}
CSingleton* CSingleton::m_instance=NULL;	//因為宣告為 static,所以可以這樣給值.
int main( int argc, char* argv[] ) {
&nbsp;&nbsp;CSingleton* obj=CSingleton::getInstance;
&nbsp;&nbsp;printf( "%s", obj->getClassName());
}
		]]>
	</description>
	<content:encoded><![CDATA[
			Singleton,確保類別永遠只有一份實體<br />
<br />
Singleton pattern, 簡言之,是一個確保類別永遠只有一份實體的範式(Pattern).<br />
在什麼情況下,我們會用到這個 Pattern 呢??<br />
比如,一台電腦裡在同一時間只能有一個視窗管理員在運行.<br />
<br />
一般性的做法,是讓類別自行管理這個唯一個物件實體,讓他確保絕對無法生出第二個物件個體.<br />
<br />
那麼在 VFP 裡面要如何實現呢??<br />
讓我們來試試看,首先先定義出 CSingleton 這個Class<br />
*<br />
* Class Singleton<br />
*<br />
DEFINE CLASS CSingleton as Custom <br />
&nbsp;&nbsp;HIDDEN m_singleton<br />
&nbsp;&nbsp;m_singleton=.NULL.<br />
&nbsp;&nbsp;PROCEDURE getInstance<br />
&nbsp;&nbsp;&nbsp;&nbsp;IF m_singleton==.NULL.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_singleton=CREATEOBJECT("CSingleton")<br />
&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN m_singleton<br />
&nbsp;&nbsp;ENDPROC<br />
&nbsp;&nbsp;PROCEDURE getClassName<br />
&nbsp;&nbsp;&nbsp;&nbsp;return "I am Singleton Class"<br />
&nbsp;&nbsp;ENDPROC<br />
ENDDEFINE<br />
我們將 m_singleton 隱藏起來,讓外界無法直接存取,並且提供 getInstance method,讓外界可以透過此 method 取得 m_singleton 這個 instance.<br />
所以當我們需要這個類別的實體時,就可以這麼寫:<br />
lo_object=CSingleton::getInstance()<br />
<br />
嘿,等等,別的語言是可以這麼寫,VFP 允許我們這樣用嗎??<br />
此外,我們也沒有辦法隱喻地將 m_instance 放到 heap,像別的語言可以用 static 表明 m_instance 要放到 heap 中,確保只會有一份實體.<br />
VFP 必須要先為 CSingleton 類別產生實體,才能呼叫 getInstance()<br />
也就是要先這樣子<br />
local lo_class, lo_object<br />
lo_class=createobject("CSingleton")<br />
lo_object=lo_class.getInstance()<br />
才能讓 lo_object 取得實體.<br />
<br />
<br />
那這不就違反我們的本意了嗎??<br />
當使用者呼叫了多次 createobject("CSingleton"), 等於是創建了好幾次 m_singleton,我們就無法讓 m_singleton 是系統中唯一的一個實體了.<br />
<br />
那麼還有別的方法嗎??<br />
嗯,用全域變數如何??<br />
我們可以用全域變數搭配一個Function來使用.<br />
所以就可以這麼寫<br />
public m_instance<br />
....<br />
* 主程式<br />
m_instance=.null.<br />
...<br />
* Function<br />
function getInstance<br />
&nbsp;&nbsp;if m_instance==.null.<br />
&nbsp;&nbsp;&nbsp;&nbsp;m_instance=createobject("CSingleton")<br />
&nbsp;&nbsp;endif<br />
&nbsp;&nbsp;return m_instance<br />
endfunc<br />
...<br />
* 要使用的時候<br />
lo_object=getInstance()<br />
? lo_object.getClassName()<br />
...<br />
這樣子總算是解決問題了,只要維持一個良好的撰寫習慣<br />
就可以保證CSingleton的實體是唯一.<br />
可是萬一後繼者不明白,直接去存取了全域變數 m_instance 的話,該怎麼辦呢??<br />
<br />
嗯~~再換個方向來想<br />
VFP 不是有個函數叫做 getobject() 嗎??<br />
如果我們將類別轉為 OLEPUBLIC 之後,再使用 getobject() 去取得 instance,就可以取得唯一的實體來使用了.<br />
這也不失為一個不錯的解法.<br />
<br />
綜觀上面推論,或許還有其他的方法,是我沒有想到的.(我有想過用 fopen() 或 flock()...等等的)<br />
但是就目前看來,在 VFP 裡面對 Singleton 並沒有一個完美的解法.<br />
只有期待 VFP 未來能加入新的語言特性,讓我們能更靈活的運用了.<br />
<br />
附錄: C++ 的解法<br />
class CSingleton {<br />
private:<br />
&nbsp;&nbsp;static CSingleton* m_instance;<br />
protected:	//保護起來,不讓 constructor 直接被叫用.<br />
&nbsp;&nbsp;Singleton();<br />
&nbsp;&nbsp;Singleton(const Singleton&amp;);<br />
&nbsp;&nbsp;Singleton& operator= (const Singleton&amp;);<br />
public:<br />
&nbsp;&nbsp;CSingleton* getInstance(void) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;if( m_instance==NULL )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_instance=new CSingleton();<br />
&nbsp;&nbsp;&nbsp;&nbsp;return m_instance;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;char* getClassName(void) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;return "Hello! Singleton Pattern!!\n";<br />
&nbsp;&nbsp;}<br />
}<br />
CSingleton* CSingleton::m_instance=NULL;	//因為宣告為 static,所以可以這樣給值.<br />
int main( int argc, char* argv[] ) {<br />
&nbsp;&nbsp;CSingleton* obj=CSingleton::getInstance;<br />
&nbsp;&nbsp;printf( "%s", obj->getClassName());<br />
}
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553913.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553913.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Tue, 04 Nov 2003 22:59:00 +0800</pubDate>
</item>
<item>
	<title>Design Pattern-Dispatcher</title>
	<description><![CDATA[
			看完 RUN!PC 六月號由李維先生所寫的"由軟體品質檢驗談Design Pattern的應用"一文,我覺得用 VFP 就可以很簡單的作到,所以就以 VFP 實作.

該文以計算牌照稅為引子
計算牌照稅的時候,會需要依照汽缸的cc數以及私人/營業用車來判定收費的標準,照一般的寫法,很自然就會用到很多 If...Then...Else 或 do case...endcase, 可是這樣子程式碼就會變得很長很長,而難以維護.
像是這樣:

If cc < 500
&nbsp;&nbsp;money=900
else
&nbsp;&nbsp;if cc < 600 
&nbsp;&nbsp;&nbsp;&nbsp;money=1200
&nbsp;&nbsp;&nbsp;&nbsp;&amp;&amp;..... 略
&nbsp;&nbsp;endif
endif

用 do case 的話則是這樣
do case
&nbsp;&nbsp;case between( 0, 500 )
&nbsp;&nbsp;&nbsp;&nbsp;money=900
&nbsp;&nbsp;case between( 501, 599 )
&nbsp;&nbsp;&nbsp;&nbsp;money=1200
&nbsp;&nbsp;&amp;&amp; ... 略
endcase


李先生以一個 Dispatcher pattern 解決此一問題.
在 VFP 裡面可以直接結合資料庫作更好的解法

*
* ITax.prg
*
DEFINE CLASS ITax as custom
&nbsp;&nbsp;PROCEDURE Init()
&nbsp;&nbsp;&nbsp;&nbsp;create cursor crTax( cc_lo I, cc_hi I, PrivateTax Y,  BusinesTax Y )
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values (    0,  500, $ 1620, $  900 )
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values (  501,  599, $ 2160, $ 1200 )
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values (  600, 1199, $ 4320, $ 2160 )
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 1200, 1799, $ 7120, $ 3060 )
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 1800, 2399, $11230, $ 6480 )
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 2400, 2999, $15210, $ 9900 )
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 3000, 4199, $28220, $16380 )
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 4200, 5399, $46170, $24300 )
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 5400, 6599, $69690, $33660 )
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 6600, 7799, $117000, $44460 )
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 7800, 9999999, $117000, $44460 )
&nbsp;&nbsp;ENDPROC
&nbsp;&nbsp;PROCEDURE Destroy()
&nbsp;&nbsp;&nbsp;&nbsp;use in crTax
&nbsp;&nbsp;ENDPROC
&nbsp;&nbsp;PROCEDURE GetTax( cc, theKind )
&nbsp;&nbsp;&nbsp;&nbsp;local ly_result
&nbsp;&nbsp;&nbsp;&nbsp;local lc_oldalias
&nbsp;&nbsp;&nbsp;&nbsp;lc_oldalias=alias()

&nbsp;&nbsp;&nbsp;&nbsp;select("crTax")
&nbsp;&nbsp;&nbsp;&nbsp;go top
&nbsp;&nbsp;&nbsp;&nbsp;locate for between( cc, crTax.cc_lo, crTax.cc_hi )
&nbsp;&nbsp;&nbsp;&nbsp;if found()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ly_result=crTax.&theKind
&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ly_result=0
&nbsp;&nbsp;&nbsp;&nbsp;endif

&nbsp;&nbsp;&nbsp;&nbsp;select( lc_oldalias )
&nbsp;&nbsp;&nbsp;&nbsp;return ly_result
&nbsp;&nbsp;ENDPROC
&nbsp;&nbsp;PROCEDURE GetPrivateTax( cc )
&nbsp;&nbsp;&nbsp;&nbsp;return this.GetTax( cc, "PrivateTax" )
&nbsp;&nbsp;ENDPROC
&nbsp;&nbsp;PROCEDURE GetBusinessTax( cc )
&nbsp;&nbsp;&nbsp;&nbsp;return this.GetTax( cc, "BusinesTax" )
&nbsp;&nbsp;ENDPROC
ENDDEFINE

*
* test_itax.prg
*
LOCAL lo_obj
set procedure to itax.prg
lo_obj=createobject("ITax")
? lo_obj.GetPrivateTax( 1000 )
? lo_obj.GetBusinessTax( 2000 )

瞧,這樣不是簡單多了嗎??
在這裡拋磚引玉一下,希望大家如果有更好的解法
也 post 上來,讓大家觀摩一下
^_^
		]]>
	</description>
	<content:encoded><![CDATA[
			看完 RUN!PC 六月號由李維先生所寫的"由軟體品質檢驗談Design Pattern的應用"一文,我覺得用 VFP 就可以很簡單的作到,所以就以 VFP 實作.<br />
<br />
該文以計算牌照稅為引子<br />
計算牌照稅的時候,會需要依照汽缸的cc數以及私人/營業用車來判定收費的標準,照一般的寫法,很自然就會用到很多 If...Then...Else 或 do case...endcase, 可是這樣子程式碼就會變得很長很長,而難以維護.<br />
像是這樣:<br />
<br />
If cc < 500<br />
&nbsp;&nbsp;money=900<br />
else<br />
&nbsp;&nbsp;if cc < 600 <br />
&nbsp;&nbsp;&nbsp;&nbsp;money=1200<br />
&nbsp;&nbsp;&nbsp;&nbsp;&amp;&amp;..... 略<br />
&nbsp;&nbsp;endif<br />
endif<br />
<br />
用 do case 的話則是這樣<br />
do case<br />
&nbsp;&nbsp;case between( 0, 500 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;money=900<br />
&nbsp;&nbsp;case between( 501, 599 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;money=1200<br />
&nbsp;&nbsp;&amp;&amp; ... 略<br />
endcase<br />
<br />
<br />
李先生以一個 Dispatcher pattern 解決此一問題.<br />
在 VFP 裡面可以直接結合資料庫作更好的解法<br />
<br />
*<br />
* ITax.prg<br />
*<br />
DEFINE CLASS ITax as custom<br />
&nbsp;&nbsp;PROCEDURE Init()<br />
&nbsp;&nbsp;&nbsp;&nbsp;create cursor crTax( cc_lo I, cc_hi I, PrivateTax Y,  BusinesTax Y )<br />
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values (    0,  500, $ 1620, $  900 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values (  501,  599, $ 2160, $ 1200 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values (  600, 1199, $ 4320, $ 2160 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 1200, 1799, $ 7120, $ 3060 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 1800, 2399, $11230, $ 6480 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 2400, 2999, $15210, $ 9900 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 3000, 4199, $28220, $16380 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 4200, 5399, $46170, $24300 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 5400, 6599, $69690, $33660 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 6600, 7799, $117000, $44460 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;insert into crTax values ( 7800, 9999999, $117000, $44460 )<br />
&nbsp;&nbsp;ENDPROC<br />
&nbsp;&nbsp;PROCEDURE Destroy()<br />
&nbsp;&nbsp;&nbsp;&nbsp;use in crTax<br />
&nbsp;&nbsp;ENDPROC<br />
&nbsp;&nbsp;PROCEDURE GetTax( cc, theKind )<br />
&nbsp;&nbsp;&nbsp;&nbsp;local ly_result<br />
&nbsp;&nbsp;&nbsp;&nbsp;local lc_oldalias<br />
&nbsp;&nbsp;&nbsp;&nbsp;lc_oldalias=alias()<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;select("crTax")<br />
&nbsp;&nbsp;&nbsp;&nbsp;go top<br />
&nbsp;&nbsp;&nbsp;&nbsp;locate for between( cc, crTax.cc_lo, crTax.cc_hi )<br />
&nbsp;&nbsp;&nbsp;&nbsp;if found()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ly_result=crTax.&theKind<br />
&nbsp;&nbsp;&nbsp;&nbsp;else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ly_result=0<br />
&nbsp;&nbsp;&nbsp;&nbsp;endif<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;select( lc_oldalias )<br />
&nbsp;&nbsp;&nbsp;&nbsp;return ly_result<br />
&nbsp;&nbsp;ENDPROC<br />
&nbsp;&nbsp;PROCEDURE GetPrivateTax( cc )<br />
&nbsp;&nbsp;&nbsp;&nbsp;return this.GetTax( cc, "PrivateTax" )<br />
&nbsp;&nbsp;ENDPROC<br />
&nbsp;&nbsp;PROCEDURE GetBusinessTax( cc )<br />
&nbsp;&nbsp;&nbsp;&nbsp;return this.GetTax( cc, "BusinesTax" )<br />
&nbsp;&nbsp;ENDPROC<br />
ENDDEFINE<br />
<br />
*<br />
* test_itax.prg<br />
*<br />
LOCAL lo_obj<br />
set procedure to itax.prg<br />
lo_obj=createobject("ITax")<br />
? lo_obj.GetPrivateTax( 1000 )<br />
? lo_obj.GetBusinessTax( 2000 )<br />
<br />
瞧,這樣不是簡單多了嗎??<br />
在這裡拋磚引玉一下,希望大家如果有更好的解法<br />
也 post 上來,讓大家觀摩一下<br />
^_^
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553911.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553911.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Mon, 03 Nov 2003 21:57:50 +0800</pubDate>
</item>
<item>
	<title>VFP on Linux - 與 Wine 共舞的樂章</title>
	<description><![CDATA[
			寫在前面
========
老實說,這篇文章充其量,祇能說是整理而已.
純粹去網路找文章,實作,遇到與文章不符的地方,就自己動手找資料,實驗,找答案,就這樣而已.
我想,大概有百分之五十是參考資料,百分之四十是翻譯;剩下百分之十,才是我的心得與實作過程.

Wine 的歷史
===========
請直接參考 2003/08/15 的 Wine Traffic
http://kt.zork.net/wine/wn20030815_183.html#5

安裝,from tarball
=================
以 tar xzf 解開之後,進行 patch, patch 檔網址在此:
http://www.paulmcnett.com/vfp/wine/vfpwinepatchwinsize
這個 patch 檔主要是修正 WAIT WINDOW 和 TooltipText window 無法正確顯示的問題.
Patch 方法:
cat vfpwinepatchwinsize | patch -p1
也可以手動編輯 wine/dlls/x11drv/winpos.c
在約 887 行的地方,找到
BOOL
X11DRV_SetWindowPos( WINDOWPOS *winpos )
這個 function,並在裡面的
TRACE(
"hwnd %p ......
之前加上
/* This is needed to flush pending X ConfigureNotify events on this window */
MsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
存檔以後即可.

執行 ./tools/wineinstall

它會出現訊息,建議不要以 root 身分來安裝
如果你堅持要以 root 身分來安裝, 請修改此 script,讓他忽略此訊息
(178~184 行,前面加上'#' )
再執行此 script.
當然如果要用別的身分來安裝,請用 su 指令切換到其他 user 帳號
或重新以其他 user 帳號登入即可.

此 script會執行 ./configure,設置必要的設定檔以及路徑.
然後再執行
make depend && make && make install
進行編譯及安裝工作.

若以其他user進行安裝的話,就依照 script指示即可
wine 最後會以 SUID 形式存在.

RPM 安裝
========
請到官方網站下載符合你 Linux distribution 的 RPM 版本
然後執行 rpm -ivh wine-2003xxxx.ix86.rpm
即可~
但要注意的是,不保證可以用,建議還是以 tarball 安裝較佳.這樣也可加上 patch.

Usage
=====
winhelp, notepad, regsvr32, regedit 這幾個不用說明,就跟Windows 上的一樣~
progman 的話就跟 Windows 3.1 上的 Progman 一樣,執行以後,
有用過 Windows 3.1 的人,大概會很懷念~
winefile 則是檔案總管
wcmd 是"命令提示字元"
uninstaller 則是"新增/移除程式"
winecfg 則是調校 wine 設定的程式
執行軟體時,以 wine 執行之,假設你複製了小算盤(calc.exe)進去
那麼就輸入 wine calc.exe 即可~
安裝軟體,也一樣,執行 setup 即可: wine setup.exe

Configuration
=============
"Version"Section 的 Windows key 值改為 win2k
"DllOverrides" Section 中所有 key 值改為 "native, builtin"
此外把你自己 Winnt\system32 或 Windows\system 下的
OLEAUT32.DLL
COMMDLG.DLL
COMDLG32.DLL
SHELL.DLL
SHELL32.DLL
SHFOLDER.DLL
SHLWAPI.DLL
SHDOCVW.DLL
ADVAPI32.DLL
MSVCRT*.DLL
VFP6*.DLL
ODBC32.DLL
ODBC32GT.DLL
ODBC16GT.DLL
ODBCINT.DLL
ODBCCONF.DLL
都複製到 ~/c/windows/system 下
此外,OLE32.DLL, ADVAPI32.DLL, NTDLL.DLL 是不需要複製的,因為會造成無法執行.
REGEDIT.EXE 也請複製到 ~/c/windows 下,因為我們要把 ODBC 的 Registry import 進去.
你也許會問 wine 不是提供了 regedit.exe 嗎?可是根據我自己的試驗,它並無法匯入.
請在 Windows 下執行 regedit.exe 將
HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\ODBC Drivers
以及
HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\Microsoft Visual FoxPro Driver
這兩個機碼都匯出.分別存為 ODBCDrivers.reg 及 VFPDriver.reg
然後編輯 ODBCDrivers.reg ,將其他 Driver 都刪掉,只留下 Microsoft Visual FoxPro Driver 即可
接著就拿到 Linux 上,執行 regedit.exe 匯入囉.

開始使用 VFP
============
我自己是建議不要用 setup 安裝,網路上的一些狐友也這樣說
就是用 copy 的方式把 Program Files 目錄下的 VFP 目錄直接複製到 ~/c/Program Files 下
再參考上面的 Configuration 一節作修正.
接著就可以執行 wine VFP6.EXE 啦~~
進入以後,你會發現 command window 無法顯示游標,請用 Alt+TAB 切到別的視窗, 再按一次 Alt+TAB 切回 VFP,即可.

Issue
=====
Declare DLL ok
大部分函數都已經實作出來了~
可能會發生的問題,多半是路徑問題,此問題可以藉著修改 ~/.wine/config 來解決.

Record locking
20030318 版之前是有問題的,但之後的版本就都可以了

ActiveX
有些 ActiveX 會無法使用,那是因為有些 function 還沒實作出來的原因.

中文
對我們來說,這是最大的問題了
Linux 中雖然已經支援中文,可是 wine 看來是還未支援,也因此,文字無法輸入到 VFP 視窗中.
此外,字型名稱也是一大問題,由於小弟對中文字型設定這部分還不是很熟
再加上目前 X 組織又提出一個新的技術 Xft 要解決字型名稱問題,所以請期待吧~

其他
沒有 HTML Help.
在 Class Designer/Form Designer 裡面無法 copy/paste 物件.
Undocked windows 需要被設定為 undockable (在Title band 按下滑鼠右鍵) 或他們無法取得 focus.

EULA(End User Licence Aggreement) - Microsoft 的阻撓
====================================================
以下大致從 http://www.linuxtransfer.com/h/misc_vfplinuxjackofhearts.htm 譯出.
僅將大意譯出,如果譯的不好,還請見諒.

事情是這樣開始的,就在今年的四月左右,Ken Levy,Whil Hentzen在展示一個關於 VFP on Linux 的 Demo 之後,他接到一通來自微軟的電話,告知他說,這樣的一個 Demo 將可能會與 VFP EULA 衝突.後來這件事情就慢慢的擴散....
什麼是 EULA ?? EULA 就是 End User Licence Aggreement 的縮寫.
以下就是與 VFP on Linux 有關的 VFP8 EULA條款:
3.1 General Distribution Requirements.
(a) If you choose to redistribute Sample Code, or Redistributable Code (collectively, the "Redistributables") as described in Section 2, you agree:
(i) except as otherwise noted in Section 2.1 (Sample Code), to distribute the Redistributables only in object code form and in conjunction with and as a part of a software application product developed by you that adds significant and primary functionality to the Redistributables ("Licensee Software");
(ii) that the Redistributables only operate in conjunction with Microsoft Windows platforms;
在 VFP 社群要求微軟作進一步說明的一星期後,這是微軟的說明(澄清):
Visual FoxPro was designed and tested for use in creating applications that run on the Microsoft Windows platform; the same applies to the components that are provided to developers for redistribution with Visual FoxPro-based applications. If a developer wishes to distribute the Visual FoxPro runtime with an application, the runtime may only operate in conjunction with a Microsoft Windows platform. As with any contract, you should seek your own legal counsel's advice when interpreting your rights and obligations under the Visual FoxPro End User License Agreement.
大意是,VFP本身是在 Windows 平台上發展及測試的,和VFP一起提供給開發者散佈的元件也是.如果開發者想要將VFP runtime和應用程式一起發佈,runtime 應該只能(may only)在Microsoft Windows 平台上運行.如同任何的合約,你應該尋求你的法律顧問的建議.
在這篇文章中,http://www.linuxtransfer.com/h/misc_vfplinuxjackofhearts.htm
提出了三點疑問,
1.Running the VFP Development Environment on Linux
VFP 開發者想要在一台 Linux 機器上將 VFP 當作一個開發環境.
這個企圖正是 McNett's FoxTalk 文章的主旨,而且是Levy舉辦該活動的主題,卻又宣告他是與VFP7 和 VFP8 的 EULA 衝突,不允許公開展示.
2.Deploying custom VFP applications on Linux workstations
VFP 如同大家所知的,AP都是要與 runtime 一同包裝,並安裝到客戶那兒.以前很簡單,都只要幾個DLL檔案就行了,現在,最後一版的VFP,都是以MSM 形式給Installer tool使用.只有這些 MSM 檔案列在 REDIST.TXT 中,卻沒有明確的指定是哪些VFP DLL 檔案.
所以只要用這個方法是不是就可以避免了呢?
第一個問題是,如果發布自訂的VFP DLLs 在 EULA 裡是不被允許的,那麼
(1)如果不用 Windows Installer 技術的話,那麼市場上還有許多不使用 Windows Installer 技術的安裝工具,這些工具是不是就與 VFP EULA 衝突了呢??
(2)為什麼從6.0 到7.0,這樣的一個改變,卻沒有任何公告??就正常來說,一個產品的改變應該會被公告於 "Read Me" 或 "What's New" 檔案中.可是這卻被放到 EULA 中,而缺乏任何說明.
ok,假設VFP EULA 禁止散佈 VFP DLLs,只能使用 Windows Installer 技術.
總之,看起來,Microsoft 就是想把它們的應用程式綁在他們的 OS 上.
3.The Business Issues
Microsoft 之所以需要 VFP, FoxBase 和 FoxPro, 主要就是為了要打擊Desktop database市場上其他的對手.那個時候,幾乎所有產品都不需要 runtime license,就這樣,一直延續到現在.Microsoft長期忽略 VFP,大概與Business Model有關,他們寧可開發者用VB 和 SQL Server,這樣就可從 SQL Server 那兒收到 licenses 費用.
VFP 可以在 Linux 上執行是非常吸引人的,想想一套便宜(或免費)的作業系統加上一個不貴又有威力的開發工具,和一個便宜(或免費)的後端資料庫,是多麼的不錯.很簡單的可以看出來為什麼 Microsoft 要試著去對抗他,並強加了和以往不一樣的的授權限制.

參考網址: (謝謝Ruey提供部份資料)
===============================
安裝:
http://www.pinpub.com/FT/FTmag.nsf/0/843B563D8FB169F485256D6700710C3A
http://www.paulmcnett.com/vfp/vfp7wine.html (安裝)
http://www.paulmcnett.com/vfp/wine/foxtalk1.html
相關資料收集:
http://fox.wikis.com/wc.dll?Wiki~VFPandLinux~VFP
http://www.associateddata.co.uk/VFPLinux.htm
微軟的恫嚇與EULA的相關討論:
http://www.linuxworld.com/story/32665.htm
http://mail.linux.ie/pipermail/ilug/2003-April/002197.html
http://www.linuxtransfer.com/h/misc_vfplinuxjackofhearts.htm
http://www.linuxjournal.com/article.php?sid=6869&mode=thread&order=0
Wine 官方網站 Guide:
http://www.winehq.com/Docs/wine-user/
Wine 應用程式相容性:
http://appdb.winehq.com/
http://frankscorner.org/
Wine 所收錄的 VFP Profile:
http://appdb.winehq.com/appview.php?appId=296;PHPSESSID=9e9d479fa55fb6c759ad092fd5aa3184
		]]>
	</description>
	<content:encoded><![CDATA[
			寫在前面<br />
========<br />
老實說,這篇文章充其量,祇能說是整理而已.<br />
純粹去網路找文章,實作,遇到與文章不符的地方,就自己動手找資料,實驗,找答案,就這樣而已.<br />
我想,大概有百分之五十是參考資料,百分之四十是翻譯;剩下百分之十,才是我的心得與實作過程.<br />
<br />
Wine 的歷史<br />
===========<br />
請直接參考 2003/08/15 的 Wine Traffic<br />
http://kt.zork.net/wine/wn20030815_183.html#5<br />
<br />
安裝,from tarball<br />
=================<br />
以 tar xzf 解開之後,進行 patch, patch 檔網址在此:<br />
http://www.paulmcnett.com/vfp/wine/vfpwinepatchwinsize<br />
這個 patch 檔主要是修正 WAIT WINDOW 和 TooltipText window 無法正確顯示的問題.<br />
Patch 方法:<br />
cat vfpwinepatchwinsize | patch -p1<br />
也可以手動編輯 wine/dlls/x11drv/winpos.c<br />
在約 887 行的地方,找到<br />
BOOL<br />
X11DRV_SetWindowPos( WINDOWPOS *winpos )<br />
這個 function,並在裡面的<br />
TRACE(<br />
"hwnd %p ......<br />
之前加上<br />
/* This is needed to flush pending X ConfigureNotify events on this window */<br />
MsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );<br />
存檔以後即可.<br />
<br />
執行 ./tools/wineinstall<br />
<br />
它會出現訊息,建議不要以 root 身分來安裝<br />
如果你堅持要以 root 身分來安裝, 請修改此 script,讓他忽略此訊息<br />
(178~184 行,前面加上'#' )<br />
再執行此 script.<br />
當然如果要用別的身分來安裝,請用 su 指令切換到其他 user 帳號<br />
或重新以其他 user 帳號登入即可.<br />
<br />
此 script會執行 ./configure,設置必要的設定檔以及路徑.<br />
然後再執行<br />
make depend && make && make install<br />
進行編譯及安裝工作.<br />
<br />
若以其他user進行安裝的話,就依照 script指示即可<br />
wine 最後會以 SUID 形式存在.<br />
<br />
RPM 安裝<br />
========<br />
請到官方網站下載符合你 Linux distribution 的 RPM 版本<br />
然後執行 rpm -ivh wine-2003xxxx.ix86.rpm<br />
即可~<br />
但要注意的是,不保證可以用,建議還是以 tarball 安裝較佳.這樣也可加上 patch.<br />
<br />
Usage<br />
=====<br />
winhelp, notepad, regsvr32, regedit 這幾個不用說明,就跟Windows 上的一樣~<br />
progman 的話就跟 Windows 3.1 上的 Progman 一樣,執行以後,<br />
有用過 Windows 3.1 的人,大概會很懷念~<br />
winefile 則是檔案總管<br />
wcmd 是"命令提示字元"<br />
uninstaller 則是"新增/移除程式"<br />
winecfg 則是調校 wine 設定的程式<br />
執行軟體時,以 wine 執行之,假設你複製了小算盤(calc.exe)進去<br />
那麼就輸入 wine calc.exe 即可~<br />
安裝軟體,也一樣,執行 setup 即可: wine setup.exe<br />
<br />
Configuration<br />
=============<br />
"Version"Section 的 Windows key 值改為 win2k<br />
"DllOverrides" Section 中所有 key 值改為 "native, builtin"<br />
此外把你自己 Winnt\system32 或 Windows\system 下的<br />
OLEAUT32.DLL<br />
COMMDLG.DLL<br />
COMDLG32.DLL<br />
SHELL.DLL<br />
SHELL32.DLL<br />
SHFOLDER.DLL<br />
SHLWAPI.DLL<br />
SHDOCVW.DLL<br />
ADVAPI32.DLL<br />
MSVCRT*.DLL<br />
VFP6*.DLL<br />
ODBC32.DLL<br />
ODBC32GT.DLL<br />
ODBC16GT.DLL<br />
ODBCINT.DLL<br />
ODBCCONF.DLL<br />
都複製到 ~/c/windows/system 下<br />
此外,OLE32.DLL, ADVAPI32.DLL, NTDLL.DLL 是不需要複製的,因為會造成無法執行.<br />
REGEDIT.EXE 也請複製到 ~/c/windows 下,因為我們要把 ODBC 的 Registry import 進去.<br />
你也許會問 wine 不是提供了 regedit.exe 嗎?可是根據我自己的試驗,它並無法匯入.<br />
請在 Windows 下執行 regedit.exe 將<br />
HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\ODBC Drivers<br />
以及<br />
HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\Microsoft Visual FoxPro Driver<br />
這兩個機碼都匯出.分別存為 ODBCDrivers.reg 及 VFPDriver.reg<br />
然後編輯 ODBCDrivers.reg ,將其他 Driver 都刪掉,只留下 Microsoft Visual FoxPro Driver 即可<br />
接著就拿到 Linux 上,執行 regedit.exe 匯入囉.<br />
<br />
開始使用 VFP<br />
============<br />
我自己是建議不要用 setup 安裝,網路上的一些狐友也這樣說<br />
就是用 copy 的方式把 Program Files 目錄下的 VFP 目錄直接複製到 ~/c/Program Files 下<br />
再參考上面的 Configuration 一節作修正.<br />
接著就可以執行 wine VFP6.EXE 啦~~<br />
進入以後,你會發現 command window 無法顯示游標,請用 Alt+TAB 切到別的視窗, 再按一次 Alt+TAB 切回 VFP,即可.<br />
<br />
Issue<br />
=====<br />
Declare DLL ok<br />
大部分函數都已經實作出來了~<br />
可能會發生的問題,多半是路徑問題,此問題可以藉著修改 ~/.wine/config 來解決.<br />
<br />
Record locking<br />
20030318 版之前是有問題的,但之後的版本就都可以了<br />
<br />
ActiveX<br />
有些 ActiveX 會無法使用,那是因為有些 function 還沒實作出來的原因.<br />
<br />
中文<br />
對我們來說,這是最大的問題了<br />
Linux 中雖然已經支援中文,可是 wine 看來是還未支援,也因此,文字無法輸入到 VFP 視窗中.<br />
此外,字型名稱也是一大問題,由於小弟對中文字型設定這部分還不是很熟<br />
再加上目前 X 組織又提出一個新的技術 Xft 要解決字型名稱問題,所以請期待吧~<br />
<br />
其他<br />
沒有 HTML Help.<br />
在 Class Designer/Form Designer 裡面無法 copy/paste 物件.<br />
Undocked windows 需要被設定為 undockable (在Title band 按下滑鼠右鍵) 或他們無法取得 focus.<br />
<br />
EULA(End User Licence Aggreement) - Microsoft 的阻撓<br />
====================================================<br />
以下大致從 http://www.linuxtransfer.com/h/misc_vfplinuxjackofhearts.htm 譯出.<br />
僅將大意譯出,如果譯的不好,還請見諒.<br />
<br />
事情是這樣開始的,就在今年的四月左右,Ken Levy,Whil Hentzen在展示一個關於 VFP on Linux 的 Demo 之後,他接到一通來自微軟的電話,告知他說,這樣的一個 Demo 將可能會與 VFP EULA 衝突.後來這件事情就慢慢的擴散....<br />
什麼是 EULA ?? EULA 就是 End User Licence Aggreement 的縮寫.<br />
以下就是與 VFP on Linux 有關的 VFP8 EULA條款:<br />
3.1 General Distribution Requirements.<br />
(a) If you choose to redistribute Sample Code, or Redistributable Code (collectively, the "Redistributables") as described in Section 2, you agree:<br />
(i) except as otherwise noted in Section 2.1 (Sample Code), to distribute the Redistributables only in object code form and in conjunction with and as a part of a software application product developed by you that adds significant and primary functionality to the Redistributables ("Licensee Software");<br />
(ii) that the Redistributables only operate in conjunction with Microsoft Windows platforms;<br />
在 VFP 社群要求微軟作進一步說明的一星期後,這是微軟的說明(澄清):<br />
Visual FoxPro was designed and tested for use in creating applications that run on the Microsoft Windows platform; the same applies to the components that are provided to developers for redistribution with Visual FoxPro-based applications. If a developer wishes to distribute the Visual FoxPro runtime with an application, the runtime may only operate in conjunction with a Microsoft Windows platform. As with any contract, you should seek your own legal counsel's advice when interpreting your rights and obligations under the Visual FoxPro End User License Agreement.<br />
大意是,VFP本身是在 Windows 平台上發展及測試的,和VFP一起提供給開發者散佈的元件也是.如果開發者想要將VFP runtime和應用程式一起發佈,runtime 應該只能(may only)在Microsoft Windows 平台上運行.如同任何的合約,你應該尋求你的法律顧問的建議.<br />
在這篇文章中,http://www.linuxtransfer.com/h/misc_vfplinuxjackofhearts.htm<br />
提出了三點疑問,<br />
1.Running the VFP Development Environment on Linux<br />
VFP 開發者想要在一台 Linux 機器上將 VFP 當作一個開發環境.<br />
這個企圖正是 McNett's FoxTalk 文章的主旨,而且是Levy舉辦該活動的主題,卻又宣告他是與VFP7 和 VFP8 的 EULA 衝突,不允許公開展示.<br />
2.Deploying custom VFP applications on Linux workstations<br />
VFP 如同大家所知的,AP都是要與 runtime 一同包裝,並安裝到客戶那兒.以前很簡單,都只要幾個DLL檔案就行了,現在,最後一版的VFP,都是以MSM 形式給Installer tool使用.只有這些 MSM 檔案列在 REDIST.TXT 中,卻沒有明確的指定是哪些VFP DLL 檔案.<br />
所以只要用這個方法是不是就可以避免了呢?<br />
第一個問題是,如果發布自訂的VFP DLLs 在 EULA 裡是不被允許的,那麼<br />
(1)如果不用 Windows Installer 技術的話,那麼市場上還有許多不使用 Windows Installer 技術的安裝工具,這些工具是不是就與 VFP EULA 衝突了呢??<br />
(2)為什麼從6.0 到7.0,這樣的一個改變,卻沒有任何公告??就正常來說,一個產品的改變應該會被公告於 "Read Me" 或 "What's New" 檔案中.可是這卻被放到 EULA 中,而缺乏任何說明.<br />
ok,假設VFP EULA 禁止散佈 VFP DLLs,只能使用 Windows Installer 技術.<br />
總之,看起來,Microsoft 就是想把它們的應用程式綁在他們的 OS 上.<br />
3.The Business Issues<br />
Microsoft 之所以需要 VFP, FoxBase 和 FoxPro, 主要就是為了要打擊Desktop database市場上其他的對手.那個時候,幾乎所有產品都不需要 runtime license,就這樣,一直延續到現在.Microsoft長期忽略 VFP,大概與Business Model有關,他們寧可開發者用VB 和 SQL Server,這樣就可從 SQL Server 那兒收到 licenses 費用.<br />
VFP 可以在 Linux 上執行是非常吸引人的,想想一套便宜(或免費)的作業系統加上一個不貴又有威力的開發工具,和一個便宜(或免費)的後端資料庫,是多麼的不錯.很簡單的可以看出來為什麼 Microsoft 要試著去對抗他,並強加了和以往不一樣的的授權限制.<br />
<br />
參考網址: (謝謝Ruey提供部份資料)<br />
===============================<br />
安裝:<br />
http://www.pinpub.com/FT/FTmag.nsf/0/843B563D8FB169F485256D6700710C3A<br />
http://www.paulmcnett.com/vfp/vfp7wine.html (安裝)<br />
http://www.paulmcnett.com/vfp/wine/foxtalk1.html<br />
相關資料收集:<br />
http://fox.wikis.com/wc.dll?Wiki~VFPandLinux~VFP<br />
http://www.associateddata.co.uk/VFPLinux.htm<br />
微軟的恫嚇與EULA的相關討論:<br />
http://www.linuxworld.com/story/32665.htm<br />
http://mail.linux.ie/pipermail/ilug/2003-April/002197.html<br />
http://www.linuxtransfer.com/h/misc_vfplinuxjackofhearts.htm<br />
http://www.linuxjournal.com/article.php?sid=6869&mode=thread&order=0<br />
Wine 官方網站 Guide:<br />
http://www.winehq.com/Docs/wine-user/<br />
Wine 應用程式相容性:<br />
http://appdb.winehq.com/<br />
http://frankscorner.org/<br />
Wine 所收錄的 VFP Profile:<br />
http://appdb.winehq.com/appview.php?appId=296;PHPSESSID=9e9d479fa55fb6c759ad092fd5aa3184
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553886.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553886.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Sat, 23 Aug 2003 20:39:39 +0800</pubDate>
</item>
<item>
	<title>VFP Toolkit for Visual Studio.NET</title>
	<description><![CDATA[
			其實他根本就是一個 wrapper
把 .net 的 code 給包裝起來
看起來的確變的很類似 vfp
但實際上宣告變數以及語法仍然遵循 c# 或 vb.net
而非原來的 vfp 

不過文件上說的沒錯
他提供了絕大部分的 vfp 函數
可是~
存取資料時
仍然要使用 sqlconnect
而不是 use
也因此沒有索引的功能
但有提供索引搜尋跟切換索引的功能
只是這些東西仍然依存於 .net dataview 元件的能力
換言之
如果要細調其執行效能
恐怕仍然需要了解 .net ado.net

source code 很有幫助,並不是很困難
建議也下載回去看
對上手 .net 有相當的助益
		]]>
	</description>
	<content:encoded><![CDATA[
			其實他根本就是一個 wrapper<br />
把 .net 的 code 給包裝起來<br />
看起來的確變的很類似 vfp<br />
但實際上宣告變數以及語法仍然遵循 c# 或 vb.net<br />
而非原來的 vfp <br />
<br />
不過文件上說的沒錯<br />
他提供了絕大部分的 vfp 函數<br />
可是~<br />
存取資料時<br />
仍然要使用 sqlconnect<br />
而不是 use<br />
也因此沒有索引的功能<br />
但有提供索引搜尋跟切換索引的功能<br />
只是這些東西仍然依存於 .net dataview 元件的能力<br />
換言之<br />
如果要細調其執行效能<br />
恐怕仍然需要了解 .net ado.net<br />
<br />
source code 很有幫助,並不是很困難<br />
建議也下載回去看<br />
對上手 .net 有相當的助益
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553849.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553849.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Sat, 21 Dec 2002 17:14:06 +0800</pubDate>
</item>
<item>
	<title>VFP OLEDB Drivers How-To</title>
	<description><![CDATA[
			限制:
以6.0而言,似乎一定要用 ado 來開啟

範例:
OConn = CREATEOBJECT("ADODB.Connection")
OConn.ConnectionString = "provider=vfpoledb.1;;
data source=.\testdbc.dbc"
OConn.Open

語法:
Provider = VFPOLEDB 
Data Source=cPath 
Specifies the path to the Visual FoxPro database or folder containing free tables. For example, d:\vfp7\samples\data\testdata.dbc 
Mode=cMode 
Specifies one of the following: Read, ReadWrite, Share Deny None (default), Share Deny Read, Share Deny Write, Share Exclusive (inclusive of the previous two modes). 

可以丟如下指令
The Visual FoxPro OLE DB Provider supports the native Visual FoxPro language syntax for the following commands: 

CREATE TABLE - SQL Command 
Creates a table having the specified fields. 
DELETE - SQL Command 
Marks records for deletion. 
DROP TABLE Command 
Removes a table from the database specified with the data source and deletes it from disk. 
INSERT - SQL Command 
Appends a record to the end of a table that contains the specified field values. 
SELECT - SQL Command 
Retrieves data from one or more tables. 
UPDATE - SQL Command 
Updates records in a table with new values. 
The Visual FoxPro Language Reference contains detailed information about the following supported commands: 

ALTER TABLE - SQL Command 
Programmatically modifies the structure of a table. 
CREATE TABLE - SQL Command 
Creates a table having the specified fields. 
Using Data Definition Language (DDL)
You cannot include DDL in the following places: 

In a batch SQL statement that requires a transaction 
Following a previously executed statement that required a transaction if not in auto-commit mode and if your application has not yet called SQLTransact. 
For example, if you want to create a temporary table, you should create the table before you begin the statement requiring a transaction. If you include the CREATE TABLE statement in a batch SQL statement that requires a transaction, the provider returns an error message. 

DELETE - SQL Command 
Marks records for deletion. 
DELETE TAG Command 
Removes a tag or tags from a compound index (.cdx) file. 
DROP TABLE Command 
Removes a table from the database specified with the data source and deletes it from disk. 
INDEX Command 
Creates an index file to display and access table records in a logical order. 
INSERT - SQL Command 
Appends a record to the end of a table that contains the specified field values. 
SELECT - SQL Command 
Retrieves data from one or more tables. 
The Visual FoxPro OLE DB Provider supports the native Visual FoxPro language syntax for this command. 

SET ANSI Command 
Determines how comparisons between strings of different lengths are made with the = operator in Visual FoxPro SQL commands. 
SET BLOCKSIZE Command 
Specifies how disk space is allocated for the storage of memo fields. 
SET COLLATE Command 
Specifies a collation sequence for character fields in subsequent indexing and sorting operations. 
SET DELETED Command 
Specifies whether records marked for deletion are processed and whether they are available for use in other commands. 
SET EXACT Command 
Specifies the rules for comparing two strings of different lengths. 
SET EXCLUSIVE Command 
Specifies whether table files are opened for exclusive or shared use on a network. 
SET NULL Command 
Determines how null values are supported by the ALTER TABLE - SQL, CREATE TABLE - SQL, and INSERT - SQL commands. 
SET PATH Command 
Specifies a path for file searches. 
Provider Remarks
If you issue SET PATH in a stored procedure, it will be ignored by the following functions and commands: SELECT, INSERT, UPDATE, DELETE, and CREATE TABLE 

If you issue SET PATH in a stored procedure and do not subsequently set the path back to its original state, other connections to the database will use the new path (because SET PATH is not scoped to data sessions).

If you want to create, select, or update tables in a directory other than that specified by the data source, specify the full path of the file with your command. 

SET REPROCESS Command 
Specifies how many times or for how long to lock a file or record after an unsuccessful locking attempt. 
SET UNIQUE Command 
Specifies whether records with duplicate index key values are maintained in an index file. 
UPDATE - SQL Command 
Updates records in a table with new values.
		]]>
	</description>
	<content:encoded><![CDATA[
			限制:<br />
以6.0而言,似乎一定要用 ado 來開啟<br />
<br />
範例:<br />
OConn = CREATEOBJECT("ADODB.Connection")<br />
OConn.ConnectionString = "provider=vfpoledb.1;;<br />
data source=.\testdbc.dbc"<br />
OConn.Open<br />
<br />
語法:<br />
Provider = VFPOLEDB <br />
Data Source=cPath <br />
Specifies the path to the Visual FoxPro database or folder containing free tables. For example, d:\vfp7\samples\data\testdata.dbc <br />
Mode=cMode <br />
Specifies one of the following: Read, ReadWrite, Share Deny None (default), Share Deny Read, Share Deny Write, Share Exclusive (inclusive of the previous two modes). <br />
<br />
可以丟如下指令<br />
The Visual FoxPro OLE DB Provider supports the native Visual FoxPro language syntax for the following commands: <br />
<br />
CREATE TABLE - SQL Command <br />
Creates a table having the specified fields. <br />
DELETE - SQL Command <br />
Marks records for deletion. <br />
DROP TABLE Command <br />
Removes a table from the database specified with the data source and deletes it from disk. <br />
INSERT - SQL Command <br />
Appends a record to the end of a table that contains the specified field values. <br />
SELECT - SQL Command <br />
Retrieves data from one or more tables. <br />
UPDATE - SQL Command <br />
Updates records in a table with new values. <br />
The Visual FoxPro Language Reference contains detailed information about the following supported commands: <br />
<br />
ALTER TABLE - SQL Command <br />
Programmatically modifies the structure of a table. <br />
CREATE TABLE - SQL Command <br />
Creates a table having the specified fields. <br />
Using Data Definition Language (DDL)<br />
You cannot include DDL in the following places: <br />
<br />
In a batch SQL statement that requires a transaction <br />
Following a previously executed statement that required a transaction if not in auto-commit mode and if your application has not yet called SQLTransact. <br />
For example, if you want to create a temporary table, you should create the table before you begin the statement requiring a transaction. If you include the CREATE TABLE statement in a batch SQL statement that requires a transaction, the provider returns an error message. <br />
<br />
DELETE - SQL Command <br />
Marks records for deletion. <br />
DELETE TAG Command <br />
Removes a tag or tags from a compound index (.cdx) file. <br />
DROP TABLE Command <br />
Removes a table from the database specified with the data source and deletes it from disk. <br />
INDEX Command <br />
Creates an index file to display and access table records in a logical order. <br />
INSERT - SQL Command <br />
Appends a record to the end of a table that contains the specified field values. <br />
SELECT - SQL Command <br />
Retrieves data from one or more tables. <br />
The Visual FoxPro OLE DB Provider supports the native Visual FoxPro language syntax for this command. <br />
<br />
SET ANSI Command <br />
Determines how comparisons between strings of different lengths are made with the = operator in Visual FoxPro SQL commands. <br />
SET BLOCKSIZE Command <br />
Specifies how disk space is allocated for the storage of memo fields. <br />
SET COLLATE Command <br />
Specifies a collation sequence for character fields in subsequent indexing and sorting operations. <br />
SET DELETED Command <br />
Specifies whether records marked for deletion are processed and whether they are available for use in other commands. <br />
SET EXACT Command <br />
Specifies the rules for comparing two strings of different lengths. <br />
SET EXCLUSIVE Command <br />
Specifies whether table files are opened for exclusive or shared use on a network. <br />
SET NULL Command <br />
Determines how null values are supported by the ALTER TABLE - SQL, CREATE TABLE - SQL, and INSERT - SQL commands. <br />
SET PATH Command <br />
Specifies a path for file searches. <br />
Provider Remarks<br />
If you issue SET PATH in a stored procedure, it will be ignored by the following functions and commands: SELECT, INSERT, UPDATE, DELETE, and CREATE TABLE <br />
<br />
If you issue SET PATH in a stored procedure and do not subsequently set the path back to its original state, other connections to the database will use the new path (because SET PATH is not scoped to data sessions).<br />
<br />
If you want to create, select, or update tables in a directory other than that specified by the data source, specify the full path of the file with your command. <br />
<br />
SET REPROCESS Command <br />
Specifies how many times or for how long to lock a file or record after an unsuccessful locking attempt. <br />
SET UNIQUE Command <br />
Specifies whether records with duplicate index key values are maintained in an index file. <br />
UPDATE - SQL Command <br />
Updates records in a table with new values.
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553848.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553848.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Sat, 21 Dec 2002 17:04:51 +0800</pubDate>
</item>
<item>
	<title>VFP7 與 Web Service</title>
	<description><![CDATA[
			前言
建立Web Service
建立Web Service Client 端程式
使用其他語言建立的 Web Service
與資料庫結合
結論
參考資料

前言
VFP 這項產品一直被謠傳微軟將不再支援，但在今年六月，微軟將VFP7自Visual Studio.NET中獨立出來銷售，總算是打破了這個謠言。此外，也為這項產品添加了不少功能，比如 Intellisense、對COM的更完整支援、SOAP與Web Service 等等。這裡就為各位解說新增的SOAP與Web Service功能。

SOAP 與 Web Service 這兩個名詞，相信我不用再多做解釋了，大家在這一陣子的耳濡目染之下，應該都大致了解，在此就不再贅述。如果想了解的人請參考前幾期RUN!PC李維老師的文章，有詳細的解說。



建立Web Service
首先讓我們來製作 Web Service，稍後，再來撰寫如何使用 Web Service 的 Client 端程式。
要使用VFP7製作Web Service之前，請先在[Internet 服務管理員]中，新增一個虛擬目錄，在此，我們先命名為 WebServices。
接下來得製作一個COM元件，在這裡我們就以一個簡單的相加函數來作為一個範例。
請先建立一個新專案，名稱叫做MyWebService，在Project Manager(專案管理員)中，切換到 Program頁籤，點選 ”New”，將下列這段程式碼貼到裡面去，然後存檔為 prog1.prg。

DEFINE CLASS MyCalculator AS session OLEPUBLIC
Name = "MyCalculator"
PROCEDURE doAdd
                Parameters A , B
        Return A+B
ENDPROC
ENDDEFINE


這一段程式碼只是將傳入的兩個參數做一個簡單的相加而已。
接著就要進行編譯的工作了，點選”Build”，建立的型態選為”Single-threaded COM Server(dll)”，按下 ”確定” 來建立一個dll型態的COM伺服器。



建立完成後，你會發現VFP7為你產生了一個mywebservice.dll，並已經為你註冊到電腦中了，讓我們驗證一下VFP7是否已經編譯成功，請在命令列中依序輸入：


obj=createobject(“MyWebService.MyCalculator”)
? obj.doAdd(100,100)


如果成功的話，你應該會看到VFP7回應了 200 這個答案，表示COM伺服器已經建立成功。

VFP7提供了一個方便的精靈，讓你可以直接在VFP7的整合環境中建立 Web Service，而不需要另外去執行 SOAP toolkit 來製作。

請你在Project Manager中，以滑鼠右鍵點選叫出快捷選單，選擇Builder。此時，會出現一個選擇精靈的對話方盒(如圖)，選擇Web Services Publisher，並按下確定。



接著會出現Web Services Publisher這個對話盒(如圖)，我們按下 “…” 按鈕，去搜尋我們剛剛建立的MyWebService.MyCalculator COM伺服器。找到並確定之後，再按下”Advanced”，讓我們看看可以再多做些什麼設定。

在 Advanced 設定中，我們可以指定

WSDL 產出的位置。
SOAP Listener型態。
IntelliSense的Script名稱。
告訴VFP7在Project Build之後，是否自動產出相關的 Web Service 檔案。
產出的WSDL檔案是否要以UTF-16 Unicode作為預設編碼。







在確定所有設定無誤之後，按下 Generate，Web Service Publish精靈就會利用SOAP toolkit為我們在指定的位置產出Web Service的相關檔案。


Web Service Client 程式
那麼，我們要如何使用這個 Web Service 呢?
讓我們寫一個簡單的 form 來呼叫

請開一個新檔案，類型選為Form (表單)，在表單裡面放置一個按鈕(如下圖)，在按鈕的OnClick事件內放置如下的程式碼：


x = CREATEOBJECT("MSSOAP.SoapClient")
x.MSSoapInit("http://ellery/webservices/MyCalculator.WSDL", , "MyCalculatorSoapPort")

=messagebox( str( x.doAdd( 100,100 ) ) )


執行這個表單，在click按鈕之後，你會發現你並沒有辦法呼叫!!是VFP7的bug嗎??

首先,因為soap物件會利用 wsdl 檔案做 Initialization 的動作，所以我檢查了一下產出的 wsdl：


…略…
  &lt;message name='MyCalculator.doAdd'&gt;
  &lt;/message&gt;
  &lt;message name='MyCalculator.doAddResponse'&gt;
    &lt;part name='Result' type='xsd:anyType'/&gt;
  &lt;/message&gt;
…略…


在這裡 SOAP toolkit wizard 並沒有為我們的 COM 元件產生參數的宣告。
產出的 WSDL 碼應該是下面這樣子才對的呀.


…略…
  &lt;message name='MyCalculator.doAdd'&gt;
    &lt;part name='A' type='xsd:int'/&gt;
    &lt;part name='B' type='xsd:int'/&gt;
  &lt;/message&gt;

  &lt;message name='MyCalculator.doAddResponse'&gt;
    &lt;part name='Result' type='xsd:anyType'/&gt;
  &lt;/message&gt;
…略…


為了這個疑惑，我將問題貼到 Microsoft Newsgroup(http://communities.microsoft.com/newsgroups/default.asp) 和 Universal Thread(http://www.universalthread.com) 網站去詢問，過了兩天，就有了結果，兩個地方給我的回答都是相同的，我們必須將PROCEDURE doAdd 的宣告修改為

PROCEDURE doAdd(A as Integer, B as Integer)

並把 parameters 敘述移除。

修改後，重新 Build、利用 Wizard 發布之後，再執行剛剛我們建立好的 client 端Form，你應該就可以看到Web Service 被起始後的結果了。


使用其他語言建立的web service
為了驗證一下，VFP也能使用其他語言或其他平台上建立的 Web Service，我們仿效李維老師於RUN!PC 90 期文章中所寫的範例，寫一個取得溫度的簡單範例。

請依照下圖來製作一個表單：

 
然後，在”取得溫度”按鈕的 onclick 事件中，置入下列程式碼：

LOCAL obj
obj = CREATEOBJECT("MSSOAP.SoapClient")
obj.MSSoapInit("http://www.xmethods.net/sd/2001/TemperatureService.wsdl")
thisform.text2.value=obj.getTemp(thisform.text1.value)


在執行這個表單之後，在州代號的欄位中，輸入 07060，再按下 “取得溫度” 按鈕，下面的當地氣溫欄位便顯示出氣溫，表示可以正確的呼叫!

 

與資料庫結合

VFP為了因應 XML 的流行，在這個版本中添加了與XML 相關的三個函數：CURSORTOXML()、XMLTOCURSOR()、XMLUPDATEGRAM()，正好可以用來在 Web Services 中傳遞資料。

請在Project Manager中，新增一個程式檔(program)，然後將下列的程式碼加入，並命名為 prog2.prg：

DEFINE CLASS tastrade AS session OLEPUBLIC
Name = "tastrade"
PROCEDURE getAllEmployee()
        LOCAL handle as Integer 
        LOCAL lc_xml as String 

        handle=SQLSTRINGCONNECT("Driver=Microsoft Visual FoxPro Driver;” + ;
		“UID=;PWD=;” + ;
		“SourceDB=C:\WebService\Data\testdata.dbc;” + ;
		“SourceType=DBC;Exclusive=No;BackgroundFetch=Yes;” + ;
		“Collate=Machine;Null=Yes;Deleted=Yes;")
        =SQLEXEC(handle, ;
		"select emp_id, last_name, first_name, title from employee order by emp_id", ;
		"employees")
        =sqldisconnect(handle)
        CursorToXML("employees", "lc_xml")
        RETURN lc_xml
ENDPROC

PROCEDURE updateEmployee( c_request as string )
        LOCAL handle
        LOCAL o_xmlDom, o_nodelist1, o_nodelist2, o_nodeEmployee, o_node
        LOCAL strWhere as String , strSet as String , strSql as String 
        LOCAL ll_cycle as Boolean , ln_ret as Integer 

        c_request=STRTRAN( c_request, 'encoding="Windows-1252" ', "" )
        o_xmlDom=CreateObject("Microsoft.XMLDOM")
        o_xmlDom.async="false"
        o_xmlDom.loadXML(c_request)

        * parse xml and combine update-sql syntax
        IF o_xmlDom.hasChildNodes()
        ELSE
                RETURN
        ENDIF

        * create connection
        handle=SQLSTRINGCONNECT("Driver=Microsoft Visual FoxPro Driver;” + ;
	“UID=;PWD=;” + ;
	“SourceDB=C:\WebService\Data\testdata.dbc;” + ;
	“SourceType=DBC;Exclusive=No;BackgroundFetch=Yes;” + ;
	“Collate=Machine;Null=Yes;Deleted=Yes;")
        strWhere=""
        strSet=""
        l_cycle=.F.

        for each o_nodelist1 in o_xmlDom.documentElement.childNodes
                FOR EACH o_nodelist2 IN o_nodelist1.childNodes
                        * initialize variables
                        if o_nodelist2.nodeName="updg:before"
                                FOR EACH o_nodeEmployee IN o_nodelist2.childNodes
                                        FOR EACH o_node IN o_nodeEmployee.childNodes
                                                IF o_Node.nodeName="emp_id"
                                                        strWhere=strWhere+o_Node.nodeName+"="+"'" + ;
								TRANSFORM(o_Node.text,"@J 999999") + "' and "
                                                ELSE
                                                        strWhere=strWhere+o_Node.nodeName+"="+"'" + ;
								o_Node.text + "' and "
                                                ENDIF
                                        NEXT
                                NEXT
                        ENDIF
                        IF o_nodelist2.nodeName="updg:after"
                                IF NOT o_nodelist2.hasChildNodes()
                                ELSE
                                        FOR EACH o_nodeEmployee IN o_nodelist2.childNodes
                                                FOR EACH o_node IN o_nodeEmployee.childNodes
                                                        IF o_Node.nodeName="emp_id"
                                                        strSet=strSet+o_Node.nodeName+"="+"'" + ;
								TRANSFORM(o_Node.text,"@J 999999") + "',"
                                                        ELSE
                                                                strSet=strSet+o_Node.nodeName+"="+"'" + o_Node.text + "',"
                                                        ENDIF
                                                NEXT
                                        NEXT
                                ENDIF
                                l_cycle=.T.
                        ENDIF
                        IF l_cycle = .T.
                                * generate sql syntax
                                strWhere=LEFT(strWhere,LEN(strWhere)-4)
                                IF EMPTY(strSet)
                                        strSql="Delete from employee where "+ strWhere
                                ELSE
                                        strSet=LEFT(strSet,LEN(strSet)-1)
                                        strSql="Update employee set " + strSet + " where " + strWhere
                                ENDIF

                                * call sqlexec() to send update-sql
                                * and we can update our database
                                ln_ret=SQLEXEC(handle,strSql)
                                l_cycle=.F.
                                strWhere=""
                                strSet=""
                        ENDIF
                NEXT
        NEXT

        * disconnect    
        =sqldisconnect(handle)
ENDPROC
ENDDEFINE


這段程式碼裡面包含了一個類別，類別裡面包含了兩個方法：

getAllEmployee 利用 SPT 這組函數取得所有員工的員工編號、姓、名以及職稱，然後再利用 CURSORTOXML() 函數將 Cursor 資料轉換為 XML並傳回。

UpdateEmployee 則依據傳來的 update xml 資料作分析並更新。

再依照之前建立 Web Service 的步驟再做一次 Build COM 元件以及發布的動作。

接著，讓我們來撰寫 client 端的畫面，請依照下圖放置一個 Grid 控制項還有兩個 Button 控制項，然後同樣地，將下列的程式碼分別置放到兩個按鈕的 onclick 事件中。

 

在 Retrieve 按鈕的 onclick 事件中置放如下程式碼：


LOCAL x as Object , lc_xml as String 

*因為在[Update]按鈕中的 xmlupdategram() 函數需要設製 buffermode 並將 multilocks 設為 True
SET MULTILOCKS ON 
IF USED("employee")
        thisform.grid1.RecordSource=""
        USE IN employee
ENDIF

x = CREATEOBJECT("MSSOAP.SoapClient")
x.MSSoapInit("http://ellery/webservice/tastrade.WSDL")
lc_xml=x.getAllEmployee( ) 
XMLToCursor(lc_xml,"employee")
thisform.grid1.RecordSource="employee"
thisform.Refresh()

SELECT employee
=CURSORSETPROP("buffering",5)


在 Update 按鈕的 onclick 事件中置放：

LOCAL lc_ret
LOCAL x, lc_xml

*檢查是否已經取得資料
IF NOT USED("employee")
        =MESSAGEBOX("[Retrieve] button not pressed!")
        RETURN
ENDIF

*產生異動的 xml
lc_ret=XMLUPDATEGRAM("employee")
IF EMPTY(lc_ret)    &&如果沒有異動,發出警告
        =MESSAGEBOX("You don't update any thing")
ENDIF
=MESSAGEBOX(lc_ret,"XMLUPDATEGRAM() generates following codes")

*將資料更新回去!
x = CREATEOBJECT("MSSOAP.SoapClient")
x.MSSoapInit("http://ellery/webservice/tastrade.WSDL")
x.updateEmployee( lc_ret )
SELECT employee


然後將這個表單命名為 form2，然後讓我們執行這個表單。

當我們按下 Retrieve 時，這個 client 端的表單就會為我們取回 Server 端的XML資料，並利用 XMLTOCURSOR() 轉換為 Cursor，以便能順利與 VFP 的控制項結合。

當按下更新的時候，我們也能利用 XMLUPDATEGRAM() 函數取得需要更新的必要資料，送回 Server 端，讓 Service 端能根據這份資料來更新資料。


結論
VFP 在7.0版之後就不再被包含在 Visual Studio.NET 之中，但是，VFP開發小組承諾會繼續為這個產品添加更多的功能以迎合使用者的需求。就我個人而言，對 VFP 仍懷有一份特殊的情感，尤其是在使用其他語言開發資料庫時，有時候仍然會忍不住有 “唉!怎麼沒有這個功能，VFP就有” 這個想法，所以我還是會繼續看相關的 VFP 資料。
不過，我感覺到微軟雖然對 VFP 的使用者作出了相當的承諾，可是，從 5.0 到 6.0 到 7.0 ，除了使用者介面與開發COM元件的支援外，其實並沒有什麼太大的改進，我想很多人也會和我有一樣的看法吧。


參考資料：
MSDN - Walkthrough: Creating Web Services with Visual FoxPro
RUN!PC 90 期
XML 網頁製作徹底研究 旗標出版
		]]>
	</description>
	<content:encoded><![CDATA[
			<a href="#overview">前言</a><br />
<a href="#createws">建立Web Service</a><br />
<a href="#wsclient">建立Web Service Client 端程式</a><br />
<a href="#otherws">使用其他語言建立的 Web Service</a><br />
<a href="#databind">與資料庫結合</a><br />
<a href="#conclution">結論</a><br />
<a href="#referencedata">參考資料</a><br />
<br />
<a name="overview"></a>前言<br />
VFP 這項產品一直被謠傳微軟將不再支援，但在今年六月，微軟將VFP7自Visual Studio.NET中獨立出來銷售，總算是打破了這個謠言。此外，也為這項產品添加了不少功能，比如 Intellisense、對COM的更完整支援、SOAP與Web Service 等等。這裡就為各位解說新增的SOAP與Web Service功能。<br />
<br />
SOAP 與 Web Service 這兩個名詞，相信我不用再多做解釋了，大家在這一陣子的耳濡目染之下，應該都大致了解，在此就不再贅述。如果想了解的人請參考前幾期RUN!PC李維老師的文章，有詳細的解說。<br />
<br />
<br />
<a name="createws"></a><br />
建立Web Service<br />
首先讓我們來製作 Web Service，稍後，再來撰寫如何使用 Web Service 的 Client 端程式。<br />
要使用VFP7製作Web Service之前，請先在[Internet 服務管理員]中，新增一個虛擬目錄，在此，我們先命名為 WebServices。<br />
接下來得製作一個COM元件，在這裡我們就以一個簡單的相加函數來作為一個範例。<br />
請先建立一個新專案，名稱叫做MyWebService，在Project Manager(專案管理員)中，切換到 Program頁籤，點選 ”New”，將下列這段程式碼貼到裡面去，然後存檔為 prog1.prg。<br />
<pre><br />
DEFINE CLASS MyCalculator AS session OLEPUBLIC<br />
Name = "MyCalculator"<br />
PROCEDURE doAdd<br />
                Parameters A , B<br />
        Return A+B<br />
ENDPROC<br />
ENDDEFINE<br />
</pre><br />
<br />
這一段程式碼只是將傳入的兩個參數做一個簡單的相加而已。<br />
接著就要進行編譯的工作了，點選”Build”，建立的型態選為”Single-threaded COM Server(dll)”，按下 ”確定” 來建立一個dll型態的COM伺服器。<br />
<br />
<img alt="image002.jpg" src="images/vfp7ws_image002.jpg" border="0" /><br />
<br />
建立完成後，你會發現VFP7為你產生了一個mywebservice.dll，並已經為你註冊到電腦中了，讓我們驗證一下VFP7是否已經編譯成功，請在命令列中依序輸入：<br />
<br />
<pre><br />
obj=createobject(“MyWebService.MyCalculator”)<br />
? obj.doAdd(100,100)<br />
</pre><br />
<br />
如果成功的話，你應該會看到VFP7回應了 200 這個答案，表示COM伺服器已經建立成功。<br />
<br />
VFP7提供了一個方便的精靈，讓你可以直接在VFP7的整合環境中建立 Web Service，而不需要另外去執行 SOAP toolkit 來製作。<br />
<br />
請你在Project Manager中，以滑鼠右鍵點選叫出快捷選單，選擇Builder。此時，會出現一個選擇精靈的對話方盒(如圖)，選擇Web Services Publisher，並按下確定。<br />
<br />
<img alt="image004.jpg" src="images/vfp7ws_image004.jpg" border="0" /><br />
<br />
接著會出現Web Services Publisher這個對話盒(如圖)，我們按下 “…” 按鈕，去搜尋我們剛剛建立的MyWebService.MyCalculator COM伺服器。找到並確定之後，再按下”Advanced”，讓我們看看可以再多做些什麼設定。<br />
<br />
在 Advanced 設定中，我們可以指定<br />
<ol><br />
<li>WSDL 產出的位置。</li><br />
<li>SOAP Listener型態。</li><br />
<li>IntelliSense的Script名稱。</li><br />
<li>告訴VFP7在Project Build之後，是否自動產出相關的 Web Service 檔案。</li><br />
<li>產出的WSDL檔案是否要以UTF-16 Unicode作為預設編碼。<br />
<img alt="image006.jpg" src="images/vfp7ws_image006.jpg" border="0" /><br />
<img alt="image008.jpg" src="images/vfp7ws_image08.jpg" border="0" /><br />
<img alt="image010.jpg" src="images/vfp7ws_image010.jpg" border="0" /><br />
<img alt="image012.jpg" src="images/vfp7ws_image012.jpg" border="0" /><br />
</li><br />
</ol><br />
<br />
在確定所有設定無誤之後，按下 Generate，Web Service Publish精靈就會利用SOAP toolkit為我們在指定的位置產出Web Service的相關檔案。<br />
<br />
<a name="wsclient"></a><br />
Web Service Client 程式<br />
那麼，我們要如何使用這個 Web Service 呢?<br />
讓我們寫一個簡單的 form 來呼叫<br />
<br />
請開一個新檔案，類型選為Form (表單)，在表單裡面放置一個按鈕(如下圖)，在按鈕的OnClick事件內放置如下的程式碼：<br />
<br />
<pre><br />
x = CREATEOBJECT("MSSOAP.SoapClient")<br />
x.MSSoapInit("http://ellery/webservices/MyCalculator.WSDL", , "MyCalculatorSoapPort")<br />
<br />
=messagebox( str( x.doAdd( 100,100 ) ) )<br />
</pre><br />
<br />
執行這個表單，在click按鈕之後，你會發現你並沒有辦法呼叫!!是VFP7的bug嗎??<br />
<br />
首先,因為soap物件會利用 wsdl 檔案做 Initialization 的動作，所以我檢查了一下產出的 wsdl：<br />
<br />
<pre><br />
…略…<br />
  &lt;message name='MyCalculator.doAdd'&gt;<br />
  &lt;/message&gt;<br />
  &lt;message name='MyCalculator.doAddResponse'&gt;<br />
    &lt;part name='Result' type='xsd:anyType'/&gt;<br />
  &lt;/message&gt;<br />
…略…<br />
</pre><br />
<br />
在這裡 SOAP toolkit wizard 並沒有為我們的 COM 元件產生參數的宣告。<br />
產出的 WSDL 碼應該是下面這樣子才對的呀.<br />
<br />
<pre><br />
…略…<br />
  &lt;message name='MyCalculator.doAdd'&gt;<br />
    &lt;part name='A' type='xsd:int'/&gt;<br />
    &lt;part name='B' type='xsd:int'/&gt;<br />
  &lt;/message&gt;<br />
<br />
  &lt;message name='MyCalculator.doAddResponse'&gt;<br />
    &lt;part name='Result' type='xsd:anyType'/&gt;<br />
  &lt;/message&gt;<br />
…略…<br />
</pre><br />
<br />
為了這個疑惑，我將問題貼到 Microsoft Newsgroup(http://communities.microsoft.com/newsgroups/default.asp) 和 Universal Thread(http://www.universalthread.com) 網站去詢問，過了兩天，就有了結果，兩個地方給我的回答都是相同的，我們必須將PROCEDURE doAdd 的宣告修改為<br />
<pre><br />
PROCEDURE doAdd(A as Integer, B as Integer)<br />
</pre><br />
並把 parameters 敘述移除。<br />
<br />
修改後，重新 Build、利用 Wizard 發布之後，再執行剛剛我們建立好的 client 端Form，你應該就可以看到Web Service 被起始後的結果了。<br />
<br />
<a name="otherws"></a><br />
使用其他語言建立的web service<br />
為了驗證一下，VFP也能使用其他語言或其他平台上建立的 Web Service，我們仿效李維老師於RUN!PC 90 期文章中所寫的範例，寫一個取得溫度的簡單範例。<br />
<br />
請依照下圖來製作一個表單：<br />
<img alt="image014.jpg" src="images/vfp7ws_image014.jpg" border="0" /><br />
 <br />
然後，在”取得溫度”按鈕的 onclick 事件中，置入下列程式碼：<br />
<pre><br />
LOCAL obj<br />
obj = CREATEOBJECT("MSSOAP.SoapClient")<br />
obj.MSSoapInit("http://www.xmethods.net/sd/2001/TemperatureService.wsdl")<br />
thisform.text2.value=obj.getTemp(thisform.text1.value)<br />
</pre><br />
<br />
在執行這個表單之後，在州代號的欄位中，輸入 07060，再按下 “取得溫度” 按鈕，下面的當地氣溫欄位便顯示出氣溫，表示可以正確的呼叫!<br />
<img alt="image016.jpg" src="images/vfp7ws_image016.jpg" border="0" /><br />
 <br />
<a name="databind"></a><br />
與資料庫結合<br />
<br />
VFP為了因應 XML 的流行，在這個版本中添加了與XML 相關的三個函數：CURSORTOXML()、XMLTOCURSOR()、XMLUPDATEGRAM()，正好可以用來在 Web Services 中傳遞資料。<br />
<br />
請在Project Manager中，新增一個程式檔(program)，然後將下列的程式碼加入，並命名為 prog2.prg：<br />
<pre><br />
DEFINE CLASS tastrade AS session OLEPUBLIC<br />
Name = "tastrade"<br />
PROCEDURE getAllEmployee()<br />
        LOCAL handle as Integer <br />
        LOCAL lc_xml as String <br />
<br />
        handle=SQLSTRINGCONNECT("Driver=Microsoft Visual FoxPro Driver;” + ;<br />
		“UID=;PWD=;” + ;<br />
		“SourceDB=C:\WebService\Data\testdata.dbc;” + ;<br />
		“SourceType=DBC;Exclusive=No;BackgroundFetch=Yes;” + ;<br />
		“Collate=Machine;Null=Yes;Deleted=Yes;")<br />
        =SQLEXEC(handle, ;<br />
		"select emp_id, last_name, first_name, title from employee order by emp_id", ;<br />
		"employees")<br />
        =sqldisconnect(handle)<br />
        CursorToXML("employees", "lc_xml")<br />
        RETURN lc_xml<br />
ENDPROC<br />
<br />
PROCEDURE updateEmployee( c_request as string )<br />
        LOCAL handle<br />
        LOCAL o_xmlDom, o_nodelist1, o_nodelist2, o_nodeEmployee, o_node<br />
        LOCAL strWhere as String , strSet as String , strSql as String <br />
        LOCAL ll_cycle as Boolean , ln_ret as Integer <br />
<br />
        c_request=STRTRAN( c_request, 'encoding="Windows-1252" ', "" )<br />
        o_xmlDom=CreateObject("Microsoft.XMLDOM")<br />
        o_xmlDom.async="false"<br />
        o_xmlDom.loadXML(c_request)<br />
<br />
        * parse xml and combine update-sql syntax<br />
        IF o_xmlDom.hasChildNodes()<br />
        ELSE<br />
                RETURN<br />
        ENDIF<br />
<br />
        * create connection<br />
        handle=SQLSTRINGCONNECT("Driver=Microsoft Visual FoxPro Driver;” + ;<br />
	“UID=;PWD=;” + ;<br />
	“SourceDB=C:\WebService\Data\testdata.dbc;” + ;<br />
	“SourceType=DBC;Exclusive=No;BackgroundFetch=Yes;” + ;<br />
	“Collate=Machine;Null=Yes;Deleted=Yes;")<br />
        strWhere=""<br />
        strSet=""<br />
        l_cycle=.F.<br />
<br />
        for each o_nodelist1 in o_xmlDom.documentElement.childNodes<br />
                FOR EACH o_nodelist2 IN o_nodelist1.childNodes<br />
                        * initialize variables<br />
                        if o_nodelist2.nodeName="updg:before"<br />
                                FOR EACH o_nodeEmployee IN o_nodelist2.childNodes<br />
                                        FOR EACH o_node IN o_nodeEmployee.childNodes<br />
                                                IF o_Node.nodeName="emp_id"<br />
                                                        strWhere=strWhere+o_Node.nodeName+"="+"'" + ;<br />
								TRANSFORM(o_Node.text,"@J 999999") + "' and "<br />
                                                ELSE<br />
                                                        strWhere=strWhere+o_Node.nodeName+"="+"'" + ;<br />
								o_Node.text + "' and "<br />
                                                ENDIF<br />
                                        NEXT<br />
                                NEXT<br />
                        ENDIF<br />
                        IF o_nodelist2.nodeName="updg:after"<br />
                                IF NOT o_nodelist2.hasChildNodes()<br />
                                ELSE<br />
                                        FOR EACH o_nodeEmployee IN o_nodelist2.childNodes<br />
                                                FOR EACH o_node IN o_nodeEmployee.childNodes<br />
                                                        IF o_Node.nodeName="emp_id"<br />
                                                        strSet=strSet+o_Node.nodeName+"="+"'" + ;<br />
								TRANSFORM(o_Node.text,"@J 999999") + "',"<br />
                                                        ELSE<br />
                                                                strSet=strSet+o_Node.nodeName+"="+"'" + o_Node.text + "',"<br />
                                                        ENDIF<br />
                                                NEXT<br />
                                        NEXT<br />
                                ENDIF<br />
                                l_cycle=.T.<br />
                        ENDIF<br />
                        IF l_cycle = .T.<br />
                                * generate sql syntax<br />
                                strWhere=LEFT(strWhere,LEN(strWhere)-4)<br />
                                IF EMPTY(strSet)<br />
                                        strSql="Delete from employee where "+ strWhere<br />
                                ELSE<br />
                                        strSet=LEFT(strSet,LEN(strSet)-1)<br />
                                        strSql="Update employee set " + strSet + " where " + strWhere<br />
                                ENDIF<br />
<br />
                                * call sqlexec() to send update-sql<br />
                                * and we can update our database<br />
                                ln_ret=SQLEXEC(handle,strSql)<br />
                                l_cycle=.F.<br />
                                strWhere=""<br />
                                strSet=""<br />
                        ENDIF<br />
                NEXT<br />
        NEXT<br />
<br />
        * disconnect    <br />
        =sqldisconnect(handle)<br />
ENDPROC<br />
ENDDEFINE<br />
</pre><br />
<br />
這段程式碼裡面包含了一個類別，類別裡面包含了兩個方法：<br />
<br />
getAllEmployee 利用 SPT 這組函數取得所有員工的員工編號、姓、名以及職稱，然後再利用 CURSORTOXML() 函數將 Cursor 資料轉換為 XML並傳回。<br />
<br />
UpdateEmployee 則依據傳來的 update xml 資料作分析並更新。<br />
<br />
再依照之前建立 Web Service 的步驟再做一次 Build COM 元件以及發布的動作。<br />
<br />
接著，讓我們來撰寫 client 端的畫面，請依照下圖放置一個 Grid 控制項還有兩個 Button 控制項，然後同樣地，將下列的程式碼分別置放到兩個按鈕的 onclick 事件中。<br />
<br />
<img alt="image017.jpg" src="images/vfp7ws_image017.jpg" border="0" /> <br />
<br />
在 Retrieve 按鈕的 onclick 事件中置放如下程式碼：<br />
<br />
<pre><br />
LOCAL x as Object , lc_xml as String <br />
<br />
*因為在[Update]按鈕中的 xmlupdategram() 函數需要設製 buffermode 並將 multilocks 設為 True<br />
SET MULTILOCKS ON <br />
IF USED("employee")<br />
        thisform.grid1.RecordSource=""<br />
        USE IN employee<br />
ENDIF<br />
<br />
x = CREATEOBJECT("MSSOAP.SoapClient")<br />
x.MSSoapInit("http://ellery/webservice/tastrade.WSDL")<br />
lc_xml=x.getAllEmployee( ) <br />
XMLToCursor(lc_xml,"employee")<br />
thisform.grid1.RecordSource="employee"<br />
thisform.Refresh()<br />
<br />
SELECT employee<br />
=CURSORSETPROP("buffering",5)<br />
</pre><br />
<br />
在 Update 按鈕的 onclick 事件中置放：<br />
<pre><br />
LOCAL lc_ret<br />
LOCAL x, lc_xml<br />
<br />
*檢查是否已經取得資料<br />
IF NOT USED("employee")<br />
        =MESSAGEBOX("[Retrieve] button not pressed!")<br />
        RETURN<br />
ENDIF<br />
<br />
*產生異動的 xml<br />
lc_ret=XMLUPDATEGRAM("employee")<br />
IF EMPTY(lc_ret)    &&如果沒有異動,發出警告<br />
        =MESSAGEBOX("You don't update any thing")<br />
ENDIF<br />
=MESSAGEBOX(lc_ret,"XMLUPDATEGRAM() generates following codes")<br />
<br />
*將資料更新回去!<br />
x = CREATEOBJECT("MSSOAP.SoapClient")<br />
x.MSSoapInit("http://ellery/webservice/tastrade.WSDL")<br />
x.updateEmployee( lc_ret )<br />
SELECT employee<br />
</pre><br />
<br />
然後將這個表單命名為 form2，然後讓我們執行這個表單。<br />
<br />
當我們按下 Retrieve 時，這個 client 端的表單就會為我們取回 Server 端的XML資料，並利用 XMLTOCURSOR() 轉換為 Cursor，以便能順利與 VFP 的控制項結合。<br />
<br />
當按下更新的時候，我們也能利用 XMLUPDATEGRAM() 函數取得需要更新的必要資料，送回 Server 端，讓 Service 端能根據這份資料來更新資料。<br />
<br />
<a href="conclution"></a><br />
結論<br />
VFP 在7.0版之後就不再被包含在 Visual Studio.NET 之中，但是，VFP開發小組承諾會繼續為這個產品添加更多的功能以迎合使用者的需求。就我個人而言，對 VFP 仍懷有一份特殊的情感，尤其是在使用其他語言開發資料庫時，有時候仍然會忍不住有 “唉!怎麼沒有這個功能，VFP就有” 這個想法，所以我還是會繼續看相關的 VFP 資料。<br />
不過，我感覺到微軟雖然對 VFP 的使用者作出了相當的承諾，可是，從 5.0 到 6.0 到 7.0 ，除了使用者介面與開發COM元件的支援外，其實並沒有什麼太大的改進，我想很多人也會和我有一樣的看法吧。<br />
<br />
<a name="referencedata"></a><br />
參考資料：<br />
MSDN - Walkthrough: Creating Web Services with Visual FoxPro<br />
RUN!PC 90 期<br />
XML 網頁製作徹底研究 旗標出版
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553841.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553841.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Fri, 23 Aug 2002 22:09:51 +0800</pubDate>
</item>
<item>
	<title>VFP7研討會後報告</title>
	<description><![CDATA[
			我想這個研討會對各位應該是沒有什麼關係才對~~
為了避免浪費大家的時間,我就在這裡做個簡短報告,如果有興趣摸摸看的話,再私下來找我~

首先我假設各位已經使用過 6.0 了~
7.0 與 6.0 其實差別性不大,幾個重點:
1. UI 加強,以前沒有 IntelliSense,現在有了,什麼是 IntelliSense, 簡單的說,就是像VB一樣,我隨便打個 rsCustomer. (假設rsCustomer是adodb.recordset),VB 就會很貼心的跑出一狗票方法跟屬性讓你選.
2. COM 加強,之前的版本建立 COM 物件,實際上並沒有實做出所有應有的 Interface,以及建立標準的 IDL (Interface Definition Language),所以在某些特定的情況有問題.現在除了遵循標準之外,也更加強了控制 COM 物件的能力.
3. XML 與 Web Service, 提供了三個函數來支援 XML 與 Cursor 之間的轉換,並且多了一個精靈來產生 Web Service,這個精靈實際上是應用 SOAP ToolKit 2.0 sp2 來產生 Web Service 的.
4. Database 提供 Event 以及 OLEDB Provider, 這個我認為不是很重要,因為現在用 vfp 資料庫的人越來越少了.

說完以上幾點,大概就沒什麼了,也因此,這次的研討論,前面廢話一陣之後,直接就介紹 XML 的三個函數與 Web Service 精靈,介紹的範例寫的不錯,令人能一目了然.

會畢,大家提出一些問題~有兩個問題是讓我比較印象深刻的
1.關於 Microsoft 是否繼續推廣 VFP 的問題,基本上,我覺得問的人很笨,因為上課的人並不是微軟的人,就算是,他也沒辦法回答.我個人的答案是,目前桌上型資料庫的市場已經是 VFP 跟 ACCESS 獨大了,所有的敵人都已經死光光(Paradox,dBase,Clipper...等),他根本不需要再推廣,否則等於是拿石頭砸自己的腳.
2.有個傢伙問售後服務,他說能不能主動寄發 Service Pack 給客戶,或者在購買VFP的時候,能主動附上目前最新的 Service Pack. 否則的話,光華賣的補帖服務還比微軟好,因為補帖出貨的時候,連 Service Pack 都燒進去.那幹?還用正版.聽到這裡,深深覺得售後服務的重要性.

會後,填完問卷,還領了一張資源光碟,我還沒有看,待會我會放到 Server 上去.

報告完畢.
		]]>
	</description>
	<content:encoded><![CDATA[
			我想這個研討會對各位應該是沒有什麼關係才對~~<br />
為了避免浪費大家的時間,我就在這裡做個簡短報告,如果有興趣摸摸看的話,再私下來找我~<br />
<br />
首先我假設各位已經使用過 6.0 了~<br />
7.0 與 6.0 其實差別性不大,幾個重點:<br />
1. UI 加強,以前沒有 IntelliSense,現在有了,什麼是 IntelliSense, 簡單的說,就是像VB一樣,我隨便打個 rsCustomer. (假設rsCustomer是adodb.recordset),VB 就會很貼心的跑出一狗票方法跟屬性讓你選.<br />
2. COM 加強,之前的版本建立 COM 物件,實際上並沒有實做出所有應有的 Interface,以及建立標準的 IDL (Interface Definition Language),所以在某些特定的情況有問題.現在除了遵循標準之外,也更加強了控制 COM 物件的能力.<br />
3. XML 與 Web Service, 提供了三個函數來支援 XML 與 Cursor 之間的轉換,並且多了一個精靈來產生 Web Service,這個精靈實際上是應用 SOAP ToolKit 2.0 sp2 來產生 Web Service 的.<br />
4. Database 提供 Event 以及 OLEDB Provider, 這個我認為不是很重要,因為現在用 vfp 資料庫的人越來越少了.<br />
<br />
說完以上幾點,大概就沒什麼了,也因此,這次的研討論,前面廢話一陣之後,直接就介紹 XML 的三個函數與 Web Service 精靈,介紹的範例寫的不錯,令人能一目了然.<br />
<br />
會畢,大家提出一些問題~有兩個問題是讓我比較印象深刻的<br />
1.關於 Microsoft 是否繼續推廣 VFP 的問題,基本上,我覺得問的人很笨,因為上課的人並不是微軟的人,就算是,他也沒辦法回答.我個人的答案是,目前桌上型資料庫的市場已經是 VFP 跟 ACCESS 獨大了,所有的敵人都已經死光光(Paradox,dBase,Clipper...等),他根本不需要再推廣,否則等於是拿石頭砸自己的腳.<br />
2.有個傢伙問售後服務,他說能不能主動寄發 Service Pack 給客戶,或者在購買VFP的時候,能主動附上目前最新的 Service Pack. 否則的話,光華賣的補帖服務還比微軟好,因為補帖出貨的時候,連 Service Pack 都燒進去.那幹?還用正版.聽到這裡,深深覺得售後服務的重要性.<br />
<br />
會後,填完問卷,還領了一張資源光碟,我還沒有看,待會我會放到 Server 上去.<br />
<br />
報告完畢.
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553818.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553818.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Thu, 13 Dec 2001 17:02:40 +0800</pubDate>
</item>
<item>
	<title>VFP與SQL Server的連結與最佳化</title>
	<description><![CDATA[
			摘要:介紹VFP與SQL Server連結的最佳化設定
內容:
建置測試環境
  測試
  FetchAsNeeded?? 
點選這裡來下載本文章的範例程式
建置測試環境
1.請先利用 sql server enterprise manager去建立一個 database,叫做demo
  然後利用 Query Analyzer 執行以下的sql script
  use demo
  if exists (select * from sysobjects where id = object_id(N'[dbo].[demo]') and 
  OBJECTPROPERTY(id, N'IsUserTable') = 1)
  drop table [dbo].[demo]
  GO
  
  CREATE TABLE [dbo].[demo] (
  [cus_no] [int] IDENTITY (1, 1) NOT NULL ,
  [cus_name] [char] (10) NOT NULL ,
  [comment] [text] NULL 
  ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
  GO
  
  ALTER TABLE [dbo].[demo] WITH NOCHECK ADD 
  CONSTRAINT [PK_demo] PRIMARY KEY NONCLUSTERED 
  (
  [cus_no]
  ) ON [PRIMARY] 
  GO
  
  
  2.請再設定一下控制台中的ODBC
  
  3.設定一下 class 裡面的 demo.vcx 中的 prjhook QueryRunFile Event 中的路徑
  然後在專案上面點一下滑鼠右鍵
  選擇 專案資訊,接著把專案類別設為 demo.vcx 
  然後以後你執行程式的時候,就只要按 執行 就好了
  
  4.接著
  去 變更一下 database 中的 connection
  

測試
  
  以程式動態模擬 1000 筆資料寫入 sql server 資料庫中
  直接利用 vfp 的 connection + remote view
  硬體: cyrix 200 + 128 mb ram + 4g hd
  軟體: m$ sql server 7 + ado 2.6
情況 1 :
  不設 buffering
  vfp 當然是每新增一筆, 就會寫一筆到 sql server 中
  想當然耳,速度超慢
情況 2 :
  設定 buffering 為 5
  這個時候,新增就粉快了,因為新增的資料都是放到 local 端
  不過 tableupdate 的時候,就超慢了
情況 3 :
  設定 buffering 為 5, batchupdatecount 為 1000, prepared 為 true
  第一次新增 1000 筆,tableupdate 寫入,僅僅花了二分鐘多左右
  效率還算讓人滿意
  在程式執行的同時,我也有利用 sql 的 profiler 去觀察
  vfp的確有先產生 prepare 的指令, 再執行 insert 的動作
  仔細看了一下 tableupdate 的指令說明
  tableupdate 的第一個參數如果帶 1, 而且 buffering 有開啟的時候,就會只把有變動的記錄更新回去
  這一點我呆會會再另外用另外一種方法來測試是否真的有這麼去tableupdate
  第二次執行的時候,花了約四分鐘,這次我發現vfp有多花一些時間在requery()上,所以我把 use demo 改為 use demo nodata
  果然就又回復到約二分鐘多左右了
  這次我把 prepare 拿掉試試看
  發現了很有趣的現象,profiler 中,仍然使用了 prepare 
  不知道是不是因為 odbc driver 的關係
第四次(prog2)
  測試 requery() 的速度
  我知道memo的大小會影響速度,所以直接先把 fetchmemo 設為 false
  程式很快就run完了,我感到質疑
  因此我用browse去看
  我發現 vfp 會 requery() 一個程度之後,開始在background去抓資料
  如果這個時候去browse,速度就變的粉慢
  怎麼變快??
  於是我接著把 FetchAsNeeded 設為 True, FetchSize 設為 100
  重新執行, 果然速度變快很多,因為vfp只抓了 100 筆
  我利用 browse 去觀察的時候,向下 page down, vfp 還會自動往下抓100筆記錄
  這真是太棒了
  不過我後來直接把 scroll bar 移到最下面,這個requery的時間就很久了


  第五次(form1)
  我寫了一個簡單的表單
  寫的過程,遇到一個小問題,我在dataenvironment中拉入view,接著把view拖到表單上
  產生grid的時候粉慢,這時候我建議各位先在指令列下 use demo nodata, 然後再來拖
  會順利很多!!
  做好的畫面如form1
  畫面很簡單
  右上角是我測試的重點之一,我輸入一個數值,按下&quot;跳到&quot;,會自動移到該筆記錄去
  當我 go 100 的時候,果然vfp會自動抓下一百筆資料
  另外當我點選到 memo 欄位時,vfp也會自動去抓取該欄位的memo值
  (因為之前把fetchmemo設為false,所以不會抓memo值)
  不過這時候又產生了另外一個問題
  如果我想知道總共有多少記錄的時候要怎麼辦呢??雖然輔助說明中說requery()之後,
  會把取得的記錄數目存放在_tally變數中,but似乎不是這樣,因為我取得的_tally總是與事實不符
  翻遍輔助說明,看來都沒有適合的指令可以取得
  只好利用 select count() 了
  我把這段指令寫在 &quot;總筆數!!&quot; 這個按鈕上
  千萬不要用 reccount() ,這會把所有資料 dl 下來!!

FetchAsNeeded??
  第六次 (form1)
  這次我們要試的是 tableupdate 是否真的只把我們有更動的資料寫回去
  因此我們使用 tableupdate( 1, .T. ) 來作
  可是粉奇怪,profiler 並沒有顯示任何 update 的動作
  這太奇怪了~~
  我搞了好久
  才在 vfp 的 programmer's guide 找到
  當 fetchasneeded 設為 true 的時候,是無法做任何更新動作的!!!!
  必須要先 sqlcancel 之後才能去做
  最後實驗 tableupdate( 1, .T. )也順利成功
  程式碼在[奇數碼更新]裡面!!
  vfp 果然會只更新有變動的部分而已!!!
		]]>
	</description>
	<content:encoded><![CDATA[
			<p>摘要:介紹VFP與SQL Server連結的最佳化設定</p>
<p>內容:<br/>
<p><a href="#HowToBuild">建置測試環境</a><br/>
  <a href="#Test">測試</a><br/>
  <a href="#FetchAsNeeded">FetchAsNeeded??</a> </p>
<p><a href="files/spt_research_demo.zip">點選這裡來下載本文章的範例程式</a></p>
<a name="HowToBuild"></a><b>建置測試環境</b>
<p>1.請先利用 sql server enterprise manager去建立一個 database,叫做demo<br/>
  然後利用 Query Analyzer 執行以下的sql script<br/>
  <span class="codes">use demo<br/>
  if exists (select * from sysobjects where id = object_id(N'[dbo].[demo]') and 
  OBJECTPROPERTY(id, N'IsUserTable') = 1)<br/>
  drop table [dbo].[demo]<br/>
  GO<br/>
  <br/>
  CREATE TABLE [dbo].[demo] (<br/>
  [cus_no] [int] IDENTITY (1, 1) NOT NULL ,<br/>
  [cus_name] [char] (10) NOT NULL ,<br/>
  [comment] [text] NULL <br/>
  ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]<br/>
  GO<br/>
  <br/>
  ALTER TABLE [dbo].[demo] WITH NOCHECK ADD <br/>
  CONSTRAINT [PK_demo] PRIMARY KEY NONCLUSTERED <br/>
  (<br/>
  [cus_no]<br/>
  ) ON [PRIMARY] <br/>
  GO<br/>
  <br/>
  </span><br/>
  2.請再設定一下控制台中的ODBC<br/>
  <br/>
  3.設定一下 class 裡面的 demo.vcx 中的 prjhook QueryRunFile Event 中的路徑<br/>
  然後在專案上面點一下滑鼠右鍵<br/>
  選擇 專案資訊,接著把專案類別設為 demo.vcx <br/>
  然後以後你執行程式的時候,就只要按 執行 就好了<br/>
  <br/>
  4.接著<br/>
  去 變更一下 database 中的 connection<br/>
  <br/>
</p>
<p><a name="Test"></a><b>測試</b><br/>
  <br/>
  以程式動態模擬 1000 筆資料寫入 sql server 資料庫中<br/>
  直接利用 vfp 的 connection + remote view<br/>
  硬體: cyrix 200 + 128 mb ram + 4g hd<br/>
  軟體: m$ sql server 7 + ado 2.6</p>
<p>情況 1 :<br/>
  不設 buffering<br/>
  vfp 當然是每新增一筆, 就會寫一筆到 sql server 中<br/>
  想當然耳,速度超慢</p>
<p>情況 2 :<br/>
  設定 buffering 為 5<br/>
  這個時候,新增就粉快了,因為新增的資料都是放到 local 端<br/>
  不過 tableupdate 的時候,就超慢了</p>
<p>情況 3 :<br/>
  設定 buffering 為 5, batchupdatecount 為 1000, prepared 為 true<br/>
  第一次新增 1000 筆,tableupdate 寫入,僅僅花了二分鐘多左右<br/>
  效率還算讓人滿意<br/>
  在程式執行的同時,我也有利用 sql 的 profiler 去觀察<br/>
  vfp的確有先產生 prepare 的指令, 再執行 insert 的動作<br/>
  仔細看了一下 tableupdate 的指令說明<br/>
  tableupdate 的第一個參數如果帶 1, 而且 buffering 有開啟的時候,就會只把有變動的記錄更新回去<br/>
  這一點我呆會會再另外用另外一種方法來測試是否真的有這麼去tableupdate<br/>
  第二次執行的時候,花了約四分鐘,這次我發現vfp有多花一些時間在requery()上,所以我把 use demo 改為 use demo nodata<br/>
  果然就又回復到約二分鐘多左右了<br/>
  這次我把 prepare 拿掉試試看<br/>
  發現了很有趣的現象,profiler 中,仍然使用了 prepare <br/>
  不知道是不是因為 odbc driver 的關係</p>
<p>第四次(prog2)<br/>
  測試 requery() 的速度<br/>
  我知道memo的大小會影響速度,所以直接先把 fetchmemo 設為 false<br/>
  程式很快就run完了,我感到質疑<br/>
  因此我用browse去看<br/>
  我發現 vfp 會 requery() 一個程度之後,開始在background去抓資料<br/>
  如果這個時候去browse,速度就變的粉慢<br/>
  怎麼變快??<br/>
  於是我接著把 FetchAsNeeded 設為 True, FetchSize 設為 100<br/>
  重新執行, 果然速度變快很多,因為vfp只抓了 100 筆<br/>
  我利用 browse 去觀察的時候,向下 page down, vfp 還會自動往下抓100筆記錄<br/>
  這真是太棒了<br/>
  不過我後來直接把 scroll bar 移到最下面,這個requery的時間就很久了<br/>
</p>
<p><br/>
  第五次(form1)<br/>
  我寫了一個簡單的表單<br/>
  寫的過程,遇到一個小問題,我在dataenvironment中拉入view,接著把view拖到表單上<br/>
  產生grid的時候粉慢,這時候我建議各位先在指令列下 use demo nodata, 然後再來拖<br/>
  會順利很多!!<br/>
  做好的畫面如form1<br/>
  畫面很簡單<br/>
  右上角是我測試的重點之一,我輸入一個數值,按下&quot;跳到&quot;,會自動移到該筆記錄去<br/>
  當我 go 100 的時候,果然vfp會自動抓下一百筆資料<br/>
  另外當我點選到 memo 欄位時,vfp也會自動去抓取該欄位的memo值<br/>
  (因為之前把fetchmemo設為false,所以不會抓memo值)<br/>
  不過這時候又產生了另外一個問題<br/>
  如果我想知道總共有多少記錄的時候要怎麼辦呢??雖然輔助說明中說requery()之後,<br/>
  會把取得的記錄數目存放在_tally變數中,but似乎不是這樣,因為我取得的_tally總是與事實不符<br/>
  翻遍輔助說明,看來都沒有適合的指令可以取得<br/>
  只好利用 select count() 了<br/>
  我把這段指令寫在 &quot;總筆數!!&quot; 這個按鈕上<br/>
  千萬不要用 reccount() ,這會把所有資料 dl 下來!!<br/>
</p>
<p><a name="FetchAsNeeded"></a><b>FetchAsNeeded??</b><br/>
  第六次 (form1)<br/>
  這次我們要試的是 tableupdate 是否真的只把我們有更動的資料寫回去<br/>
  因此我們使用 tableupdate( 1, .T. ) 來作<br/>
  可是粉奇怪,profiler 並沒有顯示任何 update 的動作<br/>
  這太奇怪了~~<br/>
  我搞了好久<br/>
  才在 vfp 的 programmer's guide 找到<br/>
  當 fetchasneeded 設為 true 的時候,是無法做任何更新動作的!!!!<br/>
  必須要先 sqlcancel 之後才能去做<br/>
  最後實驗 tableupdate( 1, .T. )也順利成功<br/>
  程式碼在[奇數碼更新]裡面!!<br/>
  vfp 果然會只更新有變動的部分而已!!!</p>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553806.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553806.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Tue, 18 Sep 2001 19:47:12 +0800</pubDate>
</item>
<item>
	<title>SELECT-SQL UNION ALL Clause</title>
	<description><![CDATA[
			很久以前就知道在別的大型資料庫系統裡, Select 有 Union這個子句(clause)

但我不知道VFP有這個子句

前兩天在看VFP輔助說明的時候,才發現到,VFP也有。

那那那...這個指令有啥好處呢?

我用個範例來做說明好了,這個範例是從BBS的Database版上借下來的,有經過改寫,原本是ORACLE的範例：

首先先建立一個Database,然後建好多個 Table,其結構都相同

CREATE DATABASE DEMO

CREATE TABLE DEMO_1995 ;

(TRANS_DATE D, cTEXT C(80), ;

CHECK (TRANS_DATE>={^1995/01/01} AND TRANS_DATE={^1996/01/01} AND TRANS_DATE={^1997/01/01} AND TRANS_DATE={^1998/01/01} AND TRANS_DATE={^1999/01/01} AND TRANS_DATE={^1998/01/01} AND TRANS_DATE
		]]>
	</description>
	<content:encoded><![CDATA[
			很久以前就知道在別的大型資料庫系統裡, Select 有 Union這個子句(clause)<br />
<br />
但我不知道VFP有這個子句<br />
<br />
前兩天在看VFP輔助說明的時候,才發現到,VFP也有。<br />
<br />
那那那...這個指令有啥好處呢?<br />
<br />
我用個範例來做說明好了,這個範例是從BBS的Database版上借下來的,有經過改寫,原本是ORACLE的範例：<br />
<br />
首先先建立一個Database,然後建好多個 Table,其結構都相同<br />
<br />
CREATE DATABASE DEMO<br />
<br />
CREATE TABLE DEMO_1995 ;<br />
<br />
(TRANS_DATE D, cTEXT C(80), ;<br />
<br />
CHECK (TRANS_DATE>={^1995/01/01} AND TRANS_DATE<{^1996/01/01}))<br />
<br />
CREATE TABLE DEMO_1996 ;<br />
<br />
(TRANS_DATE D, cTEXT C(80), ;<br />
<br />
CHECK (TRANS_DATE>={^1996/01/01} AND TRANS_DATE<{^1997/01/01}))<br />
<br />
CREATE TABLE DEMO_1997 ;<br />
<br />
(TRANS_DATE D, cTEXT C(80), ;<br />
<br />
CHECK (TRANS_DATE>={^1997/01/01} AND TRANS_DATE<{^1998/01/01}))<br />
<br />
CREATE TABLE DEMO_1998 ;<br />
<br />
(TRANS_DATE D, cTEXT C(80), ;<br />
<br />
CHECK (TRANS_DATE>={^1998/01/01} AND TRANS_DATE<{^1999/01/01}))<br />
<br />
CREATE TABLE DEMO_1999 ;<br />
<br />
(TRANS_DATE D, cTEXT C(80), ;<br />
<br />
CHECK (TRANS_DATE>={^1999/01/01} AND TRANS_DATE<{^2000/01/01}))<br />
<br />
CREATE SQL VIEW DEMO AS ;<br />
<br />
SELECT * FROM DEMO_1995 ;<br />
<br />
UNION ALL SELECT * FROM DEMO_1996 ;<br />
<br />
UNION ALL SELECT * FROM DEMO_1997 ;<br />
<br />
UNION ALL SELECT * FROM DEMO_1998 ;<br />
<br />
UNION ALL SELECT * FROM DEMO_1999<br />
<br />
接著放入一些資料(這就不用我教了吧,想辦法放進去吧)<br />
<br />
之後如果我們要從這些年度去查閱東西,就可以用<br />
<br />
SELECT * FROM DEMO WHERE TRANS_DATE>={^1998/01/01} AND TRANS_DATE<{^1999/07/01}<br />
<br />
或者 你也可以不需要建DEMO這個View<br />
<br />
你也可以直接用<br />
<br />
SELECT * FROM DEMO_1995 ;<br />
<br />
UNION ALL ;<br />
<br />
SELECT * FROM DEMO_1996 ;<br />
<br />
UNION ALL ;<br />
<br />
SELECT * FROM DEMO_1997 ;<br />
<br />
UNION ALL ;<br />
<br />
SELECT * FROM DEMO_1998 ;<br />
<br />
UNION ALL ;<br />
<br />
SELECT * FROM DEMO_1999<br />
<br />
這個時候 也許你會問,這有啥好處呢?? 看來是沒有啊 請注意...<br />
<br />
相信各位都曾經有過這種迷惘-以年度區分(或其他)的資料檔到底是要分開呢?還是要放在一起?<br />
<br />
假設你選擇了分開,那麼在作整合查詢的時候,就會相當的麻煩。<br />
<br />
通常只能先建立一個暫存資料檔,然後依序將零星的資料匯入之後,再對此一暫存資料檔作查詢。<br />
<br />
使用了union all,就可以不需要那麼麻煩了。
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553805.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553805.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Tue, 18 Sep 2001 07:47:12 +0800</pubDate>
</item>
<item>
	<title>VFP7 對 XML 的支援</title>
	<description><![CDATA[
			XML是一種在網路上用來描述與傳遞的標準語言,就跟 HTML 是用來建立並顯示網頁的標準語言一樣.
XML使用標籤和屬性來界定資料,並且完整的保留資料原有的解釋讓應用程式去閱讀.

為了盡可能的要讓你更容易的利用XML來實作資料交換,VFP提供如下的新函數和功能:

CURSORTOXML( )		將一個Cursor轉換成XML. 
XMLUPDATEGRAM( )	從一個有被變更過的工作區或cursor建立一個XML更新語法. 
XMLTOCURSOR( )		將XML資料轉換成Cursor或資料表格. 

以上轉譯自 VFP7 提供的輔助說明.
以下就簡單介紹用法,但詳細用法,仍請參照輔助說明.

CursorToXML()
直接把工作區的資料轉換為一個xml檔案
舉例來說
CursorToXML("LABELS", "myXMLFile.xml", 1, 512, 0, ;
	"mySchema.xsd", "http://www.microsoft.com/mySchema.xsd")
這一行就是說把 LABELS 這個工作區的資料,轉換為 myXMLFile.xml
1 的意思就是Element-centric XML ,轉換為以元素為主的XML.
512 是表示第二個參數是一個檔案
0 則是設定編碼原則
"mySchema.xsd" 則是轉出後的規則檔
"http://www.microsoft.com/mySchema.xsd" 則是表示規則要參照 www.microsoft.com 上的 mySchema.xsd

XMLTOCursor()
就是把xml檔案轉換為一個工作區,注意:目前工作區若有開啟檔案,將會被關閉!
XMLToCursor("myXMLFile.xml","LABELS")

XMLUpdateGram()
這是一個很有用的函數,使用前,你必須先把目前的buffering開啟
它主要是把目前工作區有被變更過的資料轉變為 xml
只有變更過的才會喔~
於是可以聯想到,資料在Client被處理完,可以只把有被變更過的傳回Server
大大減低網路的負荷,並且提昇速度喔
之後就可以利用 xmltocursor() 函數來處理
		]]>
	</description>
	<content:encoded><![CDATA[
			XML是一種在網路上用來描述與傳遞的標準語言,就跟 HTML 是用來建立並顯示網頁的標準語言一樣.<br />
XML使用標籤和屬性來界定資料,並且完整的保留資料原有的解釋讓應用程式去閱讀.<br />
<br />
為了盡可能的要讓你更容易的利用XML來實作資料交換,VFP提供如下的新函數和功能:<br />
<br />
CURSORTOXML( )		將一個Cursor轉換成XML. <br />
XMLUPDATEGRAM( )	從一個有被變更過的工作區或cursor建立一個XML更新語法. <br />
XMLTOCURSOR( )		將XML資料轉換成Cursor或資料表格. <br />
<br />
以上轉譯自 VFP7 提供的輔助說明.<br />
以下就簡單介紹用法,但詳細用法,仍請參照輔助說明.<br />
<br />
CursorToXML()<br />
直接把工作區的資料轉換為一個xml檔案<br />
舉例來說<br />
CursorToXML("LABELS", "myXMLFile.xml", 1, 512, 0, ;<br />
	"mySchema.xsd", "http://www.microsoft.com/mySchema.xsd")<br />
這一行就是說把 LABELS 這個工作區的資料,轉換為 myXMLFile.xml<br />
1 的意思就是Element-centric XML ,轉換為以元素為主的XML.<br />
512 是表示第二個參數是一個檔案<br />
0 則是設定編碼原則<br />
"mySchema.xsd" 則是轉出後的規則檔<br />
"http://www.microsoft.com/mySchema.xsd" 則是表示規則要參照 www.microsoft.com 上的 mySchema.xsd<br />
<br />
XMLTOCursor()<br />
就是把xml檔案轉換為一個工作區,注意:目前工作區若有開啟檔案,將會被關閉!<br />
XMLToCursor("myXMLFile.xml","LABELS")<br />
<br />
XMLUpdateGram()<br />
這是一個很有用的函數,使用前,你必須先把目前的buffering開啟<br />
它主要是把目前工作區有被變更過的資料轉變為 xml<br />
只有變更過的才會喔~<br />
於是可以聯想到,資料在Client被處理完,可以只把有被變更過的傳回Server<br />
大大減低網路的負荷,並且提昇速度喔<br />
之後就可以利用 xmltocursor() 函數來處理
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553797.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553797.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Wed, 05 Sep 2001 22:31:29 +0800</pubDate>
</item>
<item>
	<title>初試啼聲 - 利用 Visual FoxPro 建立 Web Services</title>
	<description><![CDATA[
			本文轉譯自VFP7光碟片 \technical articles\vfpws.doc 
McAlister Merchant
  Microsoft Corporation
  Created: March 2001
  Revised: March 2001
  Applies To: Microsoft Visual Foxpro
總覽
Web Services 可以在任何地方被使用.你可以自己建立他們,或者你可以在他們被公佈的地方存取他們.
  你可以使用VFP去建立 Web Services, 而且如果你在IntelliSense中註冊他們,VFP使得你能近乎自動化地存取他們變的可能.
  你也可以使用VFP存取利用其他語言建立的 Web Services.
內容
介紹
  Web Services
  Establishing a Virtual Directory (建立一個虛擬目錄)
  Creating a Project (建立專案)
  Creating a COM Server (建立一個COM伺服器)
  Creating and Publishing a Web Service (建立並發布一個 Web Service)
  Registering a Web Service (註冊一個 Web Service)
  Using a Web Service (使用一個 Web Service)
  更多資訊
  譯註 
&nbsp;
介紹
使用VFP建立 Web Services 是一個複雜的過程,因為牽涉到使用IIS, VFP COM伺服器和SOAP.
  你使用IIS去建立一個虛擬目錄來參照到你的Service擺放在硬碟上的位置.
  IIS可以利用MS NT4 Option Pack, MS W2k Professional或MS W2K Server來安裝.(在Option Pack中,IIS是其中的一部份,在W2K 
  Pro中可以利用新增/移除來安裝,W2K Server則是安裝時會自動一併安裝).譯註1.
  然後你可以使用專案管理員去建立或編譯COM物件.當COM物件被建立了,你可以使用VFP Web Services精靈把他們公佈到你的虛擬目錄中.
  你可以利用VFP的IntelliSense管理員去註冊 Web Services,所以Web Service的佈置和程式碼中必要呼叫的常式能迅速被執行.
  這篇文章引領你為現存的COM伺服器建立Web Serveice並且準備Web Service以使用的這個複雜過程.
  你能從一個COM伺服器建立一個簡單的Web Service,讓任何人都能從HTTP協定上存取.
  這個 Web Service 提供一個關於目前目錄和有多少檔案在目錄中的簡單報告.
Web Services
Web Services延展了你自己的COM伺服器的可存取能力,能夠使得其他開發者能透過瀏覽器來存取.
  Web Services提供機能並且能跨平台和在異質連接中存取資料.
  你可以從Web Service存在的地方建立並使用Web Services去提供或者獲得功能.(譯註2)
  大部分Web Service重要的觀點是Web Services使用HTTP協定和SOAP代理人,因此功能可以在跨越防火牆之後,仍然有效.
  因為HTTP和SOAP是不管平台的,所以Web Services也是不管平台的.在某些案件,這仍能在COM失效的時候提供功能.
  要發布一個 Web Service, 你必須在IIS中建立一個虛擬目錄,然後建立或複製一個COM伺服器,從而產生一個Web Service到你的虛擬目錄中.
&nbsp;
Establishing a Virtual Directory(建立一個虛擬目錄)
你必須建立或識別一個目錄以存放你的 Web Services.
  儘管你可以使用一個已存在的目錄,你仍可能想要在你硬碟上建立一個不一樣的地方存放這些檔案以方便管理你的Web Service檔案.
  去建立一個虛擬目錄,譯註3
  1.在VFP主要目錄下(\Program Files\Microsofft Visual FoxPro 7)建立一個資料夾,並命名為 Web Services.
  2.在控制台裡的系統管理工具資料夾中,雙擊Internet服務管理員.
  3.Internet服務管理員視窗打開,在左邊會顯示一個樹狀目錄,他顯示了你的硬碟.展開節點,以便能看到子資料夾.
  4.在樹狀目錄中選擇預設的Web站台.
  5.從右擊選單中,選擇&quot;新增&quot;,然後點選&quot;虛擬目錄&quot;.這會開啟&quot;虛擬目錄新增精靈&quot;.
  6.遵循精靈的指示進行,選擇虛擬目錄的時候,指定到步驟一所建立的 Web Services 資料夾.
  你已經建立了一個虛擬目錄,參照到你的Web Services資料夾,之後你將會在這裡存放你建立的所有Web Services檔案.
&nbsp;
Creating a Project (建立一個專案)
專案管理員在VFP中是十分基礎的應用程式建立工具.
  在VFP專案中,你可以組合各式各項的文件,資料,類別,程式碼和其他類型的檔案等.
  一個專案提供了你可能想要含括到一個伺服器中的所有元件,並且容納,以便編輯.
  在這個範例中,你使用專案去編譯你的 Web Services
  去建立一個專案,譯註4
  1.在File(檔案)選單中,選擇 New(開新檔案)
  2.在New(開新檔案)的對話盒中選擇 Project(專案),並點選 New File(開新檔案).
  3.在 Create(建立)對話盒中,選擇你之前建立的 Web Services 資料夾,並且取名為 myWServ1.
  4.點選 Save(存檔)
  現在你已經在 Web Services 資料夾中建立了你的專案.這使得當你完成加入元件後可以在正確的資料夾中自動的儲存並編譯.
&nbsp;
Creating a COM Server(建立一個COM伺服器)
因為,一個Web Service是一個.dll或.exe的檔案,你必須使用一個COM伺服器來當作你Web Service的基礎.
  一個COM伺服器在VFP來說是一個有.dll或.exe副檔名,裡面包含從一個利用OLEPUBLIC識別字所建立的類別.
  當一個物件被指定為OLEPUBLIC時,表示可以被Automation客戶端存取.當你從.dll檔案發布Web Service時,一個新的.wsdl檔案將會被產生.
  .wsdl檔案有必要的XML源碼,他描述在.dll檔中的類別和參照實際在Web Service背後出力的.dll檔案.
  從這個COM伺服器範例中,你將建立一個custom類別,他簡單回報了一些非常簡單的訊息.
  在這個過程中,你將要寫一個程式來建立一個包含兩個方法的類別,並且編譯這個專案成一個COM伺服器和一個已發布的Web Service.
  去建立一個簡單的類別,譯註5
  1.在File(檔案)選單中,選擇New(新增).
  2.在New(開新檔案)對話盒中,選擇Project(專案),並點選New file(開新檔案).這會開啟Project Manager(專案管理員).
  3.在Project Manager(專案管理員)的All(所有)頁籤中,將Code(程式)展開,選擇Programs(程式碼),然後選擇New(開新檔案).
  4.將下列的程式碼複製到程式碼編輯視窗中.
  *-- returns curdir() and number of JPEG files
DEFINE CLASS showem AS session OLEPUBLIC
 Name = &quot;showem&quot;
 PROCEDURE justshow
  howmany=ADIR(afilArry,&quot;*.jpg&quot;)
  IF howmany &lt;1
  fileNm=&quot;no&quot;
  ELSE
  fileNm=ALLTRIM(STR(howmany))
  ENDIF
  
  X = &quot;about &quot; + CURDIR() + &quot; ... &quot;
  Y = &quot;There are &quot; + fileNm + &quot; JPEG files here.&quot;
  RETURN x + y 
  ENDPROC
  ENDDEFINE
這個程式定義了一個類別 showem,他有一個方法 justshow
  5.關閉編輯視窗,並在Save As(另存新檔)對話盒中,將程式命名為myWServ1,並點選存檔.
  6.確定 myServ1 設定為主程式.(如果他被設定為主程式,他將會以粗體呈現).如果沒有,在Project Manager(專案管理員)中,以滑鼠右鍵點選myWServ1並在快捷選單中選擇Set 
  Main(設為主程式).
&nbsp;
去編譯這個COM伺服器
1.在Project Manager(專案管理員)中,選擇 Build (建立)
  2.選擇 Single-threaded COM Server
  3.選擇 Ok, 並接受名稱為 myWServ1
  VFP將會編譯這個myWServ1檔案為一個COM伺服器,之後你就可以將這個COM伺服器轉為Web Service.
&nbsp;
Creating and Publishing a Web Service(建立並發布一個Web Service)
必要地加入一個元件並且編譯COM伺服器,才能將你的COM伺服器轉為Web Service, 當成一個 Web Service發布.譯註6
  在你指定完這些設定,VFP會建立必要的XML和SOAP檔案以將你的伺服器轉為一個 Web Service,註冊你的新 Web Service,並發布到你的虛擬目錄中.
  去編譯和發佈一個Web Service
  1.在你完成前一個步驟,並且編譯好COM伺服器myWServ1.dll,以滑鼠右鍵點選Project Manager(專案管理員),並從快捷選單中選擇Builder.
  2.在Wizard Selection(精靈選擇)對話盒中,選擇Web Services Publisher,然後按下 Ok.
  3.在VFP Web Services Publisher對話盒中,使用 Ellipsis 按鈕去找到 myWServ1, 然後選擇你想要從伺服器中註冊的類別.在這個你建立的COM伺服器中,myWServ1,你只有一個類別 
  showem
  Note 點選 Advance(進階)按鈕以確定Web Services Publisher對話盒參照到正確的檔案是一個不錯的主意,特別是如果你建立了相似名稱的伺服器或者服務在不同資料夾的時候.如果正確的檔案沒有被顯示在下拉清單中,使用 
  Ellipsis 按鈕(...)去找到正確的檔案.
  IntelliSense scripts 欄位下方顯示了你(和SOAP toolkit)將找到的名稱.在Advance Web Services Publisher對話盒中確認了資訊之後,點選Ok
  譯註7.
  4.點選Generate(產生)按鈕
  在VFP產生Web Service檔案後, Web Services Publishing Results對話盒會出現,顯示包含COM伺服器,.wsdl檔案,ISAPI或ASP 
  listener和IntelliSense路徑名稱和編輯結果的清單.
  到了這裡,你已經建立和發布你的Web Service.任何存取到你早先所建立的這個虛擬目錄,就能使用HTTP去存取你剛剛建立的Web Service.
  要使用這個Web Service,你必須撰寫SOAP用戶端,一個listener(傾聽者)和瀏覽器的程式碼並且必須利用好幾個協定的層級和過程.
  在VFP裡面,只要藉著在IntelliSense管理者中註冊Web Service就能簡化許多.
&nbsp;
Registering a Web Service(註冊一個Web Service)

  你可以在IntelliSense管理者中註冊Web Services(你所建立的或被其他人建立的).
  當你做完,IntelliSense在你存取一個已註冊的Web Service時會提供了支援的程式碼.
去註冊一個Web Service
  1.在 Tools(工具)選單,選擇IntelliSense Manager.
  2.在IntelliSense Manager的Types頁籤,按下Web Services按鈕以註冊你新的Web Services(你的新類別也將會出現在Types清單中)
  現在,當你加入一個強制型別的變數到你的VFP程式碼中時,IntelliSense將會提供你的Web Services如同一個非必要的選擇.
  譯註8
&nbsp;
Using a Web Service(使用一個Web Service)
使用Web Service就跟你想要一個應用程式的任何COM伺服器把功能公開出來給另一個應用程式或程式一樣.
  舉例來說,你可以建立一個呼叫範例Web Service, myWServ1,的VFP程式.
  在一個VFP程式中,宣告一個強制型別的變數,如同下列的程式碼一樣,藉著從IntelliSense下拉選單中可以參照到你的Web Service, myServ1.
  LOCAL x AS myWServ1
  VFP IntelliSense使用這個Web Service已註冊的資訊,去完成下列的程式碼:
  x = CREATEOBJECT(&quot;MSSOAP.SoapClient&quot;)
  x.MSSoapInit(&quot;http://TheVirtualDisk/web services/myWServ1.WSDL&quot;, , 
  &quot; myWServ1SoapPort&quot;)
  然後,你可以像以前呼叫COM物件或類別的方法一樣去呼叫,就像下列的程式碼一樣:
  ? x.justshow()
  譯註9
  你可以加入相似的程式碼到VFP程式或應用程式中,去存取你自己的或其他Web Services.
&nbsp;
更多資訊
要取得更多關於Web Services的資訊,請看VFP輔助說明中的 &quot;Web Services Overview&quot;.
  要取得更多關於COM伺服器的資訊,請看VFP輔助說明中的 &quot;Creating Automation Servers&quot;.
Text for description meta tag:VFP使得從COM伺服器建立Web Services變的可能.
KeyWords(關鍵字):VFP Web Services, creating; VFP, creating Web Services;VFP, Web 
  Services.
&nbsp;
譯註
譯註1:此句翻譯的不好,本來只有一句,但我切成兩句.
  譯註2:此句也翻譯的不好.意思有到了.
  譯註3:這邊的步驟,我都照做一次,並將原有的英文W2k上的字眼換成中文w2k上的字眼.
  譯註4:因為我的VFP7是英文版的,所以我使用英文的字,不用中文的
  譯註5:如果你前面有建立專案的話,就不需要再建立了,直接從步驟三開始吧.
  譯註6:這句翻的非常不好,附上原文: To add the components necessary to turn your COM server into 
  a Web Service, you must compile the COM server as a Web Service.
  譯註7:此處務必要自己玩過一遍,盡量多按一按,因為這邊寫的不是很清楚.
  譯註8:如果你之前為虛擬目錄取名為 &quot;Web Services&quot; 時,會出現錯誤,因為他不允許名稱中間有空白!!
  譯註9:這段程式碼讓我花了一些時間去測試,不過錯誤原因在於我自己在建立並發布Web Services的時候,選擇了以ASP的方式產生,後來改為ISAPI的方式產生就ok了.

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>本文轉譯自VFP7光碟片 \technical articles\vfpws.doc </p>
<p>McAlister Merchant<br>
  <a href="http://www.microsoft.com">Microsoft Corporation</a><br>
  Created: March 2001<br>
  Revised: March 2001<br>
  Applies To: Microsoft Visual Foxpro</p>
<h3>總覽</h3>
<p>Web Services 可以在任何地方被使用.你可以自己建立他們,或者你可以在他們被公佈的地方存取他們.<br>
  你可以使用VFP去建立 Web Services, 而且如果你在IntelliSense中註冊他們,VFP使得你能近乎自動化地存取他們變的可能.<br>
  你也可以使用VFP存取利用其他語言建立的 Web Services.</p>
<h3>內容</h3>
<p><a href="#introduce">介紹</a><br>
  <a href="#webservices">Web Services</a><br>
  <a href="#virtualdirectory">Establishing a Virtual Directory (建立一個虛擬目錄)</a><br>
  <a href="#createproject">Creating a Project (建立專案)</a><br>
  <a href="#createcom">Creating a COM Server (建立一個COM伺服器)</a><br>
  <a href="#publishing">Creating and Publishing a Web Service (建立並發布一個 Web Service)</a><br>
  <a href="#registering">Registering a Web Service (註冊一個 Web Service)</a><br>
  <a href="#usingwebservice">Using a Web Service (使用一個 Web Service)</a><br>
  <a href="#more">更多資訊</a><br>
  <a href="#translate">譯註</a> </p>
<p>&nbsp;</p>
<h3>介紹<a name="introduce"></a></h3>
<p>使用VFP建立 Web Services 是一個複雜的過程,因為牽涉到使用IIS, VFP COM伺服器和SOAP.<br>
  你使用IIS去建立一個虛擬目錄來參照到你的Service擺放在硬碟上的位置.<br>
  IIS可以利用MS NT4 Option Pack, MS W2k Professional或MS W2K Server來安裝.(在Option Pack中,IIS是其中的一部份,在W2K 
  Pro中可以利用新增/移除來安裝,W2K Server則是安裝時會自動一併安裝).譯註1.<br>
  然後你可以使用專案管理員去建立或編譯COM物件.當COM物件被建立了,你可以使用VFP Web Services精靈把他們公佈到你的虛擬目錄中.<br>
  你可以利用VFP的IntelliSense管理員去註冊 Web Services,所以Web Service的佈置和程式碼中必要呼叫的常式能迅速被執行.<br>
  這篇文章引領你為現存的COM伺服器建立Web Serveice並且準備Web Service以使用的這個複雜過程.<br>
  你能從一個COM伺服器建立一個簡單的Web Service,讓任何人都能從HTTP協定上存取.<br>
  這個 Web Service 提供一個關於目前目錄和有多少檔案在目錄中的簡單報告.</p>
<h3>Web Services<a name="webservices"></a></h3>
<p>Web Services延展了你自己的COM伺服器的可存取能力,能夠使得其他開發者能透過瀏覽器來存取.<br>
  Web Services提供機能並且能跨平台和在異質連接中存取資料.<br>
  你可以從Web Service存在的地方建立並使用Web Services去提供或者獲得功能.(譯註2)<br>
  大部分Web Service重要的觀點是Web Services使用HTTP協定和SOAP代理人,因此功能可以在跨越防火牆之後,仍然有效.<br>
  因為HTTP和SOAP是不管平台的,所以Web Services也是不管平台的.在某些案件,這仍能在COM失效的時候提供功能.<br>
  要發布一個 Web Service, 你必須在IIS中建立一個虛擬目錄,然後建立或複製一個COM伺服器,從而產生一個Web Service到你的虛擬目錄中.</p>
<p>&nbsp;</p>
<h3>Establishing a Virtual Directory(建立一個虛擬目錄)<a name="virtualdirectory"></a></h3>
<p>你必須建立或識別一個目錄以存放你的 Web Services.<br>
  儘管你可以使用一個已存在的目錄,你仍可能想要在你硬碟上建立一個不一樣的地方存放這些檔案以方便管理你的Web Service檔案.<br>
  去建立一個虛擬目錄,譯註3<br>
  1.在VFP主要目錄下(\Program Files\Microsofft Visual FoxPro 7)建立一個資料夾,並命名為 Web Services.<br>
  2.在控制台裡的系統管理工具資料夾中,雙擊Internet服務管理員.<br>
  3.Internet服務管理員視窗打開,在左邊會顯示一個樹狀目錄,他顯示了你的硬碟.展開節點,以便能看到子資料夾.<br>
  4.在樹狀目錄中選擇預設的Web站台.<br>
  5.從右擊選單中,選擇&quot;新增&quot;,然後點選&quot;虛擬目錄&quot;.這會開啟&quot;虛擬目錄新增精靈&quot;.<br>
  6.遵循精靈的指示進行,選擇虛擬目錄的時候,指定到步驟一所建立的 Web Services 資料夾.<br>
  你已經建立了一個虛擬目錄,參照到你的Web Services資料夾,之後你將會在這裡存放你建立的所有Web Services檔案.</p>
<p>&nbsp;</p>
<h3>Creating a Project (建立一個專案)<a name="createproject"></a></h3>
<p>專案管理員在VFP中是十分基礎的應用程式建立工具.<br>
  在VFP專案中,你可以組合各式各項的文件,資料,類別,程式碼和其他類型的檔案等.<br>
  一個專案提供了你可能想要含括到一個伺服器中的所有元件,並且容納,以便編輯.<br>
  在這個範例中,你使用專案去編譯你的 Web Services<br>
  去建立一個專案,譯註4<br>
  1.在File(檔案)選單中,選擇 New(開新檔案)<br>
  2.在New(開新檔案)的對話盒中選擇 Project(專案),並點選 New File(開新檔案).<br>
  3.在 Create(建立)對話盒中,選擇你之前建立的 Web Services 資料夾,並且取名為 myWServ1.<br>
  4.點選 Save(存檔)<br>
  現在你已經在 Web Services 資料夾中建立了你的專案.這使得當你完成加入元件後可以在正確的資料夾中自動的儲存並編譯.</p>
<p>&nbsp;</p>
<h3>Creating a COM Server(建立一個COM伺服器)<a name="createcom"></a></h3>
<p>因為,一個Web Service是一個.dll或.exe的檔案,你必須使用一個COM伺服器來當作你Web Service的基礎.<br>
  一個COM伺服器在VFP來說是一個有.dll或.exe副檔名,裡面包含從一個利用OLEPUBLIC識別字所建立的類別.<br>
  當一個物件被指定為OLEPUBLIC時,表示可以被Automation客戶端存取.當你從.dll檔案發布Web Service時,一個新的.wsdl檔案將會被產生.<br>
  .wsdl檔案有必要的XML源碼,他描述在.dll檔中的類別和參照實際在Web Service背後出力的.dll檔案.<br>
  從這個COM伺服器範例中,你將建立一個custom類別,他簡單回報了一些非常簡單的訊息.<br>
  在這個過程中,你將要寫一個程式來建立一個包含兩個方法的類別,並且編譯這個專案成一個COM伺服器和一個已發布的Web Service.<br>
  去建立一個簡單的類別,譯註5<br>
  1.在File(檔案)選單中,選擇New(新增).<br>
  2.在New(開新檔案)對話盒中,選擇Project(專案),並點選New file(開新檔案).這會開啟Project Manager(專案管理員).<br>
  3.在Project Manager(專案管理員)的All(所有)頁籤中,將Code(程式)展開,選擇Programs(程式碼),然後選擇New(開新檔案).<br>
  4.將下列的程式碼複製到程式碼編輯視窗中.<br>
  *-- returns curdir() and number of JPEG files</p>
<p>DEFINE CLASS showem AS session OLEPUBLIC</p>
<p> Name = &quot;showem&quot;</p>
<p> PROCEDURE justshow<br>
  howmany=ADIR(afilArry,&quot;*.jpg&quot;)<br>
  IF howmany &lt;1<br>
  fileNm=&quot;no&quot;<br>
  ELSE<br>
  fileNm=ALLTRIM(STR(howmany))<br>
  ENDIF<br>
  <br>
  X = &quot;about &quot; + CURDIR() + &quot; ... &quot;<br>
  Y = &quot;There are &quot; + fileNm + &quot; JPEG files here.&quot;<br>
  RETURN x + y <br>
  ENDPROC<br>
  ENDDEFINE</p>
<p>這個程式定義了一個類別 showem,他有一個方法 justshow<br>
  5.關閉編輯視窗,並在Save As(另存新檔)對話盒中,將程式命名為myWServ1,並點選存檔.<br>
  6.確定 myServ1 設定為主程式.(如果他被設定為主程式,他將會以粗體呈現).如果沒有,在Project Manager(專案管理員)中,以滑鼠右鍵點選myWServ1並在快捷選單中選擇Set 
  Main(設為主程式).</p>
<p>&nbsp;</p>
<h3>去編譯這個COM伺服器<a name="compilecom"></a></h3>
<p>1.在Project Manager(專案管理員)中,選擇 Build (建立)<br>
  2.選擇 Single-threaded COM Server<br>
  3.選擇 Ok, 並接受名稱為 myWServ1<br>
  VFP將會編譯這個myWServ1檔案為一個COM伺服器,之後你就可以將這個COM伺服器轉為Web Service.</p>
<p>&nbsp;</p>
<h3>Creating and Publishing a Web Service(建立並發布一個Web Service)<a name="publishing"></a></h3>
<p>必要地加入一個元件並且編譯COM伺服器,才能將你的COM伺服器轉為Web Service, 當成一個 Web Service發布.譯註6<br>
  在你指定完這些設定,VFP會建立必要的XML和SOAP檔案以將你的伺服器轉為一個 Web Service,註冊你的新 Web Service,並發布到你的虛擬目錄中.<br>
  去編譯和發佈一個Web Service<br>
  1.在你完成前一個步驟,並且編譯好COM伺服器myWServ1.dll,以滑鼠右鍵點選Project Manager(專案管理員),並從快捷選單中選擇Builder.<br>
  2.在Wizard Selection(精靈選擇)對話盒中,選擇Web Services Publisher,然後按下 Ok.<br>
  3.在VFP Web Services Publisher對話盒中,使用 Ellipsis 按鈕去找到 myWServ1, 然後選擇你想要從伺服器中註冊的類別.在這個你建立的COM伺服器中,myWServ1,你只有一個類別 
  showem<br>
  Note 點選 Advance(進階)按鈕以確定Web Services Publisher對話盒參照到正確的檔案是一個不錯的主意,特別是如果你建立了相似名稱的伺服器或者服務在不同資料夾的時候.如果正確的檔案沒有被顯示在下拉清單中,使用 
  Ellipsis 按鈕(...)去找到正確的檔案.<br>
  IntelliSense scripts 欄位下方顯示了你(和SOAP toolkit)將找到的名稱.在Advance Web Services Publisher對話盒中確認了資訊之後,點選Ok<br>
  譯註7.<br>
  4.點選Generate(產生)按鈕<br>
  在VFP產生Web Service檔案後, Web Services Publishing Results對話盒會出現,顯示包含COM伺服器,.wsdl檔案,ISAPI或ASP 
  listener和IntelliSense路徑名稱和編輯結果的清單.<br>
  到了這裡,你已經建立和發布你的Web Service.任何存取到你早先所建立的這個虛擬目錄,就能使用HTTP去存取你剛剛建立的Web Service.<br>
  要使用這個Web Service,你必須撰寫SOAP用戶端,一個listener(傾聽者)和瀏覽器的程式碼並且必須利用好幾個協定的層級和過程.<br>
  在VFP裡面,只要藉著在IntelliSense管理者中註冊Web Service就能簡化許多.</p>
<p>&nbsp;</p>
<h3>Registering a Web Service(註冊一個Web Service)<a name="registering"></a></h3>
<p><br>
  你可以在IntelliSense管理者中註冊Web Services(你所建立的或被其他人建立的).<br>
  當你做完,IntelliSense在你存取一個已註冊的Web Service時會提供了支援的程式碼.</p>
<p>去註冊一個Web Service<br>
  1.在 Tools(工具)選單,選擇IntelliSense Manager.<br>
  2.在IntelliSense Manager的Types頁籤,按下Web Services按鈕以註冊你新的Web Services(你的新類別也將會出現在Types清單中)<br>
  現在,當你加入一個強制型別的變數到你的VFP程式碼中時,IntelliSense將會提供你的Web Services如同一個非必要的選擇.<br>
  譯註8</p>
<p>&nbsp;</p>
<h3>Using a Web Service(使用一個Web Service)<a name="usingwebservice"></a></h3>
<p>使用Web Service就跟你想要一個應用程式的任何COM伺服器把功能公開出來給另一個應用程式或程式一樣.<br>
  舉例來說,你可以建立一個呼叫範例Web Service, myWServ1,的VFP程式.<br>
  在一個VFP程式中,宣告一個強制型別的變數,如同下列的程式碼一樣,藉著從IntelliSense下拉選單中可以參照到你的Web Service, myServ1.<br>
  LOCAL x AS myWServ1<br>
  VFP IntelliSense使用這個Web Service已註冊的資訊,去完成下列的程式碼:<br>
  x = CREATEOBJECT(&quot;MSSOAP.SoapClient&quot;)<br>
  x.MSSoapInit(&quot;http://TheVirtualDisk/web services/myWServ1.WSDL&quot;, , 
  &quot; myWServ1SoapPort&quot;)<br>
  然後,你可以像以前呼叫COM物件或類別的方法一樣去呼叫,就像下列的程式碼一樣:<br>
  ? x.justshow()<br>
  譯註9<br>
  你可以加入相似的程式碼到VFP程式或應用程式中,去存取你自己的或其他Web Services.</p>
<p>&nbsp;</p>
<h3>更多資訊<a name="more"></a></h3>
<p>要取得更多關於Web Services的資訊,請看VFP輔助說明中的 &quot;Web Services Overview&quot;.<br>
  要取得更多關於COM伺服器的資訊,請看VFP輔助說明中的 &quot;Creating Automation Servers&quot;.</p>
<p>Text for description meta tag:VFP使得從COM伺服器建立Web Services變的可能.</p>
<p>KeyWords(關鍵字):VFP Web Services, creating; VFP, creating Web Services;VFP, Web 
  Services.</p>
<p>&nbsp;</p>
<h3>譯註<a name="translate"></a></h3>
<p>譯註1:此句翻譯的不好,本來只有一句,但我切成兩句.<br>
  譯註2:此句也翻譯的不好.意思有到了.<br>
  譯註3:這邊的步驟,我都照做一次,並將原有的英文W2k上的字眼換成中文w2k上的字眼.<br>
  譯註4:因為我的VFP7是英文版的,所以我使用英文的字,不用中文的<br>
  譯註5:如果你前面有建立專案的話,就不需要再建立了,直接從步驟三開始吧.<br>
  譯註6:這句翻的非常不好,附上原文: To add the components necessary to turn your COM server into 
  a Web Service, you must compile the COM server as a Web Service.<br>
  譯註7:此處務必要自己玩過一遍,盡量多按一按,因為這邊寫的不是很清楚.<br>
  譯註8:如果你之前為虛擬目錄取名為 &quot;Web Services&quot; 時,會出現錯誤,因為他不允許名稱中間有空白!!<br>
  譯註9:這段程式碼讓我花了一些時間去測試,不過錯誤原因在於我自己在建立並發布Web Services的時候,選擇了以ASP的方式產生,後來改為ISAPI的方式產生就ok了.<br>
</p>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553798.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553798.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Wed, 05 Sep 2001 22:31:29 +0800</pubDate>
</item>
<item>
	<title>VFP7-Behavior Changes since the Previous Version</title>
	<description><![CDATA[
			本章翻譯自 foxhelp.chm Behavior Changes since the Previous Version.
很多可能翻譯的與原文不同,但是大意是一樣的.

從前一版到現在的行為改變
這個章節描述了這一版和前版VFP行為較為不同的地方,這些改變可能會影響到已經存在的程式碼.
._Screen 和 _VFP 這兩個物件的屬性已經經過調整,使得這兩個物件的屬性比較容易區分._VFP就是協調整個VFP應用程式的視窗(包含選單和狀態列)._Screen就是負責協調目前整個桌面區域(比如使用?指令時,會有輸出結果的視窗)
.為了效率,CreateObject()函數不再為一個動態已被建立的Name屬性的值加入連續號碼.這會應用到在prg檔案中的沒有明確定義Name屬性或基本類別的類別定義.(似乎影響不大)
.因為支援 IntelliSense 和 COM Server 型態(舉例來說 Local cName as string), 利用空白字元隔開的變數宣告(如 local x y z)將不再被允許.宣告變數的時候必須以 , 隔開(如 local x,y,z ).
.Session類別現在在為一個OLEPUBLIC的子類別產生Type Library的時候隱藏了固有的屬性,方法和事件. 另外,當利用session物件使用一個私有的data session時,SET TALK,SET EXCLUSIVE,SET SAFETY預設設定為 off.
.Version函數傳回的格式改變了. Build number現在移到最後面去了.如果你有使用AGETFILEVERSION函數的話,這也可能影響到.
.某些 Home([n]) 傳回的數值被改變了.這些變化只會影響到目前安裝的 Visual Studio. Samples和Graphics資料夾現在移到VFP的根目錄下.
.儲存檔案的新預設位置為了要和Windows 2000 Logo Guide相容的關係,已經被改變了.你可以從選項對話方盒(檔案位置頁籤)查看(或改變)位置. 譯註1.
.選單檔案(MNX)的格式已經被改變,以便能容納新的圖形支援.
.資料庫檔案(DBC)的格式在"DBC事件"啟動的時候將會被改變.
.命令列視窗現在會自動把內容保存起來.內容存放在 _command.prg 中.
.資源檔(如 FOXUSER )現在是開啟為分享模式,所以你可以執行好幾個VFP的個體,且使用同一個資源檔.在前一個版本,你可以在選項對話方盒中去設定.
.VFP執行時期函式庫(舉例,VFP7T.DLL)不在安裝在 Windows\system 目錄下.此外,其他語言的資源檔現在將和英文的產品一同安裝.譯註2.
.當屬性視窗設定為Dockable的時候,將會一直開啟著,即使目前的form/class designer(表單/類別設計)已經關閉.
.舊版FoxBASE+所支援的FOXGRAPH,FOXVIEW,FOXGEN,FOXCODE,CENTRAL和ASSIST已經不再被支援.
.Windows檔案總管在開啟已經的VFP檔案格式的時候,現在會喚起一個新的VFP個體來開啟檔案.此外,程式檔(PRG)和查詢檔(QRY)同時支援"Open"和"Run"選項.程式檔現在的預設動作為"Open"取代了前版本的"Run".
.Class/Form Designer(類別/表單設計)畫面顯示的格子(如果有設定要顯示格線)現在以實際的像素來顯示,取代前一版本使用Fox2x的設定.譯註3.
.Grid欄位標頭現在允許顯示鍵盤快捷鍵.這僅僅只有顯示而已,所以開發者如果要處理快捷鍵的動作,必須要寫程式來處理.
.#includes 的搜尋路徑已經延展為PRGs(程式檔), SCXs(畫面檔)和VCXs(類別檔).
.使用SET EVENTTRACKING指令產生出來的事件追蹤歷史檔的格式現在包含了一個Timestamp的欄位.
._DBLCLICK系統變數不再為控制項控制incremental搜尋,如listbox. 現在這被一個新的系統變數_INCSEEK來處理.
.一個起始的應用程式(舉例,vfp7strt.app)不再和VFP發布出去.
.ASCAN()函數的 nStartPos 參數如果傳入為0的數值的話,將只產生一個錯誤. 如果傳入一個比陣列個數要多的數值,也將傳回0.
.在前版本,當呼叫Create Table ... name LongTable Name 時,我們可以利用 _ 來取代空白.當在Table Designer(表單設計)時將不會發生.在這個版本,這個功能被保留起來了,以與Table Designe的行為相同.

從前版本至今具特色的改變
接下來這些前一版本VFP的特點已經被移除了:
.文法檢查不再包含在此產品中.
.安裝精靈不再包含在此產品中. 一個以Microsoft Installer為基礎的發布工具將被提供. 細節部分請參考 Destributing Applications 這章.
.Graph不再包含,因為他本來是跟著之前的安裝精靈一併發布的. 
.執行 ActiveDoc 的選單項目不再被包含在此產品中,但是仍然有效並且可以利用Do來呼叫.
.好幾個MSDN的選單項目已經從輔助說明選單中移除.此產品的線上文件已經改變為一個獨立的輔助說明檔,他和MSDN Library一樣好.此外,"Microsoft on the Web"子選單已經被一個單獨的"Visual FoxPro on the Web"項目所取代.
.Calendar, Outline 和 FoxHWnd ActiveX控制項不再和此產品一起銷售.
.VFP ODBC 驅動程式不再和此產品一起銷售.你仍然可以從VFP網站來取得.但VFP OLEDB Provider是一個存取遠端VFP資料更好的解決方案.

譯註1:可是我並沒有發現有任何改變,我使用的環境是 Windows 2000+VFP7.我想他指的是不是 set default 呢??
譯註2:的確,現在多安裝了VFP7CHT.DLL,VFP7KOR.DLL等這些資源檔.
譯註3:簡單的說,單位已經改變了.
		]]>
	</description>
	<content:encoded><![CDATA[
			本章翻譯自 foxhelp.chm Behavior Changes since the Previous Version.<br />
很多可能翻譯的與原文不同,但是大意是一樣的.<br />
<br />
從前一版到現在的行為改變<br />
這個章節描述了這一版和前版VFP行為較為不同的地方,這些改變可能會影響到已經存在的程式碼.<br />
._Screen 和 _VFP 這兩個物件的屬性已經經過調整,使得這兩個物件的屬性比較容易區分._VFP就是協調整個VFP應用程式的視窗(包含選單和狀態列)._Screen就是負責協調目前整個桌面區域(比如使用?指令時,會有輸出結果的視窗)<br />
.為了效率,CreateObject()函數不再為一個動態已被建立的Name屬性的值加入連續號碼.這會應用到在prg檔案中的沒有明確定義Name屬性或基本類別的類別定義.(似乎影響不大)<br />
.因為支援 IntelliSense 和 COM Server 型態(舉例來說 Local cName as string), 利用空白字元隔開的變數宣告(如 local x y z)將不再被允許.宣告變數的時候必須以 , 隔開(如 local x,y,z ).<br />
.Session類別現在在為一個OLEPUBLIC的子類別產生Type Library的時候隱藏了固有的屬性,方法和事件. 另外,當利用session物件使用一個私有的data session時,SET TALK,SET EXCLUSIVE,SET SAFETY預設設定為 off.<br />
.Version函數傳回的格式改變了. Build number現在移到最後面去了.如果你有使用AGETFILEVERSION函數的話,這也可能影響到.<br />
.某些 Home([n]) 傳回的數值被改變了.這些變化只會影響到目前安裝的 Visual Studio. Samples和Graphics資料夾現在移到VFP的根目錄下.<br />
.儲存檔案的新預設位置為了要和Windows 2000 Logo Guide相容的關係,已經被改變了.你可以從選項對話方盒(檔案位置頁籤)查看(或改變)位置. 譯註1.<br />
.選單檔案(MNX)的格式已經被改變,以便能容納新的圖形支援.<br />
.資料庫檔案(DBC)的格式在"DBC事件"啟動的時候將會被改變.<br />
.命令列視窗現在會自動把內容保存起來.內容存放在 _command.prg 中.<br />
.資源檔(如 FOXUSER )現在是開啟為分享模式,所以你可以執行好幾個VFP的個體,且使用同一個資源檔.在前一個版本,你可以在選項對話方盒中去設定.<br />
.VFP執行時期函式庫(舉例,VFP7T.DLL)不在安裝在 Windows\system 目錄下.此外,其他語言的資源檔現在將和英文的產品一同安裝.譯註2.<br />
.當屬性視窗設定為Dockable的時候,將會一直開啟著,即使目前的form/class designer(表單/類別設計)已經關閉.<br />
.舊版FoxBASE+所支援的FOXGRAPH,FOXVIEW,FOXGEN,FOXCODE,CENTRAL和ASSIST已經不再被支援.<br />
.Windows檔案總管在開啟已經的VFP檔案格式的時候,現在會喚起一個新的VFP個體來開啟檔案.此外,程式檔(PRG)和查詢檔(QRY)同時支援"Open"和"Run"選項.程式檔現在的預設動作為"Open"取代了前版本的"Run".<br />
.Class/Form Designer(類別/表單設計)畫面顯示的格子(如果有設定要顯示格線)現在以實際的像素來顯示,取代前一版本使用Fox2x的設定.譯註3.<br />
.Grid欄位標頭現在允許顯示鍵盤快捷鍵.這僅僅只有顯示而已,所以開發者如果要處理快捷鍵的動作,必須要寫程式來處理.<br />
.#includes 的搜尋路徑已經延展為PRGs(程式檔), SCXs(畫面檔)和VCXs(類別檔).<br />
.使用SET EVENTTRACKING指令產生出來的事件追蹤歷史檔的格式現在包含了一個Timestamp的欄位.<br />
._DBLCLICK系統變數不再為控制項控制incremental搜尋,如listbox. 現在這被一個新的系統變數_INCSEEK來處理.<br />
.一個起始的應用程式(舉例,vfp7strt.app)不再和VFP發布出去.<br />
.ASCAN()函數的 nStartPos 參數如果傳入為0的數值的話,將只產生一個錯誤. 如果傳入一個比陣列個數要多的數值,也將傳回0.<br />
.在前版本,當呼叫Create Table ... name LongTable Name 時,我們可以利用 _ 來取代空白.當在Table Designer(表單設計)時將不會發生.在這個版本,這個功能被保留起來了,以與Table Designe的行為相同.<br />
<br />
從前版本至今具特色的改變<br />
接下來這些前一版本VFP的特點已經被移除了:<br />
.文法檢查不再包含在此產品中.<br />
.安裝精靈不再包含在此產品中. 一個以Microsoft Installer為基礎的發布工具將被提供. 細節部分請參考 Destributing Applications 這章.<br />
.Graph不再包含,因為他本來是跟著之前的安裝精靈一併發布的. <br />
.執行 ActiveDoc 的選單項目不再被包含在此產品中,但是仍然有效並且可以利用Do來呼叫.<br />
.好幾個MSDN的選單項目已經從輔助說明選單中移除.此產品的線上文件已經改變為一個獨立的輔助說明檔,他和MSDN Library一樣好.此外,"Microsoft on the Web"子選單已經被一個單獨的"Visual FoxPro on the Web"項目所取代.<br />
.Calendar, Outline 和 FoxHWnd ActiveX控制項不再和此產品一起銷售.<br />
.VFP ODBC 驅動程式不再和此產品一起銷售.你仍然可以從VFP網站來取得.但VFP OLEDB Provider是一個存取遠端VFP資料更好的解決方案.<br />
<br />
譯註1:可是我並沒有發現有任何改變,我使用的環境是 Windows 2000+VFP7.我想他指的是不是 set default 呢??<br />
譯註2:的確,現在多安裝了VFP7CHT.DLL,VFP7KOR.DLL等這些資源檔.<br />
譯註3:簡單的說,單位已經改變了.
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553799.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553799.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Wed, 05 Sep 2001 22:31:29 +0800</pubDate>
</item>
<item>
	<title>Internet Transfter Control的聯想</title>
	<description><![CDATA[
			摘要:對於 Internet Transfer Control 元件的一個聯想
內容:
安裝說明
  發想
  參考

  下載本文章的範例程式: ASP端 Client端 
  (均為自動解壓縮檔)
安裝說明 
請將下載下來的 ASPCODE.EXE 解壓縮,放到 WEB Server 的某個資料夾 上, 然後在 IIS 中開啟一個虛擬目錄,對應到此資料夾.

  而 INETCTRL.EXE 解壓縮後就放在 client 端執行,只是可能要改一下程式!!你需要在 Query Customer Informat 那個按鈕的click事件中作修正. 
  請原諒我沒有作詳細的說明,主要是因為程式中已經有說明了.

  另外需要注意的是,WEB Server 必須要安裝 ADO 2.5 
  以上版本,另外要有裝 IE5.0以上版本, client 端的需求也是一樣!!
  

發想
  
  某天,我在 Microsoft Newsgroup上看到一個Inetctrl 元件的應用範例
  以前都沒想到可以用這個 Active X元件
  挺有趣的
  所以就動手寫了一個小程式,配合 ASP 做了一個有趣的應用
  ASP 負責在 WEB Server 上 抓資料,並產生 XML
  VFP 程式利用 Inetctrl 元件對 ASP 送指令,並取得 XML, 再轉換為 Recordset
  於是就可以用啦!!
  但是修改後的資料要怎麼送回去呢??
  我在 post 的按鈕裡面已經寫了一部份了
  到底在 ASP 程式還要作怎樣的配合才能把資料送回去?!
&nbsp;
參考
Active Server Pages 3.0 深度探索(國外出版社Wrox,國內則是由碁峰翻譯後發行)

&reg; 2001ellery寫的!!引用時,請加註出處!!謝謝~
		]]>
	</description>
	<content:encoded><![CDATA[
			<p>摘要:對於 Internet Transfer Control 元件的一個聯想</p>
<p>內容:<br>
<p><a href="#HowToInstall">安裝說明</a><br>
  <a href="#Association">發想</a><br>
  <a href="#Reference">參考</a></p>
<p><br>
  下載本文章的範例程式: <a href="files/aspcode.zip">ASP端</a> <a href="files/inetctrl.zip">Client端</a> 
  (均為自動解壓縮檔)</p>
<a name="HowToInstall"></a><b>安裝說明</b> 
<p>請將下載下來的 ASPCODE.EXE 解壓縮,放到 WEB Server 的某個資料夾 上, 然後在 IIS 中開啟一個虛擬目錄,對應到此資料夾.</p>
<p><br>
  而 INETCTRL.EXE 解壓縮後就放在 client 端執行,只是可能要改一下程式!!你需要在 Query Customer Informat 那個按鈕的click事件中作修正. 
  請原諒我沒有作詳細的說明,主要是因為程式中已經有說明了.</p>
<p><br>
  另外需要注意的是,WEB Server 必須要安裝 <a href="http://www.microsoft.com/data/">ADO</a> 2.5 
  以上版本,另外要有裝 IE5.0以上版本, client 端的需求也是一樣!!<br>
  <br>
</p>
<p><a name="Association"></a><b>發想</b><br>
  <br>
  某天,我在 Microsoft Newsgroup上看到一個Inetctrl 元件的應用範例<br>
  以前都沒想到可以用這個 Active X元件<br>
  挺有趣的<br>
  所以就動手寫了一個小程式,配合 ASP 做了一個有趣的應用<br>
  ASP 負責在 WEB Server 上 抓資料,並產生 XML<br>
  VFP 程式利用 Inetctrl 元件對 ASP 送指令,並取得 XML, 再轉換為 Recordset<br>
  於是就可以用啦!!<br>
  但是修改後的資料要怎麼送回去呢??<br>
  我在 post 的按鈕裡面已經寫了一部份了<br>
  到底在 ASP 程式還要作怎樣的配合才能把資料送回去?!</p>
<p>&nbsp;</p>
<p><a name="Reference"></a><b>參考</b></p>
<p>Active Server Pages 3.0 深度探索(國外出版社Wrox,國內則是由碁峰翻譯後發行)</p>
<hr>
<p>&reg; 2001<a href="mailto:ellery@icode.com.tw">ellery</a>寫的!!引用時,請加註出處!!謝謝~</p>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553793.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553793.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Wed, 05 Sep 2001 22:31:28 +0800</pubDate>
</item>
<item>
	<title>SQL pass-through的使用</title>
	<description><![CDATA[
			在VFP所附的範例或者是微軟的建議中,都一直有看到這方面的函數。
事實上,這些函數對於遠端資料的控制來說是很方便的。
如果經過適當包裝的話,就非常類似於Delphi或BCB的TQuery元件或TStoreProc元件,
有看過Delphi或BCB的人可以自行比較一下。
但是偏偏市面上的書對於這個部分如何使用...等都略過不提。
在這裡,提出一個範例供大家研究一下,略盡棉薄之力 。

p.s. Arsen=Ellery, And this article is co-write with Saint.

------------------------------------------------------------------------------------------------------------ 

*使用SPT更新表格的範例 
*作者:Arsen(Ellery)
*環境:在ODBC設定中,我設了fpm這個別名,路徑設到目錄下的foreign.dbc

Local ln_handle 

*先連接
ln_handle=sqlconnect("fpm") 

*執行查詢 
=sqlexec(ln_handle,"select emp_no,name from basic","_basic") 

*設定相關屬性:這幾個屬性必須設定,在MSDN上有詳細說明(記得多看MSDN) 
=cursorsetprop("tables","basic") &&設定欲更新的資料表格 
=cursorsetprop("sendupdates",.t.,"_basic") &&確定要進行更新 
=cursorsetprop("keyfieldlist","emp_no","_basic") &&要依據何鍵值來進行更新 =cursorsetprop("updatablefieldlist","emp_no,name","_basic") &&哪些欄位要更新 

*以下這行,比較複雜一點,空格前寫的是上一行的欄名,後面寫的是資料表格的欄名(要用alias.field這樣) =cursorsetprop("updatenamelist","emp_no basic.emp_no,name basic.name","_basic") 

Replace Next 1 alltrim(name) with alltrim(name)+"Test"

use 

*釋放連接 
=sqldisconnect(ln_handle) 


------------------------------------------------------------------------------------------------------------ 

首先,謝謝Arsen,幫我解決了想了好久無法解決的問題。
其實,我的作法和他,並無很大的不同,只有這一行
=cursorsetprop("updatenamelist","emp_no basic.emp_no,name basic.name","_basic") 
由於資料集預設的BUFFERING是3,所以只要移動記錄指標便會做存檔的動作
為了Client/Server效率上的考量,改用
=CURSORSETPROP("BUFFERING",5)
似乎是比較好的選擇。

另外附上另一份範例如下:

?sqldisconnect(0)
?sqlconnect("testdbc")
_sqlsele="sele * from mydbf" 
=sqlexec(1,_sqlsele ,"myview") 
?cursorsetprop("buffering",5) 
REPLACE NAME WITH "TEST"

=cursorsetprop("tables","mydbf","myview") 
=cursorsetprop("keyfieldlist","id","MYVIEW") 
=cursorsetprop("updatablefieldlist","name","MYVIEW") 
=cursorsetprop("sendupdates",.t.,"MYVIEW") 
*=cursorsetprop("updatenamelist","ID MYDBF.ID,name MYDBF.name")&&這一行指令,有興趣的人可以比較 
=cursorsetprop("updatenamelist","ID MYDBF.ID,name MYDBF.name") &&註解前和註解後有何差別

IF NOT TABLEUPDATE(.T.,.T.,"MYVIEW") 
=AERRO(MYERROR) 
CLEAR 
?MYERROR(1) 
?MESSAGE() 
ENDIF 


另外附上其他的做法,一檥可做到,請自行參考


AA=sqlconnect("testdbc") 
IF AA>0 
=SQLSETPROP(AA,"ASYNCHRONOUS",.F.) 
=SQLSETPROP(AA,"BATCHMODE",.T.) 
=SQLEXEC(AA,"sele * from mydbf","myview") 
M.SQLDESC="UPDATE ...." &&請參考 SQL INSERT,UPDATE 語法" 
=SQLEXEC(AA,M.SQLDESC) &&把指令送到後端讓Server去執行
ENDIF 

		]]>
	</description>
	<content:encoded><![CDATA[
			在VFP所附的範例或者是微軟的建議中,都一直有看到這方面的函數。<br />
事實上,這些函數對於遠端資料的控制來說是很方便的。<br />
如果經過適當包裝的話,就非常類似於Delphi或BCB的TQuery元件或TStoreProc元件,<br />
有看過Delphi或BCB的人可以自行比較一下。<br />
但是偏偏市面上的書對於這個部分如何使用...等都略過不提。<br />
在這裡,提出一個範例供大家研究一下,略盡棉薄之力 。<br />
<br />
p.s. Arsen=Ellery, And this article is co-write with Saint.<br />
<br />
------------------------------------------------------------------------------------------------------------ <br />
<pre><br />
*使用SPT更新表格的範例 <br />
*作者:Arsen(Ellery)<br />
*環境:在ODBC設定中,我設了fpm這個別名,路徑設到目錄下的foreign.dbc<br />
<br />
Local ln_handle <br />
<br />
*先連接<br />
ln_handle=sqlconnect("fpm") <br />
<br />
*執行查詢 <br />
=sqlexec(ln_handle,"select emp_no,name from basic","_basic") <br />
<br />
*設定相關屬性:這幾個屬性必須設定,在MSDN上有詳細說明(記得多看MSDN) <br />
=cursorsetprop("tables","basic") &&設定欲更新的資料表格 <br />
=cursorsetprop("sendupdates",.t.,"_basic") &&確定要進行更新 <br />
=cursorsetprop("keyfieldlist","emp_no","_basic") &&要依據何鍵值來進行更新 =cursorsetprop("updatablefieldlist","emp_no,name","_basic") &&哪些欄位要更新 <br />
<br />
*以下這行,比較複雜一點,空格前寫的是上一行的欄名,後面寫的是資料表格的欄名(要用alias.field這樣) =cursorsetprop("updatenamelist","emp_no basic.emp_no,name basic.name","_basic") <br />
<br />
Replace Next 1 alltrim(name) with alltrim(name)+"Test"<br />
<br />
use <br />
<br />
*釋放連接 <br />
=sqldisconnect(ln_handle) <br />
</pre><br />
<br />
------------------------------------------------------------------------------------------------------------ <br />
<br />
首先,謝謝Arsen,幫我解決了想了好久無法解決的問題。<br />
其實,我的作法和他,並無很大的不同,只有這一行<br />
=cursorsetprop("updatenamelist","emp_no basic.emp_no,name basic.name","_basic") <br />
由於資料集預設的BUFFERING是3,所以只要移動記錄指標便會做存檔的動作<br />
為了Client/Server效率上的考量,改用<br />
=CURSORSETPROP("BUFFERING",5)<br />
似乎是比較好的選擇。<br />
<br />
另外附上另一份範例如下:<br />
<pre><br />
?sqldisconnect(0)<br />
?sqlconnect("testdbc")<br />
_sqlsele="sele * from mydbf" <br />
=sqlexec(1,_sqlsele ,"myview") <br />
?cursorsetprop("buffering",5) <br />
REPLACE NAME WITH "TEST"<br />
<br />
=cursorsetprop("tables","mydbf","myview") <br />
=cursorsetprop("keyfieldlist","id","MYVIEW") <br />
=cursorsetprop("updatablefieldlist","name","MYVIEW") <br />
=cursorsetprop("sendupdates",.t.,"MYVIEW") <br />
*=cursorsetprop("updatenamelist","ID MYDBF.ID,name MYDBF.name")&&這一行指令,有興趣的人可以比較 <br />
=cursorsetprop("updatenamelist","ID MYDBF.ID,name MYDBF.name") &&註解前和註解後有何差別<br />
<br />
IF NOT TABLEUPDATE(.T.,.T.,"MYVIEW") <br />
=AERRO(MYERROR) <br />
CLEAR <br />
?MYERROR(1) <br />
?MESSAGE() <br />
ENDIF <br />
</pre><br />
<br />
另外附上其他的做法,一檥可做到,請自行參考<br />
<br />
<pre><br />
AA=sqlconnect("testdbc") <br />
IF AA>0 <br />
=SQLSETPROP(AA,"ASYNCHRONOUS",.F.) <br />
=SQLSETPROP(AA,"BATCHMODE",.T.) <br />
=SQLEXEC(AA,"sele * from mydbf","myview") <br />
M.SQLDESC="UPDATE ...." &&請參考 SQL INSERT,UPDATE 語法" <br />
=SQLEXEC(AA,M.SQLDESC) &&把指令送到後端讓Server去執行<br />
ENDIF <br />
</pre>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553792.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553792.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Wed, 05 Sep 2001 10:31:29 +0800</pubDate>
</item>
<item>
	<title>VFP的認證測驗</title>
	<description><![CDATA[
			VFP的認證測驗，主要測驗的是設計和實作分散式應用程式的解決方案。

在測驗之前，你必須要熟練以下列出的內容:
發展概念和邏輯規劃(Developing the Conceptual and Logical Design)

將資料分組為實體，並且為它們正規化。
在實體之間指定關聯。
選擇能在實體間進行關聯並且擔保指示一致性(Referential Integrity)的外來鍵(Foreign key)。
辨識出關聯到資料一致性(Data Integrity)的商業規則(Business rules)。
將商業規則和限制(Constraint)混合到資料模型中。
給予狀況以決定非正規化是否恰當。


衍伸出實體規劃
審慎評估邏輯規劃中對效率、維護、可伸展性和可利用性潛在的影響。需要考慮的部分包括COM、DCOM和中間層(middle tier)。

發展VFP元件從資料庫中存取資料。
規劃元件的屬性(Properite)和方法(Method)。
規劃類別庫。考慮的部分包含繼承、封裝、容器(containership)、委任(delegation)和多形。


完成發展環境

完成原始程式碼版本控制的環境。
為發展分散式應用程式安裝並設定VFP。
完成發展環境以執行MTS(Microsoft Transaction Server)、IIS(Inter Information Server)和MSMQ(Microsoft Message Queue Server)。


建立使用者服務

實作方向(navigational)規劃
  
    建立選單。
    增加一個快捷選單(shortcut menu)到應用程式中。
    增加控制項(controls)到表單(forms)中。
    為控制項設定屬性。
    為控制項指定程式碼以回應一個事件。
    建立一個工具列。
  
建立並管理資料輸入表單和對話盒(dialog boxes)
  
    運用控制項顯示、操作和連結資料。
    在執行時期(runtime)新增、刪除和操作控制項。
    使用表單集合( Forms collection)以在執行時期操作表單。
    給予一個狀況，增加程式碼到適當的表單事件中。這些事件包含Init、Destroy、Load、Unload、QueryUnload、Activate、Deactivate。
  
檢查使用者輸入。考慮部分包含了單層(single-tier)、二層(two-tier)和多層(n-tier)的應用程式。
在進入表單之後撰寫處理資料的程式碼。
為表單或是Container加入一個ActiveX控制項去操作資料。這些ActiveX控制項包括 TreeView、ListView、ImageList和Web Browser。
從網頁上和VFP互動。考慮到的技術包括FoxISAPI、DHTML、ASP和XML。
產生、喚起和操作一個COM元件。
在分散式應用程式中實作線上使用者輔助說明。
  
    設定恰當的屬性以讓使用者容易瞭解該屬性的用處。求助內容包括求助檔、HelpContextID(求助檔中作為指定訊息或文章的編號)和WhatsThisHelp。
    為一個應用程式建立HTML Help。
  
在桌面應用程式(Desktop Application)為使用者介面(User Interface)實作錯誤處理。
  
    辨識並捕捉執行時期錯誤。
    處理行間錯誤(inline errors)。
    提示使用者錯誤訊息。
  
經由Windows API來提昇功能。


建立並管理COM元件

建立一個實作了商業規則或邏輯的COM元件。
建立一個和其他COM元件溝通的COM元件。
為一個COM元件增加錯誤處理。
為了要錯誤處理和除錯，將錯誤記錄下來到一個錯誤檔中。
規劃並建立給MTS使用的元件。
  
    讓一個COM元件支援交易處理。
  
為一個COM元件建立適合的伺服器類型(Server type)。類型有in-process、out-of-process和multithreaded。
使用MTS Explorer來建立和管理套件。
  
    將原件增加到一個MTS套件中。
  
利用使用者權限指定使用者只能限制使用某個MTS套件。
使用元件陳列庫去管理元件。
註冊和解除註冊一個COM元件。


建立資料服務

使用ADO和RDS存取和操作資料。
使用VFP的原生資料處理和查詢能力(Query capabilities)(包含Local View)來存取和操作資料。
使用SQL pass-through存取和操作資料。
使用遠端資料集(Remote views)和本地資料集(Local views)來存取和操作資料。
管理資料庫交易以確保資料一致性和可復原性。
撰寫能取得和變更資料的SQL敘述。
撰寫使用連結(join)來從多個資料表格連結資料的SQL敘述。
撰寫能建立資料集(views)的SQL敘述。
使用適合的鎖定和緩衝策略。策略包括悲觀(pessimistic)、樂觀(optimistic)、列和表格。
建立和操作一個VFP stored procedure。
建立並實作VFP trigger。
從其他外在的資料來源匯入資料。
撰寫能更新及變更資料的SQL敘述。


建立實體資料庫

以程式來建立和維護VFP的資料庫。
規劃、建立和實作資料庫和資料表格。包含了資料一致性(Data Integrity)、參考完整性(Referential Integrity)和正規化(Normalization)。
選擇並規劃一個索引策略。考慮最佳化(經由Rushmore)和索引維護。
建立並維護索引。考慮最佳化(經由Rushmore)、程式化的操作、視覺化的操作和索引維護。


測試並除錯

決定適合的除錯技巧。
辨識和描述測試計劃的要素。要素包括beta的測試、回歸測試(Regression testing)、單元測試(unit testing)、整合測試(integration testing)和重點測試(stress testing)。
給予一個狀況，選擇適當的建立選項。(此處應是指在專案管理員裡按下建立後的一些選項)
在應用程式中使用條件編譯。(此處應是指#ifdef、#ifndef…等指令的應用)
使用除錯視窗(Debug Window)監控運算式和變數的值。
  
    使用即時運算視窗(Immediate window)來檢查或變更值。
    使用監看視窗(Watch window)來檢查或變更值。
    使用呼叫堆疊視窗(Call stack Window)來尋找錯誤。
  
在應用程式中使用 Asserts。
使用涵蓋分析工具應用程式來辨識效率瓶頸(Performance bottlenecks)和程式碼涵蓋範圍(Code coverage)。
使用事件追蹤來確定事件發生的順序。
設定中斷點以除錯應用程式。


散發應用程式

使用安裝程式精靈去建立一個能安裝分散式應用程式、註冊COM元件並容許反安裝的安裝程式。
註冊一個實作DCOM的元件。
為客戶端電腦(Client computer)和伺服器端電腦(Server computer)設定DCOM。
為客戶端電腦設定以使用一個MTS元件，並且為客戶端電腦及伺服器端電腦設定遠端自動化(Remote automation)。
為一個分散式應用程式計劃並實作以軟式磁碟機或CD為基礎的散發程式。
為一個分散式應用程式計劃並實作以Web為基礎的散發程式。
為一個分散式應用程式計劃並實作以網路(Network)為基礎的散發程式。


為應用程式提供維護和支援

為災難復原程序提出計劃並實作之。
修正錯誤並提早評估以預防未來的錯誤。
維護異常的報告。
為分散式應用程式散發應用程式更新。

		]]>
	</description>
	<content:encoded><![CDATA[
			VFP的認證測驗，主要測驗的是設計和實作分散式應用程式的解決方案。<br />
<br />
在測驗之前，你必須要熟練以下列出的內容:<br />
發展概念和邏輯規劃(Developing the Conceptual and Logical Design)<br />
<ul><br />
<li>將資料分組為實體，並且為它們正規化。</li><br />
<li>在實體之間指定關聯。</li><br />
<li>選擇能在實體間進行關聯並且擔保指示一致性(Referential Integrity)的外來鍵(Foreign key)。</li><br />
<li>辨識出關聯到資料一致性(Data Integrity)的商業規則(Business rules)。</li><br />
<li>將商業規則和限制(Constraint)混合到資料模型中。</li><br />
<li>給予狀況以決定非正規化是否恰當。</li><br />
</ul><br />
<br />
衍伸出實體規劃<br />
審慎評估邏輯規劃中對效率、維護、可伸展性和可利用性潛在的影響。需要考慮的部分包括COM、DCOM和中間層(middle tier)。<br />
<ul><br />
<li>發展VFP元件從資料庫中存取資料。</li><br />
<li>規劃元件的屬性(Properite)和方法(Method)。</li><br />
<li>規劃類別庫。考慮的部分包含繼承、封裝、容器(containership)、委任(delegation)和多形。</li><br />
</ul><br />
<br />
完成發展環境<br />
<ul><br />
<li>完成原始程式碼版本控制的環境。</li><br />
<li>為發展分散式應用程式安裝並設定VFP。</li><br />
<li>完成發展環境以執行MTS(Microsoft Transaction Server)、IIS(Inter Information Server)和MSMQ(Microsoft Message Queue Server)。</li><br />
</ul><br />
<br />
建立使用者服務<br />
<ul><br />
<li>實作方向(navigational)規劃</ul><br />
  <ul><br />
    <li>建立選單。</li><br />
    <li>增加一個快捷選單(shortcut menu)到應用程式中。</li><br />
    <li>增加控制項(controls)到表單(forms)中。</li><br />
    <li>為控制項設定屬性。</li><br />
    <li>為控制項指定程式碼以回應一個事件。</li><br />
    <li>建立一個工具列。</li><br />
  </ul><br />
<li>建立並管理資料輸入表單和對話盒(dialog boxes)</li><br />
  <ul><br />
    <li>運用控制項顯示、操作和連結資料。</li><br />
    <li>在執行時期(runtime)新增、刪除和操作控制項。</li><br />
    <li>使用表單集合( Forms collection)以在執行時期操作表單。</li><br />
    <li>給予一個狀況，增加程式碼到適當的表單事件中。這些事件包含Init、Destroy、Load、Unload、QueryUnload、Activate、Deactivate。</li><br />
  </ul><br />
<li>檢查使用者輸入。考慮部分包含了單層(single-tier)、二層(two-tier)和多層(n-tier)的應用程式。</li><br />
<li>在進入表單之後撰寫處理資料的程式碼。</li><br />
<li>為表單或是Container加入一個ActiveX控制項去操作資料。這些ActiveX控制項包括 TreeView、ListView、ImageList和Web Browser。</li><br />
<li>從網頁上和VFP互動。考慮到的技術包括FoxISAPI、DHTML、ASP和XML。</li><br />
<li>產生、喚起和操作一個COM元件。</li><br />
<li>在分散式應用程式中實作線上使用者輔助說明。</li><br />
  <ul><br />
    <li>設定恰當的屬性以讓使用者容易瞭解該屬性的用處。求助內容包括求助檔、HelpContextID(求助檔中作為指定訊息或文章的編號)和WhatsThisHelp。</li><br />
    <li>為一個應用程式建立HTML Help。</li><br />
  </ul><br />
<li>在桌面應用程式(Desktop Application)為使用者介面(User Interface)實作錯誤處理。</li><br />
  <ul><br />
    <li>辨識並捕捉執行時期錯誤。</li><br />
    <li>處理行間錯誤(inline errors)。</li><br />
    <li>提示使用者錯誤訊息。</li><br />
  </ul><br />
<li>經由Windows API來提昇功能。</li><br />
</ul><br />
<br />
建立並管理COM元件<br />
<ul><br />
<li>建立一個實作了商業規則或邏輯的COM元件。</li><br />
<li>建立一個和其他COM元件溝通的COM元件。</li><br />
<li>為一個COM元件增加錯誤處理。</li><br />
<li>為了要錯誤處理和除錯，將錯誤記錄下來到一個錯誤檔中。</li><br />
<li>規劃並建立給MTS使用的元件。</li><br />
  <ul><br />
    <li>讓一個COM元件支援交易處理。</li><br />
  </ul><br />
<li>為一個COM元件建立適合的伺服器類型(Server type)。類型有in-process、out-of-process和multithreaded。</li><br />
<li>使用MTS Explorer來建立和管理套件。<br />
  <ul><br />
    <li>將原件增加到一個MTS套件中。</li><br />
  </ul><br />
<li>利用使用者權限指定使用者只能限制使用某個MTS套件。</li><br />
<li>使用元件陳列庫去管理元件。</li><br />
<li>註冊和解除註冊一個COM元件。</li><br />
</ul><br />
<br />
建立資料服務<br />
<ul><br />
<li>使用ADO和RDS存取和操作資料。</li><br />
<li>使用VFP的原生資料處理和查詢能力(Query capabilities)(包含Local View)來存取和操作資料。</li><br />
<li>使用SQL pass-through存取和操作資料。</li><br />
<li>使用遠端資料集(Remote views)和本地資料集(Local views)來存取和操作資料。</li><br />
<li>管理資料庫交易以確保資料一致性和可復原性。</li><br />
<li>撰寫能取得和變更資料的SQL敘述。</li><br />
<li>撰寫使用連結(join)來從多個資料表格連結資料的SQL敘述。</li><br />
<li>撰寫能建立資料集(views)的SQL敘述。</li><br />
<li>使用適合的鎖定和緩衝策略。策略包括悲觀(pessimistic)、樂觀(optimistic)、列和表格。</li><br />
<li>建立和操作一個VFP stored procedure。</li><br />
<li>建立並實作VFP trigger。</li><br />
<li>從其他外在的資料來源匯入資料。</li><br />
<li>撰寫能更新及變更資料的SQL敘述。</li><br />
</ul><br />
<br />
建立實體資料庫<br />
<ul><br />
<li>以程式來建立和維護VFP的資料庫。</li><br />
<li>規劃、建立和實作資料庫和資料表格。包含了資料一致性(Data Integrity)、參考完整性(Referential Integrity)和正規化(Normalization)。</li><br />
<li>選擇並規劃一個索引策略。考慮最佳化(經由Rushmore)和索引維護。</li><br />
<li>建立並維護索引。考慮最佳化(經由Rushmore)、程式化的操作、視覺化的操作和索引維護。</li><br />
</ul><br />
<br />
測試並除錯<br />
<ul><br />
<li>決定適合的除錯技巧。</li><br />
<li>辨識和描述測試計劃的要素。要素包括beta的測試、回歸測試(Regression testing)、單元測試(unit testing)、整合測試(integration testing)和重點測試(stress testing)。</li><br />
<li>給予一個狀況，選擇適當的建立選項。(此處應是指在專案管理員裡按下建立後的一些選項)</li><br />
<li>在應用程式中使用條件編譯。(此處應是指#ifdef、#ifndef…等指令的應用)</li><br />
<li>使用除錯視窗(Debug Window)監控運算式和變數的值。<br />
  <ul><br />
    <li>使用即時運算視窗(Immediate window)來檢查或變更值。</li><br />
    <li>使用監看視窗(Watch window)來檢查或變更值。</li><br />
    <li>使用呼叫堆疊視窗(Call stack Window)來尋找錯誤。</li><br />
  </ul><br />
<li>在應用程式中使用 Asserts。</li><br />
<li>使用涵蓋分析工具應用程式來辨識效率瓶頸(Performance bottlenecks)和程式碼涵蓋範圍(Code coverage)。</li><br />
<li>使用事件追蹤來確定事件發生的順序。</li><br />
<li>設定中斷點以除錯應用程式。</li><br />
</ul><br />
<br />
散發應用程式<br />
<ul><br />
<li>使用安裝程式精靈去建立一個能安裝分散式應用程式、註冊COM元件並容許反安裝的安裝程式。</li><br />
<li>註冊一個實作DCOM的元件。</li><br />
<li>為客戶端電腦(Client computer)和伺服器端電腦(Server computer)設定DCOM。</li><br />
<li>為客戶端電腦設定以使用一個MTS元件，並且為客戶端電腦及伺服器端電腦設定遠端自動化(Remote automation)。</li><br />
<li>為一個分散式應用程式計劃並實作以軟式磁碟機或CD為基礎的散發程式。</li><br />
<li>為一個分散式應用程式計劃並實作以Web為基礎的散發程式。</li><br />
<li>為一個分散式應用程式計劃並實作以網路(Network)為基礎的散發程式。</li><br />
</ul><br />
<br />
為應用程式提供維護和支援<br />
<ul><br />
<li>為災難復原程序提出計劃並實作之。</li><br />
<li>修正錯誤並提早評估以預防未來的錯誤。</li><br />
<li>維護異常的報告。</li><br />
<li>為分散式應用程式散發應用程式更新。</li><br />
</ul>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553791.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553791.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Wed, 05 Sep 2001 10:31:29 +0800</pubDate>
</item>
<item>
	<title>VFP7 - Miscellaneous XBase Features</title>
	<description><![CDATA[
			本文譯自VFP7輔助說明中的Miscellaneous XBase Features

各種XBase的特色

VFP包含了一些新的且改進過的XBase特色,這些已經被包含在VFP語言之中.
這些包含了新工具,像是 Task List Manager(工作清單管理者), Object Browser(物件瀏覽器), IntelliSense Manager(自動完成管理), Accessibility Browser,Automated Test Harness(自動測試工具)和Web Services wizard(WebServices精靈).
這些東西在其他的What's New標題中有詳細的說明.

除了上面所提到的特色之外,VFP包含了其他豐富的XBase加強.
.新的Foundation Classes 已經加入了Microsoft Agent(代理人), Regular Expressions,Cryptography(密碼學),Enhanced File Open dialog boxes(加強的檔案開啟對話盒), Windows 2000 Logo Information, 和 Web Services 的相關類別.
.SQL Server的上移精靈包含了一些新的加強.
.新的 Solution 範例已經加入了怎麼使用新的特色以及foundation classes範例.
.一個新的COM+服務範例集合教導你怎麼使用帶有COM+服務的VFP伺服器.(COM+服務包含交易,佇列元件,COM+事件和補償資源管理者(Compensating Resource Manager,譯註1)).許多的範例教導你使用新的VFP伺服器加強功能.
.GENMENU已經更新,以支援新的選單圖形支援.一個新的編譯指示(#IMAGEPATHS)已經被加入以便全路徑(譯註2)被產生時能控制選單圖形.

譯註1:Compensating Resource Manager不是很清楚是什麼,所以翻的不好.另外這一句是倒裝句,所以我將對COM+服務的說明分離出來了,這樣應該比較容易瞭解.
譯註2:全路徑的意思應該是說像這樣子的情形 C:\TEST\TEST\TEST\TEST.JPG 發生時.
		]]>
	</description>
	<content:encoded><![CDATA[
			本文譯自VFP7輔助說明中的Miscellaneous XBase Features<br />
<br />
各種XBase的特色<br />
<br />
VFP包含了一些新的且改進過的XBase特色,這些已經被包含在VFP語言之中.<br />
這些包含了新工具,像是 Task List Manager(工作清單管理者), Object Browser(物件瀏覽器), IntelliSense Manager(自動完成管理), Accessibility Browser,Automated Test Harness(自動測試工具)和Web Services wizard(WebServices精靈).<br />
這些東西在其他的What's New標題中有詳細的說明.<br />
<br />
除了上面所提到的特色之外,VFP包含了其他豐富的XBase加強.<br />
.新的Foundation Classes 已經加入了Microsoft Agent(代理人), Regular Expressions,Cryptography(密碼學),Enhanced File Open dialog boxes(加強的檔案開啟對話盒), Windows 2000 Logo Information, 和 Web Services 的相關類別.<br />
.SQL Server的上移精靈包含了一些新的加強.<br />
.新的 Solution 範例已經加入了怎麼使用新的特色以及foundation classes範例.<br />
.一個新的COM+服務範例集合教導你怎麼使用帶有COM+服務的VFP伺服器.(COM+服務包含交易,佇列元件,COM+事件和補償資源管理者(Compensating Resource Manager,譯註1)).許多的範例教導你使用新的VFP伺服器加強功能.<br />
.GENMENU已經更新,以支援新的選單圖形支援.一個新的編譯指示(#IMAGEPATHS)已經被加入以便全路徑(譯註2)被產生時能控制選單圖形.<br />
<br />
譯註1:Compensating Resource Manager不是很清楚是什麼,所以翻的不好.另外這一句是倒裝句,所以我將對COM+服務的說明分離出來了,這樣應該比較容易瞭解.<br />
譯註2:全路徑的意思應該是說像這樣子的情形 C:\TEST\TEST\TEST\TEST.JPG 發生時.
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553780.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553780.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Tue, 24 Jul 2001 17:33:38 +0800</pubDate>
</item>
<item>
	<title>VFP7-高生產力的開發環境</title>
	<description><![CDATA[
			這篇文章也是在VFP7剛出來的時候翻譯的
後來有看到微軟中譯的文章
正好可以作個對照 ^_^

下載網址如下:
我翻譯的
微軟官方翻譯的
		]]>
	</description>
	<content:encoded><![CDATA[
			這篇文章也是在VFP7剛出來的時候翻譯的<br />
後來有看到微軟中譯的文章<br />
正好可以作個對照 ^_^<br />
<br />
下載網址如下:<br />
<a href="vfp7_HighlyProductive/vfp7_HighlyProductive_ms.zip">我翻譯的</a><br />
<a href="vfp7_HighlyProductive/vfp7_HighlyProductive_self.zip">微軟官方翻譯的</a>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/553735.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/553735.html</guid>
	<category>Visual FoxPro</category>
	<pubDate>Tue, 30 Nov 1999 00:00:00 +0800</pubDate>
</item>
</channel>
</rss>