[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: 工作點滴, 技術分享 | 標籤: | 發表留言

文章分頁導航

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google photo

您的留言將使用 Google 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

在WordPress.com寫網誌.

%d 位部落客按了讚: