-
Notifications
You must be signed in to change notification settings - Fork 1
/
ListViewSubItemEdit.asm
1427 lines (1240 loc) · 46.2 KB
/
ListViewSubItemEdit.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
IFDEF LVSIELIB
;.486 ; force 32 bit code
;.model flat, stdcall ; memory model & calling convention
;option casemap :none ; case sensitive
ENDIF
.686
.MMX
.XMM
.model flat,stdcall
option casemap:none
include \masm32\macros\macros.asm
;DEBUG32 EQU 1
;
;IFDEF DEBUG32
; PRESERVEXMMREGS equ 1
; includelib M:\Masm32\lib\Debug32.lib
; DBG32LIB equ 1
; DEBUGEXE textequ <'M:\Masm32\DbgWin.exe'>
; include M:\Masm32\include\debug32.inc
;ENDIF
include windows.inc
include kernel32.inc
include user32.inc
include gdi32.inc
include uxtheme.inc
include comctl32.inc
includelib kernel32.lib
includelib user32.lib
includelib gdi32.lib
includelib uxtheme.lib
includelib comctl32.lib
IFNDEF LVSIELIB
include Listview.inc
includelib Listview.lib
LVSIELIBEND TEXTEQU <>
ELSE
LVSIELIBEND TEXTEQU <END>
ENDIF
include ListViewSubItemEdit.inc
LVSIE_CreateEditControl PROTO :DWORD ; Main API function to create a control in the listview subitem
; Edit control procs
LVSIE_EditControlProc PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
LVSIE_EditControlInitProc PROTO :DWORD
LVSIE_EditControlValidProc PROTO :DWORD
LVSIE_EditControlProcProc PROTO :DWORD, :DWORD, :DWORD, :DWORD
LVSIE_EditControlNotifyProc PROTO :DWORD
LVSIE_LVEditControlProc PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
; Combo control procs
LVSIE_ComboControlProc PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
LVSIE_LVComboControlProc PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
; Experimental tab to next cell
LVSIE_SetNextItem PROTO :DWORD, :DWORD
IFDEF LVSIELIB
ListViewGetItemRect PROTO :DWORD, :DWORD, :DWORD
ListViewGetSubItemRect PROTO :DWORD, :DWORD, :DWORD
ListViewGetItemText PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
ListViewSetItemText PROTO :DWORD, :DWORD, :DWORD, :DWORD
ListViewGetColumnWidth PROTO :DWORD, :DWORD
ListViewGetColumnFormat PROTO :DWORD, :DWORD
ListViewGetColumnCount PROTO :DWORD
ListViewGetItemCount PROTO :DWORD
ListViewEnsureSubItemVisible PROTO :DWORD, :DWORD
ENDIF
IFNDEF MOUSEINPUT
MOUSEINPUT STRUCT
_dx DWORD ?
dy DWORD ?
mouseData DWORD ?
dwFlags DWORD ?
time DWORD ?
dwExtraInfo DWORD ?
MOUSEINPUT ENDS
ENDIF
IFNDEF KEYBDINPUT
KEYBDINPUT STRUCT
wVk WORD ?
wScan WORD ?
dwFlags DWORD ?
time DWORD ?
dwExtraInfo DWORD ?
KEYBDINPUT ENDS
ENDIF
IFNDEF HARDWAREINPUT
HARDWAREINPUT STRUCT
uMsg DWORD ?
wParamL WORD ?
wParamH WORD ?
HARDWAREINPUT ENDS
ENDIF
IFNDEF INPUT
INPUT STRUCT
dwType DWORD ?
union
mi MOUSEINPUT <>
ki KEYBDINPUT <>
hi HARDWAREINPUT <>
ends
INPUT ENDS
ENDIF
.CONST
LVSIEDATA STRUCT
iItem DD 0
iSubItem DD 0
hListview DD 0
hHeader DD 0
hParent DD 0
hControl DD 0; can be combo etc ?
dwControlType DD 0
lpControlInitProc DD 0 ; any init to be done, or null go ahead anyhow? ret true to continue or false to exit control and destroy it
lpControlProc DD 0 ; if user wants to handle themselves? subclass listview as well to pass wm_command and wm_notify back to this proc?
lpControlValidProc DD 0 ; validation etc? if null just update subitem anyhow? true to exit or false to continue
lParam DD 0 ; custom value to pass to it, for user to use in init or finish proc
;dwAllowWraparound DD 0
dwOptions DD 0
dwControlRect RECT <0,0,0,0>
dwChangesToSave DD 0
LVSIEDATA ENDS
;constants for dwType
INPUT_MOUSE equ 0
INPUT_KEYBOARD equ 1
INPUT_HARDWARE equ 2
LVSIE_RIGHT EQU 0
LVSIE_LEFT EQU 1
LVSIE_DOWN EQU 2
LVSIE_UP EQU 3
.DATA
szLVSIEEditClass DB 'Edit',0
lvsienmia NMITEMACTIVATE <>
lvsienmlv NMLISTVIEW <>
lvsiedata LVSIEDATA <>
.DATA?
;SubClassData DD ?
.CODE
;-------------------------------------------------------------------------------------
; Handles setup of listview subitem editing
;-------------------------------------------------------------------------------------
ListViewSubItemEdit PROC USES EBX ECX hListview:DWORD, dwItem:DWORD, dwSubItem:DWORD, lpLVSUBITEMEDIT:DWORD
LOCAL hParent:DWORD
LOCAL hControl:DWORD
LOCAL dwControlType:DWORD
LOCAL lParam:DWORD
LOCAL hinstance:DWORD
LOCAL SubClassData:DWORD
LOCAL rect:RECT
Invoke GetParent, hListview
mov hParent, eax
mov SubClassData, NULL
Invoke GlobalAlloc, GMEM_FIXED or GMEM_ZEROINIT, SIZEOF LVSIEDATA
.IF eax == NULL
mov eax, NULL
ret
.ENDIF
mov SubClassData, eax
mov ecx, eax
; save passed structure info to our own subclass data
mov ebx, lpLVSUBITEMEDIT
mov ecx, SubClassData
;mov eax, [ebx].LVSUBITEMEDIT.iItem
mov eax, dwItem
mov [ecx].LVSIEDATA.iItem, eax
;mov eax, [ebx].LVSUBITEMEDIT.iSubItem
mov eax, dwSubItem
mov [ecx].LVSIEDATA.iSubItem, eax
;mov eax, [ebx].LVSUBITEMEDIT.hListview
mov eax, hListview
mov [ecx].LVSIEDATA.hListview, eax
;mov eax, [ebx].LVSUBITEMEDIT.hParent
mov eax, hParent
mov [ecx].LVSIEDATA.hParent, eax
mov eax, [ebx].LVSUBITEMEDIT.dwControlType
mov dwControlType, eax
mov [ecx].LVSIEDATA.dwControlType, eax
mov eax, [ebx].LVSUBITEMEDIT.lpControlInitProc
;PrintDec eax
mov [ecx].LVSIEDATA.lpControlInitProc, eax
mov eax, [ebx].LVSUBITEMEDIT.lpControlProc
mov [ecx].LVSIEDATA.lpControlProc, eax
mov eax, [ebx].LVSUBITEMEDIT.lpControlValidProc
;PrintDec eax
mov [ecx].LVSIEDATA.lpControlValidProc, eax
mov eax, [ebx].LVSUBITEMEDIT.lParam
mov [ecx].LVSIEDATA.lParam, eax
;mov eax, [ebx].LVSUBITEMEDIT.dwAllowWraparound
;mov [ecx].LVSIEDATA.dwAllowWraparound, eax
mov eax, [ebx].LVSUBITEMEDIT.dwOptions
.IF eax == 0
mov eax, LVSIO_NAV_ALL or LVSIO_WRAP_ALL or LVSIO_NOTIFY_NMCLICK
.ENDIF
mov [ecx].LVSIEDATA.dwOptions, eax
;DbgDump ecx, SIZEOF LVSIEDATA
mov eax, dwControlType
.IF eax == LVSIC_EDIT
Invoke GetDlgItem, hListview, 1
.IF eax != NULL
IFDEF DEBUG32
PrintText 'GetDlgItem, hListview, 1 found'
PrintDec eax
ENDIF
.ENDIF
Invoke LVSIE_CreateEditControl, SubClassData
.ENDIF
.IF eax == NULL
.IF SubClassData != NULL
Invoke GlobalFree, SubClassData
.ENDIF
mov eax, NULL
ret
.ENDIF
ret
ListViewSubItemEdit ENDP
;-------------------------------------------------------------------------------------
; Create edit control for listview subitem editing
;-------------------------------------------------------------------------------------
LVSIE_CreateEditControl PROC USES EBX lpSubClassData
LOCAL iItem:DWORD
LOCAL iSubItem:DWORD
LOCAL hListview:DWORD
LOCAL hHeader:DWORD
LOCAL hParent:DWORD
LOCAL hControl:DWORD
LOCAL lParam:DWORD
LOCAL hinstance:DWORD
LOCAL szItemText[MAX_PATH]:BYTE
LOCAL rect:RECT
LOCAL dwStyle:DWORD
Invoke GetModuleHandle, NULL
mov hinstance, eax
; Get information from our data
mov ebx, lpSubClassData
mov eax, [ebx].LVSIEDATA.iItem
mov iItem, eax
mov eax, [ebx].LVSIEDATA.iSubItem
mov iSubItem, eax
mov eax, [ebx].LVSIEDATA.hListview
mov hListview, eax
mov eax, [ebx].LVSIEDATA.hParent
mov hParent, eax
; Get area to put our editbox in
.IF iSubItem == 0 ; LVM_GETSUBITEMRECT doesnt work with iSubItem == 0 so we calc it another way
mov rect.left, LVIR_BOUNDS
Invoke ListViewGetItemRect, hListview, iItem, Addr rect
Invoke ListViewGetColumnWidth, hListview, 0
mov rect.right, eax
.ELSE
mov eax, iSubItem
mov rect.top, eax
mov rect.left, LVIR_BOUNDS
Invoke ListViewGetSubItemRect, hListview, iItem, Addr rect
.ENDIF
; Adjust area to fit our control perfectly
dec rect.bottom
dec rect.right
inc rect.left
inc rect.left
mov eax, rect.right
sub eax, rect.left
mov rect.right, eax
mov eax, rect.bottom
sub eax, rect.top
mov rect.bottom, eax
; Set editbox style based on column format: left or right aligned or centered
mov eax, WS_CLIPCHILDREN+WS_CHILD+WS_VISIBLE+ES_AUTOHSCROLL
mov dwStyle, eax
Invoke ListViewGetColumnFormat, hListview, iSubItem
and eax, LVCFMT_LEFT + LVCFMT_RIGHT + LVCFMT_CENTER
.IF eax == LVCFMT_LEFT
or dwStyle, ES_LEFT
.ELSEIF eax == LVCFMT_RIGHT
or dwStyle, ES_RIGHT
.ELSEIF eax == LVCFMT_CENTER
or dwStyle, ES_CENTER
.ENDIF
; Create our editbox control
invoke CreateWindowEx, WS_EX_CLIENTEDGE, Addr szLVSIEEditClass, NULL, dwStyle,
rect.left, rect.top, rect.right, rect.bottom, hListview, 1, hinstance, NULL
.IF eax == NULL
ret
.ENDIF
; If control created succesfully we fill in some info into our subclass data area
mov hControl, eax
invoke SetFocus, hControl ; do this before any subclassing, that way if an existing control exists, for whatever reason, setting focus on this, should destroy old one.
mov ebx, lpSubClassData
mov eax, hControl
mov [ebx].LVSIEDATA.hControl, eax
mov eax, rect.bottom
mov [ebx].LVSIEDATA.dwControlRect.bottom, eax
Invoke ListViewGetItemText, hListview, iItem, iSubItem, Addr szItemText, MAX_PATH
; Get listview header, mainly for notification if user resizes a column whilst control is displaying (it will size according to new col size - and closes as focus has been lost)
Invoke SendMessage, hListview, LVM_GETHEADER, NULL, NULL
mov hHeader, eax
mov ebx, lpSubClassData
mov [ebx].LVSIEDATA.hHeader, eax
; Get font from listview and set editbox to same
invoke SendMessage, hListview, WM_GETFONT, 0, 0
invoke SendMessage, hControl, WM_SETFONT, eax, 0 ; set font same as listview has
invoke SetWindowPos, hControl, HWND_TOP, 0,0,0,0, SWP_SHOWWINDOW or SWP_NOMOVE or SWP_NOSIZE
Invoke SetWindowSubclass, hControl, Addr LVSIE_EditControlProc, 0, lpSubClassData
Invoke SetWindowSubclass, hListview, Addr LVSIE_LVEditControlProc, 0, lpSubClassData
; Final stuff for control before setting focus and calling initdialog for it (we use intidialog to call users lpControlInitProc if specified)
Invoke SendMessage, hControl, WM_SETTEXT, 0, Addr szItemText
Invoke SendMessage, hControl, EM_SETMARGINS, EC_LEFTMARGIN + EC_RIGHTMARGIN, 00010001h
Invoke SendMessage, hControl, EM_SETSEL, 0, -1
Invoke SetActiveWindow, hControl
Invoke SendMessage, hControl, WM_INITDIALOG, 0, 0
.IF eax == FALSE ; if user returned false from their lpControlInitProc we destroy editbox and return
xor eax, eax
.ELSE
mov eax, hControl ; else control is created and handle is passed back for user to use if required
.ENDIF
ret
LVSIE_CreateEditControl ENDP
;-------------------------------------------------------------------------------------
; Listview requires LVS_EX_FULLROWSELECT for it to pick up each item clicked
;-------------------------------------------------------------------------------------
LVSIE_EditControlProc PROC USES EBX hWin:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM, uIdSubclass:UINT, dwRefData:DWORD
LOCAL hHeader:DWORD
LOCAL hControl:DWORD
LOCAL wParamX:DWORD
mov eax, wParam
mov wParamX, eax
; if user provided us with a proc for handling stuff themselves we call that first before doing anything
mov eax, uMsg
;.IF eax == WM_DESTROY || eax == WM_NCDESTROY || eax == WM_KILLFOCUS || eax == WM_INITDIALOG || eax == WM_NOTIFY || eax == WM_COMMAND; prevent user from these for safety
;.ELSE
.IF eax == WM_CHAR || eax == WM_KEYDOWN || eax == WM_PASTE;|| eax == WM_COMMAND
Invoke LVSIE_EditControlProcProc, dwRefData, uMsg, wParam, lParam
.IF eax == 0;FALSE ; if user returned false, then they didnt want the normal messages to go through.
ret
.ENDIF
.IF eax > 1
mov wParamX, eax
;PrintDec wParamX
.ENDIF
.ENDIF
mov eax, uMsg
.IF eax == WM_NCDESTROY
;PrintText 'WM_NCDESTROY'
Invoke RemoveWindowSubclass, hWin, Offset LVSIE_LVEditControlProc, uIdSubclass ; remove our temp subclass of listview (it was just for our WM_NOTIFY and WM_COMMAND events)
Invoke RemoveWindowSubclass, hWin, Offset LVSIE_EditControlProc, uIdSubclass ; remove editbox subclass before we leave it.
mov eax, dwRefData
.IF eax != NULL
Invoke GlobalFree, eax ; Free the memory we allocated for our subclass data when we created control, dont need it anymore
.ENDIF
.ELSEIF eax == WM_INITDIALOG
;PrintText 'WM_INITDIALOG'
mov ebx, dwRefData
mov [ebx].LVSIEDATA.dwChangesToSave, FALSE
Invoke LVSIE_EditControlInitProc, dwRefData
.IF eax == FALSE ; if they returned false then we dont go ahead with control and we destroy it and exit
Invoke SendMessage, hWin, WM_CLOSE, 0, 0
.ENDIF
ret
.ELSEIF eax == WM_COMMAND
;PrintText 'WM_COMMAND'
mov eax, wParam
shr eax, 16
.IF eax == EN_CHANGE ; tell control something changes, so save is needed
mov ebx, dwRefData
mov eax, TRUE
mov [ebx].LVSIEDATA.dwChangesToSave, eax
.ENDIF
.ELSEIF eax == WM_NOTIFY
mov ebx, dwRefData
mov eax, [ebx].LVSIEDATA.hHeader
mov hHeader, eax
mov ecx, lParam
mov ebx, [ecx].NMHDR.hwndFrom
mov eax, [ecx].NMHDR.code
.IF ebx == hHeader ; if user has decided to resize a column header that our control is in...
.IF eax == HDN_ITEMCHANGEDW
mov ebx, dwRefData
mov eax, [ebx].LVSIEDATA.hControl
mov hControl, eax
;mov eax, [ebx].LVSIEDATA.iSubItem
; mov iSubItem, eax
; mov ecx, lParam
; mov ebx, (NMHEADER PTR [ecx]).iItem
; .IF ebx <= iSubItem ; does it match our column for the one our control is in?
; mov ebx, dwRefData
; mov eax, [ebx].LVSIEDATA.hListview
; mov hListview, eax
; mov eax, [ebx].LVSIEDATA.hControl
; mov hControl, eax
; ; Fetch some values for adjusting our control
;; mov eax, [ebx].LVSIEDATA.dwControlRect.bottom
;; mov rect.bottom, eax
;; Invoke ListViewGetColumnWidth, hListview, iSubItem
;; dec eax
;; mov rect.right, eax
; ; Do the actual adjustment of control
Invoke SetWindowPos, hControl, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE + SWP_NOZORDER +SWP_HIDEWINDOW + SWP_NOCOPYBITS + SWP_NOSENDCHANGING ;+ SWP_NOREDRAW
;.ENDIF
.ENDIF
.ENDIF
.ELSEIF eax == WM_GETDLGCODE
mov eax, DLGC_WANTALLKEYS or DLGC_WANTTAB ;DLGC_WANTCHARS
ret
.ELSEIF eax == WM_SETTEXT || eax == WM_PASTE || eax == WM_CUT
mov ebx, dwRefData
mov eax, TRUE
mov [ebx].LVSIEDATA.dwChangesToSave, eax ; tell control we DO have something to save
.ELSEIF eax == WM_KILLFOCUS
;PrintText 'WM_KILLFOCUS'
Invoke LVSIE_EditControlValidProc, dwRefData
Invoke DestroyWindow, hWin
.ELSEIF eax == WM_CHAR
mov eax, wParamX ; character stored in eax
.IF al == VK_BACK ; allow backspace key
Invoke DefSubclassProc, hWin, uMsg, wParamX, lParam
ret
.ENDIF
.ELSEIF eax == WM_KEYDOWN
.IF wParamX == VK_ESCAPE
mov ebx, dwRefData
mov eax, FALSE
mov [ebx].LVSIEDATA.dwChangesToSave, eax ; tell control we DONT have something to save
Invoke SendMessage, hWin, WM_CLOSE, 0, 0
ret
.ELSEIF wParamX == VK_DOWN || wParamX == VK_UP
Invoke GetKeyState, VK_SHIFT
AND eax, 08000h
.IF eax == 08000h
Invoke LVSIE_EditControlValidProc, dwRefData
.IF eax == TRUE
.IF wParam == VK_DOWN
mov eax, LVSIE_DOWN
.ELSE
mov eax, LVSIE_UP
.ENDIF
Invoke LVSIE_SetNextItem, dwRefData, eax
.IF eax == TRUE
Invoke SendMessage, hWin, WM_CLOSE, 0, 0
ret
.ELSE
mov eax, 0
ret
.ENDIF
;.ELSE
;Invoke MessageBeep, MB_ICONEXCLAMATION
.ENDIF
.ENDIF
.ELSEIF wParamX == VK_TAB
Invoke LVSIE_EditControlValidProc, dwRefData
.IF eax == TRUE
Invoke GetKeyState, VK_SHIFT
AND eax, 08000h
.IF eax == 08000h
mov eax, LVSIE_LEFT
.ELSE
mov eax, LVSIE_RIGHT
.ENDIF
Invoke LVSIE_SetNextItem, dwRefData, eax
.IF eax == TRUE
Invoke SendMessage, hWin, WM_CLOSE, 0, 0
ret
.ELSE
mov eax, 0
ret
.ENDIF
.ENDIF
.ELSEIF wParamX == VK_RETURN
Invoke LVSIE_EditControlValidProc, dwRefData
.IF eax == TRUE
Invoke SendMessage, hWin, WM_CLOSE, 0, 0
ret
;.ELSE
;Invoke MessageBeep, MB_ICONEXCLAMATION
.ENDIF
.ELSE
Invoke DefSubclassProc, hWin, uMsg, wParamX, lParam
ret
.ENDIF
.ENDIF
Invoke DefSubclassProc, hWin, uMsg, wParamX, lParam
ret
LVSIE_EditControlProc ENDP
;-------------------------------------------------------------------------------------
; Calls custom init procedure of user if specified
;-------------------------------------------------------------------------------------
LVSIE_EditControlInitProc PROC USES EBX dwRefData:DWORD
LOCAL lpControlInitProc:DWORD
LOCAL hListview:DWORD
LOCAL hControl:DWORD
LOCAL iItem:DWORD
LOCAL iSubItem:DWORD
LOCAL lParam:DWORD
IFDEF DEBUG32
;PrintText 'LVSIE_EditControlInitProc'
ENDIF
mov ebx, dwRefData
mov eax, [ebx].LVSIEDATA.lpControlInitProc
.IF eax != NULL
mov lpControlInitProc, eax
;PrintDec lpControlInitProc
mov eax, [ebx].LVSIEDATA.iItem
mov iItem, eax
;PrintDec iItem
mov eax, [ebx].LVSIEDATA.iSubItem
mov iSubItem, eax
;PrintDec iSubItem
mov eax, [ebx].LVSIEDATA.hListview
mov hListview, eax
;PrintDec hListview
mov eax, [ebx].LVSIEDATA.hControl
mov hControl, eax
;PrintDec hControl
mov eax, [ebx].LVSIEDATA.lParam
mov lParam, eax
;PrintDec lParam
; call user's lpControlInitProc
push lParam
push iSubItem
push iItem
push hControl
push hListview
call lpControlInitProc
.IF eax == FALSE ; if user returned false, then they didnt want the normal messages to go through.
;PrintText 'lpControlInitProc:FALSE'
mov eax, FALSE
.ELSE
mov eax, TRUE
.ENDIF
.ELSE
mov eax, TRUE
.ENDIF
ret
LVSIE_EditControlInitProc ENDP
;-------------------------------------------------------------------------------------
; Calls custom procedure for handling WM_CHAR, WM_KEYDOWN and WM_COMMAND
;-------------------------------------------------------------------------------------
LVSIE_EditControlProcProc PROC USES EBX dwRefData:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
LOCAL hControl:DWORD
LOCAL iItem:DWORD
LOCAL iSubItem:DWORD
LOCAL lpControlProc:DWORD
IFDEF DEBUG32
;PrintText 'LVSIE_EditControlProcProc'
ENDIF
mov ebx, dwRefData
mov eax, [ebx].LVSIEDATA.lpControlProc
.IF eax != NULL
mov lpControlProc, eax
;PrintDec lpControlProc
mov eax, [ebx].LVSIEDATA.hControl
mov hControl, eax
mov eax, [ebx].LVSIEDATA.iItem
mov iItem, eax
mov eax, [ebx].LVSIEDATA.iSubItem
mov iSubItem, eax
push iSubItem
push iItem
push lParam
push wParam
push uMsg
push hControl
call lpControlProc
;.IF eax == FALSE ; if user returned false, then they didnt want the normal messages to go through.
; mov eax, FALSE
;.ELSE
; mov eax, TRUE
;.ENDIF
.ELSE
mov eax, TRUE
.ENDIF
ret
LVSIE_EditControlProcProc ENDP
;-------------------------------------------------------------------------------------
; Edit control save changes - calls user validation proc if exists to determine if
; it should save the changes. Saves changes made back to listview item/subitem
; This is called when user presses enter, tab, shift-tab, shift-up or shift-down
;-------------------------------------------------------------------------------------
LVSIE_EditControlValidProc PROC USES EBX dwRefData:DWORD
LOCAL hListview:DWORD
LOCAL hControl:DWORD
LOCAL iItem:DWORD
LOCAL iSubItem:DWORD
LOCAL lParam:DWORD
LOCAL lpControlValidProc:DWORD
LOCAL szItemText[MAX_PATH]:BYTE
IFDEF DEBUG32
;PrintText 'LVSIE_EditControlValidProc'
ENDIF
;PrintDec dwRefData
mov ebx, dwRefData
mov eax, [ebx].LVSIEDATA.dwChangesToSave
.IF eax == TRUE ; changes to save?
mov ebx, dwRefData
mov eax, [ebx].LVSIEDATA.hListview
mov hListview, eax
mov eax, [ebx].LVSIEDATA.hControl
mov hControl, eax
mov eax, [ebx].LVSIEDATA.iItem
mov iItem, eax
mov eax, [ebx].LVSIEDATA.iSubItem
mov iSubItem, eax
mov eax, [ebx].LVSIEDATA.lpControlValidProc
mov lpControlValidProc, eax
;PrintDec eax
.IF eax != NULL ; does user have a custom validation proc to call?
mov ebx, dwRefData
mov eax, [ebx].LVSIEDATA.lParam
; call user's lpControlValidProc
;PrintText 'Call lpControlValidProc'
push eax
push iSubItem
push iItem
push hControl
push hListview
call lpControlValidProc
.IF eax == FALSE ; if user returned false, then keep focus instead
ret
.ENDIF
.ENDIF
; else save changes
Invoke GetWindowText, hControl, Addr szItemText, MAX_PATH
Invoke ListViewSetItemText, hListview, iItem, iSubItem, Addr szItemText
mov ebx, dwRefData
mov [ebx].LVSIEDATA.dwChangesToSave, FALSE
;PrintText 'Call LVSIE_EditControlNotifyProc'
Invoke LVSIE_EditControlNotifyProc, dwRefData
.ELSE
;PrintText 'No changes to save'
.ENDIF
mov eax, TRUE
ret
LVSIE_EditControlValidProc ENDP
;-------------------------------------------------------------------------------------
; Sends a WM_NOTIFY with LVN_ITEMCHANGED to the listview to indicate subitem text has
; changed. iItem and iSubItem are set and the uChanged field is set to LVIF_TEXT
;-------------------------------------------------------------------------------------
LVSIE_EditControlNotifyProc PROC USES EBX dwRefData:DWORD
LOCAL hLVParent:DWORD
LOCAL hListview:DWORD
LOCAL iItem:DWORD
LOCAL iSubItem:DWORD
LOCAL lParam:DWORD
IFDEF DEBUG32
;PrintText 'LVSIE_EditControlNotifyProc'
ENDIF
mov ebx, dwRefData
mov eax, [ebx].LVSIEDATA.iItem
mov iItem, eax
mov eax, [ebx].LVSIEDATA.iSubItem
mov iSubItem, eax
mov eax, [ebx].LVSIEDATA.hListview
mov hListview, eax
mov eax, [ebx].LVSIEDATA.lParam
mov lParam, eax
Invoke GetParent, hListview
mov hLVParent, eax
; generate our fake NMLISTVIEW to tell original listview we updated text
lea ebx, lvsienmlv
mov eax, hListview
mov [ebx].NMLISTVIEW.hdr.hwndFrom, eax
mov [ebx].NMLISTVIEW.hdr.code, LVN_ITEMCHANGED
mov eax, iItem
mov [ebx].NMLISTVIEW.iItem, eax
mov eax, iSubItem
mov [ebx].NMLISTVIEW.iSubItem, eax
mov [ebx].NMLISTVIEW.uChanged, LVIF_TEXT
mov eax, lParam
mov [ebx].NMLISTVIEW.lParam, eax
Invoke PostMessage, hLVParent, WM_NOTIFY, hListview, Addr lvsienmlv
mov eax, TRUE
ret
LVSIE_EditControlNotifyProc ENDP
;-------------------------------------------------------------------------------------
; Listview subclass to forward on wm_command events for LVSIE_EditControlProc
;-------------------------------------------------------------------------------------
LVSIE_LVEditControlProc PROC USES EBX hWin:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM, uIdSubclass:UINT, dwRefData:DWORD
mov eax, uMsg
;.IF eax == WM_NCDESTROY
;Invoke RemoveWindowSubclass, hWin, Offset LVSIE_LVEditControlProc, uIdSubclass
.IF eax == WM_COMMAND || eax == WM_NOTIFY ; pass this back to our editbox proc
Invoke LVSIE_EditControlProc, hWin, uMsg, wParam, lParam, uIdSubclass, dwRefData
.ELSEIF eax == WM_HSCROLL || eax == WM_VSCROLL ; set focus to listview to destroy our control otherwise weird stuff happends (similar to listview col resizing)
mov ebx, dwRefData
mov eax, [ebx].LVSIEDATA.hListview
Invoke SetFocus, eax
.ELSEIF eax == WM_SIZE ; set focus to listview to destroy our control whilst listview is being resized (from main parent resizing for example)
mov ebx, dwRefData
mov eax, [ebx].LVSIEDATA.hListview
Invoke SetFocus, eax
.ENDIF
Invoke DefSubclassProc, hWin, uMsg, wParam, lParam
ret
LVSIE_LVEditControlProc ENDP
;-------------------------------------------------------------------------------------
; Moves focus to next/prev subitem or up/down to item or wraps if dwWrapAround
; specifies that is should
;-------------------------------------------------------------------------------------
LVSIE_SetNextItem PROC USES EBX dwRefData:DWORD, dwDirection:DWORD
LOCAL nTotalCols:DWORD
LOCAL nTotalRows:DWORD
LOCAL nNextItem:DWORD
LOCAL nNextSubItem:DWORD
LOCAL hLVParent:DWORD
LOCAL hListview:DWORD
LOCAL iItem:DWORD
LOCAL iSubItem:DWORD
;LOCAL dwAllowWraparound:DWORD
LOCAL dwWrapHorz:DWORD
LOCAL dwWrapVert:DWORD
LOCAL dwOptions:DWORD
LOCAL dwNotifyCode:DWORD
IFDEF DEBUG32
;PrintText 'LVSIE_SetNextItem'
ENDIF
; check if options allows certain navigations, if not we exit back with false to prevent it.
mov ebx, dwRefData
mov eax,[ebx].LVSIEDATA.dwOptions
mov dwOptions, eax
mov eax, dwDirection
mov ebx, dwOptions
and ebx, LVSIO_NAV_NONE
.IF ebx == LVSIO_NAV_NONE
mov eax, FALSE
ret
.ENDIF
mov ebx, dwOptions
.IF eax == LVSIE_RIGHT || eax == LVSIE_LEFT
and ebx, LVSIO_NAV_TABS
.IF ebx != LVSIO_NAV_TABS
mov eax, FALSE
ret
.ENDIF
.ELSEIF eax == LVSIE_DOWN || eax == LVSIE_UP
and ebx, LVSIO_NAV_ARROWS
.IF ebx != LVSIO_NAV_ARROWS
mov eax, FALSE
ret
.ENDIF
.ENDIF
; Get wrap options
mov ebx, dwOptions
and ebx, LVSIO_WRAP_NONE
.IF ebx == LVSIO_WRAP_NONE
mov dwWrapHorz, FALSE
mov dwWrapVert, FALSE
.ELSE
mov ebx, dwOptions
and ebx, LVSIO_WRAP_HORZ
.IF ebx == LVSIO_WRAP_HORZ
mov dwWrapHorz, TRUE
.ELSE
mov dwWrapHorz, FALSE
.ENDIF
mov ebx, dwOptions
and ebx, LVSIO_WRAP_VERT
.IF ebx == LVSIO_WRAP_VERT
mov dwWrapVert, TRUE
.ELSE
mov dwWrapVert, FALSE
.ENDIF
.ENDIF
mov ebx, dwRefData
mov eax, [ebx].LVSIEDATA.iItem
mov iItem, eax
mov eax, [ebx].LVSIEDATA.iSubItem
mov iSubItem, eax
mov eax, [ebx].LVSIEDATA.hListview
mov hListview, eax
;mov eax, [ebx].LVSIEDATA.dwAllowWraparound
;mov dwAllowWraparound, eax
IFDEF DEBUG32
;PrintLine
.IF dwDirection == 0
;PrintText 'Right'
.ELSEIF dwDirection == 1
;PrintText 'Left'
.ELSEIF dwDirection == 2
;PrintText 'Down'
.ELSEIF dwDirection == 3
;PrintText 'Up'
.ENDIF
ENDIF
Invoke GetParent, hListview
mov hLVParent, eax
Invoke ListViewGetColumnCount, hListview
mov nTotalCols, eax
Invoke ListViewGetItemCount, hListview
mov nTotalRows, eax
mov eax, dwDirection
.IF eax == LVSIE_RIGHT ; right - default - tab
mov eax, nTotalCols
dec eax ; for 0 based cols
mov ebx, iSubItem
inc ebx
.IF ebx <= eax
mov nNextSubItem, ebx
mov eax, iItem
mov nNextItem, eax
.ELSE
.IF dwWrapHorz == TRUE ;dwAllowWraparound == TRUE ; wrap to next line down, 0 subitem
mov nNextSubItem, 0
mov eax, nTotalRows
dec eax ; for 0 based rows
mov ebx, iItem
inc ebx
.IF ebx <= eax
mov nNextItem, ebx
.ELSE
.IF dwWrapVert == TRUE
mov nNextItem, 0 ; at last cell so go back to 0,0
.ELSE
mov eax, FALSE
ret
.ENDIF
.ENDIF
.ELSE
;Invoke GetNextDlgTabItem, hLVParent, hListview, FALSE
mov eax, FALSE
ret
.ENDIF
.ENDIF
.ELSEIF eax == LVSIE_LEFT ; left (back) - shift+tab
mov eax, nTotalCols
dec eax ; for 0 based cols
mov ebx, iSubItem
dec ebx
.IF sdword ptr ebx >= 0
mov nNextSubItem, ebx
mov eax, iItem
mov nNextItem, eax
.ELSE
.IF dwWrapHorz == TRUE ;dwAllowWraparound == TRUE ; wrap to next line up, total cols-1 subitem
mov eax, nTotalCols
dec eax ; for 0 based col count
mov nNextSubItem, eax
mov eax, nTotalRows
dec eax ; for 0 based rows
mov ebx, iItem
dec ebx
.IF sdword ptr ebx >= 0
mov nNextItem, ebx
.ELSE
.IF dwWrapVert == TRUE
mov eax, nTotalRows
dec eax ; for 0 based row count
mov nNextItem, eax ; at first cell 0,0 so go back to totalrows-1, totalcols-1
.ELSE
mov eax, FALSE
ret
.ENDIF
.ENDIF
.ELSE
;Invoke GetNextDlgTabItem, hLVParent, hListview, TRUE
mov eax, FALSE
ret
.ENDIF
.ENDIF
.ELSEIF eax == LVSIE_DOWN ; down
mov eax, iSubItem
mov nNextSubItem, eax
mov eax, nTotalRows
dec eax ; for 0 based rows
mov ebx, iItem
inc ebx
.IF ebx <= eax
mov nNextItem, ebx
.ELSE
.IF dwWrapVert == TRUE ;dwAllowWraparound == TRUE ; wrap to first line
mov nNextItem, 0
.ELSE
mov eax, FALSE
ret
.ENDIF
.ENDIF
.ELSEIF eax == LVSIE_UP ; up