35

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

Launch4j アプリケーションをタスクバーに固定した結果

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

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

javaw.exe をホスト アプリケーションとして指定した結果

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

これは、Windowsに固有の を渡すことで解決できると思いAppUserModelIDます。これには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 アプリケーションで使用できるようになると思います。

4

7 に答える 7

21

私は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()明らかにWindows 7でのみ使用できるように、アプリケーションにオペレーティングシステムの検出を追加することです。

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

編集:JNAソリューション

参照:

于 2009-12-13T16:59:46.797 に答える
5

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

于 2010-12-02T14:42:43.350 に答える
4

JSmoothを使用してみてください。いつもこれを使っています。JSmoothにはSkeletonWindowed Wrapper呼び出されたオプションがありますか

exeプロセスでJavaアプリを起動

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

JSmooth
(出典: andrels.com )

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

マルティン

于 2009-12-12T18:57:58.187 に答える
4

JNA を使用して SetCurrentProcessExplicitAppUserModelID メソッドへのアクセスを実装しましたが、MSDN ドキュメントが示唆するように使用すると非常にうまく機能します。コード スニペットのように JNA API を使用したことはありません。私の実装は、代わりに典型的な 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 で直接使用するのが非常に難しい Windows COM を利用しています。これらの API を呼び出すためのカスタム DLL の作成に成功しました (たとえば、SHGetPropertyStoreForWindow を使用してサブモジュール ウィンドウに別のアプリ ID を設定する)。その後、JNA を使用して実行時にアクセスします。

于 2009-12-22T18:32:14.870 に答える
3

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

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

于 2009-12-11T19:24:28.183 に答える
1

最新のjna-platformライブラリには、次の JNA バインディングが含まれていますSetCurrentProcessExplicitAppUserModelID

https://github.com/java-native-access/jna/pull/680

于 2016-07-22T12:33:13.680 に答える