2024年4月12日金曜日

ChromeでSNSをウィンドウサイズ固定で別ウィンドウで開きたい

という要望を持ったのだが。
  • --window-position, --window-size などのコマンドラインオプションがまともに作用しない。
  • JavaScript指定して調整する方法があるも、windowの体裁が変になる。
  • プロファイルを別に指定するとオプションが効く風でもあるが、プロファイルが変わるとログインが面倒。
ということで、標準的な手順を断念。新規に起動したらいんじゃね?という事に。 Win32API の CreateProcess で chrome 直撃したらウィンドウが別に開いた。嬉しい。 悲報:CreateProcess の引数に渡す STARTUPINFO 構造体の座標・サイズ情報は有効に作用しない! という訳で、新規に開いたウィンドウを自前で探索して移動してやろう! やり方としてはもっとスマートな方法があるのやもしれんが、一先ずこれで。
  1. その時点で開いているChromeのウィンドウのhWndを記録しておく。
  2. CreateProcessでChromeを--new-windowオプションとURLを指定して開く。
  3. ちょっと待機する。(即時にはウィンドウが開かない)
  4. 再度ウィンドウを探索し、先に記録しておいたものと突合し、合致しないのが居たらそいつがルパン。
  5. 対象ウィンドウをMoveWindowでお好きな位置に。
汎用性を持たせた書き方をしたいんだけどパラメータを設定ファイルに持たせるのが賢いのかな…全指定はきちゃない気がする。 一応これで動くよってサンプルはこんなところ。
#include <iostream>
#include <tchar.h>
#include <windows.h>
#include <list>

const TCHAR CHROME_PATH[] = _T( "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe" );

struct TFindData {
	std::list<HWND> chromeWnds;
	bool bFound;
};

bool isChromeWindow( HWND hWnd, DWORD& dwProcessId ) {
	bool bResult = false;
	dwProcessId = 0;
	DWORD dwThreadId = GetWindowThreadProcessId( hWnd, &dwProcessId );

	HANDLE hProcess = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcessId );
	if ( hProcess ) {
		TCHAR buf[ MAX_PATH ] = {};
		DWORD dwBufLength = MAX_PATH - 1;
		if ( QueryFullProcessImageName( hProcess, 0, buf, &dwBufLength ) ) {
			if ( !lstrcmpi( CHROME_PATH, buf ) ) {
				bResult = true;
			}
		}
		CloseHandle( hProcess );
	}
	return bResult;
}

BOOL CALLBACK EnumChromeWndProc( HWND hWnd, LPARAM lParam ) {
	TFindData* pData = reinterpret_cast< TFindData* >( lParam );

	DWORD dwProcessId = 0;

	if ( isChromeWindow( hWnd, dwProcessId ) ) {
		pData->chromeWnds.push_back( hWnd );
	}
	return TRUE;
}

void MoveChromeWnd( HWND hWnd ) {
	MoveWindow( hWnd, 4380, 0, 740, 1440, TRUE );
}

BOOL CALLBACK MoveNewChromeWnd( HWND hWnd, LPARAM lParam ) {
	TFindData* pData = reinterpret_cast< TFindData* >( lParam );
	DWORD dwProcessId = 0;
	if ( isChromeWindow( hWnd, dwProcessId ) ) {
		for ( std::list<HWND>::iterator it = pData->chromeWnds.begin(); it != pData->chromeWnds.end(); it++ ) {
			if ( *it == hWnd ) {
				return TRUE;
			}
		}
		MoveChromeWnd( hWnd );
		pData->bFound = true;
		return FALSE;
	}
	return TRUE;
}

int _tmain( int argc, TCHAR* argv[] ) {
	setlocale( LC_ALL, "JAPANESE" );

	TFindData data;
	data.bFound = false;
	BOOL bResult = FALSE;

	bResult = EnumWindows( EnumChromeWndProc, reinterpret_cast< LPARAM >( &data ) );

	STARTUPINFO si = {};
	si.cb = sizeof( si );
	PROCESS_INFORMATION pi = {};
	TCHAR OPEN_TWITTER[] = _T( "\"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe\" --new-window \"https://twitter.com/home\" \"https://bsky.app/\"\0\0" );
	bResult = CreateProcess( NULL, OPEN_TWITTER, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
	if ( !bResult ) {
		return 0;
	}
	data.bFound = false;
	for ( int i = 0; i < 5; i++ ) {
		Sleep( 200 );
		bResult = EnumWindows( MoveNewChromeWnd, reinterpret_cast< LPARAM >( &data ) );
		if ( !bResult ) {
			break;
		}
		if ( data.bFound ) {
			break;
		}
		Sleep( 300 );
	}

	CloseHandle( pi.hThread );
	CloseHandle( pi.hProcess );
	return 0;
}

0 件のコメント:

コメントを投稿

LogiTune、おまえかい!

やっぱりそうやんなぁ、っていう。 前回に引き続き、OBSでの録画終了できない問題です。まことしやかに「GPU負荷高すぎで処理が終われない」とか書いてあるけど、どれだけ負荷下げた設定にしたって、ソース構成をシンプルにしたって駄目だったし。そもそもx264のソフトウェアエンコードにし...