Solved

Is my OCX already in use?

Posted on 2000-03-30
17
337 Views
Last Modified: 2010-05-18
This is probably a bit strange but it is important...

I have an OCX that is going to have some very special code in it. This OCX is not to be used by more than one program at a time on any given machine (which I know is not the point of an OCX). I only want one copy running in memory and only one application to use it at any given moment.

Why? There are some hook codes in there along with special file connection routines. If more than one program access these commands problems could be caused. Such as a system crash when it comes to the hooks.

It is being written mainly to make it really easy to get various user interface forms and these routines into new programs without the need to recode or include the original code.



HERE IS THE QUESTION

In the initialization routine, is there a way to check if this routine is already in use by another program and send an error message or better yet trigger an event telling the calling program to shut down?

Help me detect another program already using this OCX. I can figure out how to best cause a program shut down later.
0
Comment
Question by:schworak
  • 7
  • 3
  • 3
  • +3
17 Comments
 
LVL 1

Expert Comment

by:mcmonniesa
ID: 2670168
Here's a suggestion, why not allow the OCX to make and test a boolean entry (InUse) into the registry where the OCX is registered.  So when the OCX first intializes test the boolean in the registry.  If it' s true, off to the error handler.  If It's false, set it to true then press on.  Don't forget to reset it back to false when your finished.
0
 
LVL 9

Expert Comment

by:samopal
ID: 2670255
To mcmonniesa: Not a good idea. What happens if your app crash ? Yes, you will never start it again before you clean InUse in registry.
To schworak: Does your OCX has visual interface? If not, change it to DLL. If yes, may be add additional DLL, and make your OCX to register in this DLL every time it's started. This DLL will return an error, if your OCX try to register at the second time...
0
 
LVL 3

Author Comment

by:schworak
ID: 2670262
I do use a graphic interface. But please, explane about the DLL concept. I would split the program into an OCX and DLL combo if your idea works.



I just had a suggestion... How about setting an environment variable? Can we do this from VB and read it back?

That way if there is a crash the variable will be cleared from memory automatically on reboot. The program may not run again before a reboot but I don't care about that.
0
 
LVL 3

Author Comment

by:schworak
ID: 2670268
This would also allow me to do other things like pass variables between several programs if needed. (I do need that in another project later)
0
 
LVL 2

Expert Comment

by:bhamilto
ID: 2670448
If I remember correctly, a BAS module in any activeX control (OCX or DLL) is shared among all instances of the control.  In fact hook routines for multi-use controls (which must use "addressof") have to jump through hoops because of this.

So won't a simp;e usage count in a BAS module work just fine?

0
 
LVL 1

Expert Comment

by:j3877
ID: 2670557
This is an ugly solution:


Put a winsock control on the form
(It only increases the distribution file size by about 30KB...)

set the remotehost to "localhost" / "127.0.0.1", then:

bind the control to some port (eg. 3487) - you'll get an error if the program's already in use! Just catch this error, & terminate.... It would be fine if your program crashes, because it doesn't rely on setting regvalues. If you're using it on multiple machines, get them to send udp messages to one another when the OCX inits, and therefore you'll know (based on whether/not there are responses) whether or not another computer is using it, and you'll know wot computer's using it...
0
 
LVL 3

Author Comment

by:schworak
ID: 2670633
No, I don't really want to do something hokey like hooking to a winsock port.

There has got to be a better way.


The idea of using a variable within the BAS module doesn't seem to be working either.
0
 
LVL 2

Expert Comment

by:bhamilto
ID: 2670673
Here is the MS article about a shared BAS module with multiple instances of a control.
http://support.microsoft.com/support/kb/articles/Q179/3/98.ASP
The 3rd paragraph of "MORE INFORMATION" explains the basic premise.

I don't see why you can't take advantage of this for your control
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 4

Expert Comment

by:gcs001
ID: 2670779
The problem with the variable won't work because each new VB program will create it's own instance of your OCX, thereby creating  a new variable global to itself, not to the other programs already running.

You would probably have to write code within your OCX to search the OS's memory to determine if another instance of the OCX is already loaded.  Their should be some System API call you could use to do this.
Unfortunately I don't know of any off-hand.

Check up on MSDN if anything comes up.

Regards,
Grant.
0
 
LVL 4

Expert Comment

by:gcs001
ID: 2670787
The problem with the variable won't work because each new VB program will create it's own instance of your OCX, thereby creating  a new variable global to itself, not to the other programs already running.

You would probably have to write code within your OCX to search the OS's memory to determine if another instance of the OCX is already loaded.  There should be some System API call you could use to do this.
Unfortunately I don't know of any off-hand.

Check up on MSDN if anything comes up.

Regards,
Grant.
0
 
LVL 2

Expert Comment

by:bhamilto
ID: 2670814
gcs001

This is true with Class and Form modules, but not BAS modules in the control.  Check-out the MS article I referenced.
0
 
LVL 9

Accepted Solution

by:
samopal earned 100 total points
ID: 2670876
Schworak, you idea with environment variables is great! If you don't worry that you variable will stay in system after your program crash, then

Set WSHShell = CreateObject("WScript.Shell")
set WSE = WshShell.Environment
if WSE("MyCheckOCX") = "" Then
  WSE("MyCheckOCX") = "Started"
Else
  MSGBOX "Already started!"
'do smth
end if

Don't forget to clear it before exit program :-))
0
 
LVL 3

Author Comment

by:schworak
ID: 2671301
The variable idea didn't work. It may be that the code is not being replicated, but the variables are and each get their own section of memory. I ran some tests and every time the control reported that it was the only copy in memory. I know it wasn't because I could see the others all at one time.
0
 
