RE: single instance application delivery?
> From: owner-lisp-hug@lispworks.com
> [mailto:owner-lisp-hug@lispworks.com] On Behalf Of Chris Perkins
> Sent: 21 February 2007 03:21
> To: lisp-hug@lispworks.com
> Subject: single instance application delivery?
>
>
> When revisiting my delivery on Windows I noticed that the
application
> is a multiple instance application (the Windows default). Can this
> be changed? I'm looking through the Delivery keywords and I haven't
> found an applicable one yet.
>
> If it matters, my application is multithreaded and headless, using
> neither the console nor CAPI. But, if launched repeatedly I get
> repeated instances in the process queue, which I'd prefer to avoid.
>
> Chris
There may be a better way, but after my application starts
I use DDE to check whether another instance exists.
My application uses CAPI and has the idea of files/documents
that belong to the application, so some of the following
is probably not relevant to you. But I've included those
details because they may be interesting to someone else.
On startup, my application determines whether there is an
already-existing instance by sending a DDE message. If
there is no other instance, it starts a DDE server. If
there is another instance, the new instance sends the old
instance a message to get it to open a document or activate
the main application window and then the new instance quits.
The DDE server also allows files/documents to be opened from
Windows Explorer if you set up a Windows file type
appropriately.
I wrote the code below a very long time ago and am not proud
of (sheez -- it has an EVAL), but it works. (Well, I've
removed some fluff from the code before posting it so maybe
I've removed something important, but I don't think so.)
Here's a note I made at the time I wrote the code:
- Whenever you call any DDE function, the current thread
is registered with the DDE library and is expected to
process Windows messages. So when on startup you check
whether this is a duplicate application instance, the DDE
message must be sent in the same process as will later run
the DDE server. Otherwise you get all sorts of nasty hanging.
I suppose that's true, but I feel like it was written by someone
else (it was me a long time ago) and, also, perhaps things
have changed, so I won't make any promises.
If you're not using CAPI, I guess you need to run this code
in a separate process and after everything is set up arrange
for the processing of Windows messages. To process Windows
messages you can do
(CAPI::LOOP-PROCESS-EVENTS NIL NIL NIL NIL NIL)
CAPI::LOOP-PROCESS-EVENTS is undocumented and maybe unsupported;
I think LW support told me about it.
Here's the code:
------------------------------------------
(defun quit-if-duplicate-application-instance (service-name)
(labels ((dde-service-exists-p (service-name)
(handler-case
(progn
(win32:dde-execute-command* service-name
'general
"exists_p"
'())
t)
(condition () nil))))
(when (dde-service-exists-p service-name)
(let* ((filename (get-command-line-arg-for-file-to-open)))
(if filename
(win32:dde-execute-command* service-name
'edit
"open"
(list filename))
(win32:dde-execute-command* service-name
'general
"activate"
'())))
(lw:quit))))
(defun def-generic-app-dde-things (service-name
document-open-fun
activate-fun)
(quit-if-duplicate-application-instance service-name)
(eval `(win32:define-dde-server generic-app-dde-server ()
()
(:service ,service-name)))
(win32:define-dde-dispatch-topic edit
:server
generic-app-dde-server)
(win32:define-dde-server-function (open :topic edit)
:execute
((filename string))
(let* ((path (probe-file filename)))
(when path
(funcall document-open-fun path)))
t ; successful return value
; -- I'm not sure that this makes a difference
)
(win32:define-dde-dispatch-topic general
:server
generic-app-dde-server)
(win32:define-dde-server-function (exists_p :topic general)
:execute
()
t ; successful return value
)
(win32:define-dde-server-function (activate :topic general)
:execute
()
(funcall activate-fun)
t ; successful return value
)
(win32:start-dde-server 'generic-app-dde-server))
------------------------------------------
I've run this code with no problems for many years now on
Windows 98, Windows 2000 and Windows XP.
HTH,
Simon