hit counter for blogger

黑暗執行緒

 黑暗執行緒搬新家囉!! http://www.darkthread.net

12/29/2006

TIPS-抛棄式的Email信箱

今天看到Goston分享了一招 [資訊] Google Gmail 防止廣告信的一個小技巧

跟許多人一樣,我也是今天才發現Gmail有這項方便的功能!  如Goston所提,有時會瀏覽到某些"想看東西必須註冊會員,並需要透過e-mail寄發啟用密碼"的網站,常常註冊後不久,垃圾信就有如淊淊江水,綿綿不絕~~ 弄到每次要在網站留e-mail就心驚膽跳。針對這種不想留下真實e-mail卻又要收信的需求,我就再分享另外一個在ReviewIT Blog文章看過的好東西---拋棄式的電子郵件信箱!

http://www.2prong.com 是一個免費的e-mail服務,它可以自動幫你產生一個e-mail地址(或者你也可以自訂收信人名稱),只要保持瀏覽器開啟,它便會即時將寄到該信箱的信顯示出來。這樣我們就等於有了一個只用一次的收信專用信箱,非常適合拿來了應付那些需要收信又不想留真實信箱的場合。而且為了怕被鎖定後列入黑名單,它的Domain Name會每週自動更換一次,好個貼心又周到的服務! 不過依我使用的經驗,處理中文信件時會有編碼錯亂的問題,幸好帳號啟動信件中的URL Link才是重點,一般來說,即使內文是亂碼也沒啥大礙!

不過,應用時要留意它"用過即拋"的特性,如果還打算用該信箱未來還需要陸續收到信件,可以考慮前述Gmail或Yahoo的信箱別名功能。

12/28/2006

KB-Oracle 9i NVarchar求生守則

同事反應,一個CharacterSet設為ZHT16BIG5的Oracle 9i的資料庫,其中某個Table的NVarchar2欄位完全不接受非BIG5字元,存入時會變成"?"。攪和了近一個月,反覆嘗試了多種工具、方法,也請教了朋友、求助Oracle Support、查了Oracle KB,結論幾乎都指向---"Oracle 9i的NVarchar在非UTF8字元集資料庫裡無法接受非BIG5字元,而會將其轉為問號。要解決這個問題的唯一方法是是將資料庫字元集設為UTF8,或將Client & Server都昇級至10g R2"。(注意: 後來驗證的結果,這個結論不完全正確,但至少對N'...'表示法來說是如此)

直到今天,有機會重試一份簡單的Sample Code,碰巧又用對了檢查工具,才總算理出些頭緒。先來說說為什麼情況為什麼變得這麼複雜?

1.測量之前,先確定你的尺是直的!
    這大概是這次摔最慘的地方: 你所使用的資料庫查詢工具可以正確地顯示非BIG5字元嗎? 用慣MS軟體與工具的人大概自WinNT時代起就很少擔心Unicode相容性問題,但這回常用的Oracle的搭配工具幾乎全軍覆沒! Oracle自家的SqlPlus都到9i版本了還不支援,著名的Toad看來也不行! 倒是發現純Java開發的Aqua Data Studio 只要UI設定支援Unicode的TTF字型,顯示OK;另一個用.NET寫的QueryExpress若選用Oracle Driver(意味要用Microsoft OLE DB Provider For Oracle而不是Oracle Provider For OLE DB)時,也可以順利無誤地顯示Unicode字元。
    搞錯了工具,有可能INSERT成功了還不自知,或許一開始就被錯誤的觀察結果給耍了,白繞了一大圈。
[2006/12/28 Update]
還有一把歪歪的尺忘了說,.NET Console Application也不Support Unicode,而會以ANSI方式輸出,因此要視OS設定而定;我的Windows預設非Unicode語系當然是BIG5,這讓用Console App寫Test Code的我又多花了半小時...

