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.
Re: Trigger (auto execute) an application when opening file
Posted: Sat Jun 14, 2014 9:04 am
by DV
r0n,
This can be easily done via the Scripts plugin.
For example, create the following .js script under AkelFiles\Plugs\Scripts:
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".
Re: Trigger (auto execute) an application when opening file
Posted: Sat Jun 14, 2014 9:12 am
by DV
Here is another version, probably closer to what you want to achieve:
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.
Posted: Sat Jun 14, 2014 6:44 pm
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.)
Posted: Sat Jun 14, 2014 7:05 pm
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!!!
Posted: Sun Jun 15, 2014 12:40 am
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.
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).
Posted: Sun Jun 15, 2014 4:36 am
by Instructor
r0n
You cannot directly transfer data between processes.
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);
}
Posted: Sun Jun 15, 2014 8:56 am
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.
Posted: Sun Jun 15, 2014 2:59 pm
by r0n
@FeyFre and @Instructor
Thank you both for the feedback!
I will try with Instructors code and the WM_COPYDATA method.
Posted: Mon Jun 16, 2014 4:54 am
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:
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.
Posted: Mon Jun 16, 2014 4:30 pm
by Instructor
r0n
Why you need WM_COPYDATA, if you get file mapping working in QM?
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);
}
Posted: Mon Jun 16, 2014 5:11 pm
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!
Posted: Wed Jun 18, 2014 2:38 pm
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.