Gå til innhold

Anbefalte innlegg

Videoannonse
Annonse

Alle vinduer (f.eks. en form, en knapp, en listeboks osv.) i Windows har spesifisert en funksjon som operativsystemet eller andre programmer kan kalle for å kommunisere med programmet. Windows kan f.eks. sende hendelser som når musepekeren kommer over vinduet, en tast sendes til vinduet og mye mer. Programmer kan på sin side sende forespørsel om spesielle opplysninger angående vinduet; eksempelvis vil EM_GETLINECOUNT få en tekstboks til å sende tilbake antall linjer i teksten. Man kan også definere sine egne "funksjoner".

 

For å kalle disse spesielle funksjonene, kan man bruke enten PostMessage, SendMessage eller CallWindowProc (forutsetter at man kjenner adressen til prosedyren).

 

Vanligvis ser en slik funksjon ut som sådan:

 

Public Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

   ' Din kode her
   Select Case uMsg
   Case 0
       ' Noe her
   Case 1
       ' Noe her
   End Select

   WindowProc = 0 ' Returner en verdi til avsender

End Function

 

I denne funksjonen er hwnd adressen eller pekeren til vinduet avsenderen har prøvd å nå; uMsg er ID-en til funksjonen/hendelsen eller hva enn anropet gjalt; wParam er en valgfri variabel som benyttes til flere forskjellige hensikter, avhengig av ID-en - likeså er det med lParam.

 

Dersom jeg for eksempel ønsker å sette tittelbaren på en form, kunne jeg uten problemer gjort som følger:

 

Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As Any) As Long

Private Const WM_SETTEXT = &HC

Private Sub Form_Load()

   SendMessage Me.hwnd, WM_SETTEXT, 0&, "Dette er en test"

End Sub

 

Mottakeren ville så fått en melding til sin vindu-funksjon, omtrent som dette:

 

Public Function WindowProc( ... ) As Long

   ' hwnd er nå lik Me.hwnd, uMsg er WM_SETTEXT, wParam er 0 og lParam er 
   ' "Dette er en test"

   ' Det ser neppe slik ut i virkeligheten, men det gir et godt bilde
   Select Case uMsg
   Case WM_SETTEXT

       Me.Caption = lParam
   
   'Case  ... (mange flere her)
   End Select

End Function

 

Hva er så poenget med subclassing? Jo, i denne teknikken overstyrer vi rett og slett et programs egentlige vindu-funksjon ved å legge inn vår egen, og dernest sende eller la være å sende meldingen videre - alt etter hva vi ønsker. For å spesifisere vår egen vindu-funksjon, bruker vi API-kallet SetWindowLong. Studer og legg følgende eksempel inn i en modul:

 

Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Declare Function SetClipboardViewer Lib "user32" (ByVal hwnd As Long) As Long
Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As Any) As Long

Public Const WM_SETTEXT = &HC
Public Const GWL_WNDPROC = (-4)

Private PrevProc As Long ' Den originale funksjonen

Public Sub SubclassForm(F As Form)

   ' AddressOf WindowProc = gir adressen til funksjonen
   PrevProc = SetWindowLong(F.hwnd, GWL_WNDPROC, AddressOf WindowProc)
   
End Sub

Public Sub SubclassForm(F As Form)

   ' Det er SVÆRT viktig at vi tilbakestiller subclassingen. Dersom dette ikke blir gjort, krasjer hele VB
   SetWindowLong F.hwnd, GWL_WNDPROC, PrevProc
   
End Sub

Public Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
   
   Dim sTemp As String
   
   If uMsg = WM_SETTEXT Then
       ' Ikke la den egentlige teksten komme frem, erstatt den med vår egen
       sTemp = StrConv("Overstyring" & Chr(0), vbFromUnicode)
       lParam = StrPtr(sTemp)
   End If
   
   ' Kall den originiale funksjonen
   WindowProc = CallWindowProc(PrevProc, hwnd, uMsg, wParam, lParam)
       
End Function

 

Legg så inn en form med knappen cmdTest, og legg til følgende kode i formen:

 

Private Sub cmdTest_Click()

   SendMessage Me.hwnd, WM_SETTEXT, 0&, "Dette er en test"

End Sub

Private Sub Form_Load()

   ' Starter subclassingen
   SubclassForm Me

End Sub

Private Sub Form_Unload(Cancel As Integer)

   ' Dersom du stopper prosjekter (med eksempelvis stoppknappen) uten at denne blir kalt, kan det gå ille
   SubclassForm Me

End Sub

 

Når du så trykker på knappen cmdTest, vil du se at teksten som kommer opp i tittelvinduet er ikke "Dette er en test", men "Overstyring".

 

Dette har forhåpentligvis illustert bruken og teknikken bak subclassing på en forståelig og grei måte, men du kan, dersom det fremdeles er litt uklart, lese litt på denne utmerkede siden her. Skjønt, da må du nok belage deg på å lese engelsk, dessverre.

Endret av aadnk
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...