Java 응용 프로그램을 Windows 7 작업 표시 줄에 고정합니다
-
11-09-2019 - |
문제
나는 Windows 7 하에서 Java 응용 프로그램의 래퍼로서 Launch4J를 사용합니다. javaw.exe
그것은 차례로 Java 코드를 해석합니다. 결과적으로 응용 프로그램을 작업 표시 줄에 고정하려고 할 때 Windows 대신 핀 javaw.exe
. 필수 명령 줄이 없으면 응용 프로그램이 실행되지 않습니다.
보시다시피, Windows는 Java가 호스트 응용 프로그램이라는 것을 인식하지 못합니다. 응용 프로그램 자체는 "Java (TM) 플랫폼 SE 바이너리"로 설명됩니다.
레지스트리 키를 변경하려고 시도했습니다 HKEY_CLASSES_ROOT\Applications\javaw.exe
값을 추가합니다 IsHostApp
. 이것은 내 응용 프로그램의 고정을 완전히 비활성화함으로써 동작을 변화시킨다. 분명히 내가 원하는 것이 아닙니다.
읽은 후 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 용액.
참조 :
- JNI 책 더 많은 JNI 예제
- Java Native Access (JNA)
다른 팁
사용하려고 노력하십시오 jsmooth. 나는 항상 이것을 사용합니다. JSMooth에는 옵션이 있습니다 Skeleton
~에 의해 Windowed Wrapper
~라고 불리는
EXE 프로세스의 Lauch Java 앱
이 이미지를 참조하십시오.
또한 명령 줄 인수를 통과 할 수 있습니다.
나는 이것이 당신을위한 해결책이 될 수 있다고 생각합니다.
마티 -
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
:
나는 ID 설정없이 내 것을 고쳤다. 당신이 그것을 사용하고 있고 당신이 그렇게한다고 말하면 launch4j에 옵션이 있습니다 ...
헤더를 JNI GUI로 변경 한 다음 JRE로 항아리 주위를 감을 수 있습니다. 좋은 점은 항아리와 함께 javaw.exe를 실행하는 대신 프로세스에서 .exe를 실행한다는 것입니다. 아마도 후드 아래에서 그것을 할 것입니다 (확실하지 않음). 또한 나는 또한 약 40-50%의 CPU 리소스가 필요하다는 것을 알았습니다.
그리고 고정은 잘 작동하며 모든 창 기능이 활성화됩니다.
나는 거의 2 일 동안 미분식 Javafx 앱으로 그 문제를 해결하려고 노력하면서 누군가에게 도움이되기를 바랍니다.