문제

나는 Windows 7 하에서 Java 응용 프로그램의 래퍼로서 Launch4J를 사용합니다. 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 창에. 이있다 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
}

이것은 효과가없는 것으로 보이지만 함수는 오류없이 반환됩니다. 왜 나에게 미스터리가 된 이유를 진단합니다. 제안이 있습니까?

작업 구현

작동 한 최종 구현은입니다 내 후속 질문에 대한 답 통과하는 방법에 대해 AppID JNA 사용.

나는 JNI에 대한 Gregory Pakosz의 화려한 대답에 현상금을 수여하여 올바른 길을 가졌습니다.

참고 로이 기술을 사용하여 논의 된 API를 사용할 가능성이 열릴 수 있다고 생각합니다. 이 기사에서 Java 응용 프로그램에서.

도움이 되었습니까?

해결책

나는 Windows 7이 없지만 여기에 당신이 시작할 수있는 것이 있습니다.

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 Windows API로 전달하기 위해 기본 코드를 작성하지 못하게하는 또 다른 솔루션입니다. JNA로 가기로 결정했다면 사실에주의를 기울이십시오. SetCurrentProcessExplicitAppUserModelID() UTF-16 문자열을 기대하고 있습니다.

샌드 박스에서 작동하면 다음 단계는 응용 프로그램에서 운영 체제 감지를 추가하는 것입니다. SetCurrentProcessExplicitAppUserModelID() 분명히 Windows 7에서만 사용할 수 있습니다.

  • 당신은 그것을 확인하여 Java 쪽에서 그렇게 할 수 있습니다. System.getProperty("os.name"); 보고 "Windows 7".
  • 내가 준 작은 JNI 스 니펫에서 구축하면 동적으로로드하여 향상시킬 수 있습니다. shell32.dll 라이브러리 사용 LoadLibrary 그런 다음 다시 돌아옵니다 SetCurrentProcessExplicitAppUserModelID 기능 포인터 사용 GetProcAddress. 만약에 GetProcAddress 보고 NULL, 그것은 기호가 없음을 의미합니다 shell32 따라서 Windows 7이 아닙니다.

편집하다: JNA 용액.

참조 :

다른 팁

Java의 새로운 Windows 7 기능을 제공하는 Java 라이브러리가 있습니다. 라고 불린다 j7goodies ~에 의해 Strix 코드. 이를 사용하는 응용 프로그램은 Windows 7 작업 표시 줄에 올바르게 고정 될 수 있습니다. 자신만의 점프 목록 등을 만들 수도 있습니다.

사용하려고 노력하십시오 jsmooth. 나는 항상 이것을 사용합니다. JSMooth에는 옵션이 있습니다 Skeleton ~에 의해 Windowed Wrapper ~라고 불리는

EXE 프로세스의 Lauch Java 앱

이 이미지를 참조하십시오.

JSmooth

또한 명령 줄 인수를 통과 할 수 있습니다.
나는 이것이 당신을위한 해결책이 될 수 있다고 생각합니다.

마티 -

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는 Windows Com을 사용하여 JNA와 직접 사용하기가 매우 어렵습니다. 나는이 API를 호출하기 위해 사용자 정의 DLL을 만드는 성공을 거두었습니다 (예 : shgetPropertyStoreforWindow를 사용하여 하위 모듈 창에 대한 다른 앱 ID를 설정).

setCurrentProcessExplicitAppuserModelid (또는 setAppid ())는 실제로 당신이하려는 일을 할 것입니다. 그러나 바로 가기에 AppUserModel.id 속성을 설정하려면 설치 프로그램을 수정하는 것이 더 쉬울 수 있습니다. 응용 프로그램 사용자 모델 ID 위에서 언급 한 문서 :

에서 System.appusermodel.id 응용 프로그램의 바로 가기 파일의 속성. 바로 가기 (iShellLink, ClsID_ShellLink 또는 .LNK 파일)는 ipropertystore 및 쉘 전체에 사용되는 기타 속성 설정 메커니즘을 통해 속성을 지원합니다. 이를 통해 작업 표시 줄은 적절한 바로 가기를 고정시킬 수 있으며 프로세스에 속하는 Windows가 해당 작업 표시 줄 버튼과 적절하게 연관되어 있는지 확인할 수 있습니다. 참고 : System.appuserModel.id 속성은 바로 가기를 만들 때 바로 가기에 적용되어야합니다. Microsoft Windows 설치 프로그램 (MSI)을 사용하여 응용 프로그램을 설치할 때 MSISHORTCUTPROPERTY 테이블을 사용하면 설치 중에 생성 될 때 appusermodelid가 바로 가기에 적용될 수 있습니다.

최신 jna-platform 라이브러리에는 이제 JNA 바인딩이 포함되어 있습니다 SetCurrentProcessExplicitAppUserModelID:

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

나는 ID 설정없이 내 것을 고쳤다. 당신이 그것을 사용하고 있고 당신이 그렇게한다고 말하면 launch4j에 옵션이 있습니다 ...

헤더를 JNI GUI로 변경 한 다음 JRE로 항아리 주위를 감을 수 있습니다. 좋은 점은 항아리와 함께 javaw.exe를 실행하는 대신 프로세스에서 .exe를 실행한다는 것입니다. 아마도 후드 아래에서 그것을 할 것입니다 (확실하지 않음). 또한 나는 또한 약 40-50%의 CPU 리소스가 필요하다는 것을 알았습니다.

그리고 고정은 잘 작동하며 모든 창 기능이 활성화됩니다.

나는 거의 2 일 동안 미분식 Javafx 앱으로 그 문제를 해결하려고 노력하면서 누군가에게 도움이되기를 바랍니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top