|
-
Dec 15th, 2009, 05:22 AM
#1
Thread Starter
Hyperactive Member
Out Of memory Error
The code posted here works good, it takes a filename received from command and send it to the previous instance of the application.....
I am making some changes on it, and i am getting an error "Out Of Memory" ... if i try with the exe, it crashes and close, and if i am on the IDE, and i run with compile, i get an error "Out Of Memory" and the IDE stop responding
to make it easiar to identify the problem, i removed all the changes i made and kept the only ones causing the error...So here what i am trying to do is instead of sending
the file name only, i try to send another string wich is the short name of the file
Attached the original Code and the Edited one...Anyway here are the difference between both :
The error occurs on the Edited version , at the Function WndProc
line :
vb Code:
ReDim bDataArrShort(tData.cbDataShortName - 1)
As it seems here the value of the tData.cbDataShortName is too big, while when we send it at the sendStringToPrimaryInstance, it's value is the lenght so why here we receive it that big ? maybe if you have an answer to this question this will solve the problem
here are the original and edited version of the code (the original works good)
'Original
vb Code:
Private Type COPYDATASTRUCT
dwData As Long
cbData As Long
lpData As Long
End Type
'Edited
vb Code:
Private Type COPYDATASTRUCT
dwData As Long
cbData As Long
lpData As Long
cbDataShortName As Long
lpDataShortName As Long
End Type
'Original
vb Code:
Public Function sendStringToPrimaryInstance(ByRef szData As String, ByVal hWndSubordinate As Long, ByVal hWndPrimary As Long)
Dim tData As COPYDATASTRUCT, bDataArr() As Byte, lRet As Long
'--Convert (UNICODE) String to (ANSI) so it faster for Windows to marshall the data across processes
'--Note that UNICODE support dies here
bDataArr = StrConv(szData, vbFromUnicode)
'--Setup the COPYDATA Struct
tData.dwData = hWndSubordinate '--HWND of Sender
tData.cbData = UBound(bDataArr) + 1 '--Length Of data
tData.lpData = VarPtr(bDataArr(0)) '--Pointer to the data
'--Sendit to the primary instance
lRet = SendMessage(hWndPrimary, WM_COPYDATA, hWndSubordinate, tData)
End Function
'Edited
vb Code:
Public Function sendStringToPrimaryInstance(ByRef szData As String, ByVal hWndSubordinate As Long, ByVal hWndPrimary As Long)
Dim tData As COPYDATASTRUCT, bDataArr() As Byte, lRet As Long
Dim bDataArrShort() As Byte
Dim ShortFileName As String
ShortFileName = GetDirOrShortFileName(szData)
'--Convert (UNICODE) String to (ANSI) so it faster for Windows to marshall the data across processes
'--Note that UNICODE support dies here
bDataArr = StrConv(szData, vbFromUnicode)
'--Setup the COPYDATA Struct
tData.dwData = hWndSubordinate '--HWND of Sender
tData.cbData = UBound(bDataArr) + 1 '--Length Of data
tData.lpData = VarPtr(bDataArr(0)) '--Pointer to the data
'--Sendit to the primary instance
bDataArrShort = StrConv(ShortFileName, vbFromUnicode)
'UBound(bDataArrShort) + 1 ==> giving the right value wich is the length of the ShortFileName
tData.cbDataShortName = UBound(bDataArrShort) + 1
tData.lpDataShortName = VarPtr(bDataArrShort(0))
lRet = SendMessage(hWndPrimary, WM_COPYDATA, hWndSubordinate, tData)
End Function
'Original
vb Code:
Public Function WndProc(ByVal hWnd As Long, ByVal uiMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim szFilename As String, bDataArr() As Byte, tData As COPYDATASTRUCT
If (uiMsg = WM_COPYDATA) Then
'--Grab the COPYDATA struct from the pointer lParam
Call CopyMemory(tData, ByVal lParam, Len(tData))
'--Make sure its the required COPYDATA struct by making sure wParam == tData.dwData
If (tData.dwData = wParam) Then
'--Create a buffer the size of the data
ReDim bDataArr(tData.cbData - 1)
'--Copy data into the buffer
Call CopyMemory(bDataArr(0), ByVal tData.lpData, tData.cbData)
'--Create ANSI String from Byte Array
szFilename = bDataArr
'--Convert ANSI String into UNICODE so VB understands it
szFilename = StrConv(szFilename, vbUnicode)
'--Call the handler and pass it the filename passed
Call Interaction.CallByName(m_pDisp, FUNC_PROC, VbMethod, szFilename)
'--We handled the message!
WndProc = 1
Else
'--We dont care
WndProc = 0
End If
Else
'Default impl.
WndProc = CallWindowProc(m_lPrevProc, hWnd, uiMsg, wParam, lParam)
End If
End Function
'Edited
vb Code:
Public Function WndProc(ByVal hWnd As Long, ByVal uiMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim szFilename As String, bDataArr() As Byte, tData As COPYDATASTRUCT
Dim szFilenameShort As String, bDataArrShort() As Byte
If (uiMsg = WM_COPYDATA) Then
'--Grab the COPYDATA struct from the pointer lParam
Call CopyMemory(tData, ByVal lParam, Len(tData))
'--Make sure its the required COPYDATA struct by making sure wParam == tData.dwData
If (tData.dwData = wParam) Then
'--Create a buffer the size of the data
ReDim bDataArr(tData.cbData - 1)
'--Copy data into the buffer
Call CopyMemory(bDataArr(0), ByVal tData.lpData, tData.cbData)
'--Create ANSI String from Byte Array
szFilename = bDataArr
'--Convert ANSI String into UNICODE so VB understands it
szFilename = StrConv(szFilename, vbUnicode)
'--Call the handler and pass it the filename passed
'Added Code
'Here it's getting out of memory !
ReDim bDataArrShort(tData.cbDataShortName - 1)
Call CopyMemory(bDataArrShort(0), ByVal tData.lpDataShortName, tData.cbDataShortName)
szFilenameShort = bDataArrShort
szFilenameShort = StrConv(szFilenameShort, vbUnicode)
Call Interaction.CallByName(m_pDisp, FUNC_PROC, VbMethod, szFilename, szFilenameShort)
'--We handled the message!
WndProc = 1
Else
'--We dont care
WndProc = 0
End If
Else
'Default impl.
WndProc = CallWindowProc(m_lPrevProc, hWnd, uiMsg, wParam, lParam)
End If
End Function
'Original
vb Code:
Public Function filenameReceived(ByRef szFilename As String)
Call lstFiles.AddItem(szFilename)
End Function
'Edited
vb Code:
Public Function filenameReceived(ByRef szFilename As String, ByRef szFilenameShort As String)
Call lstFiles.AddItem(szFilename)
Call lstFiles.AddItem(szFilenameShort)
End Function
'Edited-New Function
vb Code:
Public Function GetDirOrShortFileName(ByVal ScanString As String) As String
'This function works well
Dim intPos As Integer
Dim intPosSave As Integer
intPos = 1
Do
intPos = InStr(intPos, ScanString, "\")
If intPos = 0 Then
Exit Do
Else
intPos = intPos + 1
intPosSave = intPos - 1
End If
Loop
GetDirOrShortFileName = Mid(ScanString, intPosSave + 1, Len(ScanString) - intPosSave)
End Function
thanks again to all for your support till now , your advides till now helped me a lot to advance in my appliction
X3 Passing Filenames.zip
X3 Passing Filenames_Edited.zip
Last edited by justgreat; Dec 15th, 2009 at 05:57 AM.
-
Dec 15th, 2009, 09:40 AM
#2
Re: Out Of memory Error
You cannot modify the COPYDATASTRUCT structure. WM_COPYDATA is a special message that Windows knows about and expects a 12 byte structure, no more no less. When this message is sent, Windows basically reserves space in the targets process' memory space and copies the data pointed to by .lpData, for a total of .cbData bytes.
I think you have 2 choices.
1. Send the message twice, once with long file names, once with short file names
2. Create your own custom UDT/array that contains all the information you need in contiguous bytes, then set the .lpData with the VarPtr() of that UDT/array, and the .cbData will be the total size of the UDT/array. This can be tricky initially, but not extremely difficult. See if this example helps.
Edited. The reason for the crash is most likely due to your lpDataShortName. That pointer is pointing to memory in the sender's process space not the target's space. So when you try to read it, you will either crash or get garbage.
WM_COPYDATA ensures that .lpData points to the target's memory space not the sender's. You can test this if curious. I doubt that the value of .lpData sent is the same value when received, assuming sender and target are not in the same process.
Last edited by LaVolpe; Dec 15th, 2009 at 09:59 AM.
-
Dec 15th, 2009, 10:21 AM
#3
Thread Starter
Hyperactive Member
Re: Out Of memory Error
 Originally Posted by LaVolpe
You cannot modify the COPYDATASTRUCT structure. WM_COPYDATA is a special message that Windows knows about and expects a 12 byte structure, no more no less. When this message is sent, Windows basically reserves space in the targets process' memory space and copies the data pointed to by .lpData, for a total of .cbData bytes.
I think you have 2 choices.
1. Send the message twice, once with long file names, once with short file names
2. Create your own custom UDT/array that contains all the information you need in contiguous bytes, then set the .lpData with the VarPtr() of that UDT/array, and the .cbData will be the total size of the UDT/array. This can be tricky initially, but not extremely difficult. See if this example helps.
Edited. The reason for the crash is most likely due to your lpDataShortName. That pointer is pointing to memory in the sender's process space not the target's space. So when you try to read it, you will either crash or get garbage.
WM_COPYDATA ensures that .lpData points to the target's memory space not the sender's. You can test this if curious. I doubt that the value of .lpData sent is the same value when received, assuming sender and target are not in the same process.
thanks a lot for your answer, i will check the link you gave me, but please
confirm if i understand your answer, because i got an idea, and want to see if it works or not...
What i understand is that
Whenever i want to use the SendMessage, if i send a WM_COPYDATA parameters, i have to send with it a structure of 12 byte ....
Is it related to SendMessage only or also WndProc won't accept except a 12 byte ?
To solve my problem i got 2 ideas, please tell me, if it may work
1) can't i use something like :
vb Code:
so lRet = SendMessage(hWndPrimary, WM_COPYDATA, tData1, tData)
where tData1 is another structure of 12 byte that contain the short file name ? So i do the same thing for tdata1 and tdata ?
2) Am i obliged to use the WM_COPYDATA ? What i understand from the code is that WM_COPYDATA helps to know if the message is sent from me or another application and nothing more (i may be wrong, which means i understand the code wrong)... In this case, can't i use something like :
vb Code:
CONST WM_MYOWNMESSAGE = "AnyString"
Then i use the api RegisterMessage() , to register the WM_MYOWNMESSAGE and to get a unique ID for my custom message
then i use something like
so lRet = SendMessage(hWndPrimary, WM_MYOWNMESSAGE, hWndSubordinate, tData)
where tData use a custom structure (more than 12 byte like the one
i made that send all i want ?
I mean that i keep the code as it is, all i change is that i use another message name than WM_COPYDATA ?
-
Dec 15th, 2009, 10:38 AM
#4
Re: Out Of memory Error
You have to understand pointers and address space. Each process has its own space, so if App1 passes VarPtr(something) to APP2, the value of VarPtr(something) only applies to APP1. If APP2 tries to use CopyMemory on that value, it will either crash or read garbage, because that pointer is not valid for APP2's memory space and points to something completely different in APP2, if anything at all.
WM_COPYDATA does stuff behind the scenes that allows memory to be shared between two different processes. WM_COPYDATA's primary purpose is to transfer information between two different windows. This is a bit easier to use than mapped memory files and read/writeprocessmemory apis (which I believe is what WM_CopyData is using behind the scenes).
Try to understand that your array data exists only in the sender's process memory. WM_COPYDATA ensures it is also copied to the target's process memory. Trying to send your own message and a structure does no good.... Your structure will most likely contain pointers to arrays and/or strings that the target app cannot access; if you try, you will continue to crash.
Play with the project I linked to, if I remember it correctly (been several years ago), it is a very good one to learn from and the comments allow the code to be followed easily I think.
-
Dec 15th, 2009, 06:52 PM
#5
Thread Starter
Hyperactive Member
Re: Out Of memory Error
Thanks for your valuable reply and explication.
I am reading the example now to see how can i send an array of strings...
You know if the user select multiple files multiple instance will send to the primary instance the selected files names...
Thus, I would like to know how to detect that all files has been transfered and that now i can process them, because i want to collect them all in the list box and once i finish receiving them, i start working on them ... any clue about it ?
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|