2.用英文跟老外搭訕前,先確定他懂英文
    MS SQL我用了N年,連我的膝蓋都認同N'...'表示的就是NChar字元。這個語法在Oracle 9i也支援,只可惜處理法則跟想像的很不一樣。即使用N'...'標示的Unicode字串,Oracle 9i資料庫也堅持用自身設定的字元集去解析,把不認得的字元換成?或¿再存入資料庫... 這... 這會不會太雞婆了點? 字串前的N難道是加心酸的?
    由於沒想到N'...'在資料庫字元集為BIG5時根本是黑心貨,花了大把時間做的測試純屬虛工。用N'...'測試的結果,加上幾位有Oracle奮戰朋友的佐證,推導出"除非資料庫字元集改為UTF8,否則NChar就只能接受BIG5字元"的悲觀結論。
(Oracle文件倒是提供了一些替代方案,NCHAR(505055)、UNISTR('\20AC')、chr(14844588 USING NCHAR_CS),但要把原本簡單的欄位值指定程式改成這副德行,讓人想要寫個"慘"字)

最後因緣際會下,用最原始的.NET Sample再試一次,加上湊巧用QueryExpress的Oracle Driver模式查詢,看到Oracle資料表中出現三頭牛疊羅漢(犇是這次拿來測試非BIG5的字元)的一剎那,我當場濕了眼眶~~~

正確來說,Oracle 9i的NChar, NVarchar並不黑心,只是嬌貴的它需要我們留意各項細節,小心對待才能正確地儲存資料。以下我歸納出用.NET正確Insert非BIG5字元進Oracle 9i BIG5資料庫的注意事項:

1.使用cmd.Parameters指定參數,而不要用Ad-Hoc方式組N'...'

OracleConnection cn = new OracleConnection(cnStr);

OracleCommand cmd = new OracleCommand (

"Insert Into NCharTest Values (:VC, :NVC)", cn);

cmd.Parameters.Add("VC", OracleDbType.Varchar2).Value = "牛犇";

cmd.Parameters.Add("NVC", OracleDbType.NVarchar2).Value = "牛犇";

cn.Open();

cmd.ExecuteNonQuery();

cn.Close();

2.記得明確宣告OracleDbType.NVarchar2(ODP.NET)或OracleType.NVarChar(System.Data.OracleClient)。我同事疏忽的地方便是用了cmd.Parameters.Add("VC","牛犇")的寫法,.NET自行決定的OracleDbType顯然不是NVarchar。

3.據Oracle官方文件表示,10g R2以後的版本已移除對NChar不當解析的問題。

12/23/2006

KB-Modal Dialog Mini FAQ

或許有些人對Modal Dialog不是很熟悉,基本上它就是由某個網頁另外開啟的一個網頁,但新開啟的網頁會強制取得焦點,直到該視窗關閉後才歸還,它特別適用於彈出另一個網頁強迫使用者檢視、選擇或輸入後再返回的場合。要套用這種強制使用者選擇、操作後再返回的模式,可以透過window.showModalDialog(sURL [, vArguments] [, sFeatures])函數,以Modal Dialog方式開啟指定的網頁即可。

Modal Dialog在網頁UI設計實務上還挺常見的,例如: 寫信時叫出連絡人清單視窗供使用者挑選收信人、在清單中選取一筆資料編輯後返回清單…等等。使用Modal Dialog可以避免另開的新視窗跑到背景、被最小化後不知去向的混淆。

不過,Modal Dialog是個很有個性的視窗,與一般的Window Object的行為不太相同,以下是一些經驗談:

Q1. Modal Dialog要怎麼控制大小位置?
Ans: 利用dialogWidth, dialogHeight, dialogTop, dialogLeft屬性

Q2. 如何偵測網頁是否開在Modal Dialog中?
Ans: if (widnow.dialogWidth) { alert("I am inside modal dialog!"); }

Q3. 網頁叫出Modal Dialog後,可以對其中網頁DOM進行操控嗎?
Ans: 母網頁跟Modal Dialog間沒有直接控制的管道,只能透過呼叫時傳遞參數過去(我習慣將整個Window Object傳過去,這樣就可以在Modal Dialog中存取完整的母網頁HTML DOM)。但無論如何,母網頁永遠只能扮演被動的角色,存取操作的主導權在Modal Dialog身上,這符合由Modal Dialog取得焦點,並主導操作的原始精神。

Q4. 放在Modal Dialog中的ASPX/ASP,在按下按鈕(Submit/PostBack)或點選連結時會另外開啟新視窗,要如何解決?
Ans: 可加上<base target="_self">宣告,或用Iframe嵌入ASPX網頁(後者實在有點小題大做,當我沒說好了)

Q5. Modal Dialog有什麼不方便的限制嗎?
Ans: 罄竹難書~~~
  1) 不支援history.back()history.go()
  2) 沒有地址列(Address Bar)及上一頁/下一頁的按鈕列(Standard Buttons)
  3) 不能使用右鍵叫出IE的Context Menu,所以不能列印、不能選取/複製、不能切換語系、不能Refresh...
  4) Modal Dialog對於Cache的堅持讓人敬佩,明明網頁都設定Response.Expires=-1或指定No-Cache了,Modal Dialog卻還是有偶爾會去讀到Cache中的舊資料。因此我常會在開啟URL加上亂數加以預防,例如: showModalDialog("a.aspx?rnd=" + Math.random(),window);
  5) 我有發生過在Postback前後,同一網頁的Body Margin產生位移的怪事,解決方法是隨便為網頁套用CSS(即使該CSS檔不存在的也成,絕吧?)即可克服。

12/22/2006

TIPS-如何停用工具箱的自訂控制項清單產生功能

這個痛苦只有自己寫Control的人才能體會! 在大型專案中,有時我們會將程式邏輯封裝在自訂的UserControl(使用者控制器)或Custom Control(自訂控制項,我則習慣叫它自訂控件)裡,以求能快速組裝及反覆利用。在我看過的一些專案(例如: Community Server)中,Solution中就包含了近百個UserControl。結果只要一切換到ASPX的Design頁面,就要花上數分鐘看工具箱裡冒出一個個小齒輪...

原來這又是VS 2005提供的新功能,在顯示工具箱時,會自動掃瞄專案裡出現的User Control及Custom Control,一一加入工具箱中,讓你可以在工具箱中找到自訂的Control,直接拖拉到ASPX的頁面上。這個貼心的設計方便歸方便,但當你的專案中的自訂Control數目很多時,忍受漫長的自動清單產生過程,實際上需要直接拖拉自訂Control的時機卻很有限,並不划算!

 

 

 

 

 

所幸VS 2005提供了選項,可以讓我停用這個雞婆的自動化功能,如下圖:

12/21/2006

Visual Studio 2005 SP1 來了

最近有點小忙,今天才發現Visual Studio 2005 SP1已經正式Release快一週了,依據Scott Guthrie的說法,VS2005 SP1除了將Web Application Project納為系統內建選項之外,還做了不少效能上的提升。由於一直對VS 2005 IDE的操作流暢性及Build速度有點意見,當然迫不及待想把它裝起來玩玩。(VS 2005 SP1可以在微軟網站下載: 英文版中文版,430M左右)

可惜安裝過程沒有想像中順利,前後重試了五次:

第一回合,跑了一陣子才警告我要將先前裝的Web Application Project套件移除,移除後重來一次。

第二回合,安裝程式停在"Gathering Required Information"的同一進度上約5分鐘,CPU 100%,HD無動作,耐性不夠的我以為當掉了,Cancel後重來。

第三回合,這次耐心十足地等了快半小時,終於結束了蒐集資訊的程序,卻警告我Windows Live Messenger沒關閉,將Messenger關掉後按Retry,它老兄居然又重頭開始蒐集必要資訊... orz

第四回合,又經過了20分鐘,進度顯示剩53秒時,出現Error 1718 *.msp did not pass the digital signature check,安裝過程整個Rollback! orz  Goggle了一下,找到這篇PostKB,如KB指令修改了Policy再試一次。(記得安裝完後,要將All users except local administrators的例外設定改回All users)
VS2005SP1Error

第五回合,又半小時過去,總算安裝成功了!
(過來人的建議: VS 2005 SP1安裝期間常會陷入CPU 100%,HD無動作的冥想狀態,請保持耐性,安裝SP1耗費時間長短將視你安裝VS 2005項目的多寡而定;若VS2005為完整安裝時,花上一小時應該也不稀奇。安裝前建議先依KB的說明修改Security Policy (For Window XP & Windows 2003),並關閉其他應用程式,發生突發狀況重來的機會會少一點。)

裝好後重新開啟VS 2005,可以看見新的Web Application Project選項。

VS2005SP1WAP

我嚐試了一下,HTML Source Editor的操作回應感覺有快一點,至於Build Web Site的速度,感覺有些許提升,但不是十分明顯,我認為仍在心理作用的誤差範圍內。Anyway,既是Service Pack,沒有不安裝的理由,大家找個時間,泡杯熱茶,動手安裝吧!

12/17/2006

KB-Unicode編碼解析小工具

以下是一小段我對Unicode的粗淺了解, 希望對深陷其中的云云眾生有所幫助:

1. Unicode是為了應付全世界所有文字符號編碼而發明的,古早的ASCII Code只能表示255個字元,所以Universal Character Set-2(UCS-2)的標準被制定出來,以16bit表示文字,企圖容納世界上所有文字符號,目前(Unicode 2.0)已經制定了38,885個字,但仍有許多國家的文字與符號仍未被納入,餘下的26650個字肯定不夠用。因此目前又有UCS-4的誕生,以4個位元組來表示一個字符,未來將可容納20億個字元集。Windows NT以後的版本,其核心已採用Unicode作為文字編碼標準,採用的便是UCS-2。

2. Big5是古早前制定出來以2個Byte表示中文的編號法則,英文部分仍是以一個位元組表示,在這種混合長度的編碼法則中,由前一個字元來決定接下來的字元與他成為一個中文字或是另一個獨立英文字母。

 3. UCS-2固定以兩個位元組表示一個字,即使是英文字母也佔要2Byte,因此UTF(UCS Transformation Format)-8就誕生了。它是UCS-4標準的一部分,和 Big5的原理類似,英文只用一個byte,中文或符號就用2-3個byte。就純英文而言,可以大量減少資料量,但用在中文字上則比UCS-2多了50%(2 bytes vs 3 bytes)的資料量。

維基百科上有關於上述標準的完整說明,有興趣的人可以看看: UCS-2/UTF-16UTF-8BIG5Unicode。另外在台灣,為了彌補BIG5字碼不足的問題,也有BIG5e狗尾續貂,若以與世界接軌的觀點來看,還是應該回歸Unicode,向世界標準看齊才是王道!
(這篇由 堃(方方土) 探討 Big5e 編碼的文章,是我了解Unicode的入門讀物,解釋得挺清楚,推薦給大家看)

處理中文亂碼問題,常要檢核二進位資料才能抓出問題所在,所以我寫了一個小工具,可以輸入文字顯示BIG5、GB2312、UCS-2、UTF-8編碼的十六進位資料解析,在檢核編碼是否正確時相當好用,有興趣的人可以按這裡下載。(需要.NET 2.0)

EncAnalyzer

12/15/2006

TIPS-如何修改Reporting Service的報表匯出選項

Reporting Service的每一張報表都可以匯出成HTML、PDF、Excel等多種格式,是很好用的功能。但在某些狀況下,你可能希望限制使用者只能匯出其中的幾種格式。

RSExportOption

有兩種做法,如果你希望在停用整個Reporting Service對某種匯出格式的支援,可以修改RSReportServer.config,調整Render Node下的Extension。

