2012年2月14日星期二

jQuery ajax.responseText注意事項

jQuery操作ajax技巧是相當方便的,
但是操作ajax.responseText,不得不注意到同步問題,如下面的例子:

var rtxt = $.ajax({type:"GET",
                   url:"empl.cfm",
                   data:{eno:"A001",
                   dept:"A"},
                   async:true}).responseText;
var msg = eval(rtext).message;
alert(msag);

這個是以 jQuery 利用ajax非同步呼叫 empl.cfm 頁面取得人事資料,而該頁面會以 JSON 格式回傳,該格式結構裡面會包含 message 的變數。

這個看似正常的程式碼其實隱含著很大的問題,
測試過程中,當伺服器回應在200ms以內時這個畫面會顯示 msag 內容,
當大於 200ms 就容易出現無反應 ( alert沒有執行 )。

後來反覆檢查的結果,發現原來是 async 參數會作祟,當 async為 true 時,ajax 為非同步運作:請求頁面同時,script 繼續執行並不等待請求回應,由於 responseText 指令在執行時會需要瀏覽器即時編譯,當編譯完成執行時,若請求的頁面已經返回回應資料,則此時會正常的繼續執行,若請求頁面來不及在編譯執行前返回回應資料,則會造成 rtxt 變成 undefined 狀態,使得接下來的 eval(rtext) 也變成 undefined ,如此直接取得結構 .message 時就會導致 javascript 執行錯誤停止。

當然正常的情況可以不要加入 async 屬性,因為其預設值就是 false 狀態。

2012年1月20日星期五

programming DLL using C/C++ for Powerbuilder external function

真的,用PowerBuuilder的人實在太少了,再加上又會寫C語言作為輔助的更是寥寥可數,只好自己用功一點『自學』了。

C語言有很強大的功能,但每種版本的C語言又有許多的不一樣(C、C++、C#、Object C...),真的學起來相當辛苦,如果電腦原理基礎觀念不好,操作C語言可能真的會成為夢饜,雖然C++與C#有許多強大的功能與函式,但是作為可以被『異種』程式語言呼叫的獨立函式庫,可能就非常不理想,因此需要以標準的C語言編譯,讓其他程式可以使用就是一個原則(這是我的想法,如果你有不同的意見歡迎提出)。

雖然C語言的原始碼可以跨平台,不過會由於編譯器的不同而有不太一樣的指令方式。
例如,我的開發環境在Visual Studio 2005底下,使用到某些C指令就會有所警告,像是:
strcpy => strcpy_s
strdup => _scrdup
諸如此類,雖然編譯會發生警告,但是還是可以使用。但是以 Visual Studio 的觀點來說,這些都是被列為不安全的指令。所以我撰寫的程式碼都是在符合 Visual Studio 環境底下設計的,若你需要使用到原本C語言原始指令,就可能要自行改寫或是參考一下MSDN的說明了。

好了,來說說如何製作一個標準的DLL供 PowerBuilder 使用吧(不一定限定PB,也可以是VB、Delphi之類):

首先,你必須建立一個新的專案(部分C開發環境沒有專案概念,例如:Dev-C,每個檔案都必須自行建立與整理)
然後 Project-type 選擇 Visual C++ ,點選以後,再選擇 Win32 Project,
輸入 name 專案名稱,以及選擇專案儲存的路徑 Location,按下 OK,
進入 精靈 畫面時,選擇 Application Setting,右側選擇 DLL,再按 Finish 即可。

有人說用 MFC 也可以建立 DLL,這也是可以,但是 MFC 的 DLL 必須仰賴 MFC 函式庫,若只是單純的簡易處理 PB 不足之處(例如二進位運算),說實話,做好的 DLL 還要包(Packged)上一堆 MFC 函式庫實在不單純啊,PB本身的 Runtime 已經很肥了,再加上這堆用不到的 MFC 程式會變更肥啊,請好好考慮一下吧。

建立專案以後就是撰寫程式的重點了,如果對於下列程式碼有疑問的地方可以先看看後面的參考網頁,可以了解一下為啥麼要這麼作了:

我用 test2 來建立專案名稱,這個專案會建立下面的檔案:
會看到一個 test2.cpp 的檔案,主要就是撰寫這個檔案內容,當開啟這個檔案後會看到這個檔案已經有一些內容,這些內容是標準的 C++ DLL 基本的語法結構。

這時在內容最下方加入
#ifdef  __cplusplus
extern "C" {
#endif

/* 函式寫在這裡*/

#ifedf __cplusplus
}
#endif


這個宣告的意義在於,由 extern "C" 所包起來的內容將在編譯時,編譯成標準 C 指令的函數。
而裡面函式的標準寫法如下:
__declspec(dllexport) 回傳型別 __stdcall 函式名稱(參數型別 參數名稱1,參數型別 參數名稱2,...){程式碼陳述;}
例如:

__declspec(dllexport) int __stdcall Add2U(int *i, int *j)
{
//數值傳址方式操作,可以改變原始內容
int f,x;
f = *i + *j;
x = *j;
*j = *i;
*i = x;
return f;
}

__declspec(dllexport) char* __stdcall stringToUpper(char* src)
{
//字串內容小寫轉大寫
char* dest = _strdup(src);
char* trg = dest;
for(; *dest != '\0';dest ++)
*dest = (char) toupper(*dest);
return trg;
}


有了以上內容可以當然直接編譯(Build Solution),的不過這樣PB還是會呼叫不到,因為__declspec(dllexport)之後函數名稱會被編譯器轉換,導致無法取得正確的名稱,所以必須自己建立定義檔(.DEF),所以需要在 Source Files 底下新增一個 def 檔:

新增了以後,打開 test2.def 檔案並加入下面的定義宣告,這是標準API的宣告方式,才能讓其他程式找到該 DLL 函式庫內的成員:

LIBRARY "test2"
EXPORTS
Add2U @1
stringToUpper @2


此時,就可以使用『Build』>『Build Solution』,建立好了以後可以在該專案路徑下找到『debug』資料夾,底下就會有一個 DLL 檔案,把這個檔案複製到需要呼叫它的PB程式路徑下就可以引用了。

PB的引用方式,先在 external function 定義:
function int Add(ref int x , ref int y) library "test2.dll" alias for "Add2U"
function string ToUpper(ref String  strss) library "test2.dll" alias for "stringToUpper"


然後就快樂使用囉!





參考:函數調用規則__stdcall__cdecel區別在C++底下建立DLL__declspec(dllexport)與.def文件

2012年1月9日星期一

利用 coldfusion 實作 CAPTCHA 驗證功能

 我當然知道這樣輸入很沒效率,但是這是目前比較好的防廣告文手段。

CAPTCHA,中文常被稱為『驗證碼』,其全名為 Completely Automated Public Turing test to tell Computers and Humans Apart (全自動區分計算機和人類的圖靈測試)。媽呀,好長的名字!!!

需要詳細瞭解者可以看中文版維基的解釋或是英文版本的。

如果需要輕鬆一點的可以看看 直角兄-淺談各式各樣的網路圖形驗證碼(Captcha)

因為網路上我真的找不太到中文關於使用原生 CFML 來設計 CAPTCHA 驗證碼的文章,

真的有點感嘆,所以就自己動手寫起來以備日後的紀錄與查找。

原始碼出處:http://www.bennadel.com/blog/873-Using-CAPTCHA-In-ColdFusion-8.htm

當然英文看不輪轉的就看我這裡的吧,我已經把註解都中文化,並且稍微修改了一些。

2012年1月4日星期三

SQL [Sybase] 於輸出數值前方補上0

參考來自這篇文章,只是 Sybase SQL 的指令不如 Microsoft 來得多,所以改寫成自己要的方式。

很多時候,公家機關特別喜歡的EDI格式都是固定長度的欄位資料,尤其是數字前面要補零的。

在 SQL 語法上就沒那麼便利像 Powerbuilder 的 String 指令,可以直接給一個 Format,

因此就需要一點變通了,

先來看一看舊式寫法好了,這是使用長度計算後的捕入方式:

DECLARE @Number INT ,@Digits INT ,@Result CHAR(8)

SELECT @Number  = 123

SELECT @Digits = 8

SELECT replicate('0',@Digits - char_length(Convert(varchar , @Number)))+Convert(varchar , @Number)


Convert(varchar , @Number) 將該數值先轉換成字串值,使用 varchar 可以得到與數值相同字元長度的字串。

2011年12月29日星期四

CFSCRIPT是什麼?


來聊一下什麼是 CFSCRIPT 吧:

ColdFusion 使用的基礎語言是 CFML ,原文:ColdFusion Markup Language。

意思是 Coldfusion 標記語言,就跟 HTML 一樣屬於標記式 ( tag ) 的程式語法。

相關的資訊可以在維基網站查得到,這裡不再多述。

那麼有了 CFML 後為什麼又需要 CFSCRIPT 了呢?

2011年12月28日星期三

Coldfusion如何使用編/解碼

以下程式碼可能需要CF9以上的版本,目前測試 Railo 3.3 可以正常運作。

傳遞資料的時候有時候須要將資料進行編碼或是解碼,

雖然 javascript 可以完成這樣的工作,

但有時候因為隱匿的關係不希望使用者端解譯其運作原理,所以最好是在 Server 端完成。

Coldfusion 可以處理基本的編解碼有三種形式:


  1. Hex:
  2. use the characters 0-9 and A-F to represent the hexadecimal value of each byte; for example, 3A.
  1. UU:
  2. use the UNIX UUencode algorithm to convert the data.
  1. Base64:
  2. use the Base64 algorithm to convert the data, as specified by IETF RFC 2045, at www.ietf.org/rfc/rfc2045.txt.


比較常見的大多是 Base64吧。

以下是完整的測試網頁:

2011年12月27日星期二

在CFSCRIPT下使用Cookie

Coldfusion繼續來玩Cookie吧,

注意下面的操作可能需要CF9以上的版本,Railo 3.3 以上的版本執行上沒有問題。

繼上一篇 Using cookie in CFML 之後,如果想在 Cfscript 中使用cookie的操作要怎麼辦?

目前尋遍 adobe 官方文件得到的結果是:
Direct assignment of Cookie scope memory-only variables. You cannot use direct assignment to set persistent cookies that are stored on the user's system.
真是沒輒!!

但是還是有辦法操作的,就是利用 cf-tag 與 cfscript 混用:

首先,寫一段處理 cookie 的 Function :

<cffunction name="setCookie" access="public" returnType="void" output="false">
 <cfargument name="name" type="string" required="true">
 <cfargument name="value" type="string" required="false">
 <cfargument name="expires" type="any" required="false">
 <cfargument name="domain" type="string" required="false">
 <cfargument name="httpOnly" type="boolean" required="false">
 <cfargument name="path" type="string" required="false">
 <cfargument name="secure" type="boolean" required="false">
 <cfset var args = {}>
 <cfset var arg = "">
 <cfloop item="arg" collection="#arguments#">
    <cfif not isNull(arguments[arg])>
        <cfset args[arg] = arguments[arg]>
    </cfif>
 </cfloop>
 <cfcookie attributecollection="#args#">
</cffunction>