web-dev-qa-db-ja.com

JavaアプリケーションをWindows7タスクバーに固定する

Launch4jをWindows7でのJavaアプリケーションのラッパーとして使用します。これは、私の理解では、本質的にjavaw.exeのインスタンスをフォークし、それがJavaコード。その結果、アプリケーションをタスクバーに固定しようとすると、Windowsは代わりにjavaw.exeを固定します。必要なコマンドラインがないと、アプリケーションは実行されません。

Result of pinning a Launch4j application to the taskbar

ご覧のとおり、WindowsはJavaがホストアプリケーションであることも認識していません。アプリケーション自体は「Java(TM)プラットフォームSEバイナリ」として記述されています。

レジストリキーHKEY_CLASSES_ROOT\Applications\javaw.exeを変更して値IsHostAppを追加しようとしました。これにより、アプリケーションの固定が完全に無効になり、動作が変わります。明らかに私が望むものではありません。

Result of specifying javaw.exe as a Host application

Windowsが単一のアプリケーションのインスタンスをどのように解釈するか (および この質問で説明されている現象 )について読んだ後、アプリケーションユーザーモデルID(AppUserModelID)を自分のに埋め込むことに興味を持ちました。 Javaアプリケーション。

一意のAppUserModelIDをWindowsに渡すことでこれを解決できると思います。これにはShell32メソッドがあります SetCurrentProcessExplicitAppUserModelID 。 Gregory Pakoszの提案に従って、アプリケーションをjavaw.exeの個別のインスタンスとして認識させるために実装しました。

NativeLibrary lib;
try {
    lib = NativeLibrary.getInstance("Shell32");
} catch (Error e) {
    Logger.out.error("Could not load Shell32 library.");
    return;
}
Object[] args = { "Vendor.MyJavaApplication" };
String functionName = "SetCurrentProcessExplicitAppUserModelID";
try {
    Function function = lib.getFunction(functionName);
    int ret = function.invokeInt(args);
    if (ret != 0) {
        Logger.out.error(function.getName() + " returned error code "
                + ret + ".");
    }
} catch (UnsatisfiedLinkError e) {
    Logger.out.error(functionName + " was not found in "
            + lib.getFile().getName() + ".");
    // Function not supported
}

これは効果がないように見えますが、関数はエラーなしで戻ります。なぜそれを診断するのは私には謎のようなものです。助言がありますか?

実用的な実装

うまくいった最終的な実装は 私のフォローアップの質問への答え JNAを使用してAppIDを渡す方法に関するものです。

私は、Gregory PakoszのJNIに対する見事な回答に報奨金を授与し、私を正しい軌道に乗せました。

参考までに、この手法を使用すると、説明したAPIのいずれかを使用できる可能性が広がると思います この記事で Javaアプリケーションで。

35
Paul Lammertsma

私はWindows7を持っていませんが、ここにあなたが始めるかもしれない何かがあります:

Java側:

_package com.stackoverflow.homework;

public class MyApplication
{
  static native boolean setAppUserModelID();

  static
  {
    System.loadLibrary("MyApplicationJNI");
    setAppUserModelID();
  }
}
_

そしてネイティブ側では、 `MyApplicationJNI.dllライブラリのソースコードで:

_JNIEXPORT jboolean JNICALL Java_com_stackoverflow_homework_MyApplication_setAppUserModelID(JNIEnv* env)
{
  LPCWSTR id = L"com.stackoverflow.homework.MyApplication";
  HRESULT hr = SetCurrentProcessExplicitAppUserModelID(id);

  return hr == S_OK;
}
_

あなたの質問は明示的にJNIソリューションを求めていました。ただし、アプリケーションは他のネイティブメソッドを必要としないため、 jna は、WindowsAPIに転送するためだけにネイティブコードを記述しないようにする別のソリューションです。 jnaに移行する場合は、SetCurrentProcessExplicitAppUserModelID()がUTF-16文字列を予期していることに注意してください。

サンドボックスで機能する場合、次のステップは、アプリケーションにオペレーティングシステムの検出を追加することです。これは、SetCurrentProcessExplicitAppUserModelID()が明らかにWindows7でのみ使用できるためです。

  • System.getProperty("os.name");が_"Windows 7"_を返すことを確認することにより、Java側からこれを行うことができます。
  • 私が提供した小さなJNIスニペットからビルドする場合は、 LoadLibrary を使用して_Shell32.dll_ライブラリを動的にロードし、SetCurrentProcessExplicitAppUserModelID関数を取得することで拡張できます。 GetProcAddress を使用したポインタ。 GetProcAddressNULLを返す場合、シンボルが_Shell32_に存在しないため、Windows7ではないことを意味します。

編集: JNAソリューション

参照:

21
Gregory Pakosz

Java Java用の新しいWindows7機能を提供するライブラリがあります。これは J7Goodies by Strix Code と呼ばれます。これを使用するアプリケーションは適切に使用できます。 Windows7タスクバーに固定されています。独自のジャンプリストなどを作成することもできます。

5
torn

JNAを使用してSetCurrentProcessExplicitAppUserModelIDメソッドへのアクセスを実装しましたが、MSDNドキュメントが示すように使用すると非常にうまく機能します。コードスニペットのようにJNAAPIを使用したことはありません。私の実装は、代わりに 通常のJNAの使用法 に従います。

まず、Shell32インターフェイスの定義:

interface Shell32 extends StdCallLibrary {

    int SetCurrentProcessExplicitAppUserModelID( WString appID );

}

次に、JNAを使用してShell32をロードし、関数を呼び出します。

final Map<String, Object> WIN32API_OPTIONS = new HashMap<String, Object>() {
    {
       put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
       put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
    }
};
Shell32 Shell32 = (Shell32) Native.loadLibrary("Shell32", Shell32.class,
           WIN32API_OPTIONS);
WString wAppId = new WString( "Vendor.MyJavaApplication" );
Shell32.SetCurrentProcessExplicitAppUserModelID( wAppId );

前回の記事で言及したAPIの多くは、JNAで直接使用するのが非常に難しいWindowsCOMを使用しています。これらのAPIを呼び出すためのカスタムDLLを作成して(たとえば、SHGetPropertyStoreForWindowを使用してサブモジュールウィンドウに別のアプリIDを設定する)、実行時にJNAを使用してアクセスすることに成功しました。

4
The_Fire

JSmooth を使用してみてください。私はいつもこれを使います。 JSmoothには、Skeletonの下にWindowed Wrapperによって呼び出されるオプションがあります

Lauch Java exeプロセスのアプリ

この画像を参照してください。

JSmooth

コマンドライン引数を渡すこともできます。
これはあなたにとっての解決策になると思います。

マルティン

4

SetCurrentProcessExplicitAppUserModelID(またはSetAppID())は、実際には、実行しようとしていることを実行します。ただし、インストーラーを変更して、ショートカットにAppUserModel.IDプロパティを設定する方が簡単な場合があります-上記の アプリケーションユーザーモデルID ドキュメントから引用します。

アプリケーションのショートカットファイルの System.AppUserModel.ID プロパティ。ショートカット(IShellLink、CLSID_ShellLink、または.lnkファイルとして)は、IPropertyStoreおよびシェル全体で使用されるその他のプロパティ設定メカニズムを介してプロパティをサポートします。これにより、タスクバーはピン留めするための適切なショートカットを識別し、プロセスに属するウィンドウがそのタスクバーボタンに適切に関連付けられるようになります。注:ショートカットの作成時に、System.AppUserModel.IDプロパティをショートカットに適用する必要があります。 Microsoft Windowsインストーラー(MSI)を使用してアプリケーションをインストールする場合、 MsiShortcutProperty テーブルを使用すると、インストール中に作成されたショートカットにAppUserModelIDを適用できます。

3
Eric Brown

最新の jna-platformライブラリにSetCurrentProcessExplicitAppUserModelIDのJNAバインディングが含まれるようになりました。

https://github.com/Java-native-access/jna/pull/68

1
rednoah

IDを設定せずに修正しました。 Launch4Jを使用していて、使用すると言う場合は、Launch4Jにオプションがあります...

ヘッダーをJNIGuiに変更してから、JREでjarにラップすることができます。良い点は、jarでjavaw.exeを実行する代わりに、プロセスで.exeを実行することです。それはおそらくボンネットの下でそれを行います(確かではありません)。また、CPUリソースが約40〜50%少なくて済み、さらに優れていることにも気づきました。

また、ピン留めは正常に機能し、すべてのウィンドウ機能が有効になります。

装飾されていないjavafxアプリでその問題を解決するために2日近く費やしたので、誰かに役立つことを願っています。

0
LazerBanana