Monthly Archives: 六月 2021

[VBNET] 取得文字盒的游標位置


這個主題應該到處都搜尋得到,這邊討論一下我沒找到的部分。

我不確定我原始碼最早從哪來,也是天下文章一大抄,在 VB6 抄的,移植到 VBNET ,這邊假定我原始碼是抄 cww 的:

參考位置:http://www.hosp.ncku.edu.tw/~cww/html/q00221.html

原先的原始碼,會在超過約 32kb 以上的內容發生定位錯誤,當然就是溢位錯誤導致計算為負,google 後大部分原始碼都是這樣,所以只好自己偵錯。

首先先研讀 Windows API 說明,微軟已經把 Windows API 說明中文化了,所以不要再因為閱讀障礙不去看:

EM_GETSEL: https://docs.microsoft.com/zh-tw/windows/win32/controls/em-getsel

EM_LINEFROMCHAR: https://docs.microsoft.com/zh-tw/windows/win32/controls/em-linefromchar

EM_LINEINDEX: https://docs.microsoft.com/zh-tw/windows/win32/controls/em-lineindex

從 EM_GETSEL 說明中,可以看到,其實分成目前游標及選擇區域 (反白) 兩種模式,為了不把問題複雜化,只看目前游標。

傳回位置有提到分成 LOWORD (低位元組) 與 HIWORD (高位元組) ,任何一數超過 65536 則傳回 -1 ,我猜很多人看到超過回傳 -1 ,就沒管了,這也是網路上搜尋到的範例基本上只適合小文字檔。

說明也提到建議使用 wParam / lParam ,我測出這兩參數回傳結果都是 0 ,暫時放棄。

由於 HIWORD 是 65536 ,但 VBNET 的 Integer 的 HIWORD 只能到 32768 ,所以 32 kb 以上文件會出問題。因此這邊將 Windows API 呼叫改為 UInt32 來接收:

<Runtime.InteropServices.DllImport("user32.dll", EntryPoint:="SendMessage")>
Public Function SendMessageUInt32(
	hWnd As Integer,
	wMsg As enuWindowMessageId,
	wParam As Integer,
	lParam As Integer

) As UInt32
End Function

所以解決了 64 kb 以下檔案問題。

經過測試,EM_GETSEL 超過 64kb 並不會回傳 -1 ,所以應該是原始文件誤植,或是微軟已經擴充功能後沒有正確更新文件。

所以游標計算方式更新如下:

Public Function GetCaretPos(ByVal EditControl As Control) As System.Drawing.Point
	Dim i, j, k As Long
	Dim lineNo, colNo As Integer
	Dim lParam, wParam As Integer
	i = SendMessageUInt32(EditControl.Handle, EditTextMessage.EM_GETSEL, wParam, lParam)
	j = Int(i / 65536)
	lineNo = SendMessageUInt32(EditControl.Handle, EditTextMessage.EM_LINEFROMCHAR, -1, 0) + 1
	k = SendMessageUInt32(EditControl.Handle, EditTextMessage.EM_LINEINDEX, -1, 0)
	colNo = ((j + 65536 - (k Mod 65536)) Mod 65536) + 1
	Return New System.Drawing.Point(lineNo, colNo)
End Function

VBNET 並不完全支援 UInt32 ,很多函數僅支援 VBNET 內建型別,因此在收 SendMessageUInt32 回傳值時,都立刻改為 Long 。

j 在算 HIWORD ,這個數值超過 65535 後,會從 0 再開始,類似里程表。

而在呼叫 EM_LINEFROMCHAR 時,依照 Windows API 說明,回傳目前位置是使用 -1 ,有用到選擇範圍時才用 lParm ,所以直接改成 -1 。

在計算欄位置時 (每行第幾個字元) ,j 僅 65536 以下,k 可超過 65536 ,所以這邊要先取餘數,但我現在還沒碰到這樣的文字檔,測試 TextBox 超過 1024 字元會自動換行,所以暫時先擺著。

以後有碰到可以測試的文字檔再來測,有問題再修改這篇。目前側到 4MB 的 log 都能正常跑。

Categories: 工作點滴, 技術分享 | 標籤: | 發表留言

[T-SQL] WITH 通用資料表運算式:暫時資料表