RSConfigFile

如果只想針對某幾張報表隱藏某幾個選項,則可以修改Reporting Services\ReportServer\styles\htmlviewer.css後另存一個新的limitedExport.css,就可以在CSS中動手腳。連線時則要加上rc:stylesheetcommand=limitedExport,就可以讓CSS中的設定或Javascript發威。只是這種做法會在沒有指定StyleSheet時失效,這點要留意!

12/14/2006

KB-IIS重裝後的Reporting Service還原

算是特殊案例,但還是寫出來給萬一遭逢此等不幸的人參考。

狀況是: Reporting Service所在的IIS毀損,但資料庫、Reporting Service的相關檔案安然無恙。重裝IIS後,原本的Reports與ReportServer兩個Virtual Directory當然就遺失了,另外找了一台正常的Reporting Service作為參考,重建Virtual Directory後(注意: Reports的使用權限(Execute Permission)為"指令及執行檔",而ReportServer則為"無"),連上/Reports,卻得到以下訊息:

The underlying connection was closed: Could not establish secure channel for SSL/TLS.
下列連接已經關閉: 無法建立 SSL/TLS 的安全通道。

Google了一下,找到問題所在。先前在建ReportServer目錄時,對它的使用權限要設"無"就滿心狐疑,心想,明明有asmx,怎麼會是無呢? 後來找到這篇文章,提到了加掛"*"的Appliction Extensions Mapping的步驟,消除了我的疑惑,也解決了問題。Reporting Service又還魂了~~~

RSDR

12/13/2006

KB-VS 2005中拖入自訂網頁控制項時出現錯誤

在VS 2005中要將自訂Web控件(Custom Web Control)拖入ASPX時發生以下錯誤: (我的經驗多發生在控件改版後)

Control cannot be created because Visual Studio cannot find the control’s type in the control assembly
無法建立控制項,因為 Visual Studio 在控制項組件中找不到控制項的型別。

網路上有不少討論(例如: 這裡這裡這裡),但似乎都跟我的問題不太一樣。最後我找到的解法是將BIN下原本已存在的控件相關.DLL檔刪除,再次拖拉控件時,VS 2005會重新複製一份DLL過去,問題就可以解決了。

12/12/2006

KB-失控的HTML物件

當你在VS 2005中新增一個ASP.NET網頁,預設會套用XHTML標準,也就是你會在頁首看到這麼一列DOCTYPE的宣告: (想多了解一點DOCTYPE的人可以看這裡)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

過渡型的(Transaitional)的XHTML Schema是三種DOCTYPE標準中最隨和的一個,但套用在我們過去慣用HTML的"隨便"寫法上,還是會引發一堆語法警告及錯誤(想眼不見為淨的人可以參考這裡)。除此之外,我開始陸續發現,套用XHTML規格後,在解析既有的HTML Code時,顯示結果有時會有差異。

例如: 我從以前的網頁中Copy了以下這段HTML Code,插入到VS 2005新建立的ASPX中,打算定義一個600x300的TextArea
<textarea style="width: 600; height:300" id=T></textarea>

結果,用IE 6/7看,TextArea會變成只有160x36的哈比人,而且不管怎麼改變width的值,TextArea都不動如山,完全失控。最後我才發現,得修改成style="width: 600px; height: 300px",它才會正常顯示。

我查了W3C上的XHTML 1.0相容性說明,沒看到這一點,利用W3C的Validator檢查,也未指出此一錯誤。本來的推測是,或許IE解析HTML及XHTML規格的Parser是兩個Team寫的,對這種小細節,雙方處置的標準不一所致,但後來試了Firefox發現也是同樣的結果,因此看來是XHTML對style宣告要求更嚴謹所造成的吧! 不過,先不用緊張要去全面Review HTML Code,反正全世界目前仍有93%的網頁都不符合XHTML的規範,大家就一起同流合污吧!!

