- Offizieller Beitrag
Ich habe nun versucht mein SciTEInterface auf Nim Basis auszuführen.
Das Übertragen in Richtung SciTE klappt. Aber ich bekomme es nicht gebacken, die Callbackfunktion zu installieren. Sie muss vom Typ SENDASYNCPROC sein - das bekomme ich nicht umgesetzt. Die entsprechenden Bereiche sind auskommentiert.
Zum Testen muss SciTE geöffnet sein, ich habe noch keine Fehlerbehandlung drin und gehe davon aus, dass ich ein Handle bekomme.
Vielleicht habt ihr einen zündenden Gedanken .
Code
# Nim-SciTE-Interface
include winim/[inc\winuser]
import wNim/[wApp, wFrame, wPanel, wTextCtrl]
import strformat, strutils, os, re
type
WndID = object
pid, tid: int
EnumWnd = object
hwnd: HWND
class: WideCStringObj
title: WideCStringObj
pid, tid: int
var
received: string
sEnumWnd = newSeq[EnumWnd]()
lp: LPARAM
classfilter = newWideCString("", 256)
titlefilter = newWideCString("", 4096)
proc MyFindWindow(class = "", title = ""): HWND =
let
className = newWideCString(class, class.len)
wndName = newWideCString(title, title.len)
if class == "" and title == "":
result = FindWindowW(nil, nil)
elif class != "" and title == "":
result = FindWindowW(cast[LPWSTR](className), nil)
elif class == "" and title != "":
result = FindWindowW(nil, cast[LPWSTR](wndName))
else:
result = FindWindowW(cast[LPWSTR](className), cast[LPWSTR](wndName))
# Fensteranwendung für Interface
let
nsiApp = App()
nsiFrame = Frame(title="Nim-SciTE interface", size=(320,220))
nsiPanel = Panel(nsiFrame)
nsiText = TextCtrl(nsiPanel, style=wTeMultiLine, pos=(10,10), size=(300,200))
hRecv = MyFindWindow(class="wFrame1", title="Nim-SciTE interface")
nsiFrame.wIdExit do ():
nsiFrame.delete()
proc my_WndEnumProc(hwnd: HWND, lp: LPARAM): WINBOOL {.stdcall.} =
if GetParent(hwnd) == 0:
var buflen = GetWindowTextLengthW(hwnd) + 1
if buflen == 0: return TRUE
var buf = newWideCString("", buflen)
discard GetWindowTextW(hwnd, cast[LPWSTR](addr buf[0]), buflen)
if titlefilter.len > 0:
if fmt"{buf}" != fmt"{titlefilter}": return TRUE
var className = newWideCString("", 4096)
discard GetClassNameW(hwnd, cast[LPWSTR](className), 4096)
if classfilter.len > 0:
if fmt"{className}" != fmt"{classfilter}": return TRUE
var
pPID: LPDWORD
pTID = GetWindowThreadProcessId(hwnd, cast[LPDWORD](addr pPID))
oWndID = WndID(pid: cast[int](pPID), tid: cast[int](pTID))
sEnumWnd.add(EnumWnd(hwnd: hwnd,
class: className,
title: buf,
pid: oWndID.pid,
tid: oWndID.tid))
return TRUE
# callback WM_COPYDATA - verwenden mit SendMessageCallbackW für SciTE-Antwort
# stimmt so nicht mit Typ: SENDASYNCPROC überein
# proc my_WMCopyData(hwnd: HWND, msg: UINT, dwData: ptr COPYDATASTRUCT, lresult: LRESULT): VOID {.stdcall.} =
# let
# cds: COPYDATASTRUCT = dwData[]
# recvLen = cds.cbData
# var
# buffer: string
# buffer = cast[ptr string](cds.lpData)[]
# received = buffer[0..recvLen - 1]
proc GetIDByWindow(hWnd: HWND): WndID =
var
pPID: LPDWORD
pTID = GetWindowThreadProcessId(hWnd, cast[LPDWORD](addr pPID))
result = WndID(pid: cast[int](pPID), tid: cast[int](pTID))
proc GetEnumWindows(cfilter, tfilter: string): int =
titlefilter = newWideCString(tfilter, tfilter.len + 1)
classfilter = newWideCString(cfilter, cfilter.len + 1)
sEnumWnd = newSeq[EnumWnd]()
EnumWindows(my_WndEnumProc, lp)
result = sEnumWnd.len
proc GetHwndDirectorExtension(): HWND =
# let hActive = GetForegroundWindow() # zum Test auskommentiert
let hScite = MyFindWindow("SciTEWindow")
# if hActive != hScite: return 0 # zum Test auskommentiert
let pidScite = GetIDByWindow(hScite).pid
let dirExtCount = GetEnumWindows("DirectorExtension", "")
if dirExtCount == 1: result = sEnumWnd[0].hwnd
else:
for i in 0..dirExtCount - 1:
if pidScite == sEnumWnd[i].pid: return sEnumWnd[i].hwnd
proc SendCommand(hwnd: HWND, cmd: string, recv: bool = false): bool =
if hwnd == 0: return false
var
cmdScite = ":" & $hwnd & ":" & cmd
cds: COPYDATASTRUCT
cds.dwData = 1
cds.cbData = int32(cmdScite.len + 1)
cds.lpData = addr cmdScite[0]
received = ""
SendMessage(hwnd, WM_COPYDATA, cast[WPARAM](hRecv), cast[LPARAM](addr cds))
if recv:
# callback auswerten
var nWait = 0
while received == "" or nWait < 100:
sleep(20)
nWait += 1
if received == "": return false
return true
# Editor Funktionen:
proc OutputConsole(hwnd: HWND, value: string): bool {.discardable.} =
result = hwnd.SendCommand("output:" & value)
proc MenuCmd(hwnd: HWND, cmdID: int): bool {.discardable.} =
result = hwnd.SendCommand("menucommand:" & $cmdID)
proc ClearOutput(hwnd: HWND): bool {.discardable.} =
result = hwnd.SendCommand("extender:dostring do output:ClearAll() end")
proc CurrentFile(hwnd: HWND): string =
if hwnd.SendCommand("askfilename:", true):
result = received.replace(re"^:\d+:[^:]+:")
else:
result = ""
proc GetProperty(hwnd: HWND, property: string): string =
if hwnd.SendCommand("askproperty:" & property, true):
result = received.replace(re"^:\d+:([^:]+:){2}")
else:
result = ""
# Ergebnisse im Fenster anzeigen
proc TextAdd(s: string, nl: bool = true) =
var nextline = "\n"
if not nl: nextline = ""
nsiText.appendText(s & nextline)
# Scite DirectorExtension
let hScite = GetHwndDirectorExtension()
TextAdd("Handle DirectorExtension: 0x" & $toHex(hScite))
# WM_COPYDATA mit Receive-Window verknüpfen - aber wie?
# var
# cdscb: COPYDATASTRUCT
# wpcb: WPARAM
# lpcb: LPARAM
# SendMessageCallbackW(hRecv, WM_COPYDATA, wpcb, lpcb, proccb, addr cdscb)
TextAdd("ClearOutput: ", false) # ==> OK
TextAdd($hScite.ClearOutput())
TextAdd("OutputConsole: ", false) # ==> OK
TextAdd($hScite.OutputConsole(r"! Das ist ein Test\n- TEST\n> TEST"))
# TextAdd("Get CurrentFile: ", false)
# TextAdd(hScite.CurrentFile())
nsiFrame.show()
nsiApp.mainLoop()
Alles anzeigen