Skip to Content
author's profile photo Former Member
Former Member

How to pass info to an app that is already running via commandline parms

I have a powerbuilder application and now we are taking part of this application and migrating them to our new

.net app. Our delimma is that we must use both applications at this time and in order to move back and forth

between these applications both applications must pass data between both apps to determine the modules user is

working with.

Our .net developers tell me that they have created a method in thier app that when there app is called, if app

is not already running it starts the app but if app is running the instance that is running somehow determines

this call to launch and then since it is already running does not start another instance of the app and simply

takes the parms passed via commandline and passes them to the instance of the app already running. (how they do that I have no idea because I am under the impression that even the .net app will fire the open event of the app (.net app is window based app) and will try to start a new instance why it tries to send this to an instance that is already running I am not sure but they claim it is happening)

Is this possible in my PB application? I know I can code the open event of my app and check for the main window

winhandle = FindWindow( 0, "w_main")

if I have defined the FindWindow fucntion from user32.dll as an external fucntion and if an instance is already

open then I can get the Commandline argument in the open event to get the commandline parms and not open another

instance but these commandline parms will be in the context of the second instance that was being strated.

The first instance already running have no clue about the commandline parms but I want these commandline parms

to be used in the first instance? is this even possible? does my question make sense? Please help.

Add a comment
10|10000 characters needed characters exceeded

Assigned Tags

Related questions

6 Answers

  • Best Answer
    author's profile photo Former Member
    Former Member
    Posted on Sep 19, 2013 at 07:49 PM

    Hi Javed:

    I built a small test case that hopefully helps.

    Here's the outline:

    Global External functions:

    PUBLIC FUNCTION unsignedlong FindWindow (long classname, string windowname) LIBRARY "user32.dll" ALIAS FOR FindWindowW

    PUBLIC FUNCTION int SetForegroundWindow (unsignedlong hwnd) LIBRARY "user32.dll"

    PB application Open:

    unsignedlong hwnd

    hwnd = FindWindow( 0, "MyPBApp")

    if hwnd = 0 then

    // No previous instance, so open the main window

    open( w_myapp )

    else

    // Open the previous instance window and halt

    SetForegroundWindow( hwnd )

    // Save new command line in Registry

    RegistrySet("HKEY_LOCAL_MACHINE\Software\MyPBApp","commandline", RegString!, commandline)

    // Trigger pbm_custom01 event on currently open MyPBApp to read new commandline

    Send(hwnd, 1024, 1, 0)

    HALT CLOSE

    end if

    Define a user event on your main window (MyPBApp) mapped to pbm_custom01 populated with hte following Powerscript:

    string commandline

    RegistryGet("HKEY_LOCAL_MACHINE\Software\MyPBApp","commandline", RegString!, commandline)
    MessageBox("New commandline", commandline)

    I tested and it seems to work. Let me know if you need clarification.

    Cheers...Bob

    Add a comment
    10|10000 characters needed characters exceeded

    • Former Member Former Member

      Bob: never mind my previous question about findwindow method not working. I found out that the second parm passed to findwindow method must be the 'title' of the window and not the acutal name of the window which makes sense because api can probably find the title because title is an attribute of the window that stays valid through out the life of the object whereas the object name may only be internal to the program (it makes sense) and after I passed to window title the findwindow method was able to find the handle and hence I was able to call my custom event I wrote for that window and now everything is working seamlessley, thanks to you for your idea.

  • author's profile photo Former Member
    Former Member
    Posted on Sep 19, 2013 at 01:53 PM

    The short answer is NO - you cannot provide information to a currently running processing via commandline parameters - at least according to the commonly understand definition of command line parameters. Your .net guys have likely implemented a method to "place" the appropriate information into a running application that is accessed (within the application) as the commandline parameters. I suggest you simply ignore "how" they did it in their app since that is mostly irrelevent.

    The basic issue here is how to communicate (i.e., pass information) between running applications. This is called IPC - inter-process communication. A start in the MS documentation: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365574(v=vs.85).aspx

    Another very simply method is to get a handle to a window of the application and send messages to it (this has significant limitations) - this is what Chris mentioned. You will need to identify what information needs to be shared and how you want to share it in both directions.

    Add a comment
    10|10000 characters needed characters exceeded

  • author's profile photo Former Member
    Former Member
    Posted on Sep 19, 2013 at 05:17 PM

    Instead of making apps that can send/receive data directly, have you considered a database table to be used as a queue for processing commands?

    App A has a window (or object of some type) polling for data in a table (fifo order) every N seconds (or minutes). App B puts data into the table to be processed and it gets done when the timer hits.

    Or possibly a combination of the two styles. App A won't process anything until it receives a message from App B that there's data to be processed. Then app A will process all pending records until none are left and stop processing until the next message comes in.

    The only problem with using a database table is that both apps need to be connected to the same database.

    Add a comment
    10|10000 characters needed characters exceeded

  • author's profile photo Former Member
    Former Member
    Posted on Sep 19, 2013 at 12:48 PM

    Hi,

    You can send text messages Fom/To PowerBuilder and .Net applications using the window message WM_SETTEXT.


    To do that, each application has to know a window control of the other one where to send the message.

    I wrote a simple DLL as a gateway between the two application. (See Code Below.)


    PB Application <---> PbDotNetInterface <---> .Net Application


    The two applications have to register a Window control having the 'text' property to receive the message sent by the other application. The controls handles are stored in shared memory segment.


    1-For Powerbuilder :
    - Declare the external functions :

    FUNCTION boolean registerControl (ulong hctl ) LIBRARY "Your_Path\DotNetToPB.dll" ALIAS FOR "registerPbControl;ansi"

    FUNCTION boolean sendMessageToDotNet (ref string msg) LIBRARY "Your_Path\DotNetToPB.dll" ALIAS FOR "sendMessageToDotNet;utf8"


    - To register for ex. a multiLineEdit control

    boolean lb

    lb = registerControl (handle (mle_1))

    if lb THEN ..... //OK
    - and you send the message to .Net like this :

    sendMessageToDotNet(ref string)


    2-For the .Net application, you declare the DLL function :

    [DllImport("Your_Path\\DotNetToPB.dll", SetLastError=true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]static extern bool sendMessageToPB(string msg);

    [DllImport("Your_Path\\DotNetToPB.dll", SetLastError=true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]static extern bool registerDotNetControl (Int32 hwnd);


    - You register for example a textBox as this :

    public Form1()

    {

    InitializeComponent();

    registerDotNetControl (this.textBox1.Handle.ToInt32());


    - And you send the string message to PB

    sendMessageToPB(msg);


    Hope this helps.

    Best Regards.


    Abdallah.

    //-------------------DLL Code --------------------------


    #include "stdafx.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #ifdef _MANAGED
    #pragma managed(push, off)
    #endif

    #pragma data_seg (".myseg")
    static unsigned long hDotNetControl = 0;
    static unsigned long hPbControl = 0;
    static WCHAR msg [102400] = L" ";
    #pragma data_seg()
    #pragma comment(linker, "/section:.myseg,RWS")

    BOOL APIENTRY DllMain( HMODULE hModule,
    DWORD ul_reason_for_call,
    LPVOID lpReserved
    )
    {
    return TRUE;
    }

    WCHAR* getMessageFromPB ()
    {
    return msg;
    }

    bool sendMessageToPB (LPCWSTR msg)
    {
    if (hPbControl == 0) return false;
    SendMessage((HWND) hPbControl, WM_SETTEXT, 0, (LPARAM) msg);
    PostMessage((HWND) hPbControl, WM_ACTIVATE, 0, 0);
    PostMessage((HWND) hPbControl, WM_NOTIFY, 0, 0);
    return true;
    }

    bool registerPbControl (unsigned long hctl)
    {
    hPbControl = hctl;
    return true;
    }

    bool registerDotNetControl (unsigned long hctl)
    {
    hDotNetControl = hctl;
    return true;
    }
    bool sendMessageToDotNet (LPCWSTR msg)
    {
    if (hDotNetControl == 0) return false;
    SendMessage((HWND) hDotNetControl, WM_SETTEXT, 0, (LPARAM) msg);
    PostMessage((HWND) hDotNetControl, WM_ACTIVATE, 0, 0);
    PostMessage((HWND) hDotNetControl, WM_NOTIFY, 0, 0);
    return true;
    }

    #ifdef _MANAGED
    #pragma managed(pop)
    #endif

    //----To Be Exported ----

    EXPORTS

    DllMain @1

    registerPbControl @2

    sendMessageToPB @3

    sendMessageToDotNet @4

    registerDotNetControl @5

    Add a comment
    10|10000 characters needed characters exceeded

    • Former Member

      OK: i get it, thanks to both you and Chris for your responses, I kept doing my research while I posed the question in the forum and yes there are functions at least in user32.dll like findwindow to find the handle and then you can use sendmessage method to send the message to a particular window both between .net and PB. As a matter of fact as Chris suggested i could use the send method in PB to send a message to any windnow as long as I have the handle for it. However my problem is that not only I want to send the message to the PB window from my .net app (which is not a problem now that I know about user32.dll fucntions) I actually want my PB app to open that window with a particular patient data if it is not already opened and process the data if it is already opened. I can retrieve the message from the message qeue only after I open the window but how do I invoke the window I am not sure if I can really do that?

  • author's profile photo Former Member
    Former Member
    Posted on Sep 23, 2013 at 05:56 PM

    For talking to apps that are already running, DDE is an oldie but a goodie.

    Add a comment
    10|10000 characters needed characters exceeded

  • author's profile photo Former Member
    Former Member
    Posted on Sep 19, 2013 at 03:19 AM

    Hi Javed;

    Have you thought about using the PB "SEND" command?

    Regards ... Chris

    Add a comment
    10|10000 characters needed characters exceeded

Before answering

You should only submit an answer when you are proposing a solution to the poster's problem. If you want the poster to clarify the question or provide more information, please leave a comment instead, requesting additional details. When answering, please include specifics, such as step-by-step instructions, context for the solution, and links to useful resources. Also, please make sure that you answer complies with our Rules of Engagement.
You must be Logged in to submit an answer.

Up to 10 attachments (including images) can be used with a maximum of 1.0 MB each and 10.5 MB total.