在微軟文件是寫暫存資料表,不過我覺得會跟 tempdb 裡面的暫存資料表混淆,所以我把暫存改為暫時。

WITH 我用到的機會不多,所以我以為我在 blog 上寫過跟 WITH 相關的主題,以便提醒自己。前天我要在 SSMS 下個 T-SQL ,要使用到 WITH ,但太久沒用了,完全想不起來關鍵字,google 暫存資料表不是舊的 tempdb ,不然就是 MSSQL 2016 以後支援的記憶體暫存資料表,根本找不到我想要的,翻了好久才翻到,所以這次要記下來,不然下次找不到。

在一個複雜或是資料龐大的查詢中,如果後續還要繼續對這個查詢做處理,最好把他寫到暫存資料表後再重複利用。

MSSQL 很早就有這功能,就是利用 tempdb ,使用 T-SQL 語法去處理,可以不用刪暫存資料表,SQL Server 會在斷線後自動刪除。

暫存資料表的命名就是以 # 為起頭。

詳見:https://docs.microsoft.com/zh-tw/sql/t-sql/statements/create-table-transact-sql?view=sql-server-ver15

這裡面的缺點就是建立暫存資料表時,硬碟會有大量的 IO ,所以從 SQL Server 2016 起,支援在記憶體內建立暫存資料表,以節省硬碟 IO 並加速查詢。

另一個在 SQL Server 也支援很久的就是暫時資料表。

這篇的 SQL 語法可改用 PVIOT 加速,下次來說,這篇主要是介紹 WITH。

詳見:https://docs.microsoft.com/zh-tw/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-ver15

因為不用建立暫存資料表,所以上圖的 1/2/3/6 行都沒了,只剩下 4/5 行。上圖的第 4 行轉成 WITH 語法就是下圖的 1 ~ 3 行,上圖的第 5 行為了強調重複利用暫存資料表,把它展開成 4 ~ 18 行。WITH 建立的這篇稱為暫時資料表。

從這個案例來說明,原先的資料在 Data_Hour 超過 2 億筆 (row) ,如果每次 JOIN 都從原始資料撈,會浪費大量的 IO 與計算時間。所以透過暫存資料表或暫時資料表,可以加速查詢。

暫時資料表也可以多個,甚至類似巢狀,把上圖 1 ~ 3 行拆成兩個,如 1 ~ 7 行,8 行以後維持不變。

這邊是假設第二次查詢比較複雜,所以先建立 Data_Init 查詢結果後,再由 Data_CTE 經過複雜的 WHERE 運算得到新的暫時資料表,給下方的查詢使用。

我要找 WITH 是想到有個庫齡計算的 T-SQL 語法可以透過 WITH 加速,但太久沒用,一直想不起來關鍵字,自己記錄一篇提醒自己。

Categories: 工作點滴, 技術分享 | 標籤: | 1 則迴響

[Office] 365 商業版續約可能會發生使用者無法存取 Office


我們公司是從 Office 365 開始訂閱,去年已經續約 Microsoft 365 了,今年又到續約的時間,前一個月已經完成跟經銷商的下訂,確保續約正常。

原先的訂閱週期是 06/10 ~ 06/09 ,今年續約改續約一年半,以便跟另一批 Office 365 切齊,所以訂閱 06/10 ~ 12/31 。

06/09 這天,有同事數個反應,開啟 Office 365 時,顯示沒有使用權限。

一位 IT 負責跟經銷商聯繫,查了一天沒找到問題,主要就是重新授權或是把使用者刪除重新加入,但仍然不能使用。

想說看看 06/10 後會不會恢復正常,但到了 06/10 後還是不能用,經銷商打算開 Microsoft Ticket 找微軟工程師來處理,另一位 IT 忽然想起他哥公司的案例,檢查了個人軟體細項授權,果然被不明原因拔除。

找到問題就單純了,同事逐位使用者檢視細項授權,重新把相關權限勾起來,最慘的是所有功能全部沒勾。

看起來有可能是微軟續約系統的問題,續約時,部分功能可能會移除,年底續約另一批 Office 365 時,要特別注意。

Categories: 工作點滴, 技術分享 | 標籤: | 發表留言

在WordPress.com寫網誌.

%d 位部落客按了讚: