0

I'm using wxPython, and I'm trying to make a single instance application. As far as this goes, there is no problem. My problem is passing commands to the already existing instance.
So lets say that when I double click a file that is associated with my application, it reads the file and displays, here is an example:

import wx
import sys
import os
import SocketServer
import socket
import threading
class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(320, 350))

        getfile = os.path.abspath(sys.argv[1])
        print getfile
        fopen = open (getfile, 'r')
        fread = fopen.read()

        panel = wx.Panel(self, -1)
        wx.StaticText(panel, -1, fread, (45, 25), style=wx.ALIGN_CENTRE)
        self.Centre()
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        data = self.request.recv(1024)
        cur_thread = threading.currentThread()

        # do something with the request
        print "work"
        # could instead of the length of the input, could return error codes, more
        # information (if the request was a query), etc.  Using a length function
        # as a simple example
        response = 'string length: %d' % len(data)

        print 'responding to',data,'with',response
        self.request.send(response)
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    stopped = False
    allow_reuse_address = True

    def serve_forever(self):
        while not self.stopped:
            self.handle_request()

    def force_stop(self):
        self.server_close()
        self.stopped = True

def client(ip, port, message):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((ip, port))
    sock.send(message)
    response = sock.recv(1024)
    print "Received: %s" % response
    sock.close()

def start_server(host, port):

    server = ThreadedTCPServer((host, port), ThreadedTCPRequestHandler)
    ip, port = server.server_address

    # Start a thread with the server -- that thread will then start one
    # more thread for each request
    server_thread = threading.Thread(target=server.serve_forever)
    # Exit the server thread when the main thread terminates
    server_thread.setDaemon(True)
    server_thread.start()

    return server
class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame(None, -1, 'test')
        frame.Show(True)
        self.SetTopWindow(frame)
        return True

def main():
    app = MyApp(0)
    app.MainLoop()

if __name__ == '__main__':
    HOST, PORT = socket.gethostname(), 61955

    server = None
    try:
        client(HOST, PORT, ' '.join(sys.argv))
        sys.exit()
    except socket.error:
        server = start_server(HOST, PORT)
        main()

This works just fine, but now I want to make it a single instance application. And I know that there are several ways to accomplish this, and in my case, I found that listening to a defined port is probably the best option. But even using such option, I have no idea on how I could pass the information of the file or, atleast, the name to the original instance and display it.

So the application should be:

  • A single instance application.
  • It should be able to read the double-clicked files.
  • If an instance is already open, then pass the information or file name to the original instance so it can refresh and display the file's data automatically.

Also, I didn't include any code for listening to a defined port because I really don't know much about it, so any help on this subject is also greatly appreciated.

EDIT: Code edited with "listening to a defined port", it is taken from an example. Note that print "work" does send to the running instance, I just don't know how to make it work in my occasion (because of my plain ignorance).

dpswt
  • 189
  • 4
  • 13

2 Answers2

2

A "Single Instance" application has two parts.

A "client", which is double-clicked and starts running. If the server is not running, it starts the server. It passes commands to the server. And stops. Leaving the server running.

A "server", which is started by each client. It does the "listening to a defined port". Or perhaps reading from a named pipe (which works out better sometimes).

The server does the real work. The client passes commands to it.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • Yeah, I kinda understand the basic concept of it, I really just don't quite know how to use it properly in my particular case – dpswt Apr 02 '11 at 02:40
  • @Francisco Aleixo: "just don't quite know how to use it properly". Okay. Why don't you actually read about writing clients and servers. Read about named pipes, sockets, shared memory and the like and actually write a little tiny program that is a client that starts a server, and then ask **specific** questions about that code. It's hard to provide much more here because your question ("don't quite know") is too vague to answer. – S.Lott Apr 02 '11 at 11:26
  • Well, I do have a code that actually does this and it does work in terms of making it a single instance application, and it does send info to the running instance, but I don't quite know how to handle it in order to refresh it, I'll edit the post with the code, that is actually copied from another example (And you are right, I'll read more about it) – dpswt Apr 02 '11 at 13:26
  • @Francisco Aleixo, might want to include a reference to your [original post](http://stackoverflow.com/questions/5453782/opening-file-performing-a-function/5454868#5454868) so everyone can get a better idea of what you have done so far. ;) – AWainb Apr 02 '11 at 17:18
2

This is the solution:

import wx
import sys
import os
import SocketServer
import socket
import threading
class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(320, 350))

        getfile = os.path.abspath(sys.argv[1])
        print getfile
        fopen = open (getfile, 'r')
        fread = fopen.read()

        panel = wx.Panel(self, -1)
        self.static = wx.StaticText(panel, -1, fread, (45, 25), style=wx.ALIGN_CENTRE)
        self.Centre()
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        data = self.request.recv(1024)
        cur_thread = threading.currentThread()

        data = data.split()
        gfile = os.path.abspath(data[-1])
        fopen = open(gfile, 'r')
        fread = fopen.read()
        self.server.app.static.SetLabel(fread)
        #Note to the self.server.app
        response = 'string length: %d' % len(data)

        print 'responding to',data,'with',response
        self.request.send(response)
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    stopped = False
    allow_reuse_address = True

    def serve_forever(self):
        while not self.stopped:
            self.handle_request()

    def force_stop(self):
        self.server_close()
        self.stopped = True

def client(ip, port, message):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((ip, port))
    sock.send(message)
    response = sock.recv(1024)
    print "Received: %s" % response
    sock.close()

def start_server(host, port):

    server = ThreadedTCPServer((host, port), ThreadedTCPRequestHandler)
    ip, port = server.server_address

    # Start a thread with the server -- that thread will then start one
    # more thread for each request
    server_thread = threading.Thread(target=server.serve_forever)
    # Exit the server thread when the main thread terminates
    server_thread.setDaemon(True)
    server_thread.start()

    return server
class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame(None, -1, 'test')
        frame.Show(True)
        server.app = frame
        #Note the server.app
        self.SetTopWindow(frame)
        return True

def main():
    app = MyApp(0)
    app.MainLoop()

if __name__ == '__main__':
    HOST, PORT = socket.gethostname(), 61955

    server = None
    try:
        client(HOST, PORT, ' '.join(sys.argv))
        sys.exit()
    except socket.error:
        server = start_server(HOST, PORT)
        main()

Essentially I had to bind the server.app with my frame:

class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame(None, -1, 'test')
        frame.Show(True)
        server.app = frame
        #Note the server.app

So I could call later on:

data = self.request.recv(1024)
cur_thread = threading.currentThread()

data = data.split()
gfile = os.path.abspath(data[-1])
fopen = open(gfile, 'r')
fread = fopen.read()
self.server.app.static.SetLabel(fread)

The important here is the self.server.app, although what I wanted was to pass the commands to the running instance. And the data does this for me. Let's say I open up the already open application with the file test.app then the data value will be:

\pathtoyourapplication\application.py test.app

So I grabbed its location and read, and that's pretty much it for my stupidity, hope this might be helpful for someone, in some way.

dpswt
  • 189
  • 4
  • 13