Here is the code. Put the LVM_GETITEM anywhere. Macros follow the first section. Used RadASM for dialog and listview.
Thanks...
.486
.model flat,stdcall
option casemap:none
include ListView.inc
.code
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke GetCommandLine
invoke InitCommonControls
invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style,CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc,OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,DLGWINDOWEXTRA
push hInst
pop wc.hInstance
mov wc.hbrBackground,COLOR_BTNFACE+1
mov wc.lpszMenuName,OFFSET MenuName
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx,addr wc
invoke CreateDialogParam,hInstance,addr DlgName,NULL,addr WndProc,NULL
invoke ShowWindow,hWnd,SW_SHOWNORMAL
invoke UpdateWindow,hWnd
.while TRUE
invoke GetMessage,addr msg,NULL,0,0
.BREAK .if !eax
invoke TranslateMessage,addr msg
invoke DispatchMessage,addr msg
.endw
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL rDC:DWORD
LOCAL ps:PAINTSTRUCT
LOCAL rect:RECT
mov eax,uMsg
.if eax==WM_INITDIALOG
push hWin
pop hWnd
mov hIDC_LSV1,rv(GetDlgItem,hWin,IDC_LSV1)
invoke SendMessage,hIDC_LSV1,LVM_GETNEXTITEM,-1, LVNI_FOCUSED
invoke SendMessage,hIDC_LSV1,LVM_SETEXTENDEDLISTVIEWSTYLE,0,LVS_EX_FULLROWSELECT or LVS_EX_GRIDLINES
InsertColumn 60,"Date",0
InsertColumn 60,"Time",1
InsertColumn 150,"Purpose",2
InsertColumn 150,"Place",3
InsertItem 0,0,"New Item0"
InsertItem 1,0,"New Item1"
SetItemText 0,1,"New subitem0"
SetItemText 1,1,"Newer subitem1"
.elseif eax==WM_PAINT
invoke BeginPaint,hWnd,addr ps
mov rDC,eax
invoke GetClientRect,hWnd,addr rect
RGB 100,100,0
invoke FillRect,rDC,addr rect,rv(CreateSolidBrush,eax)
ret
.elseif eax==WM_NOTIFY
.elseif eax==WM_COMMAND
mov eax,wParam
and eax,0FFFFh
.if eax==IDM_FILE_EXIT
invoke SendMessage,hIDC_LSV1,LVM_GETCOLUMN,1,addr col
; Here is the crash point. Move this line anywhere...
invoke SendMessage,hIDC_LSV1,LVM_GETITEM,0,addr pitem
invoke SendMessage,hWin,WM_CLOSE,0,0
.elseif eax==IDM_HELP_ABOUT
invoke ShellAbout,hWin,addr AppName,addr AboutMsg,NULL
.endif
.elseif uMsg==WM_SIZE
mov eax,lParam
mov edx,eax
and eax,0ffffh
sub eax,10
shr edx,16
sub edx,30
invoke MoveWindow,hIDC_LSV1, 5, 25, eax,edx,TRUE
.elseif eax==WM_CLOSE
invoke DestroyWindow,hWin
.elseif uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.else
invoke DefWindowProc,hWin,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
WndProc endp
end start
Thanks...
RGB macro red,green,blue
xor eax,eax
mov ah,blue
shl eax,8
mov ah,green
mov al,red
endm
InsertColumn MACRO width,colHeader,colPos
LOCAL lbl
LOCAL header
jmp lbl
header db colHeader,0
lbl:
mov col.imask,LVCF_TEXT or LVCF_WIDTH or LVCF_FMT
mov col.fmt,LVCFMT_LEFT
mov col.lx,width
mov col.pszText,offset header
GetTextLen
invoke SendMessage,hIDC_LSV1,LVM_INSERTCOLUMN,colPos,addr col
ENDM
InsertItem MACRO itemNum,subitemNum,itemText
LOCAL lbl
LOCAL itemTxt
jmp lbl
itemTxt db itemText,0
lbl:
mov pitem.imask,LVIF_TEXT
mov pitem.iItem,itemNum
mov pitem.iSubItem,subitemNum
mov pitem.pszText,offset itemTxt
GetTextLen
invoke SendMessage,hIDC_LSV1,LVM_INSERTITEM,0,addr pitem
ENDM
SetItemText MACRO itemNum,subitemNum,itemText
LOCAL lbl
LOCAL itemTxt
jmp lbl
itemTxt db itemText,0
lbl:
mov pitem.imask,LVIF_TEXT
mov pitem.iItem,itemNum
mov pitem.iSubItem,subitemNum
mov pitem.pszText,offset itemTxt
GetTextLen
invoke SendMessage,hIDC_LSV1,LVM_SETITEMTEXT,itemNum,addr pitem
ENDM
GetTextLen Macro
invoke lstrlen,pitem.pszText
mov pitem.cchTextMax,eax
ENDM
where is pitem defined? is your pitem a ptr to a LV_ITEM struct, or is it the struct itself?
usually the 'p' prefix indicates that the variable concerned is a Pointer - not a Struct.
I am guessing you are passing the address of the pointer to the struct, ie, a pointer to a pointer.
I'd have to see the rest of the code, but I assure you the problem is not LVM_GETITEM.
usually the 'p' prefix indicates that the variable concerned is a Pointer - not a Struct.
I am guessing you are passing the address of the pointer to the struct, ie, a pointer to a pointer.
I'd have to see the rest of the code, but I assure you the problem is not LVM_GETITEM.
Thanks for your interest Homer and here is the rest from the .inc.
This is what Windows API states:
'addr pitem' is the pointer to the struct as I understand it. Remove LVM_GETITEM and the code runs fine.
col LVCOLUMN <>
pitem LVITEM <>
This is what Windows API states:
lResult = SendMessage( // returns LRESULT in lResult
(HWND) hWndControl, // handle to destination control
(UINT) LVM_GETITEM, // message ID
(WPARAM) wParam, // = 0; not used, must be zero
(LPARAM) lParam // = (LPARAM) (LPLVITEM) pitem;
);
Parameters
wParam
Must be zero.
pitem
Pointer to an LVITEM structure that specifies the information to retrieve and receives information about the list-view item.
Return Value
Returns TRUE if successful, or FALSE otherwise.
'addr pitem' is the pointer to the struct as I understand it. Remove LVM_GETITEM and the code runs fine.
Looking at some code i have for using a listview i dont use that LVM_GETITEM directly, but use other LV_ messages to retrieve information
Such as getting the currently selected row:
Getting text from a list item or sub item:
In my data section i have:
but im thinking you need to specify in your LVItem variable before hand to tell the message what you are looking to retrieve, so that you will need to set the item index, and mask of the item type to retrieve.
Not sure if that will help you, ive a few more procs for using listviews if you want.
Such as getting the currently selected row:
;**************************************************************************
; Get Index of Currently Selected Item in Listview
;**************************************************************************
ListViewGetSelection PROC hWin:DWORD
Invoke SendMessage, hListview,LVM_GETNEXTITEM, -1, LVNI_FOCUSED
ret
ListViewGetSelection endp
Getting text from a list item or sub item:
;**************************************************************************
; Gets the text of the specified index. Stored in LVItemText on return
;**************************************************************************
ListViewGetItemText PROC hWin:DWORD, nItem:DWORD, nSubItem:DWORD
mov eax, nSubItem
mov LVItem.iSubItem, eax
invoke SendMessage, hListview, LVM_GETITEMTEXT, nItem, Addr LVItem
ret
ListViewGetItemText endp
In my data section i have:
.DATA
LVItemText db MAX_PATH dup (0) ; Buffer to hold text to display when used with LVItem
LVItem LV_ITEM <LVIF_TEXT,1,0,LVIS_FOCUSED,0,LVItemText,MAX_PATH,0,0>
.DATA?
hListview dd ? ; Listview handle
but im thinking you need to specify in your LVItem variable before hand to tell the message what you are looking to retrieve, so that you will need to set the item index, and mask of the item type to retrieve.
When the message is sent, the iItem and iSubItem members identify the item or subitem to retrieve information about and the mask member specifies which attributes to retrieve.
If the mask member specifies the LVIF_TEXT value, the pszText member must contain the pointer to the buffer that receives the item text and the cchTextMax member must specify the size of the buffer.
If the mask member specifies the LVIF_STATE value, the stateMask member specifies which item states are to be returned.
If the mask member specifies the LVIF_TEXT value, the pszText member must contain the pointer to the buffer that receives the item text and the cchTextMax member must specify the size of the buffer.
If the mask member specifies the LVIF_STATE value, the stateMask member specifies which item states are to be returned.
Not sure if that will help you, ive a few more procs for using listviews if you want.
Hi keithsrobertson, you have evidently got it right. I did some more research after your message and finally came up with this and it did not crash:
What I have been trying to do is get the current column when it is being resized so that I can save it as a setting and LVM_GETITEM not going to work. Do you have an answer??
Thanks again...
mov pitem.iItem,1
mov pitem.iSubItem,1
mov pitem.imask, LVIF_TEXT
lea eax, szBuff
mov pitem.pszText, eax
mov pitem.cchTextMax, 256
invoke SendMessage,hIDC_LSV1,LVM_GETITEM,0,addr pitem
What I have been trying to do is get the current column when it is being resized so that I can save it as a setting and LVM_GETITEM not going to work. Do you have an answer??
Thanks again...
Ive had a look at the list of notification messages passed back to the main window from a listview and cant see an exact one that would allow you to monitor the column resize directly.
Might be better to use the LVM_GETCOLUMNWIDTH message to retrieve the column widths and save them when the user exits the program instead.
Might be better to use the LVM_GETCOLUMNWIDTH message to retrieve the column widths and save them when the user exits the program instead.
Thanks keithsrobertson, I guess we will consider this one as solved at this point. Thanks again.
is the pitem structure defined in the DATA segment or in with the CODE? because writing to that address would cause a GPF due to default page permission for CODE segments.
Hello Homer, it is defined in 'data?'. I tried what keithsrobertson said and it worked.
It looks like you're using pitem for every item you add. I think the trouble is that the last time you used it
you left imask=LVIF_TEXT and pszText as the address of a string - which your macro puts in the code section.
When you try to use LVM_GETITEM it uses imask which tells it that pszText points to a buffer in .code -> access violation.
An interesting bit from the sdk
WTF???
you left imask=LVIF_TEXT and pszText as the address of a string - which your macro puts in the code section.
When you try to use LVM_GETITEM it uses imask which tells it that pszText points to a buffer in .code -> access violation.
An interesting bit from the sdk
Applications should not assume that the text will necessarily be placed in the specified buffer. The control may instead change the pszText member of the structure to point to the new text, rather than place it in the buffer.
WTF???
Well think about it - handing the user a pointer to the internal string buffer avoids the need to copy the string into the buffer that the user supplied - if we just grab the pszText pointer after the call, its always going to be valid - even if its not the pointer that we supplied.
My usual way of using a buffer is
If the pointer gets changed, who owns the memory it points to?
.data?
buffer db 260 dup (?)
.code
...
mov pitem.pszText,offset buffer
invoke SendMessage,hIDC_LSV1,LVM_GETITEM,0,offset pitem
;here I would use
invoke lstrlen,offset buffer
;rather than
invoke lstrlen,pitem.pszText
If the pointer gets changed, who owns the memory it points to?