總之,若下次網頁移至VS 2005後出現這類異常,記得先將DOCTYPE宣告移除看看。

12/06/2006

KB-在Reporting Service群組中顯示頁數

Reporting Service報表的群組概念十分實用,例如: 若要以報表方式產出信用卡帳單,只需加上Group By ClientId,就可將上百名客戶的數千筆消費記錄,依客戶別彙整成一份份帳單,再整合成一大份報表,方便一次全部列印出來,再分裝寄發。

但問題來了,每個客戶的帳單可能有多頁,帳單印上”第幾頁/共幾頁”本是天經地義的事。Reporting Service中有Global!PageNumber及Globals!TotalPages的屬性,做到這一點似非難事。但是這兩個屬性只能在整個報表的Page Header區使用(也就是只能算報表中所有客戶帳單總頁數),在Group Header或Detail中呼叫會產生Error,網路上有人試過了Me.Report.Globals繞路法,可以在Group Header或Detail區讀到這兩個數字,但它們的值卻會永遠傳回1。有人想出了Reset PageNumber的巧妙做法,但仍無法知道該Group共幾頁? 我靈光一現,想說何不每個客戶一個SubReport,在SubReport中的Page Header區,總頁數總會正確吧? 很可惜,事情並不像憨人所想的哈泥甘單,SubReport的Header & Footer一律會被忽略而無法顯示,精心想出的妙計又摃龜了。

搞了半天,幾頁之幾這麼基本的要求,Reporting Service做不到就是做不到,我Google了好一陣子,最後自己做過實驗後,終於死心了。由於Group Header跟Detail要全部Render完,Reporting Service才依這些Content的高度算出總共有幾頁,等算出來時,Group Header與Detail的內容早就定死了。故得證,除非Reporting Service改變Rendering的機制,要在Group中取得TotalPages肯定是無解了!! 莫非得砸下銀子改買Crystal Report之類的報表工具才能解脫? 

眼看為一個理所當然的小小頁碼,Reporting Service竟形同廢物,心有不甘。我決定換個方向,不再硬碰硬,逃出PageNumber跟TotalPages的死胡同。一個另類的想法是,如果單一份報表中, PageNumber跟TotalPager才能正常使用,那就一個客戶獨立出一份報表吧!

利用ASP.NET設計如下的查詢介面,依User提供的條件,可列出多個客戶的報表連結(每個報表參數不同,等同於多份彼此獨立的報表),點下連結後可檢視該客戶的報表。這樣就解決了查詢單一客戶報表的功能,足以應付大部分的查詢需求。(如下圖)

RSGrpPaging1

然而,這種做法與多客戶帳單組成一份報表,最大差別在於無法一次列印全部的帳單。於是,我從Reporting Service線上列印的功能偷出以下的程式碼,寫成一隻直接印表程式(RptPrint.aspx):

RSIssue3

只要在hdnRptSvr及hdnRptUrl中填妥報表相關的網址及參數,RptPrint.aspx就會直接啟動Reporting Service的線上列印功能,跳出選擇印表機的對話框,可預覽報表,或按確定直接列印。(如下圖)

RSGrpPaging2

有了這隻好用的直接列印程式,只要在剛才的清單頁面上用javascript跑個for loop,將N個客戶的報表URL當作參數,再以showModalDialog方式循序開啟RptPrint.aspx,就可以一口氣將N個客戶的帳單印完。現在只剩下一個棘手的問題---RSClientPrint.Print()時並不會直接輸出到印表機,而是帶出如上的印表對話框,User必須按下確定後才開始印表。這意味著如果要出1000個客戶的帳單,User得泡杯茶,帶本小說,坐在電腦前等著按1000次確定,既無聊又無奈。

留下這個尾巴,這個解決方案還不算可行。因此我參考IEUnit中威力強大的Win32Dom.Desktoop物件,寫了一個會自動按"確定"的小幫手程式。當要大量印表時,它會不斷監控是否有RSClientPrint彈出的印表對話框,一旦發現,就瞄準"確定"鈕大力按下去,由預設印表機輸出報表。如此,批次印表的流程總算是一氣喝成了!

