[RESOLVED] How to pass values into a running program?
Hello.
I'd like to pass some values into a VB6 application. I know how to do this via the command line, but what if the program is already running?
Is there a way to send command line arguments to a running VB6 program? And if so, how does that work? Or, is there a better way to send the arguments to the running program?
I welcome any comments. I have never tried to do this before so I would like some ideas on the best way to do it.
DDE, Winsock are good methods as long as you have the source code to both VB6 programs. If not, then, we'll have to figure out some other way
Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
TheTrick - I am not familiar with the DDE, MAPI, FileMapping methods. I will have to do a little research to learn about it to see if I can use any of those methods.
jmsrickland - I have the code for the VB.NET source program and the VB6 destination program, so yes, I'm sure we can find something to make it happen.
BonnieWest - I will download and try the demo project. Thank you.
I make simple example using FileMapping. You should compile and launch several instances of application and try to send message.
Code:
Option Explicit
Private Type SharedData
AppCount As Long ' Count of running applications
Counter As Long ' Counter that show how many objects read data
SenderPID As Long ' Sender process id
' String offset ---- 0xc
End Type
Private Declare Function CreateFileMapping Lib "kernel32" _
Alias "CreateFileMappingA" ( _
ByVal hFile As Long, _
ByRef lpFileMappingAttributes As Any, _
ByVal flProtect As Long, _
ByVal dwMaximumSizeHigh As Long, _
ByVal dwMaximumSizeLow As Long, _
ByVal lpName As String) As Long
Private Declare Function MapViewOfFile Lib "kernel32" ( _
ByVal hFileMappingObject As Long, _
ByVal dwDesiredAccess As Long, _
ByVal dwFileOffsetHigh As Long, _
ByVal dwFileOffsetLow As Long, _
ByVal dwNumberOfBytesToMap As Long) As Long
Private Declare Function UnmapViewOfFile Lib "kernel32" ( _
ByVal lpBaseAddress As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" ( _
ByVal hObject As Long) As Long
Private Declare Function CreateMutex Lib "kernel32" _
Alias "CreateMutexA" ( _
ByRef lpMutexAttributes As Any, _
ByVal bInitialOwner As Long, _
ByVal lpName As String) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" ( _
ByVal hHandle As Long, _
ByVal dwMilliseconds As Long) As Long
Private Declare Function ReleaseMutex Lib "kernel32" ( _
ByVal hMutex As Long) As Long
Private Declare Function lstrlen Lib "kernel32" _
Alias "lstrlenA" ( _
ByVal lpString As Any) As Long
Private Declare Function lstrcpyn Lib "kernel32" _
Alias "lstrcpynA" ( _
ByVal lpString1 As Any, _
ByVal lpString2 As Any, _
ByVal iMaxLength As Long) As Long
Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long
Private Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" ( _
ByRef Destination As Any, _
ByRef Source As Any, _
ByVal Length As Long)
Private Declare Sub ZeroMemory Lib "kernel32" _
Alias "RtlZeroMemory" ( _
ByRef Destination As Any, _
ByVal Length As Long)
Private Const FILE_MAP_WRITE As Long = &H2
Private Const PAGE_READWRITE As Long = 4&
Private Const INVALID_HANDLE_VALUE As Long = -1
Private Const INFINITE As Long = -1&
Private Const ERROR_ALREADY_EXISTS As Long = 183&
Dim lpAddrSharedData As Long ' Address of shared data
Dim hMutex As Long ' Synchronization mutex
Dim IsSending As Boolean
Dim hMap As Long
Private Sub cmdSend_Click()
Dim Dat As SharedData
' Capture mutext
WaitForSingleObject hMutex, INFINITE
CopyMemory Dat, ByVal lpAddrSharedData, Len(Dat)
If Dat.Counter > 0 Then
MsgBox "Sending"
Else
' Exclude itsels
Dat.Counter = Dat.AppCount - 1
Dat.SenderPID = GetCurrentProcessId()
lstrcpyn lpAddrSharedData + &HC, ByVal txtMessage.Text, Len(txtMessage.Text) + 1
CopyMemory ByVal lpAddrSharedData, Dat, Len(Dat)
IsSending = True
End If
' Release mutex
ReleaseMutex hMutex
End Sub
Private Sub Form_Load()
Dim Dat As SharedData
Dim isFirst As Long
hMap = CreateFileMapping(INVALID_HANDLE_VALUE, ByVal 0&, PAGE_READWRITE, 0, &H1000, "MapExample")
If hMap = 0 Then
MsgBox "Unable to create file mapping", vbCritical
End
Else
If Err.LastDllError <> ERROR_ALREADY_EXISTS Then
' First application
isFirst = True
End If
End If
lpAddrSharedData = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0)
If lpAddrSharedData = 0 Then
MsgBox "Unable to project file mapping", vbCritical
End
Else
If isFirst Then
' Clear all data
ZeroMemory ByVal lpAddrSharedData, &H1000
End If
End If
hMutex = CreateMutex(ByVal 0&, 0, "MapExampleMutex")
If hMutex = 0 Then
MsgBox "Unable to create mutex", vbCritical
UnmapViewOfFile lpAddrSharedData
End
End If
' Capture mutext
WaitForSingleObject hMutex, INFINITE
CopyMemory Dat, ByVal lpAddrSharedData, Len(Dat)
' Add application
Dat.AppCount = Dat.AppCount + 1
CopyMemory ByVal lpAddrSharedData, Dat, Len(Dat)
' Release mutex
ReleaseMutex hMutex
End Sub
Private Sub Form_Unload(Cancel As Integer)
Dim Dat As SharedData
' Capture mutext
WaitForSingleObject hMutex, INFINITE
CopyMemory Dat, ByVal lpAddrSharedData, Len(Dat)
' Delete application
Dat.AppCount = Dat.AppCount - 1
CopyMemory ByVal lpAddrSharedData, Dat, Len(Dat)
' Release mutex
ReleaseMutex hMutex
UnmapViewOfFile lpAddrSharedData
CloseHandle hMap
CloseHandle hMutex
End Sub
Private Sub tmrSurvey_Timer()
Dim Dat As SharedData
Dim SizeOfStr As Long
Dim tmpString As String
Static LastData As Long
' Capture mutext
WaitForSingleObject hMutex, INFINITE
CopyMemory Dat, ByVal lpAddrSharedData, Len(Dat)
' Check sended data
If Dat.Counter > 0 And Not IsSending Then
If LastData = 0 Then
' We hava a new message
SizeOfStr = lstrlen(lpAddrSharedData + &HC) ' Get size of string
tmpString = Space(SizeOfStr) ' Alloc space for string
lstrcpyn ByVal tmpString, lpAddrSharedData + &HC, SizeOfStr + 1 ' Copy shared string to local string
txtMessage = tmpString
lstLog.AddItem "Get string '" & tmpString & "' from " & Dat.SenderPID
' Decrement counter
Dat.Counter = Dat.Counter - 1
CopyMemory ByVal lpAddrSharedData, Dat, Len(Dat)
End If
LastData = Dat.Counter
Else
If Dat.Counter = 0 Then IsSending = False
LastData = 0
End If
' Release mutex
ReleaseMutex hMutex
End Sub
Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.
Last edited by jmsrickland; Jun 24th, 2015 at 09:32 PM.
Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.
Trying to make DDE work in .Net was so clunky Microsoft ended up punting and now refers to DDE as legacy technology and spits on it whenever they can. The old "baby can't eat steak so we all get pablum" syndrome mixed with a lot of sour grapes. But you face this sort of thing whenever you use a foreign layer on top of any OS, and .Net is no exception.
As far as I know it can only be done using a hack like NDde which was never really supported.
So DDE isn't practical if .Net is in the picture, even though it is still widely supported by native applications written in C, C++, VB6, etc. including the MS Office suite.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Last edited by jmsrickland; Jun 24th, 2015 at 07:46 PM.
Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.
I had a busy day and was in meetings for most of it. I will have to try to download and try all of these. There are certainly way more options than I expected!
Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.
I was very interested in seeing this work ( app in post #8) but it doesn't seem to for me. At least the way I imaged it would. "Click on App1 Command1' does not appear to work nor does "Click on App1 Command2'. I expected App1 to display "Left command button clicked" and so on. Sending text doesn't appear to work either. I'm on Windows 7 Professional.
One last "anomaly" is clicking App2 "copy picture to App1 Picture1" put the picture in the upper left hand corner of my screen, not on the app.
I was hoping it just worked "out of the box" to show to someone else I thought would be interested. I don't have time to try and debug it myself, at least in the near future.
Edit:
I had the apps split across two monitors and thought that might be it but being on the same one hand the same issues.
Last edited by TysonLPrice; Jun 25th, 2015 at 05:44 AM.
If you want something that works out of the box, you may use one of my personal simplest methods that does this very elegantly,
by sending input between two applications using PostMessage to a text field, who's handle is sent as a parameter to any application wishing to interact with my form.
if this was Chinese to you check this quick source i wrote here -Attachment Removed by Moderator-
Extract - compile both projects to the same folder - run Project1.exe click buttons on project2's form.
Of course once you get the hang of things, it may be more elegant to fetch the handles via APIs (FindWindow, FindWindowEx) and such, maybe even use hooks on the post_message and instead of sending it to a textbox, send it straight to the form and process it from there, the possibilities are endless.
I was very interested in seeing this work ( app in post #8) but it doesn't seem to for me. At least the way I imaged it would. "Click on App1 Command1' does not appear to work nor does "Click on App1 Command2'. I expected App1 to display "Left command button clicked" and so on. Sending text doesn't appear to work either. I'm on Windows 7 Professional.
One last "anomaly" is clicking App2 "copy picture to App1 Picture1" put the picture in the upper left hand corner of my screen, not on the app.
I was hoping it just worked "out of the box" to show to someone else I thought would be interested. I don't have time to try and debug it myself, at least in the near future.
Edit:
I had the apps split across two monitors and thought that might be it but being on the same one hand the same issues.
I do not know if it will work on Windows 7. It works on XP.
The first thing you have to do is to get the handles of App1's objects so you click on 'Get Objects From App1' button. That's it. You should now see the handle numbers of App1's objects in the left view area on App2. Now when you click on the other buttons everything works as it is expected. Make sure App1 is running before you click any buttons on App2 or you will get invalid handle numbers.
I guess if I had given it a little more thought I would have put the 'Get Objects From App1' button code in the Form_Load event. I just thought everyone would know to click that button first. My bad here.
Sorry I don't write perfect code
Last edited by jmsrickland; Jun 25th, 2015 at 10:26 AM.
Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.
Yeah, I know. I just thought the OP might be interested in seeing a description of how that simple technique works, hence my link to penagate's short article about it.
Originally Posted by stum
... but the principal is the same.
Yep, posting a WM_CHAR message to a TextBox is doing essentially the same thing as sending a WM_SETTEXT message, which jmsrickland's and penagate's examples were demonstrating. One major difference though, is that the WM_CHAR message is limited to only 1 character code per message while the WM_SETTEXT message can carry far more information.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
I do not know if it will work on Windows 7. It works on XP.
The first thing you have to do is to get the handles of App1's objects so you click on 'Get Objects From App1' button. That's it. You should now see the handle numbers of App1's objects in the left view area on App2. Now when you click on the other buttons everything works as it is expected. Make sure App1 is running before you click any buttons on App2 or you will get invalid handle numbers.
I guess if I had given it a little more thought I would have put the 'Get Objects From App1' button code in the Form_Load event. I just thought everyone would know to click that button first. My bad here.
Sorry I don't write perfect code
I wish I had just a very small fraction of your skill set