Communicate between separate program through ini file
I made VB6 program and C# program.
Those 2 program should communicate with each other through Profile(Ini file).
Once VB6 write flag(for example "N") in the ini and call C# program, which do something.
If C# program terminate its work, write flag in the ini file and terminate process by itself.
While C# do its work, VB6 check if the flag in the ini file become "Y".
VB6 check this at every 0.5sec in the loop.
Read/Write of ini is performed by WritePrivateProfileString and GetPrivateProfileString.
But I'm worring that some kind of concurrent access of ini file by 2 program(VB6 program and C# program), which may generate some undesirable result.
Can I lock ini file while one process is writting?
If possible, how could I check if the ini file is locked from the counterpart(another) program?
Re: Communicate between separate program through ini file
I believe those APIs already do a "hang on locked file, lock, batch update, unlock" on writes and a "hang on locked file, lock, batch read, unlock" on reads.
That's the main reason INI file performance is so bad when used for normal purposes.
Why not just use one of the many IPC mechanisms Windows offers instead?
Re: Communicate between separate program through ini file
Thanks for answer.
You mean WritePrivateProfileString and GetPrivateProfileString function already handle locking issue.
If so, I don't have to worry about any error.
Do you mean "ini performance is bad " speed is low?
In this mechanism, speed is not very important.
Re: Communicate between separate program through ini file
Normally the terrible performance of INI operations doesn't matter, but you said you will be polling for changes.
You can always run a test and see just how many cycles you will burn doing this.
Re: Communicate between separate program through ini file
Actually, no you DO need to worry about handling it... well, sort of. Locking is implemented by the API, so you don't need to worry about locking the file. What you need to worry about is handling the exception when it occurs... specifically, when one system has the file locked for a write, and the other tries to access it for a read, it will result in a "Unable to open file, it is locked by another process" or something along those lines. If you're checking the file every half-second... then I'd argue speed IS an issue, epecially if it takes longer than that to write the flag back out to the file.
-tg
Re: Communicate between separate program through ini file
Back in the 90s my company created some programs that needed to talk to one another in a very minor way. We decided to use an INI file for this purpose and it worked just fine. Software has been running at 100s of locations for over 15 years now, not aware of this ever causing a problem.
Re: Communicate between separate program through ini file
Quote:
Originally Posted by
jdy0803
VB6 check this at every 0.5sec in the loop.
Are you using DoEvents inside that loop? If so, I strongly recommend that you avoid that rather inelegant method. Instead, use a Timer or some other means of polling that does not involve loops and DoEvents. As suggested by dilettante, one or more of the IPC mechanisms outlined in Interprocess Communications may be viable for you.
Re: Communicate between separate program through ini file
Quote:
Originally Posted by
Bonnie West
Are you using DoEvents inside that loop? If so, I strongly recommend that you avoid that rather inelegant method. Instead, use a Timer or some other means of polling that does not involve loops and DoEvents. As suggested by dilettante, one or more of the IPC mechanisms outlined in
Interprocess Communications may be viable for you.
I use Sleep and DoEvents in the loop like this.
Do
Sleep 500
bRet = CheckIniFileStatus 'Check flag written by C# program
If bRet Then
Exit Do
DoEvents
Loop
If you don't recommend this way,.....which IPC mechanism would be better in order to communicate between 2 process made by VB6 and C#?
Re: Communicate between separate program through ini file
Quote:
Originally Posted by
jdy0803
If you don't recommend this way,.....which IPC mechanism would be better in order to communicate between 2 process made by VB6 and C#?
Well, you could try either File Mapping or Pipes. You might also want to try one or more of the various Synchronization Functions.
Can you elaborate on why you need your two programs to communicate with each other?
Re: Communicate between separate program through ini file
The best writeup I've found in the topic of thrashing on INI files is probably:
INI file handling functions are not thread-safe
The short answer is that this author recommends that you lock the INI file yourself. Of course he also says:
Quote:
Do *NOT* put wrapper functions around WritePrivateProfileString, etc, to lock/unlock before/after each function call to access the INI file.
Which means adding your own explicit locking doesn't really work well for the case at hand at all.
Considering that INI thrashing doesn't buy you notification so you have to thrash even harder using some polling technique, you may as well just look elsewhere for a solution.
The best choice may be to punt and use the least common denominator IPC mechanism: IP. You could use either TCP or UDP, but probably TCP for reliable delivery. No matter what you develop in you almost always have a way to use async TCP/IP sockets.
Re: Communicate between separate program through ini file
First off - I agree with Dilettante that another IPC mechanism would be more appropriate than using an INI.
That said, I'm curious as to what the reason might be for *NOT* putting a wrapper around INI API calls to lock/unlock access to the file (for example, waiting on a mutex). It's true that such a lock would only be useful against processes that are "playing fair" by respecting the lock, but that would appear to be the case with mechanisms other than system-based exclusive file locking (such as creating a .lock file as proposed in the article).
In any case, using a file for IPC (INI or otherwise), while perhaps simpler to implement, seems to me to have unnecessarily high overhead, and is possibly more risky (e.g. due to Antivirus scanning interfering with the file locking) than other forms of IPC such as sockets. Of course, with sockets you then have to worry about software firewalls getting in the way, so I'm not sure that there is a perfect solution.
Re: Communicate between separate program through ini file
Why not just using WM_COPYDATA ?
Re: Communicate between separate program through ini file
WM_COPYDATA could be an answer, but it means more (and more tricky) code. It also fails when process isolation is involved. Basically the technique is obsolete in the post-XP universe.
IP sockets do raise firewall issues, but they have good support in almost all development environments.
The obvious solutions would be Mailslots or Named Pipes, but VB6 doesn't have convenient support for either one. You can use them but it requires a bit of code and you still have to do polling.
Re: Communicate between separate program through ini file
Too bad, the OP didn't explain more clearly what he really needs this for...
I have a slight suspicion, that it's simply about running (shelling) a C# compiled executable -
and then just waiting for the completion of this other process (currently in a slow polling-loop).
In his first post he wrote:
..."If C# program terminate its work, write flag in the ini file and terminate process by itself."
and
..."VB6 check if the flag in the ini file become "Y". VB6 check this at every 0.5sec in the loop"
To me, that seems like a typical use-case for "ShellAndWait" - maybe that's all the OP is looking for.
Olaf
Re: Communicate between separate program through ini file
Quote:
Originally Posted by
Bonnie West
Well, you could try either
File Mapping or
Pipes. You might also want to try one or more of the various
Synchronization Functions.
Can you elaborate on why you need your two programs to communicate with each other?
My existing VB6 program is an imaging software used in the dental industry, which interface with various image sensor and too big to change with .NET language(C#).
The C# program is a x-ray taking module that interface with image sensor of which manufacturer provide only .NET library.
I couldn't make wrapper dll which VB6 program can call.
That's why I made C# program and made interact VB6 and C# program each other.
I have no idea how to implement File Mapping or Pipe in VB6.
Can you give me more information regarding that?
Re: Communicate between separate program through ini file
Sorry, It seems I didn't explain clearly.
If I explain again.....
VB6 set flag in the ini file and generate C# program.
VB6 wait until some flag is ON.
C# program do its job and set flag in the ini in order to inform VB6 of some event.
Actually, C# doesn't be terminated until VB6 kill C# program.
In most case, VB6 check(read) the flag waiting in the loop.
C# program write flag when some event occur in order to inform VB6 program.
Re: Communicate between separate program through ini file
VB6 opens (or creates for first time) INI file and sets a flag in the INI file to OFF (I assume) and then Shells the C# program
VB6 now enters a loop and reads this INI file looking for the same flag. If still OFF VB continues in loop. If ON VB does something
Is this correct
Re: Communicate between separate program through ini file
Quote:
Originally Posted by
jdy0803
Actually, C# doesn't be terminated until VB6 kill C# program.
If the C# program immediately terminates after doing its job, then as suggested by Schmidt, a Shell & Wait solution might be more suitable for you. However, if you are saying that the C# program doesn't promptly end when it's finished with its task, then one more approach you might want to try is to notify the VB6 program when the C# program completes its task via a registered Windows message.
Code for the VB6 program:
Code:
Option Explicit 'Example code for a Form
Public Sub Procedure()
MsgBox "X-ray scanning done!", vbInformation
Command1.Enabled = True
End Sub
Private Sub Command1_Click()
If Subclass(hWnd) Then
If Shell("C#.exe " & hWnd, vbNormalFocus) Then 'Pass the hWnd of this Form to the shelled app as a command line argument
Command1.Enabled = False 'If desired, disable the controls of this Form
End If
End If
End Sub
Private Sub Form_Load()
Caption = "Click The Button To Shell Worker App"
End Sub
Code:
Option Explicit 'Copy & paste all of this to a standard module named "modSubclass"
'Both VB6 and C# apps must use the same string for RegisterWindowMessage
'Any string will do just fine, as long as it's unique (like this GUID)
Private Const MyGUID As String = "{07177563-9906-4116-839A-9ED6FE9A5E0E}"
Private Const MSGFLT_ADD As Long = &H1
Private Const WM_DESTROY As Long = &H2
Private Declare Function DefSubclassProc Lib "comctl32.dll" Alias "#413" (ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function SetWindowSubclass Lib "comctl32.dll" Alias "#410" (ByVal hWnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As Long, Optional ByVal dwRefData As Long) As Long
Private Declare Function RemoveWindowSubclass Lib "comctl32.dll" Alias "#412" (ByVal hWnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As Long) As Long
Private Declare Function RegisterWindowMessageW Lib "user32.dll" (ByVal lpString As Long) As Long
Private Declare Function ChangeWindowMessageFilter Lib "user32.dll" (ByVal Message As Long, ByVal dwFlag As Long) As Long
Public Function Subclass(ByVal hWnd As Long) As Boolean
Dim WMU_JOB_DONE As Long
'Register a Windows message that this VB6 app will receive from the C# app when it's done
WMU_JOB_DONE = RegisterWindowMessageW(StrPtr(MyGUID))
If WMU_JOB_DONE Then
'ChangeWindowMessageFilter API doesn't exist before Vista, so ignore possible errors
On Error Resume Next
'Add WMU_JOB_DONE to the User Interface Privilege Isolation (UIPI) message filter
Subclass = ChangeWindowMessageFilter(WMU_JOB_DONE, MSGFLT_ADD)
On Error GoTo 0
'Start monitoring for the WMU_JOB_DONE message
Subclass = SetWindowSubclass(hWnd, AddressOf SubclassProc, AddressOf SubclassProc, WMU_JOB_DONE)
End If
Debug.Assert Subclass
End Function
Private Function SubclassProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, _
ByVal uIdSubclass As Long, ByVal WMU_JOB_DONE As Long) As Long
Select Case uMsg
Case WMU_JOB_DONE: 'The C# app has just finished with its task. This app can now do whatever needs to be done next.
'But first, subclassing must be deactivated before resuming with the rest of the program.
WMU_JOB_DONE = RemoveWindowSubclass(hWnd, uIdSubclass, uIdSubclass): Debug.Assert WMU_JOB_DONE
'The relevant public procedure can now be called here. For example:
Call Form1.Procedure
'Return a confirmation of successful message receipt (the return value should be a non-zero Long value)
SubclassProc = True
Exit Function
Case WM_DESTROY: WMU_JOB_DONE = RemoveWindowSubclass(hWnd, uIdSubclass, uIdSubclass): Debug.Assert WMU_JOB_DONE
End Select 'End subclassing if this window is destroyed (just in case the WMU_JOB_DONE was never received)
SubclassProc = DefSubclassProc(hWnd, uMsg, wParam, lParam)
End Function
VB6 code that should be converted to C# code. Modify as necessary.
Code:
Option Explicit 'Port this VB6 code to C#
'Both VB6 and C# apps must use the same string for RegisterWindowMessage
'Any string will do just fine, as long as it's unique (like this GUID)
Private Const MyGUID As String = "{07177563-9906-4116-839A-9ED6FE9A5E0E}"
Private Declare Function RegisterWindowMessageW Lib "user32.dll" (ByVal lpString As Long) As Long
Private Declare Function SendMessageW Lib "user32.dll" (ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Sub Form_Click()
Dim hWnd As Long, WMU_JOB_DONE As Long
'Register a Windows message that this app will send to its parent VB6 app once it's done
WMU_JOB_DONE = RegisterWindowMessageW(StrPtr(MyGUID))
If WMU_JOB_DONE Then
'Try obtaining the parent app's hWnd passed as a command line argument to this app
On Error Resume Next
hWnd = CLng(Command$)
On Error GoTo 0
If hWnd Then
'Send a notification to the parent app in the form of a Windows message
'A beep confirms whether the parent app successfully received the message
If SendMessageW(hWnd, WMU_JOB_DONE, 0&, 0&) Then Beep
End If
End If
End Sub
Private Sub Form_Load()
Caption = "Click Form To Notify Parent App That The Job Is Done"
End Sub
EDIT
Yet another solution that you might find a lot easier than the subclassing code above was demonstrated in VB - Send a string between VB-created apps without using subclassing. You just need to adapt the technique there to make it work in your situation.