CListCtrl::FindItem crashes
-
With FindWindow and FindChildWindows API functions, I got the handle of SysListView32 control of mmsys.cpl panel. When I was trying to search the text of each entries on the ListCtrl, it always crashed. My code snippet is as the below.
void CMainDlg::OnBnClickedGetDolby()
{
// Kill any running window if any.
KillRunningApplet(_T("Sound"));// Launch it. if(!LaunchCplApplet(\_T("mmsys.cpl"), 0, 0)) { OutputDebugString(\_T("LaunchCplApplet fails. \\n")); return; } // Make sure the applet pops up. CWnd\* pWnd = NULL; int i = 0; while(!pWnd) { pWnd = FindWindow(NULL, \_T("Sound")); if(pWnd) { OutputDebugString(\_T("Found Sound window. \\n")); break; } Sleep(10); i++; if(i > 1000) { OutputDebugString(\_T("Sound window is not found. \\n")); return; } } // --- m\_hListView = NULL; for(i = 0; i < 2; i++) { EnumChildWindows(pWnd->m\_hWnd, DoSomethingHelper, (LPARAM)this); if(m\_hListView) { OutputDebugString(\_T("Got SysListView32")); break; } else { OutputDebugString(\_T("SysListView32 is not found.")); if(i == 1) { return; } } }
// m_pListView->SendMessage(WM_KEYDOWN, VK_DOWN, 0);
// m_pListView->SendMessage(WM_KEYDOWN, VK_DOWN, 0);CListView\* pView = (CListView\*)FromHandle(m\_hListView); CListCtrl& Ctrl = pView->GetListCtrl();
// Ctrl.ShowWindow(SW_HIDE); // <-- this line tells me that I got the right handle.
LVFINDINFO info = {0}; int iIndex = 0; info.flags = LVFI\_PARTIAL | LVFI\_STRING; info.psz = \_T("Speaker\\0"); if((iIndex = Ctrl.FindItem(&info)) != -1) { // <-- crash at this line. OutputDebugString(\_T("Speaker-like entry is found.")); }
}
BOOL CALLBACK DoSomethingHelper(HWND hwnd, LPARAM lParam)
{
TCHAR sClassName[MAX_PATH] = {0};
GetClassName(hwnd, sClassName, MAX_PATH);
if(wcscmp(sClassName, _T("SysListView32")) == 0) {
CMainDlg* pMain = (CMainDlg*)lParam;
pMain->m_hListView = hwnd;
}
OutputDebugString(sClassName);
return TRUE;
}Maxwell Chen
-
With FindWindow and FindChildWindows API functions, I got the handle of SysListView32 control of mmsys.cpl panel. When I was trying to search the text of each entries on the ListCtrl, it always crashed. My code snippet is as the below.
void CMainDlg::OnBnClickedGetDolby()
{
// Kill any running window if any.
KillRunningApplet(_T("Sound"));// Launch it. if(!LaunchCplApplet(\_T("mmsys.cpl"), 0, 0)) { OutputDebugString(\_T("LaunchCplApplet fails. \\n")); return; } // Make sure the applet pops up. CWnd\* pWnd = NULL; int i = 0; while(!pWnd) { pWnd = FindWindow(NULL, \_T("Sound")); if(pWnd) { OutputDebugString(\_T("Found Sound window. \\n")); break; } Sleep(10); i++; if(i > 1000) { OutputDebugString(\_T("Sound window is not found. \\n")); return; } } // --- m\_hListView = NULL; for(i = 0; i < 2; i++) { EnumChildWindows(pWnd->m\_hWnd, DoSomethingHelper, (LPARAM)this); if(m\_hListView) { OutputDebugString(\_T("Got SysListView32")); break; } else { OutputDebugString(\_T("SysListView32 is not found.")); if(i == 1) { return; } } }
// m_pListView->SendMessage(WM_KEYDOWN, VK_DOWN, 0);
// m_pListView->SendMessage(WM_KEYDOWN, VK_DOWN, 0);CListView\* pView = (CListView\*)FromHandle(m\_hListView); CListCtrl& Ctrl = pView->GetListCtrl();
// Ctrl.ShowWindow(SW_HIDE); // <-- this line tells me that I got the right handle.
LVFINDINFO info = {0}; int iIndex = 0; info.flags = LVFI\_PARTIAL | LVFI\_STRING; info.psz = \_T("Speaker\\0"); if((iIndex = Ctrl.FindItem(&info)) != -1) { // <-- crash at this line. OutputDebugString(\_T("Speaker-like entry is found.")); }
}
BOOL CALLBACK DoSomethingHelper(HWND hwnd, LPARAM lParam)
{
TCHAR sClassName[MAX_PATH] = {0};
GetClassName(hwnd, sClassName, MAX_PATH);
if(wcscmp(sClassName, _T("SysListView32")) == 0) {
CMainDlg* pMain = (CMainDlg*)lParam;
pMain->m_hListView = hwnd;
}
OutputDebugString(sClassName);
return TRUE;
}Maxwell Chen
-
Which applicaion crashes? the applet or your application?
A dialog box popped up saying "Windows Shell Common DLL has stopped working". When I clicked [Close program] of that popup, the applet was gone but my application still was alive. I traced into the source of MFC. The problem is the m_hWnd of that CListCtrl.
_AFXCMN_INLINE int CListCtrl::FindItem(LVFINDINFO* pFindInfo, int nStart) const
{ ASSERT(::IsWindow(m_hWnd)); return (int) ::SendMessage(m_hWnd, LVM_FINDITEM, nStart, (LPARAM)pFindInfo); }Maxwell Chen
modified on Friday, September 25, 2009 2:09 AM
-
A dialog box popped up saying "Windows Shell Common DLL has stopped working". When I clicked [Close program] of that popup, the applet was gone but my application still was alive. I traced into the source of MFC. The problem is the m_hWnd of that CListCtrl.
_AFXCMN_INLINE int CListCtrl::FindItem(LVFINDINFO* pFindInfo, int nStart) const
{ ASSERT(::IsWindow(m_hWnd)); return (int) ::SendMessage(m_hWnd, LVM_FINDITEM, nStart, (LPARAM)pFindInfo); }Maxwell Chen
modified on Friday, September 25, 2009 2:09 AM
hmm.. This is because you are passing a string pointer to another process. And when the other process try to access that pointer, exception occurs. You have to allocate the memoy in the target process( VirtualAllocEx() ), copy the string to that process' memory( WriteProcessMemory()). Then set that pointer in the LVM_FINDITEM structure and call FindItem().
-
hmm.. This is because you are passing a string pointer to another process. And when the other process try to access that pointer, exception occurs. You have to allocate the memoy in the target process( VirtualAllocEx() ), copy the string to that process' memory( WriteProcessMemory()). Then set that pointer in the LVM_FINDITEM structure and call FindItem().
I did this as the below, but pBuffer is bad_ptr and WriteProcessMemory returns fail.
LVFINDINFO info = {0}; int iIndex = 0; TCHAR sTxt\[MAX\_PATH\] = {0}; SIZE\_T nByte = 0; wcscpy(sTxt, \_T("Speaker")); info.flags = LVFI\_PARTIAL | LVFI\_STRING; TCHAR\* pBuffer = (TCHAR\*)::VirtualAllocEx(m\_hCplProcess, NULL, MAX\_PATH, MEM\_RESERVE, PAGE\_READWRITE); if(!WriteProcessMemory(m\_hCplProcess, pBuffer, sTxt, MAX\_PATH, &nByte)) { return; } info.psz = pBuffer; if((iIndex = Ctrl.FindItem(&info)) != -1) { OutputDebugString(\_T("Speaker-like entry is found.")); } VirtualFreeEx(m\_hCplProcess, pBuffer, MAX\_PATH, MEM\_RELEASE);
Maxwell Chen
-
I did this as the below, but pBuffer is bad_ptr and WriteProcessMemory returns fail.
LVFINDINFO info = {0}; int iIndex = 0; TCHAR sTxt\[MAX\_PATH\] = {0}; SIZE\_T nByte = 0; wcscpy(sTxt, \_T("Speaker")); info.flags = LVFI\_PARTIAL | LVFI\_STRING; TCHAR\* pBuffer = (TCHAR\*)::VirtualAllocEx(m\_hCplProcess, NULL, MAX\_PATH, MEM\_RESERVE, PAGE\_READWRITE); if(!WriteProcessMemory(m\_hCplProcess, pBuffer, sTxt, MAX\_PATH, &nByte)) { return; } info.psz = pBuffer; if((iIndex = Ctrl.FindItem(&info)) != -1) { OutputDebugString(\_T("Speaker-like entry is found.")); } VirtualFreeEx(m\_hCplProcess, pBuffer, MAX\_PATH, MEM\_RELEASE);
Maxwell Chen
-
Maxwell Chen wrote:
TCHAR* pBuffer = (TCHAR*)::VirtualAllocEx(m_hCplProcess, NULL, MAX_PATH, MEM_RESERVE, PAGE_READWRITE);
You have to pass flAllocationType as MEM_COMMIT|MEM_RESERVE
Naveen wrote:
You have to pass flAllocationType as MEM_COMMIT|MEM_RESERVE
I did, too. And it crashed as well ... :sigh:
TCHAR\* pBuffer = NULL; pBuffer = (TCHAR\*)::VirtualAllocEx(m\_hCplProcess, NULL, MAX\_PATH, MEM\_COMMIT | MEM\_RESERVE, PAGE\_READWRITE); if(!pBuffer) { return; }
I also tried to VirtualAllocEx a LVFINDINFO object to replace the local one. It crashed too but at different line. Not at FindItem call but at the line
LVFINDINFO* pInfo = NULL;
// Do VirtualAllocEx for pInfo ...
pInfo->flags = LVFI_PARTIAL | LVFI_STRING; // <-- crash.Maxwell Chen
-
Naveen wrote:
You have to pass flAllocationType as MEM_COMMIT|MEM_RESERVE
I did, too. And it crashed as well ... :sigh:
TCHAR\* pBuffer = NULL; pBuffer = (TCHAR\*)::VirtualAllocEx(m\_hCplProcess, NULL, MAX\_PATH, MEM\_COMMIT | MEM\_RESERVE, PAGE\_READWRITE); if(!pBuffer) { return; }
I also tried to VirtualAllocEx a LVFINDINFO object to replace the local one. It crashed too but at different line. Not at FindItem call but at the line
LVFINDINFO* pInfo = NULL;
// Do VirtualAllocEx for pInfo ...
pInfo->flags = LVFI_PARTIAL | LVFI_STRING; // <-- crash.Maxwell Chen
Maxwell Chen wrote:
I also tried to VirtualAllocEx a LVFINDINFO object to replace the local one. It crashed too but at different line. Not at FindItem call but at the line
hmm..I missed that one... here is the correct step.. 1 . VirtualAlloc string in the remote process 2. write the string to that memory. 3. create local object of LVFINDINFO. 4. Set the flags and psz as the memory of the remote process 5. Allocate another memory in the remote process, who's size = sizeof( LVFINDINFO). 6. copy the content of the local LVFINDINFO structure to the remote memory using writeprocessmemory 7. Pass the pointer of the remote LVFINDINFO to the finditem() function
-
Maxwell Chen wrote:
I also tried to VirtualAllocEx a LVFINDINFO object to replace the local one. It crashed too but at different line. Not at FindItem call but at the line
hmm..I missed that one... here is the correct step.. 1 . VirtualAlloc string in the remote process 2. write the string to that memory. 3. create local object of LVFINDINFO. 4. Set the flags and psz as the memory of the remote process 5. Allocate another memory in the remote process, who's size = sizeof( LVFINDINFO). 6. copy the content of the local LVFINDINFO structure to the remote memory using writeprocessmemory 7. Pass the pointer of the remote LVFINDINFO to the finditem() function
Naveen wrote:
3. create local object of LVFINDINFO. 4. Set the flags and psz as the memory of the remote process 5. Allocate another memory in the remote process, who's size = sizeof( LVFINDINFO).
Thank you very much. It does not crash now. :-D
Maxwell Chen