透過這幾記怪招的巧妙組合,算是克服了頁碼與批次列印無法兼得的困境。但還是祈禱MS能在未來的Reporting Service改版中,從核心層次解決Group中使用頁碼的問題,才是治本之道;在此之前,大家可考慮用這種方法頂著先。

KB-Reporting Service Paging By Group

Compared to those 3rd party reporting tools (ex: Crystal Report), SQL Reporting Service, which is bundled with MS SQL Server,  is almost free and tightly integrated with VS.NET and IIS.  It seems the **BEST** option for ASP.NET developers. (Once upon a time, I doubted how Crystal Report can survive?)

After using Reporting Service(RS) at some real, complex, but 100% practical reports, I begin to find features that RS can't support and know why Crystal Report can survive.  The most serious problem is -- I can't show page number in group headers.(How serious? It made me want to give up RS and began to survey alternative reporting tools.)

For example, I want to generate credit card bill for 1,000 client, Of course I design a report, using "group by ClientId" to combine several clients' bill in single report.  When the client gets his n-pages bill, he surely wants to see the "Page m of n"  on the bill header.  It's really a common and must-to-have requirement, but I found RS just can't do it!!

You can use Globals!PageNumber and Globals!TotalPages on page header zone to get "Page m of n".  But these global properties can't be used outside page header, many smart guys had tried their best, including "Me.Report.Globals!PageNumber" method (failed, it always gets 1/1), resetting page number method (here, here) (it can't get total pages)

Why it's so hard to do so simple work?  After some research, I think there is no way to get total pages inside groups!  Here's my experiment:

I put three TextBox to trigger log writting and alocate them in page header, group header and list detail area.

RSIssue1

Code.WriteLog() will append some information to a log file.

RSIssue2

Here's the log:

18:18:39 Group Header
18:18:39 Detail 2301
18:18:39 Detail 2302
... Ignored ...
18:20:28 Detail 2398
18:20:28 Detail 2399
18:20:28 Page Header
18:20:28 Page Header

In the log file, I found the truth!!  The group header is rendered only at the first page of group, then details are rendered row by row.  Only after all group headers, detail rows are completely rendered, RS begins to assembly group headers, detail rows, calculating content height, split pages and finally gets the number of total pages.  When it knows TotalPages, group headers and detail rows are already rendered and can't be modified.  So there is no way to know TotalPages inside group header or detail row, unless RS change the way of rendering. (The order of rendering also explained why Me.Report.Globals method always return "1 / 1".) To get total pages inside group, maybe a "preview rendering" is necessary to calculate the total pages, then the "real rendering".  But if the height of group header changes (maybe depends on TotalPages) in the "real rendering", then the TotalPages need to be recalculated... (Recursive? orz)

Really hard, right?  Maybe it's tough for Microsoft Reporting Service team, too.  So this paging by group is not included.

I am still trying to find a solution.  The only idea I have is to make the report only for a client, then the PageNumber and TotalPages works fine in page header zone.  What if I want to print 1,000 clients' bill?  I wrote a ASPX to generate a list of 1,000 report link, use javascript to showModalDialog 1,000 times.  In the modal dialog, I use RSClientPrint OCX to print the report.

RSIssue3

The only thing we have to worry is RSClientPrint.Print() will popup a printer selection dialog, need user to press "OK" button to print out.  The user must sit there, be waiting, and click 1000 times?  In IEUnit, there is a powerful Win32Dom.Desktoop class, it can find window in your desktop, get the button on it and click it.  Reference the source code, you can write a "OK-button robot", then everything goes fine! 

Maybe this solution is a little ugly, but it works.  At least, I saved more than 5,000 USD to purchase another reporting tool, but I hope Microsoft can put this feature in the wishlist of reporting service, that's the real way to solve this problem.