Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

Recommended Posts

I started working on this today, got it working, and figured I'd share. I still have more work to do but this is a good start. Could use cleaning up but that's for later.



Import "-lpsapi"

Const PROCESS_VM_READ:Int = $0010
Const PROCESS_VM_WRITE:Int = $0020

Extern "Win32"
Function GetLastError:Int()
Function OpenProcess:Int(dwDesiredAccess:Int, bInheritHandle:Int, dwProcessId:Int)
Function EnumProcesses(pProcessIds:Byte Ptr, cb:Int, pBytesReturned:Int Ptr)="EnumProcesses@12"
Function EnumProcessModules(hProcess:Int, lphModule:Byte Ptr, cb:Int, lpcbNeeded:Int Ptr)
Function GetModuleBaseName(hProcess:Int, hModule:Int, lpBaseName:Byte Ptr, nSize:Int) = "GetModuleBaseNameA@16"
Function TerminateProcess(hProcess:Int, uExitCode:Int)
Function CloseHandle(hObject:Int)
Function GetModuleFileName(hModule:Int, lpFileName:Byte Ptr, nSize:Int)
Function GetModuleFileNameExA(hProcess:Int, hModule:Int, lpFilename:Byte Ptr, nSize:Int)
Function GetProcessImageFileNameA(hProcess:Int, lpImageFileName:Byte Ptr, nSize:Int)

' enumerate all processes '
Function EnumerateProcesses:Int[]()
Local pProcessIds:Byte Ptr
Local cb:Int = 1024
Local bBytesReturned:Int
Local processes:Int[]

pProcessIds = MemAlloc(cb)
	If Not EnumProcesses(pProcessIds , cb, Varptr bBytesReturned)
		MemFree(pProcessIds )
		Return Null
processes = New Int[bBytesReturned / 4]
MemCopy(Varptr processes[0], pProcessIds, bBytesReturned)

Return processes

' get process name from process id '
Function GetProcessName:String(id:Int)
Local hProcess:Int
Local hModule:Int = 0
Local lpBaseName:Byte Ptr[1024]
Local nSize:Int = 1024
Local processName:String = ""

	If hProcess = 0 Return ""

GetModuleBaseName(hProcess, hModule, Varptr lpBaseName[0], nSize)

processName = String.FromCString(lpBaseName)

	If processName = "?" Or processName = Null
		GetProcessImageFileNameA(hProcess, Varptr lpBaseName[0], nSize)
		processName = StripDir(String.FromCString(lpBaseName))


Return processName


Local pList:Int[] = EnumerateProcesses()

  If pList.length > 0

	 For Local i:Int = 0 To pList.length - 1

		   If pList[i] <> 0

			  Local pname:String = GetProcessName(pList[i])

				 If pname <> "" Notify(pname)




Link to post
Share on other sites


#include "xwinuser.h"

HWND _GetNextWindow(HWND hWnd, UINT wCmd)
  return GetNextWindow(hWnd, wCmd);



#include <Windows.h>
#include <Winuser.h>

#ifdef __cplusplus
extern "C"{

extern HWND _GetNextWindow(HWND hWnd, UINT wCmd);

#ifdef __cplusplus



Import "xwinuser.c"

Const GW_HWNDNEXT:int = 2
Const GW_HWNDPREV:int = 3

Extern "Win32"
   Function _GetNextWindow:Int(hWnd:Int, wCmd:Int) = "_GetNextWindow"


Not sure if this would be called "proper" but it works.

Link to post
Share on other sites

lol, technically yeah, I could make my own task manager.


However, my purpose is to deny multiple instances of my application, and eventually send messages (SendMessageW) to the application - which I'm working on now. My attempt is to deny a second application execution and send the application arguments to the application already running (this way double clicking a file that my application is registered to will open up in the application already running).


Forgot about the tags.


And fixed.

Link to post
Share on other sites

Had this working but never tested actually getting the message, I only confirmed it worked with a notification, and so I spent all day trying to actually get the message. Going to give this more of a shot but if I still can't get it working strictly in BMax I'm probably going to take a shortcut and provide a helper function in C.

Link to post
Share on other sites

I just now got this working and I haven't made it all organized yet, I'm going to do that when I add it to my actual application, instead of using this testing application. One portion turned out to be a problem. When trying to get the window handle from the process ID it actually is a list of the window and basically any/all gadgets that can receive messages (active panels for example). I don't know for fact that this is true but that's what it seems like to me, otherwise I don't see how all of these returned results from "GetWindowThreadProcessId" are all from the same process ID.


Here is the function get the results from a process ID, one of which will be the window, and this has to be filtered in some way (send a message, check the title, something along those lines; I haven't done this filter yet):


' get the list of threads/windows matching the passed in process id '
Function GetProcessWindow:int[](id:int)
 Local hWnd:int = GetTopWindow(0)
 Local hWnds:int[]

  Local pId:int
  Local dThreadId:int = GetWindowThreadProcessId(hWnd, Varptr pId)

	If pId = id
	  hWnds = hWnds[..hWnds.Length+1]
	  hWnds[hWnds.Length-1] = hWnd

  hWnd = _GetNextWindow(hWnd, GW_HWNDNEXT)

 Return hWnds


Now, you can use this list and send the message to all of them, which I did to be quick about it, and it seems safe because the message will just fail to send if it's not a correct window. That seems odd, so a filtering process should be done, but I haven't done that yet. Either way you will still be sending a message of some kind to all of the returned results before having the actual window handle.


Anyway, the following is how to send the message (which would be a separate application at the time) and receive it (which would be the already running instance of the application).



Global ChangeWindowMessageFilter:Int(message:Int, dwFlag:Int) = GetProcAddress(LoadLibraryA("user32.dll"), "ChangeWindowMessageFilter")

Local MsgStr:String = "THIS IS A TEST"
Local MsgData:int[3]
MsgData[0] = 1
MsgData[1] = Len(MsgStr) + 1
MsgData[2] = Int(MsgStr.ToCString())

ChangeWindowMessageFilter(WM_COPYDATA, 1)
SendMessageW(pHandle, WM_COPYDATA, 0, Int Byte Ptr MsgData)



Local MsgData:int[3]
MemCopy(MsgData, Byte Ptr lp, 12)

' MsgData[0] - 1 '
' MsgData[1] - Size '
' MsgData[2] - String '

Notify(String.FromCString(Byte Ptr MsgData[2]))


And there you have it. It will notify "THIS IS A TEST" correctly. You can use "MsgData[0]" as a form of message identification so you can decide what to do with the string you've received.




For receiving, it's best to edit "win32maxguiex.bmx" and explains the "lp" variable. Line 372, you would do something like:

' Select msg '
local msgData:int[3]
MemCopy(msgData, Byte Ptr lp, 12)

PostGuiEvent(EVENT_DATARECEIVED, Null, 0, 0, 0, 0, String.FromCString(Byte Ptr msgData[2]))


Add the "EVENT_DATARECEIVED" to "brl.mod/event.bmx", around line 193:



And around line 234:

TEvent.RegisterId EVENT_DATARECEIVED,"DataReceived"


Rebuild the two modules, and now you can use it like:


 select eventid()



That should be it.



Thanks goes out to "col" from the BlitzMax forums for his help in figuring out the sending/receiving of the message.

Link to post
Share on other sites

C++ version to send a message to BMax window (yes, it's specific, any other way doesn't work correctly that I've noticed):


HWND pHandle = FindWindow(NULL, _T("WINDOW TITLE"));

if(pHandle != NULL && GetLastError() != ERROR_SUCCESS)
 std::string msgString = "THIS IS A TEST";

 dataStruct.dwData = 3;  // this just tells my app that this is coming from C++ DLL - use any number
 dataStruct.cpData = (msgString.length() + 1);
 dataStruct.lpData = (PVOID)msgString.c_str();

 LRESULT msgSent = SendMessage(pHandle, WM_COPYDATA, (WPARAM)pHandle, (LPARAM)(LPVOID)&dataStruct);


I still cannot figure out why BMax cannot read from the named pipe (different subject, just using this spot for quick thoughts). Using pure C++ I have no problems, BMax can only send, but not receive. I'm guessing it's something wrong I'm doing in BMax but it's hard to tell.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...