Trigger (auto execute) an application when opening file

English main discussion
  • Author
  • Message
r0n
Offline
Posts: 23
Joined: Sat Jun 14, 2014 3:56 am

Trigger (auto execute) an application when opening file

Post by r0n »

Is there a (simple) way to do the following:

Every time I open a textfile within Akelpad, execute a file (and pass the filepath as a parameter to the executable).

I am experimenting with Akelpad for a week now and I read the documentation on:
http://members.shaw.ca/atbcls/akelpad/

I am trying to write mini applications (application is actually a to big word) that should interact with akelpad and I am doing this in the macro application quick macros
The application allows programming in a language that can interact with the windows API and the language might be remotely comparable to VBS/C++. However I am not remotely accomplished in both languages.

I assume my request needs some sort of way to "catch" a SendMessage from Akelpad (I probably am not using the correct terms, but I hope someone understands of what I am trying to say.)

I am aware that this is difficult request to be solved "simply" but I thought I give it a try and ask here.

DV
Offline
Posts: 1250
Joined: Thu Nov 16, 2006 11:53 am
Location: Kyiv, Ukraine

Re: Trigger (auto execute) an application when opening file

Post by DV »

r0n,
This can be easily done via the Scripts plugin.
For example, create the following .js script under AkelFiles\Plugs\Scripts:

Code: Select all

var hSubClass;

if (hSubClass=AkelPad.WindowSubClass(1 /*WSC_MAINPROC*/, MainCallback, 0x435 /*AKDN_OPENDOCUMENT_START*/))
{
  //Message loop
  AkelPad.WindowGetMessage();

  AkelPad.WindowUnsubClass(1 /*WSC_MAINPROC*/);
}

function MainCallback(hWnd, uMsg, wParam, lParam)
{
  if (uMsg == 0x435 /*AKDN_OPENDOCUMENT_START*/)
  {
    AkelPad.Exec("cmd.exe"); // your command
  }
}


Read more in the document "AkelFiles\Docs\Scripts-Eng.txt".
To see the available messages and notifications (such as AKDN_OPENDOCUMENT_START), download the sources of AkelPad or any of its plugin and refer to the file "AkelDLL.h".

DV
Offline
Posts: 1250
Joined: Thu Nov 16, 2006 11:53 am
Location: Kyiv, Ukraine

Re: Trigger (auto execute) an application when opening file

Post by DV »

Here is another version, probably closer to what you want to achieve:

Code: Select all

var hSubClass;

if (hSubClass=AkelPad.WindowSubClass(1 /*WSC_MAINPROC*/, MainCallback, 0x436 /*AKDN_OPENDOCUMENT_FINISH*/))
{
  //Message loop
  AkelPad.WindowGetMessage();

  AkelPad.WindowUnsubClass(1 /*WSC_MAINPROC*/);
}

function MainCallback(hWnd, uMsg, wParam, lParam)
{
  if (uMsg == 0x436 /*AKDN_OPENDOCUMENT_FINISH*/)
  {
    var filePath = AkelPad.GetEditFile(0);
    AkelPad.Exec("notepad.exe \"" + filePath + "\"");
  }
}

r0n
Offline
Posts: 23
Joined: Sat Jun 14, 2014 3:56 am

Post by r0n »

@DV

Thank you very much for this!!

It works perfectly!!!!!!!!

Thank you!

Спасибі! (I hope that is 'Thanks' in Ukrainian, or else my apologies!)

r0n
Offline
Posts: 23
Joined: Sat Jun 14, 2014 3:56 am

Post by r0n »

Sorry for new (final question).

As a final step I am trying the sendmessage method.

I can send a message using JSCRIPT to my created mini application using:
AkelPad.SendMessage(591236,32768+177,0,0)

591236 = the handle of application.

But I want the window handle to retrieved like this (or something like it):

Code: Select all

var w = AkelPad.Open("", "form");
The target application window name = "form"
Of course this does not work, I get the error that the method/property is not supported.

The endgoal is to use the sendmessage code like this:

Code: Select all

AkelPad.SendMessage(w,32768+177,0,0)
Is there a workaround? Is it possible?
The beauty of this solution is that I can have the mini-application loaded once and do a sendmessage to that window (target application).
In other words, in stead of constantly opening the same application when I open a document, I could do a sendmessage to the already opened application.

If there isn't a way to do this then the posted code by DV is something I can fallback to.

I searched in the AkelPad plugins manual, in the scripts section.

DV
Offline
Posts: 1250
Joined: Thu Nov 16, 2006 11:53 am
Location: Kyiv, Ukraine

Post by DV »

I'm not aware of an easy way to do it outside of your mini-application. It looks like Win API or several command-line tools need to be used in combination to achieve this. E.g. first you determine a process id (PID) of your mini-application, then enum its windows and retrieve the handle of the main window. (You can ask Google for something like "get process handle by path" and "get process main window".)
But it must be much easier to modify your mini-application in such way that it will search for another instances of itself on start, and delegate the command line parameters to already running instance, if any. (Actually, this approach also assumes some knowledge of Win API mentioned above, but at least all the modifications would reside in your mini-application, without need to invoke something external.)

r0n
Offline
Posts: 23
Joined: Sat Jun 14, 2014 3:56 am

Post by r0n »

@DV

Thank you very much for the feedback, you gave me some good ideas for approaching this!!!
I will post here when I have a workable solution!

Thank you again for your very fast response!!!

r0n
Offline
Posts: 23
Joined: Sat Jun 14, 2014 3:56 am

Post by r0n »

I finally have a solution that almost perfectly works, It is quite simply actually on first runtime of my application I just let alter the script that does the sendmessage. I alter the line that contains the sendmessage and modify it to contain the correct handle (the application can output it).

The final thing I need is a way to send a send a string with the SendMessage command.

I have this

Code: Select all

var x="test\r\n"
AkelPad.SendMessage(WinHandle,32768+177,x,0) // don't mind "WinHandle"
I do not know if this is the correct method to send a string with SendMessage and WM_APP (32768).

This is really the final thing I need and then my mini app could could work.



My mini app, only for the interested (it's not important or related to the problem described above):
I am trying to convert AkelPad into a notetaking application with the ability to have file attachments for each text note. AkelPad already has a tree based explorer plugin AND one click file open possibility AND tabbed display of text-files.
What my "add-on" does. It attaches a small stripped folder cabinet without the un-needed buttons. It displays the content "connected" to text-file.

The connection is made like this:
I have a subfolder called "attachments" within the "attachment" folder I have folders with the exact name of the textfile.
So if you open textfile "project_1.txt" the attached window opens the contents of "attachment\project_1"-folder. It automatically changes location when user navigates to other textfile. The attached window is small and moves attached with the AkelPad window and also hides itself when AkelPad is put into the background (and restores itself when AkelPad is restored).

Why I did this, other notetaking programs are bloated or put notes in a (proprietary) format. Als notetaking applications have very little automation options and command-line options. I discovered that AkelPad is small beast when it comes to command-line/scripting options...
And the notes and attachments are left in their original state (file/folder structure) AkelPad does the "heavy" lifting.
But I am not done yet I have it working 85% now, I do not know If can get it to work fully... I really hope so.

If can get this working I have some other projects I can connect this application! (but now I am really looking to far ahead).

Offline
Site Admin
Posts: 6311
Joined: Thu Jul 06, 2006 7:20 am

Post by Instructor »

r0n
You cannot directly transfer data between processes.

Without creating file in temp folder, you have some alternatives: Interprocess Communications.

Added:

Code: Select all

var hMainWnd=AkelPad.GetMainWnd();
var hMem;
var szName;
var szMem;
var dwMemSize=1000;

if (szName=AkelPad.MemAlloc(16))
{
  AkelPad.MemCopy(szName, "Global\\AkelPad", 0 /*DT_ANSI*/);

  //Create named memory object.
  if (hMem=AkelPad.SendMessage(hMainWnd, 1305 /*AKD_MEMCREATE*/, szName, dwMemSize))
  {
    if (szMem=AkelPad.SendMessage(hMainWnd, 1306 /*AKD_MEMMAP*/, hMem, dwMemSize))
    {
      AkelPad.MemCopy(szMem, "Test", 0 /*DT_ANSI*/);
      AkelPad.SendMessage(hMainWnd, 1307 /*AKD_MEMUNMAP*/, szMem, 0);
    }

    //Call external application. This application should call:
    //hMem=OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, "Global\\AkelPad");
    //szMem=MapViewOfFile(hMem, FILE_MAP_ALL_ACCESS, 0, 0, 1000);
    //Read szMem.
    //UnmapViewOfFile(szMem);

    AkelPad.SendMessage(hMainWnd, 1308 /*AKD_MEMCLOSE*/, hMem, 0);
  }
  AkelPad.MemFree(szName);
}

Offline
Posts: 2247
Joined: Tue Aug 07, 2007 2:03 pm
Location: Vinnitsa, Ukraine

Post by FeyFre »

r0n
Mapping memory ranges into space of other processes(call Marshaling) is only done by system for some messages <WM_USER (<1024), for all other messages user must take care of it manually.
WM_COPYDATA is only message which can send custom user data buffer to windows of other processes.

r0n
Offline
Posts: 23
Joined: Sat Jun 14, 2014 3:56 am

Post by r0n »

@FeyFre and @Instructor

Thank you both for the feedback!
I will try with Instructors code and the WM_COPYDATA method.

r0n
Offline
Posts: 23
Joined: Sat Jun 14, 2014 3:56 am

Post by r0n »

@Instructor

I am sorry to ask this, but could you give a WM_COPYDATA example?
(If possible).
The QM programming language I work in, supports it.

My apologies again: I got the filemapping working, the example had almost perfect example for me, but it contained the following:

Code: Select all

OpenFileMappingA
This didn't work for me, so assumed this wouldn't work, I removed the "A" at the end and my environment (QM) recognized "OpenFileMapping"
Now I can send the string "test" successfully!!! (I do not know if "OpenFileMappingA" is official MSDN command, but by removing the 'A' I could work with it further).

I would still really appreciate an WM_COPYDATA example and how to read the string "test" if send it from my executable using FileMapping in AkelPad.

Offline
Site Admin
Posts: 6311
Joined: Thu Jul 06, 2006 7:20 am

Post by Instructor »

r0n
Why you need WM_COPYDATA, if you get file mapping working in QM?

Code: Select all

var hMainWnd=AkelPad.GetMainWnd();
var hMem;
var szName;
var szMem;
var dwMemSize=1000;
var pOutput="";

if (szName=AkelPad.MemAlloc(16))
{
  AkelPad.MemCopy(szName, "Global\\AkelPad", 0 /*DT_ANSI*/);

  //Create named memory object.
  if (hMem=AkelPad.SendMessage(hMainWnd, 1305 /*AKD_MEMCREATE*/, szName, dwMemSize))
  {
    //Write to shared memory.
    if (szMem=AkelPad.SendMessage(hMainWnd, 1306 /*AKD_MEMMAP*/, hMem, dwMemSize))
    {
      AkelPad.MemCopy(szMem, "Test", 0 /*DT_ANSI*/);
      AkelPad.SendMessage(hMainWnd, 1307 /*AKD_MEMUNMAP*/, szMem, 0);
    }

    //Call external application. This application should call:
    //hMem=OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, "Global\\AkelPad");
    //szMem=MapViewOfFile(hMem, FILE_MAP_ALL_ACCESS, 0, 0, 1000);
    //Read szMem.
    //Write szMem.
    //UnmapViewOfFile(szMem);

    //Read from shared memory.
    if (szMem=AkelPad.SendMessage(hMainWnd, 1306 /*AKD_MEMMAP*/, hMem, dwMemSize))
    {
      pOutput=AkelPad.MemRead(szMem, 0 /*DT_ANSI*/);
      AkelPad.SendMessage(hMainWnd, 1307 /*AKD_MEMUNMAP*/, szMem, 0);
    }

    AkelPad.SendMessage(hMainWnd, 1308 /*AKD_MEMCLOSE*/, hMem, 0);
  }
  AkelPad.MemFree(szName);
}

r0n
Offline
Posts: 23
Joined: Sat Jun 14, 2014 3:56 am

Post by r0n »

@Instructor

I tried most exe to exe communications with COPYDATA with QM.
I just wanted toe learn what the syntaxt is in .JS
But I am really happy 'filemapping' works!!!

Thank you for the FileMappingExample2.js example!!!

It is really appreciated!

r0n
Offline
Posts: 23
Joined: Sat Jun 14, 2014 3:56 am

Post by r0n »

Sorry for this question, but what is the code for triggering after a tab-switch? (Below is the code for triggering on a new document).
I need the exact same but only for a TAB switch. (when user clicks on an other tab.

I got my application working but I forgot about the possibility when the user focuses on another tab.

Code: Select all

var hSubClass;

if (hSubClass=AkelPad.WindowSubClass(1 /*WSC_MAINPROC*/, MainCallback, 0x436 /*AKDN_OPENDOCUMENT_FINISH*/))
{
  //Message loop
  AkelPad.WindowGetMessage();

  AkelPad.WindowUnsubClass(1 /*WSC_MAINPROC*/);
}

function MainCallback(hWnd, uMsg, wParam, lParam)
{
  if (uMsg == 0x436 /*AKDN_OPENDOCUMENT_FINISH*/)
  {
    var filePath = AkelPad.GetEditFile(0);
    AkelPad.Exec("notepad.exe \"" + filePath + "\"");
  }
}

I think these lines need to be adjusested?
if (hSubClass=AkelPad.WindowSubClass(1 /*WSC_MAINPROC*/, MainCallback, 0x436 /*AKDN_OPENDOCUMENT_FINISH*/))

or the following part:

uMsg == 0x436
Post Reply