Crashing when sending a pointer to a large chunk of shared memory via an IPC SendMessage
Author |
Message |
Greg Gursk #1 / 9
|
Crashing when sending a pointer to a large chunk of shared memory via an IPC SendMessage
Hello: In the shell context menu handler that I am writing, I need to send a variable size CStringArray from the handler to a program that the handler launches prior to the interprocess communication (IPC). The CStringArray is populated with the selected file paths from Explorer. When the list is small (under about 75 entries), there is no problem. But when I send a large number (lets say over 100) it causes explorer to crash. Interestingly, when debugging I put an AfxMessageBox("PreIPC") just before the SendMessage that sends the pointer to the other process. After pressing OK the crash does not happen. So it looks like a delay at that point prevents the crash. Of note, my testbed is a Win2k SP2 system. I know IPC usually requires some stringent synchronization, but I don't see how it could be affecting this situation as only one process at a time should be accessing the data. I think this, because the data is prepared before the other process is sent the message to use it. Below is some of the code that I use to accomplish this. I replaced some sections with comments for brevity: (The other process works with and frees the shared memory, but the crash comes before the SendMessage is processed by the other process). // This code is from InvokeCommand() in the context menu handler // m_csaPaths is the CStringArchive that I am sending CMemFile file; CArchive ar(&file, CArchive::store, 40960); ASSERT(m_csaPaths.IsSerializable()); m_csaPaths.Serialize(ar); ar.Close(); DWORD dwLengthMemFile = file.GetLength(); void *lpSerializedData = file.Detach(); void *lpPathsStringArray; HANDLE hMem = ::CreateFileMapping((HANDLE)0xFFFFFFFF, NULL,PAGE_READWRITE,0, dwLengthMemFile, "DBFM_IPC_StringArray_FileMappingName"); if (!hMem) { // HANDLE ERROR } lpPathsStringArray = ::MapViewOfFile(hMem,FILE_MAP_WRITE,0,0,0); if (!lpPathsStringArray) { // HANDLE ERROR } memcpy (lpPathsStringArray, lpSerializedData, dwLengthMemFile); hwndSoughtHandle = ::FindWindow(NULL, _T("DBFileMaker")); g_uintDBFM_IPC_Message = RegisterWindowMessage("WM_DBFM_IPC"); if ((hwndSoughtHandle) && (g_uintDBFM_IPC_Message)) { // A pause here seems to resolve the issue ::SendMessage(hwndSoughtHandle, g_uintDBFM_IPC_Message, (WPARAM)lpPathsStringArray, (LPARAM)dwLengthMemFile); } else { // HANDLE ERROR } if (lpSerializedData) free(lpSerializedData); lpSerializedData = NULL; I'd appreciate any insight into this. This is my first project to use IPC so I'm sure I'm breaking some rules for that. Also, I've never been particularly good at using CMemFile/CArchive, so I may have made mistakes there as well. Thank you, Greg Gursky -- Greg Gursky
|
Wed, 18 Feb 2004 03:48:31 GMT |
|
|
Alex Blekhma #2 / 9
|
Crashing when sending a pointer to a large chunk of shared memory via an IPC SendMessage
Quote: > Hello: > In the shell context menu handler that I am writing, I need to send > a variable size CStringArray from the handler to a program that the > handler launches prior to the interprocess communication (IPC). > The CStringArray is populated with the selected file paths from > Explorer. When the list is small (under about 75 entries), there is > no problem. But when I send a large number (lets say over 100) > it causes explorer to crash. > Interestingly, when debugging I put an AfxMessageBox("PreIPC") > just before the SendMessage that sends the pointer to the other > process. After pressing OK the crash does not happen. So it > looks like a delay at that point prevents the crash. Of note, my > testbed is a Win2k SP2 system. > I know IPC usually requires some stringent synchronization, but I > don't see how it could be affecting this situation as only one > process at a time should be accessing the data. I think this, because > the data is prepared before the other process is sent the message > to use it. > Below is some of the code that I use to accomplish this. I replaced > some sections with comments for brevity: (The other process > works with and frees the shared memory, but the crash comes > before the SendMessage is processed by the other process). > // This code is from InvokeCommand() in the context menu handler > // m_csaPaths is the CStringArchive that I am sending > CMemFile file; > CArchive ar(&file, CArchive::store, 40960); > ASSERT(m_csaPaths.IsSerializable()); > m_csaPaths.Serialize(ar); > ar.Close(); > DWORD dwLengthMemFile = file.GetLength(); > void *lpSerializedData = file.Detach(); > void *lpPathsStringArray; > HANDLE hMem = ::CreateFileMapping((HANDLE)0xFFFFFFFF, > NULL,PAGE_READWRITE,0, dwLengthMemFile, > "DBFM_IPC_StringArray_FileMappingName"); > if (!hMem) { // HANDLE ERROR } > lpPathsStringArray = ::MapViewOfFile(hMem,FILE_MAP_WRITE,0,0,0); > if (!lpPathsStringArray) { // HANDLE ERROR } > memcpy (lpPathsStringArray, lpSerializedData, dwLengthMemFile); > hwndSoughtHandle = ::FindWindow(NULL, _T("DBFileMaker")); > g_uintDBFM_IPC_Message = RegisterWindowMessage("WM_DBFM_IPC"); > if ((hwndSoughtHandle) && (g_uintDBFM_IPC_Message)) > { > // A pause here seems to resolve the issue > ::SendMessage(hwndSoughtHandle, g_uintDBFM_IPC_Message, > (WPARAM)lpPathsStringArray, > (LPARAM)dwLengthMemFile); > } > else > { // HANDLE ERROR } > if (lpSerializedData) > free(lpSerializedData); > lpSerializedData = NULL; > I'd appreciate any insight into this. This is my first project to use IPC > so I'm sure I'm breaking some rules for that. Also, I've never been > particularly good at using CMemFile/CArchive, so I may have made > mistakes there as well.
Dou you pass lpPathsStringArray to other process? How do you treat it in other program? Pointer in app A has no any meaning in app B. You should open file mapping in other process by calling to OpenFileMapping/CreateFileMapping and only values that are valid across process boundaries is offset from file mapping beginning and file mapping size.
|
Wed, 18 Feb 2004 16:46:31 GMT |
|
|
Greg Gursk #3 / 9
|
Crashing when sending a pointer to a large chunk of shared memory via an IPC SendMessage
Quote: >Dou you pass lpPathsStringArray to other process? How do you treat it >in other program? Pointer in app A has no any meaning in app B.
Dear Alex: Thanks for your reply. I was indeed passing lpPathsStringArray to the other process. However, that was just some old code that I forgot to remove. I was not using it on the other end. I replaced the lpPathsStringArray in the SendMessage with a NULL as it should have been. Unfortunately, that did not resolve the problem. The other process properly maps "DBFM_IPC_StringArray_FileMappingName" and uses it. When the number of file paths is small, it works fine, but when sending a large number, it crashes. Of note, its definately this process that is crashing and not the process that the data is being sent to. And it seems its crashing during the SendMessage. I have no way to debug inside the SendMessage, however, to see specifically why its happening. Also, calling an AfxMessageBox() right before the call to SendMessage seems to remedy this. I have no idea why. It makes it sound like a timing issue, but I dont see how timing can have anything to do with it since all the functions I'm using are "blocking" functions. (The term doesn't exactly apply here, but I think you know what I mean.) I'd appreciate any further input you may be able to provide. If you want to see the OnIPCMessage() function from the other app, I'll be happy to post it, but I'm pretty sure its not the cause of this problem. I feel this, because if the crash occurs that message handler in the other app actually never gets called. Thank you, Greg Quote:
>> Hello: >> In the shell context menu handler that I am writing, I need to send >> a variable size CStringArray from the handler to a program that the >> handler launches prior to the interprocess communication (IPC). >> The CStringArray is populated with the selected file paths from >> Explorer. When the list is small (under about 75 entries), there is >> no problem. But when I send a large number (lets say over 100) >> it causes explorer to crash. >> Interestingly, when debugging I put an AfxMessageBox("PreIPC") >> just before the SendMessage that sends the pointer to the other >> process. After pressing OK the crash does not happen. So it >> looks like a delay at that point prevents the crash. Of note, my >> testbed is a Win2k SP2 system. >> I know IPC usually requires some stringent synchronization, but I >> don't see how it could be affecting this situation as only one >> process at a time should be accessing the data. I think this, >because >> the data is prepared before the other process is sent the message >> to use it. >> Below is some of the code that I use to accomplish this. I replaced >> some sections with comments for brevity: (The other process >> works with and frees the shared memory, but the crash comes >> before the SendMessage is processed by the other process). >> // This code is from InvokeCommand() in the context menu handler >> // m_csaPaths is the CStringArchive that I am sending >> CMemFile file; >> CArchive ar(&file, CArchive::store, 40960); >> ASSERT(m_csaPaths.IsSerializable()); >> m_csaPaths.Serialize(ar); >> ar.Close(); >> DWORD dwLengthMemFile = file.GetLength(); >> void *lpSerializedData = file.Detach(); >> void *lpPathsStringArray; >> HANDLE hMem = ::CreateFileMapping((HANDLE)0xFFFFFFFF, >> NULL,PAGE_READWRITE,0, dwLengthMemFile, >> "DBFM_IPC_StringArray_FileMappingName"); >> if (!hMem) { // HANDLE ERROR } >> lpPathsStringArray = ::MapViewOfFile(hMem,FILE_MAP_WRITE,0,0,0); >> if (!lpPathsStringArray) { // HANDLE ERROR } >> memcpy (lpPathsStringArray, lpSerializedData, dwLengthMemFile); >> hwndSoughtHandle = ::FindWindow(NULL, _T("DBFileMaker")); >> g_uintDBFM_IPC_Message = RegisterWindowMessage("WM_DBFM_IPC"); >> if ((hwndSoughtHandle) && (g_uintDBFM_IPC_Message)) >> { >> // A pause here seems to resolve the issue >> ::SendMessage(hwndSoughtHandle, g_uintDBFM_IPC_Message, >> (WPARAM)lpPathsStringArray, >> (LPARAM)dwLengthMemFile); >> } >> else >> { // HANDLE ERROR } >> if (lpSerializedData) >> free(lpSerializedData); >> lpSerializedData = NULL; >> I'd appreciate any insight into this. This is my first project to >use IPC >> so I'm sure I'm breaking some rules for that. Also, I've never been >> particularly good at using CMemFile/CArchive, so I may have made >> mistakes there as well.
-- Greg Gursky
|
Thu, 19 Feb 2004 04:09:18 GMT |
|
|
#4 / 9
|
Crashing when sending a pointer to a large chunk of shared memory via an IPC SendMessage
|
Wed, 18 Jun 1902 08:00:00 GMT |
|
|
Greg Gursk #5 / 9
|
Crashing when sending a pointer to a large chunk of shared memory via an IPC SendMessage
Dear Alex (and anyone else following this thread): I believe I've solved the problem. I wasn't calling UnmapViewOfFile() on the mapped data before calling the SendMessage. While I know I should have done this, I'm still not sure why the crash occurred in the SendMessage (which doesnt send anything other than a notification to the other process). Anyways, calling ::UnmapViewOfFile(lpPathsStringArray); after the memcpy seems to have solved it. I ran it on 9774 files I have in one of my directories and it was fine. Thanks Alex for your help. It was your question that got me investigating. Sincerely, Greg -- Greg Gursky
|
Thu, 19 Feb 2004 04:47:06 GMT |
|
|
#6 / 9
|
Crashing when sending a pointer to a large chunk of shared memory via an IPC SendMessage
|
Wed, 18 Jun 1902 08:00:00 GMT |
|
|
Greg Gursk #7 / 9
|
Crashing when sending a pointer to a large chunk of shared memory via an IPC SendMessage
Jumped the gun, it looks like. On further testing its still happening. It seems to be happening with very very large numbers of files (> approximately 5000) now. It seems to be intermittent now and requires many more files than before, but it still happens. My guess is that the unmap command is delaying things just a touch so a larger list works out. So while I can hardwire in a delay with a length dependant on the size of the CStringArray, this is hardly "proper" as its avoiding the problem and not fixing it. So if anyone can still see any error in my code (see both the original post and my first reply to Alex) I'd appreciate a heads-up. Thanks, Greg -- Greg Gursky
|
Thu, 19 Feb 2004 05:15:37 GMT |
|
|
Alex Blekhma #8 / 9
|
Crashing when sending a pointer to a large chunk of shared memory via an IPC SendMessage
Quote: > Jumped the gun, it looks like. On further testing > its still happening. > It seems to be happening with very very large > numbers of files (> approximately 5000) now. It > seems to be intermittent now and requires many > more files than before, but it still happens. My > guess is that the unmap command is delaying > things just a touch so a larger list works out. > So while I can hardwire in a delay with a length > dependant on the size of the CStringArray, this > is hardly "proper" as its avoiding the problem and > not fixing it. > So if anyone can still see any error in my code (see > both the original post and my first reply to Alex) I'd > appreciate a heads-up.
Hm.. Can it be something that related to number of files? 5000 filenames is a quite large number. Can it be stack overflow somewhere?
|
Thu, 19 Feb 2004 13:23:35 GMT |
|
|
Greg Gursk #9 / 9
|
Crashing when sending a pointer to a large chunk of shared memory via an IPC SendMessage
Quote: >Hm.. Can it be something that related to number of files? 5000 >filenames is a quite large number. Can it be stack overflow somewhere?
I'm not certain, that's for sure, but I really don't see why it would be. It seems the crash is occuring in the SendMessage. The SendMessage is simply sending a registered message and a number to another application and really knows nothing about the shared data. Also, if it were that, I don't understand why a pause (I think as little as a couple of milliseconds) before the SendMessage stops the crash. Even once without the pause it was able to handle over 9000 files probably because the OS switched to another process right about that point and slowed down the execution enough to allow it to run properly. Also, I've used other applications that successfully handled that number of files from a context menu (WinZip is one I can think of ATM) and while I can't be sure they used shared memory for doing the IPC, I think it's likely. Anyways, I'm starting to suspect it has nothing to do with the IPC at all and perhaps it has to do with something with the SendMessage itself. I need to check that the second process is perhaps not ready to receive the registered message. While the handle is valid perhaps its not ready to accept a message via SendMessage. But if this is true I dont understand why the size of the CStringArray effects it since the SendMessage really has nothing to do with the CStringArray or the shared memory I fill with it. And if all else fails I'll just introduce a waitable timer and pause it for a half a second or something when the file list is large. Thats going to be a last resort, of course, as its avoiding the problem and not fixing it. Anyways, thanks for your help. Sincerely, Greg -- Greg Gursky
|
Fri, 20 Feb 2004 00:01:53 GMT |
|
|
|