It's just one of those weekends when I don't have anything better to do than to play around with this... so here's some more stuff.
I've added a few more functions and set it up to be called from inside the IDE without shell calls. The ".ext" executable I added works like a small, backgrounded extension to LiveCode that can receive calls that resemble internal functions, such as the one "set rect 37819389 50 50 1300 750" that sets the rect of the external window with ID 37819389 to 50,50,1300,750.
All you need to do is open the process and leave it open as long as your program needs these functions, write the function calls to the process, and read the result back. Each result terminates in line with single "#" character, so you know when to stop reading. If you pass up this character and keep reading, then your program will freeze while it waits for more output. See the attached livecode sample to see how it works.
Here's the functions it has now:
Usage: [command] [value] [#] [#] [#] ...
get list [#]: Retrieve list of windows.
[0] - All minimized.
[1] - All other.
[2] - All.
get iswindow [id]: Test if id names a window.
get rect [id]: Retrieve rect of specified window.
set desktop [id]: Lock window to desktop.
set workspace [left] [top] [right] [bottom]: Set area for fullscreen windows.
set maximized [id]: Maximize specified window.
set minimized [id]: Minimize specified window.
set restored [id]: Restore specified window to default position.
set hidden [id]: Hide specified window.
set unhidden [id]: Unhide specified window.
set rect [left] [top] [right] [bottom]: Set rect of specified window.
help: Show this message.
quit: Close this process.
Using "get list" with anything other than 0 is returns a huge list and doesn't make much sense. So if you need to get window lists, try to avoid using 1 and 2 unless you can discern the real ones from the hidden and system ones somehow.
To set the rect of an external window, it must first be not minimized and not maximized. If you forget this, then the function will not do anything when called. You can use "set restored" to fix this.
If you use "set hidden" to make an external window invisible, make sure you keep track of the window ID you used. If you forget the ID, then you will have a very hard time unhiding the window.
If you need other things it would be very easy for me to add them in, so just ask.
Here's the code again:
Code: Select all
#include "stdafx.h"
using namespace std;
int global_cmp = NULL;
//bool global_exit_status;
//bool global_thread_locked;
BOOL CALLBACK enumWindowsProc(__in HWND hWnd, __in LPARAM lParam)
{
if ((global_cmp == 0) && (!::IsIconic(hWnd)))
return TRUE;
else if ((global_cmp == 1) && (::IsIconic(hWnd)))
return TRUE;
int length = ::GetWindowTextLength(hWnd);
if (0 == length) return TRUE;
TCHAR* buffer;
buffer = new TCHAR[length + 1];
memset(buffer, 0, (length + 1) * sizeof(TCHAR));
GetWindowText(hWnd, buffer, length + 1);
wstring windowTitle = wstring(buffer);
delete[] buffer;
string str(windowTitle.begin(), windowTitle.end());
cout << (long)hWnd << " " << str << std::endl;
return TRUE;
}
bool setWRect(HWND WindowID, int x, int y, int cx, int cy)
{
if (SetWindowPos(WindowID, HWND_TOP, x, y, cx - x, cy - y, SWP_NOACTIVATE | SWP_NOOWNERZORDER))
return true;
else
return false;
}
bool downLevel(HWND WindowID)
{
HWND ProgmanHwnd =
::FindWindowEx(
::FindWindowEx(
::FindWindow(L"Progman", L"Program Manager"),
NULL,
L"SHELLDLL_DefView",
L""),
NULL,
L"SysListView32",
L"FolderView");
::SetParent(WindowID, ProgmanHwnd);
//global_thread_locked = true;
//while (!(global_exit_status))
//{
//if (!IsWindowVisible(WindowID))
//return false;
//if (!(SetWindowPos(WindowID, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOREDRAW | SWP_NOREPOSITION)))
//global_exit_status = true;
//Sleep(1);
//}
return false;
}
bool setRect(long left, long top, long right, long bottom)
{
RECT workarea;
//Set up new work area size
workarea.left = left;
workarea.top = top;
workarea.right = right;
workarea.bottom = bottom;
//Set the new work area and broadcast the change to all running applications
if (SystemParametersInfo(SPI_SETWORKAREA, 0, &workarea, SPIF_SENDCHANGE))
return true;
else
return false;
}
int main(int argc, char* argv[])
{
string command;
string function;
HWND hwnd;
string word;
string t;
RECT rect;
int args;
ShowWindow(NULL, 0);
int arg1, arg2, arg3, arg4, arg5, arg6;
while (((string)command != "quit") && ((string)command != "exit"))
{
getline(cin, t);
args = 0;
istringstream iss(t);
if (iss >> word)
{
command = word;
}
if (iss >> word)
{
function = word;
}
if (iss >> word)
{
arg1 = atoi(word.c_str());
args++;
}
if (iss >> word)
{
arg2 = atoi(word.c_str());
args++;
}
if (iss >> word)
{
arg3 = atoi(word.c_str());
args++;
}
if (iss >> word)
{
arg4 = atoi(word.c_str());
args++;
}
if (iss >> word)
{
arg5 = atoi(word.c_str());
args++;
}
if (iss >> word)
{
arg6 = atoi(word.c_str());
args++;
}
t = "";
if (command == "help")
{
cout << " Usage: [command] [value] [#] [#] [#] ...\n"
<< " get list [#]\n Retrieve list of windows.\n"
<< " [0] - All minimized.\n"
<< " [1] - All other.\n"
<< " [2] - All.\n"
<< " get iswindow [id]\n Test if id names a window.\n"
<< " get rect [id]\n Retrieve rect of specified window.\n"
//<< " get release []\n Unlock desktop thread.\n"
<< " set desktop [id]\n Lock window to desktop.\n"// Locks thread.\n"
<< " set workspace [left] [top] [right] [bottom]\n Set area for fullscreen windows.\n"
<< " set maximized [id]\n Maximize specified window.\n"
<< " set minimized [id]\n Minimize specified window.\n"
<< " set restored [id]\n Restore specified window to default position.\n"
<< " set hidden [id]\n Hide specified window.\n"
<< " set unhidden [id]\n Unhide specified window.\n"
<< " set rect [left] [top] [right] [bottom]\n Set rect of specified window.\n"
<< " help\n Show this message.\n"
<< " quit\n Close this process.\n"
<< "#";
}
else if (command == "get")
{
if (function == "list")
{
if ((unsigned int)arg1 > 2)
{
cout << "ERROR: Invalid argument.\n";
}
else
{
global_cmp = (unsigned int)arg1;
EnumWindows(enumWindowsProc, NULL);
}
}
else if (function == "iswindow")
{
hwnd = (HWND)(arg1);
cout << boolalpha << IsWindow(hwnd) << endl;
}
else if (function == "rect")
{
hwnd = (HWND)(arg1);
GetWindowRect(hwnd, &rect);
cout << rect.left << ' ' << rect.top << ' ' << rect.right << ' ' << rect.bottom << endl;
}
else if (function == "release")
{
//global_exit_status = true;
//global_thread_locked = false;
}
else
{
cout << "ERROR: Unknown function.\n";
}
}
else if (command == "set")
{
if (function == "desktop")
{
if (args == 1)
{
hwnd = (HWND)(arg1);
if (!IsWindowVisible(hwnd))
{
cout << "ERROR: Invalid Window ID!\n";
}
else
downLevel(hwnd);
}
else
cout << "ERROR: Invalid arguments\n";
}
else if (function == "workspace")
{
if (args == 4)
{
if (!(setRect(arg1, arg2, arg3, arg4)))
cout << "ERROR: Failed to edit system parameters.\n";
}
else
cout << "ERROR: Invalid arguments\n";
}
else if (function == "maximized")
{
if (args == 1)
{
hwnd = (HWND)(arg1);
ShowWindow(hwnd, SW_MAXIMIZE);
}
else
cout << "ERROR: Invalid arguments\n";
}
else if (function == "minimized")
{
if (args == 1)
{
hwnd = (HWND)(arg1);
ShowWindow(hwnd, SW_FORCEMINIMIZE);
}
else
cout << "ERROR: Invalid arguments\n";
}
else if (function == "restored")
{
if (args == 1)
{
hwnd = (HWND)(arg1);
ShowWindow(hwnd, SW_RESTORE);
}
else
cout << "ERROR: Invalid arguments\n";
}
else if (function == "hidden")
{
if (args == 1)
{
hwnd = (HWND)(arg1);
ShowWindow(hwnd, SW_HIDE);
}
else
cout << "ERROR: Invalid arguments\n";
}
else if (function == "unhidden")
{
if (args == 1)
{
hwnd = (HWND)(arg1);
ShowWindow(hwnd, SW_SHOW);
}
else
cout << "ERROR: Invalid arguments\n";
}
else if (function == "rect")
{
if (args == 5)
{
hwnd = (HWND)(arg1);
if (!(setWRect(hwnd, arg2, arg3, arg4, arg5)))
cout << "ERROR: Failed to edit window.\n";
}
else
cout << "ERROR: Invalid arguments\n";
}
else
{
cout << "ERROR: Unknown function.\n";
}
}
cout << "#\n";
}
return 0;
}
EDIT:
I fixed the odd flickering on the "set desktop" function and removed the "release" function since there's no more multi-threading involved, but now it requires explorer.exe running for that function it to work. I think that should be OK for most people.
In a program I'm working on, I just edited the code I posted in the sample here to create a function so I can just use "put wSettings("set workspace 0 24 1366 768")" and the like to run any of these commands. It's much faster than those old executables I was using before and definitely much better than the freeware that was my only other option.
I also made the horrible mistake of using both wide and narrow range outputs. Now that is fixed as well.