LVL 3

Author Comment

by:schworak
ID: 2671310
Here is a little test program I used when trying to figure out a way to communicate between instances. I only needed to know if another instance was running, so anything could be loaded into the environment variable. But for this test, I only wanted one isntance to be enabled but to all to be loaded and visable.


Just copy this to a text file titled MyTest.ctl and load it into a control project and play with it.
(you can name the control file anything that ends with .ctl)


------------------------------------------------

VERSION 5.00
Begin VB.UserControl TestControl
   ClientHeight    =   2115
   ClientLeft      =   0
   ClientTop       =   0
   ClientWidth     =   2805
   ScaleHeight     =   2115
   ScaleWidth      =   2805
   Begin VB.Timer Timer1
      Interval        =   100
      Left            =   2100
      Top             =   240
   End
   Begin VB.Shape Circ
      BackStyle       =   1  'Opaque
      FillStyle       =   0  'Solid
      Height          =   375
      Left            =   840
      Shape           =   3  'Circle
      Top             =   960
      Width           =   435
   End
End
Attribute VB_Name = "TestControl"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True
Option Explicit
'
'
' This is a simple experiment in only allowing
' one control to be enabled at a time through
' the use of environment variables being passed
' between all instances of the control.
'
' The idea of only letting one instance work
' is great when dealing with subclassing controls
' or hook controls because a hook can damage another
' instance of itself.
'
' Hoods and subclassing is too hard to control when
' things go wrong. this test uses a graphic display
' to demonstarate the point.
'
' Put several of this one control on one form or on
' several forms or even on several programs. Try to
' enable more than one at any given moment. You will
' see that the first control gets to be enabled when
' the rest are locked out. You can disable the enabled
' control then you will be able to enable any other. But
' only one control will work at any given moment.
'
Dim WshShell As Object
Dim WSE As Object

Dim xi As Integer
Dim yi As Integer

Private Sub Timer1_Timer()
    Dim x As Long
    Dim y As Long
   
    x = Circ.Left + xi * Screen.TwipsPerPixelX * 3
    y = Circ.Top + yi * Screen.TwipsPerPixelY * 3
    If x < 1 Then xi = 1
    If x > UserControl.Width - Circ.Width Then xi = -1
    If y < 1 Then yi = 1
    If y > UserControl.Height - Circ.Height Then yi = -1
    Circ.Move x, y
End Sub

Public Property Get Enabled() As Boolean
    Enabled = Timer1.Enabled
End Property

Public Property Let Enabled(ByVal Mode As Boolean)
    If WSE("MyCheckOCX") = "" Or WSE("MyCheckOCX") = UserControl.hWnd Or Mode = False Then
        Timer1.Enabled = Mode
        PropertyChanged "Enabled"
    Else
        Err.Raise 1, "Testing OCX", "Only one control may be enabled at a time."
    End If
    If Mode Then
        WSE("MyCheckOCX") = UserControl.hWnd
    Else
        WSE("MyCheckOCX") = ""
    End If
End Property

Private Sub UserControl_InitProperties()
    Startup
End Sub


Private Sub Startup()
    Randomize Timer
    xi = Int(Rnd * 2) * 2 - 1
    yi = Int(Rnd * 2) * 2 - 1
   
   
    Circ.Move Int((UserControl.Width - Circ.Width) / 2), Int((UserControl.Height - Circ.Height) / 2)
   
    Set WshShell = CreateObject("WScript.Shell")
    Set WSE = WshShell.Environment
    Debug.Print "Opening " & UserControl.hWnd,
    If WSE("MyCheckOCX") = "" Or WSE("MyCheckOCX") = UserControl.hWnd Then
        WSE("MyCheckOCX") = UserControl.hWnd
        Timer1.Enabled = True
        Debug.Print "Activate"
    Else
        Timer1.Enabled = False
        Debug.Print "Deactivate"
    End If
    PropertyChanged "Enabled"
End Sub

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
    Startup
End Sub

Private Sub UserControl_Terminate()
    If WSE("MyCheckOCX") = UserControl.hWnd Then
        WSE("MyCheckOCX") = ""
    End If
    Debug.Print "Closing " & UserControl.hWnd
WSE("MyCheckOCX") = ""
End Sub
0
 
LVL 9

Expert Comment

by:samopal
ID: 2673264
I don't know why, but this works on my computer fine! It started only one copy of usercontrol; all other copies reported about their deactivations (NT4)

But... Why do we use environment variables??????? Why not to use just file?
1) Look for file (for example C:\FlagOcx.flg)
2) Not Found? - goto 5)
3) try to kill this file
4) Got error 55 (file is open) - exit
5) Open "C:\FlagOcx.flg" for input as 1

If your programm will crash, this file will be close by OS
0
 
LVL 3

Author Comment

by:schworak
ID: 2673575
Yeah, that would work too. I didn't want to write to the user's disk drive but I supose your idea will work.

It works because you can't kill a file that is opened by another process. So the first process kills and then opens the file.

The next would try to kill and fail and then exit.

The fact that we are not storing a flag to test means after a reboot we can kill and restart. Not a bad idea.
0
 
LVL 3

Author Comment

by:schworak
ID: 2673615
The nice thing about the environment variables is that I can not only use it to tell if an instance of a control (or program) is running, I can pass information from one instance to another.
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

Most everyone who has done any programming in VB6 knows that you can do something in code like Debug.Print MyVar and that when the program runs from the IDE, the value of MyVar will be displayed in the Immediate Window. Less well known is Debug.Asse…
Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now