added files.
This commit is contained in:
commit
e908ab2355
353 files changed
+130515
No files matched your search
@@ -0,0 +1,27 @@
|
||||
add_library(SlinkyNative SHARED
|
||||
src/DllMain.cpp
|
||||
src/Logger.cpp
|
||||
src/JvmManager.cpp
|
||||
src/MinecraftDetector.cpp
|
||||
src/NativeBridge.cpp
|
||||
src/PayloadLoader.cpp
|
||||
SlinkyNative.rc
|
||||
)
|
||||
|
||||
target_include_directories(SlinkyNative PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/jdk
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/jdk/win32
|
||||
)
|
||||
|
||||
target_compile_definitions(SlinkyNative PRIVATE
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
WIN32_LEAN_AND_MEAN
|
||||
EMBED_PAYLOAD_JARS
|
||||
)
|
||||
|
||||
set_target_properties(SlinkyNative PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
OUTPUT_NAME "SlinkyNative"
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
#include "include/Resource.h"
|
||||
|
||||
// If the payload jars exist at build time, embed them as RT_RCDATA (10)
|
||||
#ifdef EMBED_PAYLOAD_JARS
|
||||
IDR_PAYLOAD_NAMED RCDATA "payload/slinky-named.jar"
|
||||
IDR_PAYLOAD_SRG RCDATA "payload/slinky-srg.jar"
|
||||
IDR_PAYLOAD_OFFICIAL RCDATA "payload/slinky-official.jar"
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include "jdk/jni.h"
|
||||
#include "jdk/jvmti.h"
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
namespace SlinkyNative {
|
||||
|
||||
class JvmManager {
|
||||
public:
|
||||
static bool Initialize();
|
||||
static void Shutdown();
|
||||
|
||||
static JavaVM* GetJavaVM();
|
||||
static JNIEnv* GetEnv();
|
||||
static jvmtiEnv* GetJvmti();
|
||||
|
||||
// Hook state management for getClassBytes and retransformClass
|
||||
static void SetCaptureTarget(jclass targetClass);
|
||||
static std::vector<unsigned char> GetCapturedBytes();
|
||||
static void ClearCapturedBytes();
|
||||
|
||||
static void SetReplacementData(jclass targetClass, const unsigned char* data, jint length);
|
||||
static bool WasReplacementApplied();
|
||||
static void ClearReplacementData();
|
||||
|
||||
private:
|
||||
static void JNICALL OnClassFileLoadHook(
|
||||
jvmtiEnv* jvmti_env,
|
||||
JNIEnv* jni_env,
|
||||
jclass class_being_redefined,
|
||||
jobject loader,
|
||||
const char* name,
|
||||
jobject protection_domain,
|
||||
jint class_data_len,
|
||||
const unsigned char* class_data,
|
||||
jint* new_class_data_len,
|
||||
unsigned char** new_class_data);
|
||||
|
||||
static JavaVM* s_JavaVM;
|
||||
static JNIEnv* s_JniEnv;
|
||||
static jvmtiEnv* s_JvmtiEnv;
|
||||
|
||||
static std::mutex s_HookMutex;
|
||||
static jclass s_CaptureTarget;
|
||||
static std::vector<unsigned char> s_CapturedBytes;
|
||||
|
||||
static jclass s_ReplacementTarget;
|
||||
static const unsigned char* s_ReplacementData;
|
||||
static jint s_ReplacementLength;
|
||||
static bool s_ReplacementApplied;
|
||||
};
|
||||
|
||||
} // namespace SlinkyNative
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
|
||||
namespace SlinkyNative {
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
static void Initialize(HMODULE hModule);
|
||||
static void Shutdown();
|
||||
|
||||
// Log a wide string message with timestamp formatted identically to original Slinky
|
||||
static void Log(const wchar_t* format, ...);
|
||||
static void LogV(const wchar_t* format, va_list args);
|
||||
|
||||
// Helper for char format strings
|
||||
static void LogA(const char* format, ...);
|
||||
|
||||
static const std::wstring& GetLogFilePath();
|
||||
|
||||
private:
|
||||
static CRITICAL_SECTION s_CriticalSection;
|
||||
static std::wstring s_LogFilePath;
|
||||
static bool s_Initialized;
|
||||
};
|
||||
|
||||
} // namespace SlinkyNative
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include "jdk/jni.h"
|
||||
#include "jdk/jvmti.h"
|
||||
|
||||
namespace SlinkyNative {
|
||||
|
||||
enum class MappingType {
|
||||
Unknown = 0,
|
||||
Named = 101, // MCP mappings (resource 101)
|
||||
Srg = 102, // SRG mappings (resource 102)
|
||||
Official = 103 // Notch/Vanilla/Lunar/Badlion obfuscated mappings (resource 103)
|
||||
};
|
||||
|
||||
struct MinecraftInfo {
|
||||
MappingType mapping = MappingType::Unknown;
|
||||
std::string mappingName;
|
||||
int resourceId = 0;
|
||||
jclass minecraftClass = nullptr;
|
||||
jobject classLoader = nullptr;
|
||||
};
|
||||
|
||||
class MinecraftDetector {
|
||||
public:
|
||||
static bool Detect(MinecraftInfo& outInfo);
|
||||
};
|
||||
|
||||
} // namespace SlinkyNative
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "jdk/jni.h"
|
||||
|
||||
namespace SlinkyNative {
|
||||
|
||||
class NativeBridge {
|
||||
public:
|
||||
static bool Register(JNIEnv* env, jobject classLoader);
|
||||
|
||||
// JNI native method implementations
|
||||
static jbyteArray JNICALL GetClassBytes(JNIEnv* env, jclass clazz, jclass targetClass);
|
||||
static jint JNICALL RetransformClass(JNIEnv* env, jclass clazz, jclass targetClass, jbyteArray newBytecode);
|
||||
static void JNICALL Log(JNIEnv* env, jclass clazz, jstring message);
|
||||
};
|
||||
|
||||
} // namespace SlinkyNative
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include "MinecraftDetector.hpp"
|
||||
|
||||
namespace SlinkyNative {
|
||||
|
||||
enum class InjectionStatus {
|
||||
Success = 0,
|
||||
AlreadyRunning,
|
||||
Reloaded,
|
||||
Failed
|
||||
};
|
||||
|
||||
class PayloadLoader {
|
||||
public:
|
||||
static InjectionStatus LoadAndStart(HMODULE hModule, const MinecraftInfo& mcInfo);
|
||||
|
||||
private:
|
||||
static bool CheckPreviousState(JNIEnv* env, jobject classLoader, bool& outAlreadyRunning);
|
||||
static bool ExtractPayloadJar(HMODULE hModule, const MinecraftInfo& mcInfo, std::wstring& outJarPath);
|
||||
static bool AddJarToClassLoader(JNIEnv* env, jobject classLoader, const std::wstring& jarPath);
|
||||
static bool DefinePayloadClasses(JNIEnv* env, jobject classLoader, const std::wstring& jarPath);
|
||||
static bool LaunchBootstrap(JNIEnv* env, jobject classLoader, const MinecraftInfo& mcInfo, HMODULE hModule);
|
||||
};
|
||||
|
||||
} // namespace SlinkyNative
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define IDR_PAYLOAD_NAMED 101
|
||||
#define IDR_PAYLOAD_SRG 102
|
||||
#define IDR_PAYLOAD_OFFICIAL 103
|
||||
@@ -0,0 +1,560 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef CLASSFILE_CONSTANTS_H
|
||||
#define CLASSFILE_CONSTANTS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Classfile version number for this information */
|
||||
#define JVM_CLASSFILE_MAJOR_VERSION 52
|
||||
#define JVM_CLASSFILE_MINOR_VERSION 0
|
||||
|
||||
/* Flags */
|
||||
|
||||
enum {
|
||||
JVM_ACC_PUBLIC = 0x0001,
|
||||
JVM_ACC_PRIVATE = 0x0002,
|
||||
JVM_ACC_PROTECTED = 0x0004,
|
||||
JVM_ACC_STATIC = 0x0008,
|
||||
JVM_ACC_FINAL = 0x0010,
|
||||
JVM_ACC_SYNCHRONIZED = 0x0020,
|
||||
JVM_ACC_SUPER = 0x0020,
|
||||
JVM_ACC_VOLATILE = 0x0040,
|
||||
JVM_ACC_BRIDGE = 0x0040,
|
||||
JVM_ACC_TRANSIENT = 0x0080,
|
||||
JVM_ACC_VARARGS = 0x0080,
|
||||
JVM_ACC_NATIVE = 0x0100,
|
||||
JVM_ACC_INTERFACE = 0x0200,
|
||||
JVM_ACC_ABSTRACT = 0x0400,
|
||||
JVM_ACC_STRICT = 0x0800,
|
||||
JVM_ACC_SYNTHETIC = 0x1000,
|
||||
JVM_ACC_ANNOTATION = 0x2000,
|
||||
JVM_ACC_ENUM = 0x4000
|
||||
};
|
||||
|
||||
/* Used in newarray instruction. */
|
||||
|
||||
enum {
|
||||
JVM_T_BOOLEAN = 4,
|
||||
JVM_T_CHAR = 5,
|
||||
JVM_T_FLOAT = 6,
|
||||
JVM_T_DOUBLE = 7,
|
||||
JVM_T_BYTE = 8,
|
||||
JVM_T_SHORT = 9,
|
||||
JVM_T_INT = 10,
|
||||
JVM_T_LONG = 11
|
||||
};
|
||||
|
||||
/* Constant Pool Entries */
|
||||
|
||||
enum {
|
||||
JVM_CONSTANT_Utf8 = 1,
|
||||
JVM_CONSTANT_Unicode = 2, /* unused */
|
||||
JVM_CONSTANT_Integer = 3,
|
||||
JVM_CONSTANT_Float = 4,
|
||||
JVM_CONSTANT_Long = 5,
|
||||
JVM_CONSTANT_Double = 6,
|
||||
JVM_CONSTANT_Class = 7,
|
||||
JVM_CONSTANT_String = 8,
|
||||
JVM_CONSTANT_Fieldref = 9,
|
||||
JVM_CONSTANT_Methodref = 10,
|
||||
JVM_CONSTANT_InterfaceMethodref = 11,
|
||||
JVM_CONSTANT_NameAndType = 12,
|
||||
JVM_CONSTANT_MethodHandle = 15, // JSR 292
|
||||
JVM_CONSTANT_MethodType = 16, // JSR 292
|
||||
JVM_CONSTANT_InvokeDynamic = 18
|
||||
};
|
||||
|
||||
/* JVM_CONSTANT_MethodHandle subtypes */
|
||||
enum {
|
||||
JVM_REF_getField = 1,
|
||||
JVM_REF_getStatic = 2,
|
||||
JVM_REF_putField = 3,
|
||||
JVM_REF_putStatic = 4,
|
||||
JVM_REF_invokeVirtual = 5,
|
||||
JVM_REF_invokeStatic = 6,
|
||||
JVM_REF_invokeSpecial = 7,
|
||||
JVM_REF_newInvokeSpecial = 8,
|
||||
JVM_REF_invokeInterface = 9
|
||||
};
|
||||
|
||||
/* StackMapTable type item numbers */
|
||||
|
||||
enum {
|
||||
JVM_ITEM_Top = 0,
|
||||
JVM_ITEM_Integer = 1,
|
||||
JVM_ITEM_Float = 2,
|
||||
JVM_ITEM_Double = 3,
|
||||
JVM_ITEM_Long = 4,
|
||||
JVM_ITEM_Null = 5,
|
||||
JVM_ITEM_UninitializedThis = 6,
|
||||
JVM_ITEM_Object = 7,
|
||||
JVM_ITEM_Uninitialized = 8
|
||||
};
|
||||
|
||||
/* Type signatures */
|
||||
|
||||
enum {
|
||||
JVM_SIGNATURE_ARRAY = '[',
|
||||
JVM_SIGNATURE_BYTE = 'B',
|
||||
JVM_SIGNATURE_CHAR = 'C',
|
||||
JVM_SIGNATURE_CLASS = 'L',
|
||||
JVM_SIGNATURE_ENDCLASS = ';',
|
||||
JVM_SIGNATURE_ENUM = 'E',
|
||||
JVM_SIGNATURE_FLOAT = 'F',
|
||||
JVM_SIGNATURE_DOUBLE = 'D',
|
||||
JVM_SIGNATURE_FUNC = '(',
|
||||
JVM_SIGNATURE_ENDFUNC = ')',
|
||||
JVM_SIGNATURE_INT = 'I',
|
||||
JVM_SIGNATURE_LONG = 'J',
|
||||
JVM_SIGNATURE_SHORT = 'S',
|
||||
JVM_SIGNATURE_VOID = 'V',
|
||||
JVM_SIGNATURE_BOOLEAN = 'Z'
|
||||
};
|
||||
|
||||
/* Opcodes */
|
||||
|
||||
enum {
|
||||
JVM_OPC_nop = 0,
|
||||
JVM_OPC_aconst_null = 1,
|
||||
JVM_OPC_iconst_m1 = 2,
|
||||
JVM_OPC_iconst_0 = 3,
|
||||
JVM_OPC_iconst_1 = 4,
|
||||
JVM_OPC_iconst_2 = 5,
|
||||
JVM_OPC_iconst_3 = 6,
|
||||
JVM_OPC_iconst_4 = 7,
|
||||
JVM_OPC_iconst_5 = 8,
|
||||
JVM_OPC_lconst_0 = 9,
|
||||
JVM_OPC_lconst_1 = 10,
|
||||
JVM_OPC_fconst_0 = 11,
|
||||
JVM_OPC_fconst_1 = 12,
|
||||
JVM_OPC_fconst_2 = 13,
|
||||
JVM_OPC_dconst_0 = 14,
|
||||
JVM_OPC_dconst_1 = 15,
|
||||
JVM_OPC_bipush = 16,
|
||||
JVM_OPC_sipush = 17,
|
||||
JVM_OPC_ldc = 18,
|
||||
JVM_OPC_ldc_w = 19,
|
||||
JVM_OPC_ldc2_w = 20,
|
||||
JVM_OPC_iload = 21,
|
||||
JVM_OPC_lload = 22,
|
||||
JVM_OPC_fload = 23,
|
||||
JVM_OPC_dload = 24,
|
||||
JVM_OPC_aload = 25,
|
||||
JVM_OPC_iload_0 = 26,
|
||||
JVM_OPC_iload_1 = 27,
|
||||
JVM_OPC_iload_2 = 28,
|
||||
JVM_OPC_iload_3 = 29,
|
||||
JVM_OPC_lload_0 = 30,
|
||||
JVM_OPC_lload_1 = 31,
|
||||
JVM_OPC_lload_2 = 32,
|
||||
JVM_OPC_lload_3 = 33,
|
||||
JVM_OPC_fload_0 = 34,
|
||||
JVM_OPC_fload_1 = 35,
|
||||
JVM_OPC_fload_2 = 36,
|
||||
JVM_OPC_fload_3 = 37,
|
||||
JVM_OPC_dload_0 = 38,
|
||||
JVM_OPC_dload_1 = 39,
|
||||
JVM_OPC_dload_2 = 40,
|
||||
JVM_OPC_dload_3 = 41,
|
||||
JVM_OPC_aload_0 = 42,
|
||||
JVM_OPC_aload_1 = 43,
|
||||
JVM_OPC_aload_2 = 44,
|
||||
JVM_OPC_aload_3 = 45,
|
||||
JVM_OPC_iaload = 46,
|
||||
JVM_OPC_laload = 47,
|
||||
JVM_OPC_faload = 48,
|
||||
JVM_OPC_daload = 49,
|
||||
JVM_OPC_aaload = 50,
|
||||
JVM_OPC_baload = 51,
|
||||
JVM_OPC_caload = 52,
|
||||
JVM_OPC_saload = 53,
|
||||
JVM_OPC_istore = 54,
|
||||
JVM_OPC_lstore = 55,
|
||||
JVM_OPC_fstore = 56,
|
||||
JVM_OPC_dstore = 57,
|
||||
JVM_OPC_astore = 58,
|
||||
JVM_OPC_istore_0 = 59,
|
||||
JVM_OPC_istore_1 = 60,
|
||||
JVM_OPC_istore_2 = 61,
|
||||
JVM_OPC_istore_3 = 62,
|
||||
JVM_OPC_lstore_0 = 63,
|
||||
JVM_OPC_lstore_1 = 64,
|
||||
JVM_OPC_lstore_2 = 65,
|
||||
JVM_OPC_lstore_3 = 66,
|
||||
JVM_OPC_fstore_0 = 67,
|
||||
JVM_OPC_fstore_1 = 68,
|
||||
JVM_OPC_fstore_2 = 69,
|
||||
JVM_OPC_fstore_3 = 70,
|
||||
JVM_OPC_dstore_0 = 71,
|
||||
JVM_OPC_dstore_1 = 72,
|
||||
JVM_OPC_dstore_2 = 73,
|
||||
JVM_OPC_dstore_3 = 74,
|
||||
JVM_OPC_astore_0 = 75,
|
||||
JVM_OPC_astore_1 = 76,
|
||||
JVM_OPC_astore_2 = 77,
|
||||
JVM_OPC_astore_3 = 78,
|
||||
JVM_OPC_iastore = 79,
|
||||
JVM_OPC_lastore = 80,
|
||||
JVM_OPC_fastore = 81,
|
||||
JVM_OPC_dastore = 82,
|
||||
JVM_OPC_aastore = 83,
|
||||
JVM_OPC_bastore = 84,
|
||||
JVM_OPC_castore = 85,
|
||||
JVM_OPC_sastore = 86,
|
||||
JVM_OPC_pop = 87,
|
||||
JVM_OPC_pop2 = 88,
|
||||
JVM_OPC_dup = 89,
|
||||
JVM_OPC_dup_x1 = 90,
|
||||
JVM_OPC_dup_x2 = 91,
|
||||
JVM_OPC_dup2 = 92,
|
||||
JVM_OPC_dup2_x1 = 93,
|
||||
JVM_OPC_dup2_x2 = 94,
|
||||
JVM_OPC_swap = 95,
|
||||
JVM_OPC_iadd = 96,
|
||||
JVM_OPC_ladd = 97,
|
||||
JVM_OPC_fadd = 98,
|
||||
JVM_OPC_dadd = 99,
|
||||
JVM_OPC_isub = 100,
|
||||
JVM_OPC_lsub = 101,
|
||||
JVM_OPC_fsub = 102,
|
||||
JVM_OPC_dsub = 103,
|
||||
JVM_OPC_imul = 104,
|
||||
JVM_OPC_lmul = 105,
|
||||
JVM_OPC_fmul = 106,
|
||||
JVM_OPC_dmul = 107,
|
||||
JVM_OPC_idiv = 108,
|
||||
JVM_OPC_ldiv = 109,
|
||||
JVM_OPC_fdiv = 110,
|
||||
JVM_OPC_ddiv = 111,
|
||||
JVM_OPC_irem = 112,
|
||||
JVM_OPC_lrem = 113,
|
||||
JVM_OPC_frem = 114,
|
||||
JVM_OPC_drem = 115,
|
||||
JVM_OPC_ineg = 116,
|
||||
JVM_OPC_lneg = 117,
|
||||
JVM_OPC_fneg = 118,
|
||||
JVM_OPC_dneg = 119,
|
||||
JVM_OPC_ishl = 120,
|
||||
JVM_OPC_lshl = 121,
|
||||
JVM_OPC_ishr = 122,
|
||||
JVM_OPC_lshr = 123,
|
||||
JVM_OPC_iushr = 124,
|
||||
JVM_OPC_lushr = 125,
|
||||
JVM_OPC_iand = 126,
|
||||
JVM_OPC_land = 127,
|
||||
JVM_OPC_ior = 128,
|
||||
JVM_OPC_lor = 129,
|
||||
JVM_OPC_ixor = 130,
|
||||
JVM_OPC_lxor = 131,
|
||||
JVM_OPC_iinc = 132,
|
||||
JVM_OPC_i2l = 133,
|
||||
JVM_OPC_i2f = 134,
|
||||
JVM_OPC_i2d = 135,
|
||||
JVM_OPC_l2i = 136,
|
||||
JVM_OPC_l2f = 137,
|
||||
JVM_OPC_l2d = 138,
|
||||
JVM_OPC_f2i = 139,
|
||||
JVM_OPC_f2l = 140,
|
||||
JVM_OPC_f2d = 141,
|
||||
JVM_OPC_d2i = 142,
|
||||
JVM_OPC_d2l = 143,
|
||||
JVM_OPC_d2f = 144,
|
||||
JVM_OPC_i2b = 145,
|
||||
JVM_OPC_i2c = 146,
|
||||
JVM_OPC_i2s = 147,
|
||||
JVM_OPC_lcmp = 148,
|
||||
JVM_OPC_fcmpl = 149,
|
||||
JVM_OPC_fcmpg = 150,
|
||||
JVM_OPC_dcmpl = 151,
|
||||
JVM_OPC_dcmpg = 152,
|
||||
JVM_OPC_ifeq = 153,
|
||||
JVM_OPC_ifne = 154,
|
||||
JVM_OPC_iflt = 155,
|
||||
JVM_OPC_ifge = 156,
|
||||
JVM_OPC_ifgt = 157,
|
||||
JVM_OPC_ifle = 158,
|
||||
JVM_OPC_if_icmpeq = 159,
|
||||
JVM_OPC_if_icmpne = 160,
|
||||
JVM_OPC_if_icmplt = 161,
|
||||
JVM_OPC_if_icmpge = 162,
|
||||
JVM_OPC_if_icmpgt = 163,
|
||||
JVM_OPC_if_icmple = 164,
|
||||
JVM_OPC_if_acmpeq = 165,
|
||||
JVM_OPC_if_acmpne = 166,
|
||||
JVM_OPC_goto = 167,
|
||||
JVM_OPC_jsr = 168,
|
||||
JVM_OPC_ret = 169,
|
||||
JVM_OPC_tableswitch = 170,
|
||||
JVM_OPC_lookupswitch = 171,
|
||||
JVM_OPC_ireturn = 172,
|
||||
JVM_OPC_lreturn = 173,
|
||||
JVM_OPC_freturn = 174,
|
||||
JVM_OPC_dreturn = 175,
|
||||
JVM_OPC_areturn = 176,
|
||||
JVM_OPC_return = 177,
|
||||
JVM_OPC_getstatic = 178,
|
||||
JVM_OPC_putstatic = 179,
|
||||
JVM_OPC_getfield = 180,
|
||||
JVM_OPC_putfield = 181,
|
||||
JVM_OPC_invokevirtual = 182,
|
||||
JVM_OPC_invokespecial = 183,
|
||||
JVM_OPC_invokestatic = 184,
|
||||
JVM_OPC_invokeinterface = 185,
|
||||
JVM_OPC_invokedynamic = 186,
|
||||
JVM_OPC_new = 187,
|
||||
JVM_OPC_newarray = 188,
|
||||
JVM_OPC_anewarray = 189,
|
||||
JVM_OPC_arraylength = 190,
|
||||
JVM_OPC_athrow = 191,
|
||||
JVM_OPC_checkcast = 192,
|
||||
JVM_OPC_instanceof = 193,
|
||||
JVM_OPC_monitorenter = 194,
|
||||
JVM_OPC_monitorexit = 195,
|
||||
JVM_OPC_wide = 196,
|
||||
JVM_OPC_multianewarray = 197,
|
||||
JVM_OPC_ifnull = 198,
|
||||
JVM_OPC_ifnonnull = 199,
|
||||
JVM_OPC_goto_w = 200,
|
||||
JVM_OPC_jsr_w = 201,
|
||||
JVM_OPC_MAX = 201
|
||||
};
|
||||
|
||||
/* Opcode length initializer, use with something like:
|
||||
* unsigned char opcode_length[JVM_OPC_MAX+1] = JVM_OPCODE_LENGTH_INITIALIZER;
|
||||
*/
|
||||
#define JVM_OPCODE_LENGTH_INITIALIZER { \
|
||||
1, /* nop */ \
|
||||
1, /* aconst_null */ \
|
||||
1, /* iconst_m1 */ \
|
||||
1, /* iconst_0 */ \
|
||||
1, /* iconst_1 */ \
|
||||
1, /* iconst_2 */ \
|
||||
1, /* iconst_3 */ \
|
||||
1, /* iconst_4 */ \
|
||||
1, /* iconst_5 */ \
|
||||
1, /* lconst_0 */ \
|
||||
1, /* lconst_1 */ \
|
||||
1, /* fconst_0 */ \
|
||||
1, /* fconst_1 */ \
|
||||
1, /* fconst_2 */ \
|
||||
1, /* dconst_0 */ \
|
||||
1, /* dconst_1 */ \
|
||||
2, /* bipush */ \
|
||||
3, /* sipush */ \
|
||||
2, /* ldc */ \
|
||||
3, /* ldc_w */ \
|
||||
3, /* ldc2_w */ \
|
||||
2, /* iload */ \
|
||||
2, /* lload */ \
|
||||
2, /* fload */ \
|
||||
2, /* dload */ \
|
||||
2, /* aload */ \
|
||||
1, /* iload_0 */ \
|
||||
1, /* iload_1 */ \
|
||||
1, /* iload_2 */ \
|
||||
1, /* iload_3 */ \
|
||||
1, /* lload_0 */ \
|
||||
1, /* lload_1 */ \
|
||||
1, /* lload_2 */ \
|
||||
1, /* lload_3 */ \
|
||||
1, /* fload_0 */ \
|
||||
1, /* fload_1 */ \
|
||||
1, /* fload_2 */ \
|
||||
1, /* fload_3 */ \
|
||||
1, /* dload_0 */ \
|
||||
1, /* dload_1 */ \
|
||||
1, /* dload_2 */ \
|
||||
1, /* dload_3 */ \
|
||||
1, /* aload_0 */ \
|
||||
1, /* aload_1 */ \
|
||||
1, /* aload_2 */ \
|
||||
1, /* aload_3 */ \
|
||||
1, /* iaload */ \
|
||||
1, /* laload */ \
|
||||
1, /* faload */ \
|
||||
1, /* daload */ \
|
||||
1, /* aaload */ \
|
||||
1, /* baload */ \
|
||||
1, /* caload */ \
|
||||
1, /* saload */ \
|
||||
2, /* istore */ \
|
||||
2, /* lstore */ \
|
||||
2, /* fstore */ \
|
||||
2, /* dstore */ \
|
||||
2, /* astore */ \
|
||||
1, /* istore_0 */ \
|
||||
1, /* istore_1 */ \
|
||||
1, /* istore_2 */ \
|
||||
1, /* istore_3 */ \
|
||||
1, /* lstore_0 */ \
|
||||
1, /* lstore_1 */ \
|
||||
1, /* lstore_2 */ \
|
||||
1, /* lstore_3 */ \
|
||||
1, /* fstore_0 */ \
|
||||
1, /* fstore_1 */ \
|
||||
1, /* fstore_2 */ \
|
||||
1, /* fstore_3 */ \
|
||||
1, /* dstore_0 */ \
|
||||
1, /* dstore_1 */ \
|
||||
1, /* dstore_2 */ \
|
||||
1, /* dstore_3 */ \
|
||||
1, /* astore_0 */ \
|
||||
1, /* astore_1 */ \
|
||||
1, /* astore_2 */ \
|
||||
1, /* astore_3 */ \
|
||||
1, /* iastore */ \
|
||||
1, /* lastore */ \
|
||||
1, /* fastore */ \
|
||||
1, /* dastore */ \
|
||||
1, /* aastore */ \
|
||||
1, /* bastore */ \
|
||||
1, /* castore */ \
|
||||
1, /* sastore */ \
|
||||
1, /* pop */ \
|
||||
1, /* pop2 */ \
|
||||
1, /* dup */ \
|
||||
1, /* dup_x1 */ \
|
||||
1, /* dup_x2 */ \
|
||||
1, /* dup2 */ \
|
||||
1, /* dup2_x1 */ \
|
||||
1, /* dup2_x2 */ \
|
||||
1, /* swap */ \
|
||||
1, /* iadd */ \
|
||||
1, /* ladd */ \
|
||||
1, /* fadd */ \
|
||||
1, /* dadd */ \
|
||||
1, /* isub */ \
|
||||
1, /* lsub */ \
|
||||
1, /* fsub */ \
|
||||
1, /* dsub */ \
|
||||
1, /* imul */ \
|
||||
1, /* lmul */ \
|
||||
1, /* fmul */ \
|
||||
1, /* dmul */ \
|
||||
1, /* idiv */ \
|
||||
1, /* ldiv */ \
|
||||
1, /* fdiv */ \
|
||||
1, /* ddiv */ \
|
||||
1, /* irem */ \
|
||||
1, /* lrem */ \
|
||||
1, /* frem */ \
|
||||
1, /* drem */ \
|
||||
1, /* ineg */ \
|
||||
1, /* lneg */ \
|
||||
1, /* fneg */ \
|
||||
1, /* dneg */ \
|
||||
1, /* ishl */ \
|
||||
1, /* lshl */ \
|
||||
1, /* ishr */ \
|
||||
1, /* lshr */ \
|
||||
1, /* iushr */ \
|
||||
1, /* lushr */ \
|
||||
1, /* iand */ \
|
||||
1, /* land */ \
|
||||
1, /* ior */ \
|
||||
1, /* lor */ \
|
||||
1, /* ixor */ \
|
||||
1, /* lxor */ \
|
||||
3, /* iinc */ \
|
||||
1, /* i2l */ \
|
||||
1, /* i2f */ \
|
||||
1, /* i2d */ \
|
||||
1, /* l2i */ \
|
||||
1, /* l2f */ \
|
||||
1, /* l2d */ \
|
||||
1, /* f2i */ \
|
||||
1, /* f2l */ \
|
||||
1, /* f2d */ \
|
||||
1, /* d2i */ \
|
||||
1, /* d2l */ \
|
||||
1, /* d2f */ \
|
||||
1, /* i2b */ \
|
||||
1, /* i2c */ \
|
||||
1, /* i2s */ \
|
||||
1, /* lcmp */ \
|
||||
1, /* fcmpl */ \
|
||||
1, /* fcmpg */ \
|
||||
1, /* dcmpl */ \
|
||||
1, /* dcmpg */ \
|
||||
3, /* ifeq */ \
|
||||
3, /* ifne */ \
|
||||
3, /* iflt */ \
|
||||
3, /* ifge */ \
|
||||
3, /* ifgt */ \
|
||||
3, /* ifle */ \
|
||||
3, /* if_icmpeq */ \
|
||||
3, /* if_icmpne */ \
|
||||
3, /* if_icmplt */ \
|
||||
3, /* if_icmpge */ \
|
||||
3, /* if_icmpgt */ \
|
||||
3, /* if_icmple */ \
|
||||
3, /* if_acmpeq */ \
|
||||
3, /* if_acmpne */ \
|
||||
3, /* goto */ \
|
||||
3, /* jsr */ \
|
||||
2, /* ret */ \
|
||||
99, /* tableswitch */ \
|
||||
99, /* lookupswitch */ \
|
||||
1, /* ireturn */ \
|
||||
1, /* lreturn */ \
|
||||
1, /* freturn */ \
|
||||
1, /* dreturn */ \
|
||||
1, /* areturn */ \
|
||||
1, /* return */ \
|
||||
3, /* getstatic */ \
|
||||
3, /* putstatic */ \
|
||||
3, /* getfield */ \
|
||||
3, /* putfield */ \
|
||||
3, /* invokevirtual */ \
|
||||
3, /* invokespecial */ \
|
||||
3, /* invokestatic */ \
|
||||
5, /* invokeinterface */ \
|
||||
5, /* invokedynamic */ \
|
||||
3, /* new */ \
|
||||
2, /* newarray */ \
|
||||
3, /* anewarray */ \
|
||||
1, /* arraylength */ \
|
||||
1, /* athrow */ \
|
||||
3, /* checkcast */ \
|
||||
3, /* instanceof */ \
|
||||
1, /* monitorenter */ \
|
||||
1, /* monitorexit */ \
|
||||
0, /* wide */ \
|
||||
4, /* multianewarray */ \
|
||||
3, /* ifnull */ \
|
||||
3, /* ifnonnull */ \
|
||||
5, /* goto_w */ \
|
||||
5 /* jsr_w */ \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* CLASSFILE_CONSTANTS */
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef _JAVASOFT_JAWT_H_
|
||||
#define _JAVASOFT_JAWT_H_
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* AWT native interface (new in JDK 1.3)
|
||||
*
|
||||
* The AWT native interface allows a native C or C++ application a means
|
||||
* by which to access native structures in AWT. This is to facilitate moving
|
||||
* legacy C and C++ applications to Java and to target the needs of the
|
||||
* community who, at present, wish to do their own native rendering to canvases
|
||||
* for performance reasons. Standard extensions such as Java3D also require a
|
||||
* means to access the underlying native data structures of AWT.
|
||||
*
|
||||
* There may be future extensions to this API depending on demand.
|
||||
*
|
||||
* A VM does not have to implement this API in order to pass the JCK.
|
||||
* It is recommended, however, that this API is implemented on VMs that support
|
||||
* standard extensions, such as Java3D.
|
||||
*
|
||||
* Since this is a native API, any program which uses it cannot be considered
|
||||
* 100% pure java.
|
||||
*/
|
||||
|
||||
/*
|
||||
* AWT Native Drawing Surface (JAWT_DrawingSurface).
|
||||
*
|
||||
* For each platform, there is a native drawing surface structure. This
|
||||
* platform-specific structure can be found in jawt_md.h. It is recommended
|
||||
* that additional platforms follow the same model. It is also recommended
|
||||
* that VMs on Win32 and Solaris support the existing structures in jawt_md.h.
|
||||
*
|
||||
*******************
|
||||
* EXAMPLE OF USAGE:
|
||||
*******************
|
||||
*
|
||||
* In Win32, a programmer wishes to access the HWND of a canvas to perform
|
||||
* native rendering into it. The programmer has declared the paint() method
|
||||
* for their canvas subclass to be native:
|
||||
*
|
||||
*
|
||||
* MyCanvas.java:
|
||||
*
|
||||
* import java.awt.*;
|
||||
*
|
||||
* public class MyCanvas extends Canvas {
|
||||
*
|
||||
* static {
|
||||
* System.loadLibrary("mylib");
|
||||
* }
|
||||
*
|
||||
* public native void paint(Graphics g);
|
||||
* }
|
||||
*
|
||||
*
|
||||
* myfile.c:
|
||||
*
|
||||
* #include "jawt_md.h"
|
||||
* #include <assert.h>
|
||||
*
|
||||
* JNIEXPORT void JNICALL
|
||||
* Java_MyCanvas_paint(JNIEnv* env, jobject canvas, jobject graphics)
|
||||
* {
|
||||
* JAWT awt;
|
||||
* JAWT_DrawingSurface* ds;
|
||||
* JAWT_DrawingSurfaceInfo* dsi;
|
||||
* JAWT_Win32DrawingSurfaceInfo* dsi_win;
|
||||
* jboolean result;
|
||||
* jint lock;
|
||||
*
|
||||
* // Get the AWT
|
||||
* awt.version = JAWT_VERSION_1_3;
|
||||
* result = JAWT_GetAWT(env, &awt);
|
||||
* assert(result != JNI_FALSE);
|
||||
*
|
||||
* // Get the drawing surface
|
||||
* ds = awt.GetDrawingSurface(env, canvas);
|
||||
* assert(ds != NULL);
|
||||
*
|
||||
* // Lock the drawing surface
|
||||
* lock = ds->Lock(ds);
|
||||
* assert((lock & JAWT_LOCK_ERROR) == 0);
|
||||
*
|
||||
* // Get the drawing surface info
|
||||
* dsi = ds->GetDrawingSurfaceInfo(ds);
|
||||
*
|
||||
* // Get the platform-specific drawing info
|
||||
* dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;
|
||||
*
|
||||
* //////////////////////////////
|
||||
* // !!! DO PAINTING HERE !!! //
|
||||
* //////////////////////////////
|
||||
*
|
||||
* // Free the drawing surface info
|
||||
* ds->FreeDrawingSurfaceInfo(dsi);
|
||||
*
|
||||
* // Unlock the drawing surface
|
||||
* ds->Unlock(ds);
|
||||
*
|
||||
* // Free the drawing surface
|
||||
* awt.FreeDrawingSurface(ds);
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* JAWT_Rectangle
|
||||
* Structure for a native rectangle.
|
||||
*/
|
||||
typedef struct jawt_Rectangle {
|
||||
jint x;
|
||||
jint y;
|
||||
jint width;
|
||||
jint height;
|
||||
} JAWT_Rectangle;
|
||||
|
||||
struct jawt_DrawingSurface;
|
||||
|
||||
/*
|
||||
* JAWT_DrawingSurfaceInfo
|
||||
* Structure for containing the underlying drawing information of a component.
|
||||
*/
|
||||
typedef struct jawt_DrawingSurfaceInfo {
|
||||
/*
|
||||
* Pointer to the platform-specific information. This can be safely
|
||||
* cast to a JAWT_Win32DrawingSurfaceInfo on Windows or a
|
||||
* JAWT_X11DrawingSurfaceInfo on Solaris. On Mac OS X this is a
|
||||
* pointer to a NSObject that conforms to the JAWT_SurfaceLayers
|
||||
* protocol. See jawt_md.h for details.
|
||||
*/
|
||||
void* platformInfo;
|
||||
/* Cached pointer to the underlying drawing surface */
|
||||
struct jawt_DrawingSurface* ds;
|
||||
/* Bounding rectangle of the drawing surface */
|
||||
JAWT_Rectangle bounds;
|
||||
/* Number of rectangles in the clip */
|
||||
jint clipSize;
|
||||
/* Clip rectangle array */
|
||||
JAWT_Rectangle* clip;
|
||||
} JAWT_DrawingSurfaceInfo;
|
||||
|
||||
#define JAWT_LOCK_ERROR 0x00000001
|
||||
#define JAWT_LOCK_CLIP_CHANGED 0x00000002
|
||||
#define JAWT_LOCK_BOUNDS_CHANGED 0x00000004
|
||||
#define JAWT_LOCK_SURFACE_CHANGED 0x00000008
|
||||
|
||||
/*
|
||||
* JAWT_DrawingSurface
|
||||
* Structure for containing the underlying drawing information of a component.
|
||||
* All operations on a JAWT_DrawingSurface MUST be performed from the same
|
||||
* thread as the call to GetDrawingSurface.
|
||||
*/
|
||||
typedef struct jawt_DrawingSurface {
|
||||
/*
|
||||
* Cached reference to the Java environment of the calling thread.
|
||||
* If Lock(), Unlock(), GetDrawingSurfaceInfo() or
|
||||
* FreeDrawingSurfaceInfo() are called from a different thread,
|
||||
* this data member should be set before calling those functions.
|
||||
*/
|
||||
JNIEnv* env;
|
||||
/* Cached reference to the target object */
|
||||
jobject target;
|
||||
/*
|
||||
* Lock the surface of the target component for native rendering.
|
||||
* When finished drawing, the surface must be unlocked with
|
||||
* Unlock(). This function returns a bitmask with one or more of the
|
||||
* following values:
|
||||
*
|
||||
* JAWT_LOCK_ERROR - When an error has occurred and the surface could not
|
||||
* be locked.
|
||||
*
|
||||
* JAWT_LOCK_CLIP_CHANGED - When the clip region has changed.
|
||||
*
|
||||
* JAWT_LOCK_BOUNDS_CHANGED - When the bounds of the surface have changed.
|
||||
*
|
||||
* JAWT_LOCK_SURFACE_CHANGED - When the surface itself has changed
|
||||
*/
|
||||
jint (JNICALL *Lock)
|
||||
(struct jawt_DrawingSurface* ds);
|
||||
/*
|
||||
* Get the drawing surface info.
|
||||
* The value returned may be cached, but the values may change if
|
||||
* additional calls to Lock() or Unlock() are made.
|
||||
* Lock() must be called before this can return a valid value.
|
||||
* Returns NULL if an error has occurred.
|
||||
* When finished with the returned value, FreeDrawingSurfaceInfo must be
|
||||
* called.
|
||||
*/
|
||||
JAWT_DrawingSurfaceInfo* (JNICALL *GetDrawingSurfaceInfo)
|
||||
(struct jawt_DrawingSurface* ds);
|
||||
/*
|
||||
* Free the drawing surface info.
|
||||
*/
|
||||
void (JNICALL *FreeDrawingSurfaceInfo)
|
||||
(JAWT_DrawingSurfaceInfo* dsi);
|
||||
/*
|
||||
* Unlock the drawing surface of the target component for native rendering.
|
||||
*/
|
||||
void (JNICALL *Unlock)
|
||||
(struct jawt_DrawingSurface* ds);
|
||||
} JAWT_DrawingSurface;
|
||||
|
||||
/*
|
||||
* JAWT
|
||||
* Structure for containing native AWT functions.
|
||||
*/
|
||||
typedef struct jawt {
|
||||
/*
|
||||
* Version of this structure. This must always be set before
|
||||
* calling JAWT_GetAWT()
|
||||
*/
|
||||
jint version;
|
||||
/*
|
||||
* Return a drawing surface from a target jobject. This value
|
||||
* may be cached.
|
||||
* Returns NULL if an error has occurred.
|
||||
* Target must be a java.awt.Component (should be a Canvas
|
||||
* or Window for native rendering).
|
||||
* FreeDrawingSurface() must be called when finished with the
|
||||
* returned JAWT_DrawingSurface.
|
||||
*/
|
||||
JAWT_DrawingSurface* (JNICALL *GetDrawingSurface)
|
||||
(JNIEnv* env, jobject target);
|
||||
/*
|
||||
* Free the drawing surface allocated in GetDrawingSurface.
|
||||
*/
|
||||
void (JNICALL *FreeDrawingSurface)
|
||||
(JAWT_DrawingSurface* ds);
|
||||
/*
|
||||
* Since 1.4
|
||||
* Locks the entire AWT for synchronization purposes
|
||||
*/
|
||||
void (JNICALL *Lock)(JNIEnv* env);
|
||||
/*
|
||||
* Since 1.4
|
||||
* Unlocks the entire AWT for synchronization purposes
|
||||
*/
|
||||
void (JNICALL *Unlock)(JNIEnv* env);
|
||||
/*
|
||||
* Since 1.4
|
||||
* Returns a reference to a java.awt.Component from a native
|
||||
* platform handle. On Windows, this corresponds to an HWND;
|
||||
* on Solaris and Linux, this is a Drawable. For other platforms,
|
||||
* see the appropriate machine-dependent header file for a description.
|
||||
* The reference returned by this function is a local
|
||||
* reference that is only valid in this environment.
|
||||
* This function returns a NULL reference if no component could be
|
||||
* found with matching platform information.
|
||||
*/
|
||||
jobject (JNICALL *GetComponent)(JNIEnv* env, void* platformInfo);
|
||||
|
||||
} JAWT;
|
||||
|
||||
/*
|
||||
* Get the AWT native structure. This function returns JNI_FALSE if
|
||||
* an error occurs.
|
||||
*/
|
||||
_JNI_IMPORT_OR_EXPORT_
|
||||
jboolean JNICALL JAWT_GetAWT(JNIEnv* env, JAWT* awt);
|
||||
|
||||
#define JAWT_VERSION_1_3 0x00010003
|
||||
#define JAWT_VERSION_1_4 0x00010004
|
||||
#define JAWT_VERSION_1_7 0x00010007
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* !_JAVASOFT_JAWT_H_ */
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Java Debug Wire Protocol Transport Service Provider Interface.
|
||||
*/
|
||||
|
||||
#ifndef JDWPTRANSPORT_H
|
||||
#define JDWPTRANSPORT_H
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
enum {
|
||||
JDWPTRANSPORT_VERSION_1_0 = 0x00010000
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct jdwpTransportNativeInterface_;
|
||||
|
||||
struct _jdwpTransportEnv;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef _jdwpTransportEnv jdwpTransportEnv;
|
||||
#else
|
||||
typedef const struct jdwpTransportNativeInterface_ *jdwpTransportEnv;
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Errors. Universal errors with JVMTI/JVMDI equivalents keep the
|
||||
* values the same.
|
||||
*/
|
||||
typedef enum {
|
||||
JDWPTRANSPORT_ERROR_NONE = 0,
|
||||
JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT = 103,
|
||||
JDWPTRANSPORT_ERROR_OUT_OF_MEMORY = 110,
|
||||
JDWPTRANSPORT_ERROR_INTERNAL = 113,
|
||||
JDWPTRANSPORT_ERROR_ILLEGAL_STATE = 201,
|
||||
JDWPTRANSPORT_ERROR_IO_ERROR = 202,
|
||||
JDWPTRANSPORT_ERROR_TIMEOUT = 203,
|
||||
JDWPTRANSPORT_ERROR_MSG_NOT_AVAILABLE = 204
|
||||
} jdwpTransportError;
|
||||
|
||||
|
||||
/*
|
||||
* Structure to define capabilities
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int can_timeout_attach :1;
|
||||
unsigned int can_timeout_accept :1;
|
||||
unsigned int can_timeout_handshake :1;
|
||||
unsigned int reserved3 :1;
|
||||
unsigned int reserved4 :1;
|
||||
unsigned int reserved5 :1;
|
||||
unsigned int reserved6 :1;
|
||||
unsigned int reserved7 :1;
|
||||
unsigned int reserved8 :1;
|
||||
unsigned int reserved9 :1;
|
||||
unsigned int reserved10 :1;
|
||||
unsigned int reserved11 :1;
|
||||
unsigned int reserved12 :1;
|
||||
unsigned int reserved13 :1;
|
||||
unsigned int reserved14 :1;
|
||||
unsigned int reserved15 :1;
|
||||
} JDWPTransportCapabilities;
|
||||
|
||||
|
||||
/*
|
||||
* Structures to define packet layout.
|
||||
*
|
||||
* See: http://java.sun.com/j2se/1.5/docs/guide/jpda/jdwp-spec.html
|
||||
*/
|
||||
|
||||
enum {
|
||||
/*
|
||||
* If additional flags are added that apply to jdwpCmdPacket,
|
||||
* then debugLoop.c: reader() will need to be updated to
|
||||
* accept more than JDWPTRANSPORT_FLAGS_NONE.
|
||||
*/
|
||||
JDWPTRANSPORT_FLAGS_NONE = 0x0,
|
||||
JDWPTRANSPORT_FLAGS_REPLY = 0x80
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
jint len;
|
||||
jint id;
|
||||
jbyte flags;
|
||||
jbyte cmdSet;
|
||||
jbyte cmd;
|
||||
jbyte *data;
|
||||
} jdwpCmdPacket;
|
||||
|
||||
typedef struct {
|
||||
jint len;
|
||||
jint id;
|
||||
jbyte flags;
|
||||
jshort errorCode;
|
||||
jbyte *data;
|
||||
} jdwpReplyPacket;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
jdwpCmdPacket cmd;
|
||||
jdwpReplyPacket reply;
|
||||
} type;
|
||||
} jdwpPacket;
|
||||
|
||||
/*
|
||||
* JDWP functions called by the transport.
|
||||
*/
|
||||
typedef struct jdwpTransportCallback {
|
||||
void *(*alloc)(jint numBytes); /* Call this for all allocations */
|
||||
void (*free)(void *buffer); /* Call this for all deallocations */
|
||||
} jdwpTransportCallback;
|
||||
|
||||
typedef jint (JNICALL *jdwpTransport_OnLoad_t)(JavaVM *jvm,
|
||||
jdwpTransportCallback *callback,
|
||||
jint version,
|
||||
jdwpTransportEnv** env);
|
||||
|
||||
|
||||
|
||||
/* Function Interface */
|
||||
|
||||
struct jdwpTransportNativeInterface_ {
|
||||
/* 1 : RESERVED */
|
||||
void *reserved1;
|
||||
|
||||
/* 2 : Get Capabilities */
|
||||
jdwpTransportError (JNICALL *GetCapabilities)(jdwpTransportEnv* env,
|
||||
JDWPTransportCapabilities *capabilities_ptr);
|
||||
|
||||
/* 3 : Attach */
|
||||
jdwpTransportError (JNICALL *Attach)(jdwpTransportEnv* env,
|
||||
const char* address,
|
||||
jlong attach_timeout,
|
||||
jlong handshake_timeout);
|
||||
|
||||
/* 4: StartListening */
|
||||
jdwpTransportError (JNICALL *StartListening)(jdwpTransportEnv* env,
|
||||
const char* address,
|
||||
char** actual_address);
|
||||
|
||||
/* 5: StopListening */
|
||||
jdwpTransportError (JNICALL *StopListening)(jdwpTransportEnv* env);
|
||||
|
||||
/* 6: Accept */
|
||||
jdwpTransportError (JNICALL *Accept)(jdwpTransportEnv* env,
|
||||
jlong accept_timeout,
|
||||
jlong handshake_timeout);
|
||||
|
||||
/* 7: IsOpen */
|
||||
jboolean (JNICALL *IsOpen)(jdwpTransportEnv* env);
|
||||
|
||||
/* 8: Close */
|
||||
jdwpTransportError (JNICALL *Close)(jdwpTransportEnv* env);
|
||||
|
||||
/* 9: ReadPacket */
|
||||
jdwpTransportError (JNICALL *ReadPacket)(jdwpTransportEnv* env,
|
||||
jdwpPacket *pkt);
|
||||
|
||||
/* 10: Write Packet */
|
||||
jdwpTransportError (JNICALL *WritePacket)(jdwpTransportEnv* env,
|
||||
const jdwpPacket* pkt);
|
||||
|
||||
/* 11: GetLastError */
|
||||
jdwpTransportError (JNICALL *GetLastError)(jdwpTransportEnv* env,
|
||||
char** error);
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Use inlined functions so that C++ code can use syntax such as
|
||||
* env->Attach("mymachine:5000", 10*1000, 0);
|
||||
*
|
||||
* rather than using C's :-
|
||||
*
|
||||
* (*env)->Attach(env, "mymachine:5000", 10*1000, 0);
|
||||
*/
|
||||
struct _jdwpTransportEnv {
|
||||
const struct jdwpTransportNativeInterface_ *functions;
|
||||
#ifdef __cplusplus
|
||||
|
||||
jdwpTransportError GetCapabilities(JDWPTransportCapabilities *capabilities_ptr) {
|
||||
return functions->GetCapabilities(this, capabilities_ptr);
|
||||
}
|
||||
|
||||
jdwpTransportError Attach(const char* address, jlong attach_timeout,
|
||||
jlong handshake_timeout) {
|
||||
return functions->Attach(this, address, attach_timeout, handshake_timeout);
|
||||
}
|
||||
|
||||
jdwpTransportError StartListening(const char* address,
|
||||
char** actual_address) {
|
||||
return functions->StartListening(this, address, actual_address);
|
||||
}
|
||||
|
||||
jdwpTransportError StopListening(void) {
|
||||
return functions->StopListening(this);
|
||||
}
|
||||
|
||||
jdwpTransportError Accept(jlong accept_timeout, jlong handshake_timeout) {
|
||||
return functions->Accept(this, accept_timeout, handshake_timeout);
|
||||
}
|
||||
|
||||
jboolean IsOpen(void) {
|
||||
return functions->IsOpen(this);
|
||||
}
|
||||
|
||||
jdwpTransportError Close(void) {
|
||||
return functions->Close(this);
|
||||
}
|
||||
|
||||
jdwpTransportError ReadPacket(jdwpPacket *pkt) {
|
||||
return functions->ReadPacket(this, pkt);
|
||||
}
|
||||
|
||||
jdwpTransportError WritePacket(const jdwpPacket* pkt) {
|
||||
return functions->WritePacket(this, pkt);
|
||||
}
|
||||
|
||||
jdwpTransportError GetLastError(char** error) {
|
||||
return functions->GetLastError(this, error);
|
||||
}
|
||||
|
||||
|
||||
#endif /* __cplusplus */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* JDWPTRANSPORT_H */
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This header file defines the data structures sent by the VM
|
||||
* through the JVMTI CompiledMethodLoad callback function via the
|
||||
* "void * compile_info" parameter. The memory pointed to by the
|
||||
* compile_info parameter may not be referenced after returning from
|
||||
* the CompiledMethodLoad callback. These are VM implementation
|
||||
* specific data structures that may evolve in future releases. A
|
||||
* JVMTI agent should interpret a non-NULL compile_info as a pointer
|
||||
* to a region of memory containing a list of records. In a typical
|
||||
* usage scenario, a JVMTI agent would cast each record to a
|
||||
* jvmtiCompiledMethodLoadRecordHeader, a struct that represents
|
||||
* arbitrary information. This struct contains a kind field to indicate
|
||||
* the kind of information being passed, and a pointer to the next
|
||||
* record. If the kind field indicates inlining information, then the
|
||||
* agent would cast the record to a jvmtiCompiledMethodLoadInlineRecord.
|
||||
* This record contains an array of PCStackInfo structs, which indicate
|
||||
* for every pc address what are the methods on the invocation stack.
|
||||
* The "methods" and "bcis" fields in each PCStackInfo struct specify a
|
||||
* 1-1 mapping between these inlined methods and their bytecode indices.
|
||||
* This can be used to derive the proper source lines of the inlined
|
||||
* methods.
|
||||
*/
|
||||
|
||||
#ifndef _JVMTI_CMLR_H_
|
||||
#define _JVMTI_CMLR_H_
|
||||
|
||||
enum {
|
||||
JVMTI_CMLR_MAJOR_VERSION_1 = 0x00000001,
|
||||
JVMTI_CMLR_MINOR_VERSION_0 = 0x00000000,
|
||||
|
||||
JVMTI_CMLR_MAJOR_VERSION = 0x00000001,
|
||||
JVMTI_CMLR_MINOR_VERSION = 0x00000000
|
||||
|
||||
/*
|
||||
* This comment is for the "JDK import from HotSpot" sanity check:
|
||||
* version: 1.0.0
|
||||
*/
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
JVMTI_CMLR_DUMMY = 1,
|
||||
JVMTI_CMLR_INLINE_INFO = 2
|
||||
} jvmtiCMLRKind;
|
||||
|
||||
/*
|
||||
* Record that represents arbitrary information passed through JVMTI
|
||||
* CompiledMethodLoadEvent void pointer.
|
||||
*/
|
||||
typedef struct _jvmtiCompiledMethodLoadRecordHeader {
|
||||
jvmtiCMLRKind kind; /* id for the kind of info passed in the record */
|
||||
jint majorinfoversion; /* major and minor info version values. Init'ed */
|
||||
jint minorinfoversion; /* to current version value in jvmtiExport.cpp. */
|
||||
|
||||
struct _jvmtiCompiledMethodLoadRecordHeader* next;
|
||||
} jvmtiCompiledMethodLoadRecordHeader;
|
||||
|
||||
/*
|
||||
* Record that gives information about the methods on the compile-time
|
||||
* stack at a specific pc address of a compiled method. Each element in
|
||||
* the methods array maps to same element in the bcis array.
|
||||
*/
|
||||
typedef struct _PCStackInfo {
|
||||
void* pc; /* the pc address for this compiled method */
|
||||
jint numstackframes; /* number of methods on the stack */
|
||||
jmethodID* methods; /* array of numstackframes method ids */
|
||||
jint* bcis; /* array of numstackframes bytecode indices */
|
||||
} PCStackInfo;
|
||||
|
||||
/*
|
||||
* Record that contains inlining information for each pc address of
|
||||
* an nmethod.
|
||||
*/
|
||||
typedef struct _jvmtiCompiledMethodLoadInlineRecord {
|
||||
jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
|
||||
jint numpcs; /* number of pc descriptors in this nmethod */
|
||||
PCStackInfo* pcinfo; /* array of numpcs pc descriptors */
|
||||
} jvmtiCompiledMethodLoadInlineRecord;
|
||||
|
||||
/*
|
||||
* Dummy record used to test that we can pass records with different
|
||||
* information through the void pointer provided that they can be cast
|
||||
* to a jvmtiCompiledMethodLoadRecordHeader.
|
||||
*/
|
||||
|
||||
typedef struct _jvmtiCompiledMethodLoadDummyRecord {
|
||||
jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
|
||||
char message[50];
|
||||
} jvmtiCompiledMethodLoadDummyRecord;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* AccessBridgeCallbacks.h 1.17 05/03/21
|
||||
*/
|
||||
|
||||
/*
|
||||
* Header file defining callback typedefs for Windows routines
|
||||
* which are called from Java (responding to events, etc.).
|
||||
*/
|
||||
|
||||
#ifndef __AccessBridgeCallbacks_H__
|
||||
#define __AccessBridgeCallbacks_H__
|
||||
|
||||
#include <jni.h>
|
||||
#include "AccessBridgePackages.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*AccessBridge_PropertyChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
|
||||
wchar_t *property, wchar_t *oldValue, wchar_t *newValue);
|
||||
|
||||
typedef void (*AccessBridge_JavaShutdownFP) (long vmID);
|
||||
typedef void (*AccessBridge_JavaShutdownFP) (long vmID);
|
||||
|
||||
typedef void (*AccessBridge_FocusGainedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
typedef void (*AccessBridge_FocusLostFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
|
||||
typedef void (*AccessBridge_CaretUpdateFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
|
||||
typedef void (*AccessBridge_MouseClickedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
typedef void (*AccessBridge_MouseEnteredFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
typedef void (*AccessBridge_MouseExitedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
typedef void (*AccessBridge_MousePressedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
typedef void (*AccessBridge_MouseReleasedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
|
||||
typedef void (*AccessBridge_MenuCanceledFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
typedef void (*AccessBridge_MenuDeselectedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
typedef void (*AccessBridge_MenuSelectedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
typedef void (*AccessBridge_PopupMenuCanceledFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
typedef void (*AccessBridge_PopupMenuWillBecomeInvisibleFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
typedef void (*AccessBridge_PopupMenuWillBecomeVisibleFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
|
||||
typedef void (*AccessBridge_PropertyNameChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
|
||||
wchar_t *oldName, wchar_t *newName);
|
||||
typedef void (*AccessBridge_PropertyDescriptionChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
|
||||
wchar_t *oldDescription, wchar_t *newDescription);
|
||||
typedef void (*AccessBridge_PropertyStateChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
|
||||
wchar_t *oldState, wchar_t *newState);
|
||||
typedef void (*AccessBridge_PropertyValueChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
|
||||
wchar_t *oldValue, wchar_t *newValue);
|
||||
typedef void (*AccessBridge_PropertySelectionChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
typedef void (*AccessBridge_PropertyTextChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
typedef void (*AccessBridge_PropertyCaretChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
|
||||
int oldPosition, int newPosition);
|
||||
typedef void (*AccessBridge_PropertyVisibleDataChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
||||
typedef void (*AccessBridge_PropertyChildChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
|
||||
JOBJECT64 oldChild, JOBJECT64 newChild);
|
||||
typedef void (*AccessBridge_PropertyActiveDescendentChangeFP) (long vmID, JOBJECT64 event,
|
||||
JOBJECT64 source,
|
||||
JOBJECT64 oldActiveDescendent,
|
||||
JOBJECT64 newActiveDescendent);
|
||||
|
||||
typedef void (*AccessBridge_PropertyTableModelChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 src,
|
||||
wchar_t *oldValue, wchar_t *newValue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,706 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Wrapper functions around calls to the AccessBridge DLL
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <jni.h>
|
||||
#include "AccessBridgeCallbacks.h"
|
||||
#include "AccessBridgePackages.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define null NULL
|
||||
|
||||
typedef JOBJECT64 AccessibleContext;
|
||||
typedef JOBJECT64 AccessibleText;
|
||||
typedef JOBJECT64 AccessibleValue;
|
||||
typedef JOBJECT64 AccessibleSelection;
|
||||
typedef JOBJECT64 Java_Object;
|
||||
typedef JOBJECT64 PropertyChangeEvent;
|
||||
typedef JOBJECT64 FocusEvent;
|
||||
typedef JOBJECT64 CaretEvent;
|
||||
typedef JOBJECT64 MouseEvent;
|
||||
typedef JOBJECT64 MenuEvent;
|
||||
typedef JOBJECT64 AccessibleTable;
|
||||
typedef JOBJECT64 AccessibleHyperlink;
|
||||
typedef JOBJECT64 AccessibleHypertext;
|
||||
|
||||
|
||||
typedef void (*Windows_runFP) ();
|
||||
|
||||
typedef void (*SetPropertyChangeFP) (AccessBridge_PropertyChangeFP fp);
|
||||
|
||||
typedef void (*SetJavaShutdownFP) (AccessBridge_JavaShutdownFP fp);
|
||||
typedef void (*SetFocusGainedFP) (AccessBridge_FocusGainedFP fp);
|
||||
typedef void (*SetFocusLostFP) (AccessBridge_FocusLostFP fp);
|
||||
|
||||
typedef void (*SetCaretUpdateFP) (AccessBridge_CaretUpdateFP fp);
|
||||
|
||||
typedef void (*SetMouseClickedFP) (AccessBridge_MouseClickedFP fp);
|
||||
typedef void (*SetMouseEnteredFP) (AccessBridge_MouseEnteredFP fp);
|
||||
typedef void (*SetMouseExitedFP) (AccessBridge_MouseExitedFP fp);
|
||||
typedef void (*SetMousePressedFP) (AccessBridge_MousePressedFP fp);
|
||||
typedef void (*SetMouseReleasedFP) (AccessBridge_MouseReleasedFP fp);
|
||||
|
||||
typedef void (*SetMenuCanceledFP) (AccessBridge_MenuCanceledFP fp);
|
||||
typedef void (*SetMenuDeselectedFP) (AccessBridge_MenuDeselectedFP fp);
|
||||
typedef void (*SetMenuSelectedFP) (AccessBridge_MenuSelectedFP fp);
|
||||
typedef void (*SetPopupMenuCanceledFP) (AccessBridge_PopupMenuCanceledFP fp);
|
||||
typedef void (*SetPopupMenuWillBecomeInvisibleFP) (AccessBridge_PopupMenuWillBecomeInvisibleFP fp);
|
||||
typedef void (*SetPopupMenuWillBecomeVisibleFP) (AccessBridge_PopupMenuWillBecomeVisibleFP fp);
|
||||
|
||||
typedef void (*SetPropertyNameChangeFP) (AccessBridge_PropertyNameChangeFP fp);
|
||||
typedef void (*SetPropertyDescriptionChangeFP) (AccessBridge_PropertyDescriptionChangeFP fp);
|
||||
typedef void (*SetPropertyStateChangeFP) (AccessBridge_PropertyStateChangeFP fp);
|
||||
typedef void (*SetPropertyValueChangeFP) (AccessBridge_PropertyValueChangeFP fp);
|
||||
typedef void (*SetPropertySelectionChangeFP) (AccessBridge_PropertySelectionChangeFP fp);
|
||||
typedef void (*SetPropertyTextChangeFP) (AccessBridge_PropertyTextChangeFP fp);
|
||||
typedef void (*SetPropertyCaretChangeFP) (AccessBridge_PropertyCaretChangeFP fp);
|
||||
typedef void (*SetPropertyVisibleDataChangeFP) (AccessBridge_PropertyVisibleDataChangeFP fp);
|
||||
typedef void (*SetPropertyChildChangeFP) (AccessBridge_PropertyChildChangeFP fp);
|
||||
typedef void (*SetPropertyActiveDescendentChangeFP) (AccessBridge_PropertyActiveDescendentChangeFP fp);
|
||||
|
||||
typedef void (*SetPropertyTableModelChangeFP) (AccessBridge_PropertyTableModelChangeFP fp);
|
||||
|
||||
typedef void (*ReleaseJavaObjectFP) (long vmID, Java_Object object);
|
||||
|
||||
typedef BOOL (*GetVersionInfoFP) (long vmID, AccessBridgeVersionInfo *info);
|
||||
|
||||
typedef BOOL (*IsJavaWindowFP) (HWND window);
|
||||
typedef BOOL (*IsSameObjectFP) (long vmID, JOBJECT64 obj1, JOBJECT64 obj2);
|
||||
typedef BOOL (*GetAccessibleContextFromHWNDFP) (HWND window, long *vmID, AccessibleContext *ac);
|
||||
typedef HWND (*getHWNDFromAccessibleContextFP) (long vmID, AccessibleContext ac);
|
||||
|
||||
typedef BOOL (*GetAccessibleContextAtFP) (long vmID, AccessibleContext acParent,
|
||||
jint x, jint y, AccessibleContext *ac);
|
||||
typedef BOOL (*GetAccessibleContextWithFocusFP) (HWND window, long *vmID, AccessibleContext *ac);
|
||||
typedef BOOL (*GetAccessibleContextInfoFP) (long vmID, AccessibleContext ac, AccessibleContextInfo *info);
|
||||
typedef AccessibleContext (*GetAccessibleChildFromContextFP) (long vmID, AccessibleContext ac, jint i);
|
||||
typedef AccessibleContext (*GetAccessibleParentFromContextFP) (long vmID, AccessibleContext ac);
|
||||
|
||||
/* begin AccessibleTable */
|
||||
typedef BOOL (*getAccessibleTableInfoFP) (long vmID, AccessibleContext ac, AccessibleTableInfo *tableInfo);
|
||||
typedef BOOL (*getAccessibleTableCellInfoFP) (long vmID, AccessibleTable accessibleTable,
|
||||
jint row, jint column, AccessibleTableCellInfo *tableCellInfo);
|
||||
|
||||
typedef BOOL (*getAccessibleTableRowHeaderFP) (long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
|
||||
typedef BOOL (*getAccessibleTableColumnHeaderFP) (long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
|
||||
|
||||
typedef AccessibleContext (*getAccessibleTableRowDescriptionFP) (long vmID, AccessibleContext acParent, jint row);
|
||||
typedef AccessibleContext (*getAccessibleTableColumnDescriptionFP) (long vmID, AccessibleContext acParent, jint column);
|
||||
|
||||
typedef jint (*getAccessibleTableRowSelectionCountFP) (long vmID, AccessibleTable table);
|
||||
typedef BOOL (*isAccessibleTableRowSelectedFP) (long vmID, AccessibleTable table, jint row);
|
||||
typedef BOOL (*getAccessibleTableRowSelectionsFP) (long vmID, AccessibleTable table, jint count,
|
||||
jint *selections);
|
||||
|
||||
typedef jint (*getAccessibleTableColumnSelectionCountFP) (long vmID, AccessibleTable table);
|
||||
typedef BOOL (*isAccessibleTableColumnSelectedFP) (long vmID, AccessibleTable table, jint column);
|
||||
typedef BOOL (*getAccessibleTableColumnSelectionsFP) (long vmID, AccessibleTable table, jint count,
|
||||
jint *selections);
|
||||
|
||||
typedef jint (*getAccessibleTableRowFP) (long vmID, AccessibleTable table, jint index);
|
||||
typedef jint (*getAccessibleTableColumnFP) (long vmID, AccessibleTable table, jint index);
|
||||
typedef jint (*getAccessibleTableIndexFP) (long vmID, AccessibleTable table, jint row, jint column);
|
||||
/* end AccessibleTable */
|
||||
|
||||
/* AccessibleRelationSet */
|
||||
typedef BOOL (*getAccessibleRelationSetFP) (long vmID, AccessibleContext accessibleContext,
|
||||
AccessibleRelationSetInfo *relationSetInfo);
|
||||
|
||||
/* AccessibleHypertext */
|
||||
typedef BOOL (*getAccessibleHypertextFP)(long vmID, AccessibleContext accessibleContext,
|
||||
AccessibleHypertextInfo *hypertextInfo);
|
||||
|
||||
typedef BOOL (*activateAccessibleHyperlinkFP)(long vmID, AccessibleContext accessibleContext,
|
||||
AccessibleHyperlink accessibleHyperlink);
|
||||
|
||||
typedef jint (*getAccessibleHyperlinkCountFP)(const long vmID,
|
||||
const AccessibleContext accessibleContext);
|
||||
|
||||
typedef BOOL (*getAccessibleHypertextExtFP) (const long vmID,
|
||||
const AccessibleContext accessibleContext,
|
||||
const jint nStartIndex,
|
||||
AccessibleHypertextInfo *hypertextInfo);
|
||||
|
||||
typedef jint (*getAccessibleHypertextLinkIndexFP)(const long vmID,
|
||||
const AccessibleHypertext hypertext,
|
||||
const jint nIndex);
|
||||
|
||||
typedef BOOL (*getAccessibleHyperlinkFP)(const long vmID,
|
||||
const AccessibleHypertext hypertext,
|
||||
const jint nIndex,
|
||||
AccessibleHyperlinkInfo *hyperlinkInfo);
|
||||
|
||||
|
||||
/* Accessible KeyBindings, Icons and Actions */
|
||||
typedef BOOL (*getAccessibleKeyBindingsFP)(long vmID, AccessibleContext accessibleContext,
|
||||
AccessibleKeyBindings *keyBindings);
|
||||
|
||||
typedef BOOL (*getAccessibleIconsFP)(long vmID, AccessibleContext accessibleContext,
|
||||
AccessibleIcons *icons);
|
||||
|
||||
typedef BOOL (*getAccessibleActionsFP)(long vmID, AccessibleContext accessibleContext,
|
||||
AccessibleActions *actions);
|
||||
|
||||
typedef BOOL (*doAccessibleActionsFP)(long vmID, AccessibleContext accessibleContext,
|
||||
AccessibleActionsToDo *actionsToDo, jint *failure);
|
||||
|
||||
|
||||
/* AccessibleText */
|
||||
|
||||
typedef BOOL (*GetAccessibleTextInfoFP) (long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y);
|
||||
typedef BOOL (*GetAccessibleTextItemsFP) (long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index);
|
||||
typedef BOOL (*GetAccessibleTextSelectionInfoFP) (long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection);
|
||||
typedef BOOL (*GetAccessibleTextAttributesFP) (long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes);
|
||||
typedef BOOL (*GetAccessibleTextRectFP) (long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index);
|
||||
typedef BOOL (*GetAccessibleTextLineBoundsFP) (long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex);
|
||||
typedef BOOL (*GetAccessibleTextRangeFP) (long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len);
|
||||
|
||||
typedef BOOL (*GetCurrentAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len);
|
||||
typedef BOOL (*GetMaximumAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len);
|
||||
typedef BOOL (*GetMinimumAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len);
|
||||
|
||||
typedef void (*AddAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i);
|
||||
typedef void (*ClearAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as);
|
||||
typedef JOBJECT64 (*GetAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i);
|
||||
typedef int (*GetAccessibleSelectionCountFromContextFP) (long vmID, AccessibleSelection as);
|
||||
typedef BOOL (*IsAccessibleChildSelectedFromContextFP) (long vmID, AccessibleSelection as, int i);
|
||||
typedef void (*RemoveAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i);
|
||||
typedef void (*SelectAllAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as);
|
||||
|
||||
/* Utility methods */
|
||||
|
||||
typedef BOOL (*setTextContentsFP) (const long vmID, const AccessibleContext ac, const wchar_t *text);
|
||||
typedef AccessibleContext (*getParentWithRoleFP) (const long vmID, const AccessibleContext ac, const wchar_t *role);
|
||||
typedef AccessibleContext (*getParentWithRoleElseRootFP) (const long vmID, const AccessibleContext ac, const wchar_t *role);
|
||||
typedef AccessibleContext (*getTopLevelObjectFP) (const long vmID, const AccessibleContext ac);
|
||||
typedef int (*getObjectDepthFP) (const long vmID, const AccessibleContext ac);
|
||||
typedef AccessibleContext (*getActiveDescendentFP) (const long vmID, const AccessibleContext ac);
|
||||
|
||||
|
||||
typedef BOOL (*getVirtualAccessibleNameFP) (const long vmID, const AccessibleContext accessibleContext,
|
||||
wchar_t *name, int len);
|
||||
|
||||
typedef BOOL (*requestFocusFP) (const long vmID, const AccessibleContext accessibleContext);
|
||||
|
||||
typedef BOOL (*selectTextRangeFP) (const long vmID, const AccessibleContext accessibleContext,
|
||||
const int startIndex, const int endIndex);
|
||||
|
||||
typedef BOOL (*getTextAttributesInRangeFP) (const long vmID, const AccessibleContext accessibleContext,
|
||||
const int startIndex, const int endIndex,
|
||||
AccessibleTextAttributesInfo *attributes, short *len);
|
||||
|
||||
typedef int (*getVisibleChildrenCountFP) (const long vmID, const AccessibleContext accessibleContext);
|
||||
|
||||
typedef BOOL (*getVisibleChildrenFP) (const long vmID, const AccessibleContext accessibleContext,
|
||||
const int startIndex, VisibleChildrenInfo *children);
|
||||
|
||||
typedef BOOL (*setCaretPositionFP) (const long vmID, const AccessibleContext accessibleContext, const int position);
|
||||
|
||||
typedef BOOL (*getCaretLocationFP) (long vmID, AccessibleContext ac, AccessibleTextRectInfo *rectInfo, jint index);
|
||||
|
||||
typedef int (*getEventsWaitingFP) ();
|
||||
|
||||
typedef struct AccessBridgeFPsTag {
|
||||
Windows_runFP Windows_run;
|
||||
|
||||
SetPropertyChangeFP SetPropertyChange;
|
||||
|
||||
SetJavaShutdownFP SetJavaShutdown;
|
||||
SetFocusGainedFP SetFocusGained;
|
||||
SetFocusLostFP SetFocusLost;
|
||||
|
||||
SetCaretUpdateFP SetCaretUpdate;
|
||||
|
||||
SetMouseClickedFP SetMouseClicked;
|
||||
SetMouseEnteredFP SetMouseEntered;
|
||||
SetMouseExitedFP SetMouseExited;
|
||||
SetMousePressedFP SetMousePressed;
|
||||
SetMouseReleasedFP SetMouseReleased;
|
||||
|
||||
SetMenuCanceledFP SetMenuCanceled;
|
||||
SetMenuDeselectedFP SetMenuDeselected;
|
||||
SetMenuSelectedFP SetMenuSelected;
|
||||
SetPopupMenuCanceledFP SetPopupMenuCanceled;
|
||||
SetPopupMenuWillBecomeInvisibleFP SetPopupMenuWillBecomeInvisible;
|
||||
SetPopupMenuWillBecomeVisibleFP SetPopupMenuWillBecomeVisible;
|
||||
|
||||
SetPropertyNameChangeFP SetPropertyNameChange;
|
||||
SetPropertyDescriptionChangeFP SetPropertyDescriptionChange;
|
||||
SetPropertyStateChangeFP SetPropertyStateChange;
|
||||
SetPropertyValueChangeFP SetPropertyValueChange;
|
||||
SetPropertySelectionChangeFP SetPropertySelectionChange;
|
||||
SetPropertyTextChangeFP SetPropertyTextChange;
|
||||
SetPropertyCaretChangeFP SetPropertyCaretChange;
|
||||
SetPropertyVisibleDataChangeFP SetPropertyVisibleDataChange;
|
||||
SetPropertyChildChangeFP SetPropertyChildChange;
|
||||
SetPropertyActiveDescendentChangeFP SetPropertyActiveDescendentChange;
|
||||
|
||||
SetPropertyTableModelChangeFP SetPropertyTableModelChange;
|
||||
|
||||
ReleaseJavaObjectFP ReleaseJavaObject;
|
||||
GetVersionInfoFP GetVersionInfo;
|
||||
|
||||
IsJavaWindowFP IsJavaWindow;
|
||||
IsSameObjectFP IsSameObject;
|
||||
GetAccessibleContextFromHWNDFP GetAccessibleContextFromHWND;
|
||||
getHWNDFromAccessibleContextFP getHWNDFromAccessibleContext;
|
||||
|
||||
GetAccessibleContextAtFP GetAccessibleContextAt;
|
||||
GetAccessibleContextWithFocusFP GetAccessibleContextWithFocus;
|
||||
GetAccessibleContextInfoFP GetAccessibleContextInfo;
|
||||
GetAccessibleChildFromContextFP GetAccessibleChildFromContext;
|
||||
GetAccessibleParentFromContextFP GetAccessibleParentFromContext;
|
||||
|
||||
getAccessibleTableInfoFP getAccessibleTableInfo;
|
||||
getAccessibleTableCellInfoFP getAccessibleTableCellInfo;
|
||||
|
||||
getAccessibleTableRowHeaderFP getAccessibleTableRowHeader;
|
||||
getAccessibleTableColumnHeaderFP getAccessibleTableColumnHeader;
|
||||
|
||||
getAccessibleTableRowDescriptionFP getAccessibleTableRowDescription;
|
||||
getAccessibleTableColumnDescriptionFP getAccessibleTableColumnDescription;
|
||||
|
||||
getAccessibleTableRowSelectionCountFP getAccessibleTableRowSelectionCount;
|
||||
isAccessibleTableRowSelectedFP isAccessibleTableRowSelected;
|
||||
getAccessibleTableRowSelectionsFP getAccessibleTableRowSelections;
|
||||
|
||||
getAccessibleTableColumnSelectionCountFP getAccessibleTableColumnSelectionCount;
|
||||
isAccessibleTableColumnSelectedFP isAccessibleTableColumnSelected;
|
||||
getAccessibleTableColumnSelectionsFP getAccessibleTableColumnSelections;
|
||||
|
||||
getAccessibleTableRowFP getAccessibleTableRow;
|
||||
getAccessibleTableColumnFP getAccessibleTableColumn;
|
||||
getAccessibleTableIndexFP getAccessibleTableIndex;
|
||||
|
||||
getAccessibleRelationSetFP getAccessibleRelationSet;
|
||||
|
||||
getAccessibleHypertextFP getAccessibleHypertext;
|
||||
activateAccessibleHyperlinkFP activateAccessibleHyperlink;
|
||||
getAccessibleHyperlinkCountFP getAccessibleHyperlinkCount;
|
||||
getAccessibleHypertextExtFP getAccessibleHypertextExt;
|
||||
getAccessibleHypertextLinkIndexFP getAccessibleHypertextLinkIndex;
|
||||
getAccessibleHyperlinkFP getAccessibleHyperlink;
|
||||
|
||||
getAccessibleKeyBindingsFP getAccessibleKeyBindings;
|
||||
getAccessibleIconsFP getAccessibleIcons;
|
||||
getAccessibleActionsFP getAccessibleActions;
|
||||
doAccessibleActionsFP doAccessibleActions;
|
||||
|
||||
GetAccessibleTextInfoFP GetAccessibleTextInfo;
|
||||
GetAccessibleTextItemsFP GetAccessibleTextItems;
|
||||
GetAccessibleTextSelectionInfoFP GetAccessibleTextSelectionInfo;
|
||||
GetAccessibleTextAttributesFP GetAccessibleTextAttributes;
|
||||
GetAccessibleTextRectFP GetAccessibleTextRect;
|
||||
GetAccessibleTextLineBoundsFP GetAccessibleTextLineBounds;
|
||||
GetAccessibleTextRangeFP GetAccessibleTextRange;
|
||||
|
||||
GetCurrentAccessibleValueFromContextFP GetCurrentAccessibleValueFromContext;
|
||||
GetMaximumAccessibleValueFromContextFP GetMaximumAccessibleValueFromContext;
|
||||
GetMinimumAccessibleValueFromContextFP GetMinimumAccessibleValueFromContext;
|
||||
|
||||
AddAccessibleSelectionFromContextFP AddAccessibleSelectionFromContext;
|
||||
ClearAccessibleSelectionFromContextFP ClearAccessibleSelectionFromContext;
|
||||
GetAccessibleSelectionFromContextFP GetAccessibleSelectionFromContext;
|
||||
GetAccessibleSelectionCountFromContextFP GetAccessibleSelectionCountFromContext;
|
||||
IsAccessibleChildSelectedFromContextFP IsAccessibleChildSelectedFromContext;
|
||||
RemoveAccessibleSelectionFromContextFP RemoveAccessibleSelectionFromContext;
|
||||
SelectAllAccessibleSelectionFromContextFP SelectAllAccessibleSelectionFromContext;
|
||||
|
||||
setTextContentsFP setTextContents;
|
||||
getParentWithRoleFP getParentWithRole;
|
||||
getTopLevelObjectFP getTopLevelObject;
|
||||
getParentWithRoleElseRootFP getParentWithRoleElseRoot;
|
||||
getObjectDepthFP getObjectDepth;
|
||||
getActiveDescendentFP getActiveDescendent;
|
||||
|
||||
getVirtualAccessibleNameFP getVirtualAccessibleName;
|
||||
requestFocusFP requestFocus;
|
||||
selectTextRangeFP selectTextRange;
|
||||
getTextAttributesInRangeFP getTextAttributesInRange;
|
||||
getVisibleChildrenCountFP getVisibleChildrenCount;
|
||||
getVisibleChildrenFP getVisibleChildren;
|
||||
setCaretPositionFP setCaretPosition;
|
||||
getCaretLocationFP getCaretLocation;
|
||||
|
||||
getEventsWaitingFP getEventsWaiting;
|
||||
|
||||
} AccessBridgeFPs;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the world
|
||||
*/
|
||||
BOOL initializeAccessBridge();
|
||||
BOOL shutdownAccessBridge();
|
||||
|
||||
/**
|
||||
* Window routines
|
||||
*/
|
||||
BOOL IsJavaWindow(HWND window);
|
||||
|
||||
// Returns the virtual machine ID and AccessibleContext for a top-level window
|
||||
BOOL GetAccessibleContextFromHWND(HWND target, long *vmID, AccessibleContext *ac);
|
||||
|
||||
// Returns the HWND from the AccessibleContext of a top-level window
|
||||
HWND getHWNDFromAccessibleContext(long vmID, AccessibleContext ac);
|
||||
|
||||
|
||||
/**
|
||||
* Event handling routines
|
||||
*/
|
||||
void SetJavaShutdown(AccessBridge_JavaShutdownFP fp);
|
||||
void SetFocusGained(AccessBridge_FocusGainedFP fp);
|
||||
void SetFocusLost(AccessBridge_FocusLostFP fp);
|
||||
|
||||
void SetCaretUpdate(AccessBridge_CaretUpdateFP fp);
|
||||
|
||||
void SetMouseClicked(AccessBridge_MouseClickedFP fp);
|
||||
void SetMouseEntered(AccessBridge_MouseEnteredFP fp);
|
||||
void SetMouseExited(AccessBridge_MouseExitedFP fp);
|
||||
void SetMousePressed(AccessBridge_MousePressedFP fp);
|
||||
void SetMouseReleased(AccessBridge_MouseReleasedFP fp);
|
||||
|
||||
void SetMenuCanceled(AccessBridge_MenuCanceledFP fp);
|
||||
void SetMenuDeselected(AccessBridge_MenuDeselectedFP fp);
|
||||
void SetMenuSelected(AccessBridge_MenuSelectedFP fp);
|
||||
void SetPopupMenuCanceled(AccessBridge_PopupMenuCanceledFP fp);
|
||||
void SetPopupMenuWillBecomeInvisible(AccessBridge_PopupMenuWillBecomeInvisibleFP fp);
|
||||
void SetPopupMenuWillBecomeVisible(AccessBridge_PopupMenuWillBecomeVisibleFP fp);
|
||||
|
||||
void SetPropertyNameChange(AccessBridge_PropertyNameChangeFP fp);
|
||||
void SetPropertyDescriptionChange(AccessBridge_PropertyDescriptionChangeFP fp);
|
||||
void SetPropertyStateChange(AccessBridge_PropertyStateChangeFP fp);
|
||||
void SetPropertyValueChange(AccessBridge_PropertyValueChangeFP fp);
|
||||
void SetPropertySelectionChange(AccessBridge_PropertySelectionChangeFP fp);
|
||||
void SetPropertyTextChange(AccessBridge_PropertyTextChangeFP fp);
|
||||
void SetPropertyCaretChange(AccessBridge_PropertyCaretChangeFP fp);
|
||||
void SetPropertyVisibleDataChange(AccessBridge_PropertyVisibleDataChangeFP fp);
|
||||
void SetPropertyChildChange(AccessBridge_PropertyChildChangeFP fp);
|
||||
void SetPropertyActiveDescendentChange(AccessBridge_PropertyActiveDescendentChangeFP fp);
|
||||
|
||||
void SetPropertyTableModelChange(AccessBridge_PropertyTableModelChangeFP fp);
|
||||
|
||||
|
||||
/**
|
||||
* General routines
|
||||
*/
|
||||
void ReleaseJavaObject(long vmID, Java_Object object);
|
||||
BOOL GetVersionInfo(long vmID, AccessBridgeVersionInfo *info);
|
||||
HWND GetHWNDFromAccessibleContext(long vmID, JOBJECT64 accesibleContext);
|
||||
|
||||
/**
|
||||
* Accessible Context routines
|
||||
*/
|
||||
BOOL GetAccessibleContextAt(long vmID, AccessibleContext acParent,
|
||||
jint x, jint y, AccessibleContext *ac);
|
||||
BOOL GetAccessibleContextWithFocus(HWND window, long *vmID, AccessibleContext *ac);
|
||||
BOOL GetAccessibleContextInfo(long vmID, AccessibleContext ac, AccessibleContextInfo *info);
|
||||
AccessibleContext GetAccessibleChildFromContext(long vmID, AccessibleContext ac, jint index);
|
||||
AccessibleContext GetAccessibleParentFromContext(long vmID, AccessibleContext ac);
|
||||
|
||||
/**
|
||||
* Accessible Text routines
|
||||
*/
|
||||
BOOL GetAccessibleTextInfo(long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y);
|
||||
BOOL GetAccessibleTextItems(long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index);
|
||||
BOOL GetAccessibleTextSelectionInfo(long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection);
|
||||
BOOL GetAccessibleTextAttributes(long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes);
|
||||
BOOL GetAccessibleTextRect(long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index);
|
||||
BOOL GetAccessibleTextLineBounds(long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex);
|
||||
BOOL GetAccessibleTextRange(long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len);
|
||||
|
||||
/* begin AccessibleTable routines */
|
||||
BOOL getAccessibleTableInfo(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
|
||||
|
||||
BOOL getAccessibleTableCellInfo(long vmID, AccessibleTable accessibleTable, jint row, jint column,
|
||||
AccessibleTableCellInfo *tableCellInfo);
|
||||
|
||||
BOOL getAccessibleTableRowHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
|
||||
BOOL getAccessibleTableColumnHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
|
||||
|
||||
AccessibleContext getAccessibleTableRowDescription(long vmID, AccessibleContext acParent, jint row);
|
||||
AccessibleContext getAccessibleTableColumnDescription(long vmID, AccessibleContext acParent, jint column);
|
||||
|
||||
jint getAccessibleTableRowSelectionCount(long vmID, AccessibleTable table);
|
||||
BOOL isAccessibleTableRowSelected(long vmID, AccessibleTable table, jint row);
|
||||
BOOL getAccessibleTableRowSelections(long vmID, AccessibleTable table, jint count, jint *selections);
|
||||
|
||||
jint getAccessibleTableColumnSelectionCount(long vmID, AccessibleTable table);
|
||||
BOOL isAccessibleTableColumnSelected(long vmID, AccessibleTable table, jint column);
|
||||
BOOL getAccessibleTableColumnSelections(long vmID, AccessibleTable table, jint count, jint *selections);
|
||||
|
||||
jint getAccessibleTableRow(long vmID, AccessibleTable table, jint index);
|
||||
jint getAccessibleTableColumn(long vmID, AccessibleTable table, jint index);
|
||||
jint getAccessibleTableIndex(long vmID, AccessibleTable table, jint row, jint column);
|
||||
/* end AccessibleTable */
|
||||
|
||||
/* ----- AccessibleRelationSet routines */
|
||||
BOOL getAccessibleRelationSet(long vmID, AccessibleContext accessibleContext,
|
||||
AccessibleRelationSetInfo *relationSetInfo);
|
||||
|
||||
/* ----- AccessibleHypertext routines */
|
||||
|
||||
/*
|
||||
* Returns hypertext information associated with a component.
|
||||
*/
|
||||
BOOL getAccessibleHypertext(long vmID, AccessibleContext accessibleContext,
|
||||
AccessibleHypertextInfo *hypertextInfo);
|
||||
|
||||
/*
|
||||
* Requests that a hyperlink be activated.
|
||||
*/
|
||||
BOOL activateAccessibleHyperlink(long vmID, AccessibleContext accessibleContext,
|
||||
AccessibleHyperlink accessibleHyperlink);
|
||||
|
||||
/*
|
||||
* Returns the number of hyperlinks in a component
|
||||
* Maps to AccessibleHypertext.getLinkCount.
|
||||
* Returns -1 on error.
|
||||
*/
|
||||
jint getAccessibleHyperlinkCount(const long vmID,
|
||||
const AccessibleHypertext hypertext);
|
||||
|
||||
/*
|
||||
* This method is used to iterate through the hyperlinks in a component. It
|
||||
* returns hypertext information for a component starting at hyperlink index
|
||||
* nStartIndex. No more than MAX_HYPERLINKS AccessibleHypertextInfo objects will
|
||||
* be returned for each call to this method.
|
||||
* Returns FALSE on error.
|
||||
*/
|
||||
BOOL getAccessibleHypertextExt(const long vmID,
|
||||
const AccessibleContext accessibleContext,
|
||||
const jint nStartIndex,
|
||||
/* OUT */ AccessibleHypertextInfo *hypertextInfo);
|
||||
|
||||
/*
|
||||
* Returns the index into an array of hyperlinks that is associated with
|
||||
* a character index in document; maps to AccessibleHypertext.getLinkIndex
|
||||
* Returns -1 on error.
|
||||
*/
|
||||
jint getAccessibleHypertextLinkIndex(const long vmID,
|
||||
const AccessibleHypertext hypertext,
|
||||
const jint nIndex);
|
||||
|
||||
/*
|
||||
* Returns the nth hyperlink in a document
|
||||
* Maps to AccessibleHypertext.getLink.
|
||||
* Returns FALSE on error
|
||||
*/
|
||||
BOOL getAccessibleHyperlink(const long vmID,
|
||||
const AccessibleHypertext hypertext,
|
||||
const jint nIndex,
|
||||
/* OUT */ AccessibleHyperlinkInfo *hyperlinkInfo);
|
||||
|
||||
/* Accessible KeyBindings, Icons and Actions */
|
||||
|
||||
/*
|
||||
* Returns a list of key bindings associated with a component.
|
||||
*/
|
||||
BOOL getAccessibleKeyBindings(long vmID, AccessibleContext accessibleContext,
|
||||
AccessibleKeyBindings *keyBindings);
|
||||
|
||||
/*
|
||||
* Returns a list of icons associate with a component.
|
||||
*/
|
||||
BOOL getAccessibleIcons(long vmID, AccessibleContext accessibleContext,
|
||||
AccessibleIcons *icons);
|
||||
|
||||
/*
|
||||
* Returns a list of actions that a component can perform.
|
||||
*/
|
||||
BOOL getAccessibleActions(long vmID, AccessibleContext accessibleContext,
|
||||
AccessibleActions *actions);
|
||||
|
||||
/*
|
||||
* Request that a list of AccessibleActions be performed by a component.
|
||||
* Returns TRUE if all actions are performed. Returns FALSE
|
||||
* when the first requested action fails in which case "failure"
|
||||
* contains the index of the action that failed.
|
||||
*/
|
||||
BOOL doAccessibleActions(long vmID, AccessibleContext accessibleContext,
|
||||
AccessibleActionsToDo *actionsToDo, jint *failure);
|
||||
|
||||
|
||||
|
||||
/* Additional utility methods */
|
||||
|
||||
/*
|
||||
* Returns whether two object references refer to the same object.
|
||||
*/
|
||||
BOOL IsSameObject(long vmID, JOBJECT64 obj1, JOBJECT64 obj2);
|
||||
|
||||
/**
|
||||
* Sets editable text contents. The AccessibleContext must implement AccessibleEditableText and
|
||||
* be editable. The maximum text length that can be set is MAX_STRING_SIZE - 1.
|
||||
* Returns whether successful
|
||||
*/
|
||||
BOOL setTextContents (const long vmID, const AccessibleContext accessibleContext, const wchar_t *text);
|
||||
|
||||
/**
|
||||
* Returns the Accessible Context with the specified role that is the
|
||||
* ancestor of a given object. The role is one of the role strings
|
||||
* defined in AccessBridgePackages.h
|
||||
* If there is no ancestor object that has the specified role,
|
||||
* returns (AccessibleContext)0.
|
||||
*/
|
||||
AccessibleContext getParentWithRole (const long vmID, const AccessibleContext accessibleContext,
|
||||
const wchar_t *role);
|
||||
|
||||
/**
|
||||
* Returns the Accessible Context with the specified role that is the
|
||||
* ancestor of a given object. The role is one of the role strings
|
||||
* defined in AccessBridgePackages.h. If an object with the specified
|
||||
* role does not exist, returns the top level object for the Java Window.
|
||||
* Returns (AccessibleContext)0 on error.
|
||||
*/
|
||||
AccessibleContext getParentWithRoleElseRoot (const long vmID, const AccessibleContext accessibleContext,
|
||||
const wchar_t *role);
|
||||
|
||||
/**
|
||||
* Returns the Accessible Context for the top level object in
|
||||
* a Java Window. This is same Accessible Context that is obtained
|
||||
* from GetAccessibleContextFromHWND for that window. Returns
|
||||
* (AccessibleContext)0 on error.
|
||||
*/
|
||||
AccessibleContext getTopLevelObject (const long vmID, const AccessibleContext accessibleContext);
|
||||
|
||||
/**
|
||||
* Returns how deep in the object hierarchy a given object is.
|
||||
* The top most object in the object hierarchy has an object depth of 0.
|
||||
* Returns -1 on error.
|
||||
*/
|
||||
int getObjectDepth (const long vmID, const AccessibleContext accessibleContext);
|
||||
|
||||
/**
|
||||
* Returns the Accessible Context of the current ActiveDescendent of an object.
|
||||
* This method assumes the ActiveDescendent is the component that is currently
|
||||
* selected in a container object.
|
||||
* Returns (AccessibleContext)0 on error or if there is no selection.
|
||||
*/
|
||||
AccessibleContext getActiveDescendent (const long vmID, const AccessibleContext accessibleContext);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Accessible Value routines
|
||||
*/
|
||||
BOOL GetCurrentAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len);
|
||||
BOOL GetMaximumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len);
|
||||
BOOL GetMinimumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len);
|
||||
|
||||
/**
|
||||
* Accessible Selection routines
|
||||
*/
|
||||
void AddAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i);
|
||||
void ClearAccessibleSelectionFromContext(long vmID, AccessibleSelection as);
|
||||
JOBJECT64 GetAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i);
|
||||
int GetAccessibleSelectionCountFromContext(long vmID, AccessibleSelection as);
|
||||
BOOL IsAccessibleChildSelectedFromContext(long vmID, AccessibleSelection as, int i);
|
||||
void RemoveAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i);
|
||||
void SelectAllAccessibleSelectionFromContext(long vmID, AccessibleSelection as);
|
||||
|
||||
/**
|
||||
* Additional methods for Teton
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the AccessibleName for a component based upon the JAWS algorithm. Returns
|
||||
* whether successful.
|
||||
*
|
||||
* Bug ID 4916682 - Implement JAWS AccessibleName policy
|
||||
*/
|
||||
BOOL getVirtualAccessibleName(const long vmID, const AccessibleContext accessibleContext,
|
||||
wchar_t *name, int len);
|
||||
|
||||
/**
|
||||
* Request focus for a component. Returns whether successful.
|
||||
*
|
||||
* Bug ID 4944757 - requestFocus method needed
|
||||
*/
|
||||
BOOL requestFocus(const long vmID, const AccessibleContext accessibleContext);
|
||||
|
||||
/**
|
||||
* Selects text between two indices. Selection includes the text at the start index
|
||||
* and the text at the end index. Returns whether successful.
|
||||
*
|
||||
* Bug ID 4944758 - selectTextRange method needed
|
||||
*/
|
||||
BOOL selectTextRange(const long vmID, const AccessibleContext accessibleContext, const int startIndex,
|
||||
const int endIndex);
|
||||
|
||||
/**
|
||||
* Get text attributes between two indices. The attribute list includes the text at the
|
||||
* start index and the text at the end index. Returns whether successful;
|
||||
*
|
||||
* Bug ID 4944761 - getTextAttributes between two indices method needed
|
||||
*/
|
||||
BOOL getTextAttributesInRange(const long vmID, const AccessibleContext accessibleContext,
|
||||
const int startIndex, const int endIndex,
|
||||
AccessibleTextAttributesInfo *attributes, short *len);
|
||||
|
||||
/**
|
||||
* Returns the number of visible children of a component. Returns -1 on error.
|
||||
*
|
||||
* Bug ID 4944762- getVisibleChildren for list-like components needed
|
||||
*/
|
||||
int getVisibleChildrenCount(const long vmID, const AccessibleContext accessibleContext);
|
||||
|
||||
/**
|
||||
* Gets the visible children of an AccessibleContext. Returns whether successful.
|
||||
*
|
||||
* Bug ID 4944762- getVisibleChildren for list-like components needed
|
||||
*/
|
||||
BOOL getVisibleChildren(const long vmID, const AccessibleContext accessibleContext,
|
||||
const int startIndex,
|
||||
VisibleChildrenInfo *visibleChildrenInfo);
|
||||
|
||||
/**
|
||||
* Set the caret to a text position. Returns whether successful.
|
||||
*
|
||||
* Bug ID 4944770 - setCaretPosition method needed
|
||||
*/
|
||||
BOOL setCaretPosition(const long vmID, const AccessibleContext accessibleContext,
|
||||
const int position);
|
||||
|
||||
/**
|
||||
* Gets the text caret location
|
||||
*/
|
||||
BOOL getCaretLocation(long vmID, AccessibleContext ac,
|
||||
AccessibleTextRectInfo *rectInfo, jint index);
|
||||
|
||||
/**
|
||||
* Gets the number of events waiting to fire
|
||||
*/
|
||||
int getEventsWaiting();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef _JAVASOFT_JAWT_MD_H_
|
||||
#define _JAVASOFT_JAWT_MD_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include "jawt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Win32-specific declarations for AWT native interface.
|
||||
* See notes in jawt.h for an example of use.
|
||||
*/
|
||||
typedef struct jawt_Win32DrawingSurfaceInfo {
|
||||
/* Native window, DDB, or DIB handle */
|
||||
union {
|
||||
HWND hwnd;
|
||||
HBITMAP hbitmap;
|
||||
void* pbits;
|
||||
};
|
||||
/*
|
||||
* This HDC should always be used instead of the HDC returned from
|
||||
* BeginPaint() or any calls to GetDC().
|
||||
*/
|
||||
HDC hdc;
|
||||
HPALETTE hpalette;
|
||||
} JAWT_Win32DrawingSurfaceInfo;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !_JAVASOFT_JAWT_MD_H_ */
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef _JAVASOFT_JNI_MD_H_
|
||||
#define _JAVASOFT_JNI_MD_H_
|
||||
|
||||
#define JNIEXPORT __declspec(dllexport)
|
||||
#define JNIIMPORT __declspec(dllimport)
|
||||
#define JNICALL __stdcall
|
||||
|
||||
typedef long jint;
|
||||
typedef __int64 jlong;
|
||||
typedef signed char jbyte;
|
||||
|
||||
#endif /* !_JAVASOFT_JNI_MD_H_ */
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,43 @@
|
||||
#include <windows.h>
|
||||
#include "Logger.hpp"
|
||||
#include "JvmManager.hpp"
|
||||
#include "MinecraftDetector.hpp"
|
||||
#include "PayloadLoader.hpp"
|
||||
|
||||
static HMODULE g_hModule = nullptr;
|
||||
|
||||
DWORD WINAPI SlinkyNativeWorkerThread(LPVOID lpParam) {
|
||||
HMODULE hModule = (HMODULE)lpParam;
|
||||
|
||||
SlinkyNative::Logger::Initialize(hModule);
|
||||
|
||||
if (!SlinkyNative::JvmManager::Initialize()) {
|
||||
SlinkyNative::Logger::Log(L"FINAL STATUS: FAILED");
|
||||
return 1;
|
||||
}
|
||||
|
||||
SlinkyNative::MinecraftInfo mcInfo;
|
||||
if (!SlinkyNative::MinecraftDetector::Detect(mcInfo)) {
|
||||
SlinkyNative::Logger::Log(L"FINAL STATUS: FAILED");
|
||||
return 1;
|
||||
}
|
||||
|
||||
SlinkyNative::InjectionStatus status = SlinkyNative::PayloadLoader::LoadAndStart(hModule, mcInfo);
|
||||
|
||||
return (status == SlinkyNative::InjectionStatus::Success || status == SlinkyNative::InjectionStatus::AlreadyRunning) ? 0 : 1;
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
|
||||
switch (fdwReason) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
g_hModule = (HMODULE)hinstDLL;
|
||||
DisableThreadLibraryCalls(hinstDLL);
|
||||
CreateThread(nullptr, 0, SlinkyNativeWorkerThread, (LPVOID)hinstDLL, 0, nullptr);
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
SlinkyNative::JvmManager::Shutdown();
|
||||
SlinkyNative::Logger::Shutdown();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
#include "JvmManager.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
typedef jint(JNICALL* pfn_JNI_GetCreatedJavaVMs)(JavaVM** vmBuf, jsize bufLen, jsize* nVMs);
|
||||
|
||||
namespace SlinkyNative {
|
||||
|
||||
JavaVM* JvmManager::s_JavaVM = nullptr;
|
||||
JNIEnv* JvmManager::s_JniEnv = nullptr;
|
||||
jvmtiEnv* JvmManager::s_JvmtiEnv = nullptr;
|
||||
|
||||
std::mutex JvmManager::s_HookMutex;
|
||||
jclass JvmManager::s_CaptureTarget = nullptr;
|
||||
std::vector<unsigned char> JvmManager::s_CapturedBytes;
|
||||
|
||||
jclass JvmManager::s_ReplacementTarget = nullptr;
|
||||
const unsigned char* JvmManager::s_ReplacementData = nullptr;
|
||||
jint JvmManager::s_ReplacementLength = 0;
|
||||
bool JvmManager::s_ReplacementApplied = false;
|
||||
|
||||
bool JvmManager::Initialize() {
|
||||
Logger::Log(L"SlinkyNative loaded into PID %lu", GetCurrentProcessId());
|
||||
|
||||
HMODULE hJvm = nullptr;
|
||||
for (int i = 0; i < 60; ++i) {
|
||||
hJvm = GetModuleHandleW(L"jvm.dll");
|
||||
if (hJvm) break;
|
||||
Sleep(100);
|
||||
}
|
||||
|
||||
if (!hJvm) {
|
||||
Logger::Log(L"jvm.dll / JNI_GetCreatedJavaVMs not found; is this a Java process?");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pJNI_GetCreatedJavaVMs = (pfn_JNI_GetCreatedJavaVMs)GetProcAddress(hJvm, "JNI_GetCreatedJavaVMs");
|
||||
if (!pJNI_GetCreatedJavaVMs) {
|
||||
Logger::Log(L"JNI_GetCreatedJavaVMs export not found in jvm.dll");
|
||||
return false;
|
||||
}
|
||||
|
||||
jsize nVMs = 0;
|
||||
jint res = 0;
|
||||
for (int i = 0; i < 60; ++i) {
|
||||
res = pJNI_GetCreatedJavaVMs(&s_JavaVM, 1, &nVMs);
|
||||
if (res == JNI_OK && nVMs > 0 && s_JavaVM) break;
|
||||
Sleep(100);
|
||||
}
|
||||
|
||||
if (res != JNI_OK || nVMs == 0 || !s_JavaVM) {
|
||||
Logger::Log(L"could not attach to the JVM");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attach current thread
|
||||
res = s_JavaVM->AttachCurrentThread((void**)&s_JniEnv, nullptr);
|
||||
if (res != JNI_OK || !s_JniEnv) {
|
||||
Logger::Log(L"could not attach to the JVM");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get JVMTI 1.2
|
||||
res = s_JavaVM->GetEnv((void**)&s_JvmtiEnv, JVMTI_VERSION_1_2);
|
||||
if (res != JNI_OK || !s_JvmtiEnv) {
|
||||
Logger::Log(L"JVMTI 1.2 is unavailable");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add capabilities
|
||||
jvmtiCapabilities potentialCaps = { 0 };
|
||||
jvmtiError err = s_JvmtiEnv->GetPotentialCapabilities(&potentialCaps);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
Logger::Log(L"GetPotentialCapabilities failed: %d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!potentialCaps.can_retransform_classes) {
|
||||
Logger::Log(L"JVM cannot retransform classes");
|
||||
return false;
|
||||
}
|
||||
|
||||
jvmtiCapabilities neededCaps = { 0 };
|
||||
neededCaps.can_retransform_classes = 1;
|
||||
neededCaps.can_retransform_any_class = potentialCaps.can_retransform_any_class;
|
||||
neededCaps.can_get_bytecodes = potentialCaps.can_get_bytecodes;
|
||||
neededCaps.can_generate_all_class_hook_events = potentialCaps.can_generate_all_class_hook_events;
|
||||
|
||||
err = s_JvmtiEnv->AddCapabilities(&neededCaps);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
Logger::Log(L"AddCapabilities failed: %d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set callbacks
|
||||
jvmtiEventCallbacks callbacks = { 0 };
|
||||
callbacks.ClassFileLoadHook = &OnClassFileLoadHook;
|
||||
err = s_JvmtiEnv->SetEventCallbacks(&callbacks, sizeof(callbacks));
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
Logger::Log(L"SetEventCallbacks failed: %d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void JvmManager::Shutdown() {
|
||||
if (s_JvmtiEnv) {
|
||||
// Disable class file load hook event
|
||||
s_JvmtiEnv->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, nullptr);
|
||||
s_JvmtiEnv = nullptr;
|
||||
}
|
||||
|
||||
if (s_JavaVM) {
|
||||
s_JavaVM->DetachCurrentThread();
|
||||
s_JavaVM = nullptr;
|
||||
}
|
||||
|
||||
s_JniEnv = nullptr;
|
||||
}
|
||||
|
||||
JavaVM* JvmManager::GetJavaVM() { return s_JavaVM; }
|
||||
JNIEnv* JvmManager::GetEnv() { return s_JniEnv; }
|
||||
jvmtiEnv* JvmManager::GetJvmti() { return s_JvmtiEnv; }
|
||||
|
||||
void JvmManager::SetCaptureTarget(jclass targetClass) {
|
||||
std::lock_guard<std::mutex> lock(s_HookMutex);
|
||||
s_CaptureTarget = targetClass;
|
||||
s_CapturedBytes.clear();
|
||||
}
|
||||
|
||||
std::vector<unsigned char> JvmManager::GetCapturedBytes() {
|
||||
std::lock_guard<std::mutex> lock(s_HookMutex);
|
||||
return s_CapturedBytes;
|
||||
}
|
||||
|
||||
void JvmManager::ClearCapturedBytes() {
|
||||
std::lock_guard<std::mutex> lock(s_HookMutex);
|
||||
s_CaptureTarget = nullptr;
|
||||
s_CapturedBytes.clear();
|
||||
}
|
||||
|
||||
void JvmManager::SetReplacementData(jclass targetClass, const unsigned char* data, jint length) {
|
||||
std::lock_guard<std::mutex> lock(s_HookMutex);
|
||||
s_ReplacementTarget = targetClass;
|
||||
s_ReplacementData = data;
|
||||
s_ReplacementLength = length;
|
||||
s_ReplacementApplied = false;
|
||||
}
|
||||
|
||||
bool JvmManager::WasReplacementApplied() {
|
||||
std::lock_guard<std::mutex> lock(s_HookMutex);
|
||||
return s_ReplacementApplied;
|
||||
}
|
||||
|
||||
void JvmManager::ClearReplacementData() {
|
||||
std::lock_guard<std::mutex> lock(s_HookMutex);
|
||||
s_ReplacementTarget = nullptr;
|
||||
s_ReplacementData = nullptr;
|
||||
s_ReplacementLength = 0;
|
||||
s_ReplacementApplied = false;
|
||||
}
|
||||
|
||||
void JNICALL JvmManager::OnClassFileLoadHook(
|
||||
jvmtiEnv* jvmti_env,
|
||||
JNIEnv* jni_env,
|
||||
jclass class_being_redefined,
|
||||
jobject loader,
|
||||
const char* name,
|
||||
jobject protection_domain,
|
||||
jint class_data_len,
|
||||
const unsigned char* class_data,
|
||||
jint* new_class_data_len,
|
||||
unsigned char** new_class_data)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_HookMutex);
|
||||
|
||||
// If capturing bytecode for getClassBytes
|
||||
if (s_CaptureTarget && class_being_redefined && jni_env->IsSameObject(s_CaptureTarget, class_being_redefined)) {
|
||||
if (class_data && class_data_len > 0) {
|
||||
s_CapturedBytes.assign(class_data, class_data + class_data_len);
|
||||
}
|
||||
}
|
||||
|
||||
// If applying replacement bytecode for retransformClass
|
||||
if (s_ReplacementTarget && class_being_redefined && jni_env->IsSameObject(s_ReplacementTarget, class_being_redefined)) {
|
||||
if (s_ReplacementData && s_ReplacementLength > 0) {
|
||||
unsigned char* jvmMemory = nullptr;
|
||||
jvmtiError err = jvmti_env->Allocate(s_ReplacementLength, &jvmMemory);
|
||||
if (err == JVMTI_ERROR_NONE && jvmMemory) {
|
||||
memcpy(jvmMemory, s_ReplacementData, s_ReplacementLength);
|
||||
*new_class_data_len = s_ReplacementLength;
|
||||
*new_class_data = jvmMemory;
|
||||
s_ReplacementApplied = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SlinkyNative
|
||||
@@ -0,0 +1,93 @@
|
||||
#include "Logger.hpp"
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
namespace SlinkyNative {
|
||||
|
||||
CRITICAL_SECTION Logger::s_CriticalSection;
|
||||
std::wstring Logger::s_LogFilePath;
|
||||
bool Logger::s_Initialized = false;
|
||||
|
||||
void Logger::Initialize(HMODULE hModule) {
|
||||
if (s_Initialized) return;
|
||||
InitializeCriticalSection(&s_CriticalSection);
|
||||
|
||||
wchar_t modulePath[MAX_PATH] = { 0 };
|
||||
if (GetModuleFileNameW(hModule, modulePath, MAX_PATH) > 0) {
|
||||
wchar_t* lastSlash = wcsrchr(modulePath, L'\\');
|
||||
if (lastSlash) {
|
||||
*lastSlash = L'\0';
|
||||
s_LogFilePath = std::wstring(modulePath) + L"\\slinky-native.log";
|
||||
}
|
||||
}
|
||||
|
||||
if (s_LogFilePath.empty()) {
|
||||
wchar_t tempPath[MAX_PATH] = { 0 };
|
||||
GetTempPathW(MAX_PATH, tempPath);
|
||||
s_LogFilePath = std::wstring(tempPath) + L"slinky-native.log";
|
||||
}
|
||||
|
||||
s_Initialized = true;
|
||||
}
|
||||
|
||||
void Logger::Shutdown() {
|
||||
if (!s_Initialized) return;
|
||||
DeleteCriticalSection(&s_CriticalSection);
|
||||
s_Initialized = false;
|
||||
}
|
||||
|
||||
const std::wstring& Logger::GetLogFilePath() {
|
||||
return s_LogFilePath;
|
||||
}
|
||||
|
||||
void Logger::Log(const wchar_t* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
LogV(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Logger::LogV(const wchar_t* format, va_list args) {
|
||||
if (!s_Initialized) return;
|
||||
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
|
||||
wchar_t messageBuf[2048] = { 0 };
|
||||
vswprintf_s(messageBuf, format, args);
|
||||
|
||||
wchar_t lineBuf[2560] = { 0 };
|
||||
swprintf_s(lineBuf, L"[%04u-%02u-%02u %02u:%02u:%02u.%03u] %ls\n",
|
||||
st.wYear, st.wMonth, st.wDay,
|
||||
st.wHour, st.wMinute, st.wSecond, st.wMilliseconds,
|
||||
messageBuf);
|
||||
|
||||
EnterCriticalSection(&s_CriticalSection);
|
||||
|
||||
// Also output to debug string for debugger attach
|
||||
OutputDebugStringW(lineBuf);
|
||||
|
||||
// Write to slinky-native.log
|
||||
FILE* fp = nullptr;
|
||||
if (_wfopen_s(&fp, s_LogFilePath.c_str(), L"a, ccs=UTF-8") == 0 && fp) {
|
||||
fputws(lineBuf, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&s_CriticalSection);
|
||||
}
|
||||
|
||||
void Logger::LogA(const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
char charBuf[2048] = { 0 };
|
||||
vsprintf_s(charBuf, format, args);
|
||||
va_end(args);
|
||||
|
||||
wchar_t wideBuf[2048] = { 0 };
|
||||
MultiByteToWideChar(CP_UTF8, 0, charBuf, -1, wideBuf, 2048);
|
||||
Log(L"%ls", wideBuf);
|
||||
}
|
||||
|
||||
} // namespace SlinkyNative
|
||||
@@ -0,0 +1,121 @@
|
||||
#include "MinecraftDetector.hpp"
|
||||
#include "JvmManager.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
namespace SlinkyNative {
|
||||
|
||||
bool MinecraftDetector::Detect(MinecraftInfo& outInfo) {
|
||||
JNIEnv* env = JvmManager::GetEnv();
|
||||
jvmtiEnv* jvmti = JvmManager::GetJvmti();
|
||||
|
||||
if (!env || !jvmti) return false;
|
||||
|
||||
// Wait up to 2 minutes for Minecraft 1.8.9 to finish starting
|
||||
ULONGLONG startTime = GetTickCount64();
|
||||
const ULONGLONG timeoutMs = 120000; // 2 minutes
|
||||
|
||||
while (GetTickCount64() - startTime < timeoutMs) {
|
||||
jint classCount = 0;
|
||||
jclass* classes = nullptr;
|
||||
jvmtiError err = jvmti->GetLoadedClasses(&classCount, &classes);
|
||||
|
||||
if (err == JVMTI_ERROR_NONE && classes) {
|
||||
jclass candidateMinecraft = nullptr;
|
||||
jclass candidateAve = nullptr;
|
||||
|
||||
for (jint i = 0; i < classCount; ++i) {
|
||||
char* signature = nullptr;
|
||||
char* generic = nullptr;
|
||||
if (jvmti->GetClassSignature(classes[i], &signature, &generic) == JVMTI_ERROR_NONE && signature) {
|
||||
if (strcmp(signature, "Lnet/minecraft/client/Minecraft;") == 0) {
|
||||
candidateMinecraft = classes[i];
|
||||
} else if (strcmp(signature, "Lave;") == 0) {
|
||||
candidateAve = classes[i];
|
||||
}
|
||||
jvmti->Deallocate((unsigned char*)signature);
|
||||
if (generic) jvmti->Deallocate((unsigned char*)generic);
|
||||
}
|
||||
}
|
||||
|
||||
// Check candidateMinecraft (MCP or SRG)
|
||||
if (candidateMinecraft) {
|
||||
// Check MCP: theMinecraft (Lnet/minecraft/client/Minecraft;)
|
||||
jfieldID fId = env->GetStaticFieldID(candidateMinecraft, "theMinecraft", "Lnet/minecraft/client/Minecraft;");
|
||||
if (fId) {
|
||||
outInfo.mapping = MappingType::Named;
|
||||
outInfo.mappingName = "named";
|
||||
outInfo.resourceId = 101;
|
||||
outInfo.minecraftClass = (jclass)env->NewGlobalRef(candidateMinecraft);
|
||||
|
||||
jvmti->GetClassLoader(candidateMinecraft, &outInfo.classLoader);
|
||||
if (outInfo.classLoader) {
|
||||
outInfo.classLoader = env->NewGlobalRef(outInfo.classLoader);
|
||||
}
|
||||
|
||||
jvmti->Deallocate((unsigned char*)classes);
|
||||
Logger::Log(L"detected Minecraft 1.8.9 with %hs names", outInfo.mappingName.c_str());
|
||||
return true;
|
||||
}
|
||||
env->ExceptionClear();
|
||||
|
||||
// Check SRG: field_71432_P (Lnet/minecraft/client/Minecraft;)
|
||||
fId = env->GetStaticFieldID(candidateMinecraft, "field_71432_P", "Lnet/minecraft/client/Minecraft;");
|
||||
if (fId) {
|
||||
outInfo.mapping = MappingType::Srg;
|
||||
outInfo.mappingName = "srg";
|
||||
outInfo.resourceId = 102;
|
||||
outInfo.minecraftClass = (jclass)env->NewGlobalRef(candidateMinecraft);
|
||||
|
||||
jvmti->GetClassLoader(candidateMinecraft, &outInfo.classLoader);
|
||||
if (outInfo.classLoader) {
|
||||
outInfo.classLoader = env->NewGlobalRef(outInfo.classLoader);
|
||||
}
|
||||
|
||||
jvmti->Deallocate((unsigned char*)classes);
|
||||
Logger::Log(L"detected Minecraft 1.8.9 with %hs names", outInfo.mappingName.c_str());
|
||||
return true;
|
||||
}
|
||||
env->ExceptionClear();
|
||||
|
||||
Logger::Log(L"net.minecraft.client.Minecraft has neither MCP nor SRG members; unsupported runtime");
|
||||
jvmti->Deallocate((unsigned char*)classes);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check candidateAve (Official / Notch)
|
||||
if (candidateAve) {
|
||||
// Check official: static field S (Lave;)
|
||||
jfieldID fId = env->GetStaticFieldID(candidateAve, "S", "Lave;");
|
||||
if (fId) {
|
||||
outInfo.mapping = MappingType::Official;
|
||||
outInfo.mappingName = "official";
|
||||
outInfo.resourceId = 103;
|
||||
outInfo.minecraftClass = (jclass)env->NewGlobalRef(candidateAve);
|
||||
|
||||
jvmti->GetClassLoader(candidateAve, &outInfo.classLoader);
|
||||
if (outInfo.classLoader) {
|
||||
outInfo.classLoader = env->NewGlobalRef(outInfo.classLoader);
|
||||
}
|
||||
|
||||
jvmti->Deallocate((unsigned char*)classes);
|
||||
Logger::Log(L"detected Minecraft 1.8.9 with %hs names", outInfo.mappingName.c_str());
|
||||
return true;
|
||||
}
|
||||
env->ExceptionClear();
|
||||
|
||||
Logger::Log(L"class ave is not Minecraft 1.8.9; unsupported runtime");
|
||||
jvmti->Deallocate((unsigned char*)classes);
|
||||
return false;
|
||||
}
|
||||
|
||||
jvmti->Deallocate((unsigned char*)classes);
|
||||
}
|
||||
|
||||
Sleep(500);
|
||||
}
|
||||
|
||||
Logger::Log(L"Minecraft 1.8.9 did not finish starting within 2 minutes");
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace SlinkyNative
|
||||
@@ -0,0 +1,135 @@
|
||||
#include "NativeBridge.hpp"
|
||||
#include "JvmManager.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
namespace SlinkyNative {
|
||||
|
||||
bool NativeBridge::Register(JNIEnv* env, jobject classLoader) {
|
||||
jclass bridgeClass = nullptr;
|
||||
|
||||
// First try ClassLoader.loadClass("dev.slinky.inject.NativeBridge")
|
||||
if (classLoader) {
|
||||
jclass clClass = env->GetObjectClass(classLoader);
|
||||
jmethodID loadClassMethod = env->GetMethodID(clClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||
if (loadClassMethod) {
|
||||
jstring className = env->NewStringUTF("dev.slinky.inject.NativeBridge");
|
||||
bridgeClass = (jclass)env->CallObjectMethod(classLoader, loadClassMethod, className);
|
||||
env->DeleteLocalRef(className);
|
||||
env->ExceptionClear();
|
||||
}
|
||||
env->DeleteLocalRef(clClass);
|
||||
}
|
||||
|
||||
if (!bridgeClass) {
|
||||
bridgeClass = env->FindClass("dev/slinky/inject/NativeBridge");
|
||||
env->ExceptionClear();
|
||||
}
|
||||
|
||||
if (!bridgeClass) {
|
||||
Logger::Log(L"could not find class dev.slinky.inject.NativeBridge");
|
||||
return false;
|
||||
}
|
||||
|
||||
JNINativeMethod methods[] = {
|
||||
{ (char*)"getClassBytes", (char*)"(Ljava/lang/Class;)[B", (void*)&GetClassBytes },
|
||||
{ (char*)"retransformClass", (char*)"(Ljava/lang/Class;[B)I", (void*)&RetransformClass },
|
||||
{ (char*)"log", (char*)"(Ljava/lang/String;)V", (void*)&Log }
|
||||
};
|
||||
|
||||
jint res = env->RegisterNatives(bridgeClass, methods, sizeof(methods) / sizeof(methods[0]));
|
||||
if (res != JNI_OK) {
|
||||
Logger::Log(L"RegisterNatives dev.slinky.inject.NativeBridge failed: %d", res);
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger::Log(L"RegisterNatives dev.slinky.inject.NativeBridge succeeded");
|
||||
return true;
|
||||
}
|
||||
|
||||
jbyteArray JNICALL NativeBridge::GetClassBytes(JNIEnv* env, jclass clazz, jclass targetClass) {
|
||||
if (!targetClass) return nullptr;
|
||||
|
||||
jvmtiEnv* jvmti = JvmManager::GetJvmti();
|
||||
if (!jvmti) return nullptr;
|
||||
|
||||
JvmManager::SetCaptureTarget(targetClass);
|
||||
|
||||
// Enable ClassFileLoadHook
|
||||
jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, nullptr);
|
||||
|
||||
// Trigger ClassFileLoadHook via RetransformClasses
|
||||
jvmtiError err = jvmti->RetransformClasses(1, &targetClass);
|
||||
|
||||
// Disable ClassFileLoadHook
|
||||
jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, nullptr);
|
||||
|
||||
std::vector<unsigned char> bytes = JvmManager::GetCapturedBytes();
|
||||
JvmManager::ClearCapturedBytes();
|
||||
|
||||
if (err != JVMTI_ERROR_NONE || bytes.empty()) {
|
||||
Logger::Log(L"RetransformClasses failed: jvmti=%d, target=%p", err, targetClass);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
jbyteArray result = env->NewByteArray((jsize)bytes.size());
|
||||
if (result) {
|
||||
env->SetByteArrayRegion(result, 0, (jsize)bytes.size(), (const jbyte*)bytes.data());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
jint JNICALL NativeBridge::RetransformClass(JNIEnv* env, jclass clazz, jclass targetClass, jbyteArray newBytecode) {
|
||||
if (!targetClass || !newBytecode) return 0x74; // JVMTI_ERROR_NULL_POINTER (0x74 = 116)
|
||||
|
||||
jvmtiEnv* jvmti = JvmManager::GetJvmti();
|
||||
if (!jvmti) return 0x6e; // JVMTI_ERROR_UNATTACHED_THREAD
|
||||
|
||||
jsize len = env->GetArrayLength(newBytecode);
|
||||
jbyte* bytes = env->GetByteArrayElements(newBytecode, nullptr);
|
||||
if (!bytes) return 0x6e;
|
||||
|
||||
JvmManager::SetReplacementData(targetClass, (const unsigned char*)bytes, len);
|
||||
|
||||
// Enable ClassFileLoadHook
|
||||
jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, nullptr);
|
||||
|
||||
// Trigger retransformation
|
||||
jvmtiError err = jvmti->RetransformClasses(1, &targetClass);
|
||||
|
||||
// Disable ClassFileLoadHook
|
||||
jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, nullptr);
|
||||
|
||||
bool applied = JvmManager::WasReplacementApplied();
|
||||
JvmManager::ClearReplacementData();
|
||||
env->ReleaseByteArrayElements(newBytecode, bytes, JNI_ABORT);
|
||||
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
Logger::Log(L"RetransformClasses(apply) failed: jvmti=%d", err);
|
||||
return (jint)err;
|
||||
}
|
||||
|
||||
if (!applied) {
|
||||
Logger::Log(L"RetransformClasses(apply): load hook never matched the target; class unchanged");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void JNICALL NativeBridge::Log(JNIEnv* env, jclass clazz, jstring message) {
|
||||
if (!message) return;
|
||||
|
||||
const char* utfChars = env->GetStringUTFChars(message, nullptr);
|
||||
if (utfChars) {
|
||||
int wlen = MultiByteToWideChar(CP_UTF8, 0, utfChars, -1, nullptr, 0);
|
||||
if (wlen > 0) {
|
||||
std::vector<wchar_t> wbuf(wlen);
|
||||
MultiByteToWideChar(CP_UTF8, 0, utfChars, -1, wbuf.data(), wlen);
|
||||
Logger::Log(L"[java] %ls", wbuf.data());
|
||||
}
|
||||
env->ReleaseStringUTFChars(message, utfChars);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SlinkyNative
|
||||
@@ -0,0 +1,485 @@
|
||||
#include "PayloadLoader.hpp"
|
||||
#include "JvmManager.hpp"
|
||||
#include "NativeBridge.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace SlinkyNative {
|
||||
|
||||
InjectionStatus PayloadLoader::LoadAndStart(HMODULE hModule, const MinecraftInfo& mcInfo) {
|
||||
JNIEnv* env = JvmManager::GetEnv();
|
||||
if (!env) {
|
||||
Logger::Log(L"FINAL STATUS: FAILED");
|
||||
return InjectionStatus::Failed;
|
||||
}
|
||||
|
||||
bool alreadyRunning = false;
|
||||
if (CheckPreviousState(env, mcInfo.classLoader, alreadyRunning)) {
|
||||
if (alreadyRunning) {
|
||||
Logger::Log(L"Slinky is already active; no classes or native methods were replaced");
|
||||
Logger::Log(L"FINAL STATUS: ALREADY_RUNNING");
|
||||
return InjectionStatus::AlreadyRunning;
|
||||
} else {
|
||||
Logger::Log(L"atomic payload replacement (class schema must be compatible)");
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring jarPath;
|
||||
if (!ExtractPayloadJar(hModule, mcInfo, jarPath)) {
|
||||
Logger::Log(L"FINAL STATUS: FAILED");
|
||||
return InjectionStatus::Failed;
|
||||
}
|
||||
|
||||
// Add JAR to ClassLoader
|
||||
if (!AddJarToClassLoader(env, mcInfo.classLoader, jarPath)) {
|
||||
DeleteFileW(jarPath.c_str());
|
||||
Logger::Log(L"FINAL STATUS: FAILED");
|
||||
return InjectionStatus::Failed;
|
||||
}
|
||||
|
||||
// Read and define dev.slinky classes
|
||||
DefinePayloadClasses(env, mcInfo.classLoader, jarPath);
|
||||
|
||||
// Delete temporary jar immediately after loading
|
||||
DeleteFileW(jarPath.c_str());
|
||||
|
||||
// Register native bridge methods
|
||||
if (!NativeBridge::Register(env, mcInfo.classLoader)) {
|
||||
Logger::Log(L"FINAL STATUS: FAILED");
|
||||
return InjectionStatus::Failed;
|
||||
}
|
||||
|
||||
// Launch Bootstrap
|
||||
if (!LaunchBootstrap(env, mcInfo.classLoader, mcInfo, hModule)) {
|
||||
Logger::Log(L"bootstrap failed; unloading");
|
||||
Logger::Log(L"FINAL STATUS: FAILED");
|
||||
return InjectionStatus::Failed;
|
||||
}
|
||||
|
||||
// Set reload markers / system properties
|
||||
jclass systemClass = env->FindClass("java/lang/System");
|
||||
if (systemClass) {
|
||||
jmethodID setPropertyMethod = env->GetStaticMethodID(systemClass, "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
|
||||
if (setPropertyMethod) {
|
||||
jstring key1 = env->NewStringUTF("slinky.injected");
|
||||
jstring val1 = env->NewStringUTF("true");
|
||||
env->CallStaticObjectMethod(systemClass, setPropertyMethod, key1, val1);
|
||||
env->DeleteLocalRef(key1);
|
||||
env->DeleteLocalRef(val1);
|
||||
|
||||
jstring key2 = env->NewStringUTF("slinky.patches.installed");
|
||||
jstring val2 = env->NewStringUTF("true");
|
||||
env->CallStaticObjectMethod(systemClass, setPropertyMethod, key2, val2);
|
||||
env->DeleteLocalRef(key2);
|
||||
env->DeleteLocalRef(val2);
|
||||
}
|
||||
env->DeleteLocalRef(systemClass);
|
||||
}
|
||||
env->ExceptionClear();
|
||||
|
||||
Logger::Log(L"Slinky is running");
|
||||
Logger::Log(L"FINAL STATUS: RUNNING");
|
||||
return InjectionStatus::Success;
|
||||
}
|
||||
|
||||
bool PayloadLoader::CheckPreviousState(JNIEnv* env, jobject classLoader, bool& outAlreadyRunning) {
|
||||
outAlreadyRunning = false;
|
||||
|
||||
// Check if dev.slinky.inject.Bootstrap was already loaded
|
||||
jclass bootstrapClass = nullptr;
|
||||
if (classLoader) {
|
||||
jclass clClass = env->GetObjectClass(classLoader);
|
||||
jmethodID findLoadedClassMethod = env->GetMethodID(clClass, "findLoadedClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||
if (findLoadedClassMethod) {
|
||||
jstring className = env->NewStringUTF("dev.slinky.inject.Bootstrap");
|
||||
bootstrapClass = (jclass)env->CallObjectMethod(classLoader, findLoadedClassMethod, className);
|
||||
env->DeleteLocalRef(className);
|
||||
env->ExceptionClear();
|
||||
}
|
||||
env->DeleteLocalRef(clClass);
|
||||
}
|
||||
|
||||
if (!bootstrapClass) {
|
||||
bootstrapClass = env->FindClass("dev/slinky/inject/Bootstrap");
|
||||
env->ExceptionClear();
|
||||
}
|
||||
|
||||
if (!bootstrapClass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger::Log(L"inspect previous Bootstrap");
|
||||
|
||||
// Check dev/slinky/client/hook/GameHooks
|
||||
jclass hooksClass = env->FindClass("dev/slinky/client/hook/GameHooks");
|
||||
env->ExceptionClear();
|
||||
if (hooksClass) {
|
||||
Logger::Log(L"inspect previous GameHooks");
|
||||
jfieldID modulesField = env->GetStaticFieldID(hooksClass, "modules", "Ldev/slinky/module/ModuleManager;");
|
||||
env->ExceptionClear();
|
||||
if (modulesField) {
|
||||
Logger::Log(L"inspect previous module manager");
|
||||
jobject moduleManager = env->GetStaticObjectField(hooksClass, modulesField);
|
||||
if (moduleManager) {
|
||||
jclass mmClass = env->GetObjectClass(moduleManager);
|
||||
jfieldID shutdownField = env->GetFieldID(mmClass, "shutdown", "Ljava/util/concurrent/atomic/AtomicBoolean;");
|
||||
env->ExceptionClear();
|
||||
if (shutdownField) {
|
||||
Logger::Log(L"read previous shutdown state");
|
||||
jobject shutdownObj = env->GetObjectField(moduleManager, shutdownField);
|
||||
if (shutdownObj) {
|
||||
jclass abClass = env->GetObjectClass(shutdownObj);
|
||||
jmethodID getMethod = env->GetMethodID(abClass, "get", "()Z");
|
||||
if (getMethod) {
|
||||
jboolean isShutdown = env->CallBooleanMethod(shutdownObj, getMethod);
|
||||
if (!isShutdown) {
|
||||
outAlreadyRunning = true;
|
||||
}
|
||||
}
|
||||
env->DeleteLocalRef(abClass);
|
||||
env->DeleteLocalRef(shutdownObj);
|
||||
}
|
||||
}
|
||||
env->DeleteLocalRef(mmClass);
|
||||
env->DeleteLocalRef(moduleManager);
|
||||
}
|
||||
}
|
||||
env->DeleteLocalRef(hooksClass);
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(bootstrapClass);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PayloadLoader::ExtractPayloadJar(HMODULE hModule, const MinecraftInfo& mcInfo, std::wstring& outJarPath) {
|
||||
wchar_t dllDir[MAX_PATH] = { 0 };
|
||||
if (GetModuleFileNameW(hModule, dllDir, MAX_PATH) > 0) {
|
||||
wchar_t* lastSlash = wcsrchr(dllDir, L'\\');
|
||||
if (lastSlash) *lastSlash = L'\0';
|
||||
}
|
||||
|
||||
// Format temp jar path: slinky-%hs-%lu-%llu.jar
|
||||
wchar_t jarFileName[256] = { 0 };
|
||||
swprintf_s(jarFileName, L"slinky-%hs-%lu-%llu.jar",
|
||||
mcInfo.mappingName.c_str(),
|
||||
GetCurrentProcessId(),
|
||||
GetTickCount64());
|
||||
|
||||
outJarPath = std::wstring(dllDir) + L"\\" + jarFileName;
|
||||
|
||||
// First attempt: embedded resource
|
||||
HRSRC hRes = FindResourceW(hModule, MAKEINTRESOURCEW(mcInfo.resourceId), (LPCWSTR)10); // RT_RCDATA = 10
|
||||
if (hRes) {
|
||||
DWORD resSize = SizeofResource(hModule, hRes);
|
||||
HGLOBAL hLoad = LoadResource(hModule, hRes);
|
||||
if (hLoad && resSize >= 4) {
|
||||
const unsigned char* pData = (const unsigned char*)LockResource(hLoad);
|
||||
if (pData && pData[0] == 0x50 && pData[1] == 0x4B) { // PK magic
|
||||
HANDLE hFile = CreateFileW(outJarPath.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
DWORD written = 0;
|
||||
WriteFile(hFile, pData, resSize, &written, nullptr);
|
||||
CloseHandle(hFile);
|
||||
|
||||
Logger::Log(L"payload %hs written to %ls (%lu bytes)", mcInfo.mappingName.c_str(), outJarPath.c_str(), written);
|
||||
return true;
|
||||
} else {
|
||||
Logger::Log(L"cannot write %ls: %lu", outJarPath.c_str(), GetLastError());
|
||||
}
|
||||
} else {
|
||||
Logger::Log(L"embedded payload %d is invalid", mcInfo.resourceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger::Log(L"embedded payload %d is missing", mcInfo.resourceId);
|
||||
|
||||
// Fallback: check for standalone JAR next to the DLL (slinky-named.jar, slinky-srg.jar, slinky-official.jar, or slinky.jar)
|
||||
std::wstring candidates[] = {
|
||||
std::wstring(dllDir) + L"\\slinky-" + std::wstring(mcInfo.mappingName.begin(), mcInfo.mappingName.end()) + L".jar",
|
||||
std::wstring(dllDir) + L"\\slinky.jar",
|
||||
std::wstring(dllDir) + L"\\Slinky-0.5.0-settings.jar"
|
||||
};
|
||||
|
||||
for (const auto& candidate : candidates) {
|
||||
if (GetFileAttributesW(candidate.c_str()) != INVALID_FILE_ATTRIBUTES) {
|
||||
// Copy candidate to outJarPath
|
||||
if (CopyFileW(candidate.c_str(), outJarPath.c_str(), FALSE)) {
|
||||
Logger::Log(L"payload %hs loaded from disk %ls", mcInfo.mappingName.c_str(), candidate.c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger::Log(L"payload contains no dev.slinky classes");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PayloadLoader::AddJarToClassLoader(JNIEnv* env, jobject classLoader, const std::wstring& jarPath) {
|
||||
if (!classLoader) {
|
||||
Logger::Log(L"game class loader unavailable");
|
||||
return false;
|
||||
}
|
||||
|
||||
jclass fileClass = env->FindClass("java/io/File");
|
||||
jclass uriClass = env->FindClass("java/net/URI");
|
||||
if (!fileClass || !uriClass) return false;
|
||||
|
||||
jmethodID fileInit = env->GetMethodID(fileClass, "<init>", "(Ljava/lang/String;)V");
|
||||
jmethodID fileToURI = env->GetMethodID(fileClass, "toURI", "()Ljava/net/URI;");
|
||||
jmethodID uriToURL = env->GetMethodID(uriClass, "toURL", "()Ljava/net/URL;");
|
||||
|
||||
int u8Len = WideCharToMultiByte(CP_UTF8, 0, jarPath.c_str(), -1, nullptr, 0, nullptr, nullptr);
|
||||
std::vector<char> u8Path(u8Len);
|
||||
WideCharToMultiByte(CP_UTF8, 0, jarPath.c_str(), -1, u8Path.data(), u8Len, nullptr, nullptr);
|
||||
|
||||
jstring jPath = env->NewStringUTF(u8Path.data());
|
||||
jobject fileObj = env->NewObject(fileClass, fileInit, jPath);
|
||||
env->DeleteLocalRef(jPath);
|
||||
|
||||
if (!fileObj) return false;
|
||||
|
||||
jobject uriObj = env->CallObjectMethod(fileObj, fileToURI);
|
||||
jobject urlObj = env->CallObjectMethod(uriObj, uriToURL);
|
||||
|
||||
env->DeleteLocalRef(fileObj);
|
||||
env->DeleteLocalRef(uriObj);
|
||||
env->DeleteLocalRef(fileClass);
|
||||
env->DeleteLocalRef(uriClass);
|
||||
|
||||
if (!urlObj) return false;
|
||||
|
||||
// Try URLClassLoader.addURL(URL) on game classloader or system classloader
|
||||
jclass uclClass = env->FindClass("java/net/URLClassLoader");
|
||||
if (uclClass) {
|
||||
jmethodID addURLMethod = env->GetMethodID(uclClass, "addURL", "(Ljava/net/URL;)V");
|
||||
if (addURLMethod) {
|
||||
env->CallVoidMethod(classLoader, addURLMethod, urlObj);
|
||||
if (!env->ExceptionCheck()) {
|
||||
Logger::Log(L"payload added to the game class loader (addURL)");
|
||||
env->DeleteLocalRef(urlObj);
|
||||
env->DeleteLocalRef(uclClass);
|
||||
return true;
|
||||
}
|
||||
env->ExceptionClear();
|
||||
}
|
||||
env->DeleteLocalRef(uclClass);
|
||||
}
|
||||
|
||||
// Fallback: add to SystemClassLoader
|
||||
jclass sysClass = env->FindClass("java/lang/ClassLoader");
|
||||
if (sysClass) {
|
||||
jmethodID getSysClMethod = env->GetStaticMethodID(sysClass, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
|
||||
if (getSysClMethod) {
|
||||
jobject sysCl = env->CallStaticObjectMethod(sysClass, getSysClMethod);
|
||||
if (sysCl) {
|
||||
jclass sysUcl = env->FindClass("java/net/URLClassLoader");
|
||||
if (sysUcl) {
|
||||
jmethodID addURL = env->GetMethodID(sysUcl, "addURL", "(Ljava/net/URL;)V");
|
||||
if (addURL) {
|
||||
env->CallVoidMethod(sysCl, addURL, urlObj);
|
||||
if (!env->ExceptionCheck()) {
|
||||
Logger::Log(L"payload appended to the system class loader search");
|
||||
env->DeleteLocalRef(urlObj);
|
||||
env->DeleteLocalRef(sysCl);
|
||||
env->DeleteLocalRef(sysUcl);
|
||||
env->DeleteLocalRef(sysClass);
|
||||
return true;
|
||||
}
|
||||
env->ExceptionClear();
|
||||
}
|
||||
env->DeleteLocalRef(sysUcl);
|
||||
}
|
||||
env->DeleteLocalRef(sysCl);
|
||||
}
|
||||
}
|
||||
env->DeleteLocalRef(sysClass);
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(urlObj);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PayloadLoader::DefinePayloadClasses(JNIEnv* env, jobject classLoader, const std::wstring& jarPath) {
|
||||
jclass jarFileClass = env->FindClass("java/util/jar/JarFile");
|
||||
jclass zipEntryClass = env->FindClass("java/util/zip/ZipEntry");
|
||||
jclass enumerationClass = env->FindClass("java/util/Enumeration");
|
||||
jclass isClass = env->FindClass("java/io/InputStream");
|
||||
jclass baosClass = env->FindClass("java/io/ByteArrayOutputStream");
|
||||
|
||||
if (!jarFileClass || !zipEntryClass || !enumerationClass || !isClass || !baosClass) {
|
||||
Logger::Log(L"resolve JAR reader failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
jmethodID jarInit = env->GetMethodID(jarFileClass, "<init>", "(Ljava/lang/String;)V");
|
||||
jmethodID jarEntries = env->GetMethodID(jarFileClass, "entries", "()Ljava/util/Enumeration;");
|
||||
jmethodID jarGetInputStream = env->GetMethodID(jarFileClass, "getInputStream", "(Ljava/util/zip/ZipEntry;)Ljava/io/InputStream;");
|
||||
jmethodID jarClose = env->GetMethodID(jarFileClass, "close", "()V");
|
||||
|
||||
jmethodID entryGetName = env->GetMethodID(zipEntryClass, "getName", "()Ljava/lang/String;");
|
||||
jmethodID enumHasMore = env->GetMethodID(enumerationClass, "hasMoreElements", "()Z");
|
||||
jmethodID enumNext = env->GetMethodID(enumerationClass, "nextElement", "()Ljava/lang/Object;");
|
||||
|
||||
jmethodID isRead = env->GetMethodID(isClass, "read", "([B)I");
|
||||
jmethodID baosInit = env->GetMethodID(baosClass, "<init>", "()V");
|
||||
jmethodID baosWrite = env->GetMethodID(baosClass, "write", "([BII)V");
|
||||
jmethodID baosToByteArray = env->GetMethodID(baosClass, "toByteArray", "()[B");
|
||||
|
||||
int u8Len = WideCharToMultiByte(CP_UTF8, 0, jarPath.c_str(), -1, nullptr, 0, nullptr, nullptr);
|
||||
std::vector<char> u8Path(u8Len);
|
||||
WideCharToMultiByte(CP_UTF8, 0, jarPath.c_str(), -1, u8Path.data(), u8Len, nullptr, nullptr);
|
||||
|
||||
jstring jPath = env->NewStringUTF(u8Path.data());
|
||||
jobject jarObj = env->NewObject(jarFileClass, jarInit, jPath);
|
||||
env->DeleteLocalRef(jPath);
|
||||
|
||||
if (!jarObj || env->ExceptionCheck()) {
|
||||
env->ExceptionClear();
|
||||
Logger::Log(L"open payload jar failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
jobject entries = env->CallObjectMethod(jarObj, jarEntries);
|
||||
size_t definedCount = 0;
|
||||
size_t unresolvedCount = 0;
|
||||
|
||||
jbyteArray buffer = env->NewByteArray(4096);
|
||||
|
||||
while (entries && env->CallBooleanMethod(entries, enumHasMore)) {
|
||||
jobject entry = env->CallObjectMethod(entries, enumNext);
|
||||
if (!entry) continue;
|
||||
|
||||
jstring nameStr = (jstring)env->CallObjectMethod(entry, entryGetName);
|
||||
if (nameStr) {
|
||||
const char* nameChars = env->GetStringUTFChars(nameStr, nullptr);
|
||||
if (nameChars) {
|
||||
std::string entryName = nameChars;
|
||||
env->ReleaseStringUTFChars(nameStr, nameChars);
|
||||
|
||||
if (entryName.rfind("dev/slinky/", 0) == 0 && entryName.size() > 6 && entryName.substr(entryName.size() - 6) == ".class") {
|
||||
// Convert "dev/slinky/Foo.class" -> "dev.slinky.Foo"
|
||||
std::string className = entryName.substr(0, entryName.size() - 6);
|
||||
for (char& c : className) {
|
||||
if (c == '/') c = '.';
|
||||
}
|
||||
|
||||
// Read bytes
|
||||
jobject inputStream = env->CallObjectMethod(jarObj, jarGetInputStream, entry);
|
||||
if (inputStream) {
|
||||
jobject baos = env->NewObject(baosClass, baosInit);
|
||||
jint bytesRead = 0;
|
||||
while ((bytesRead = env->CallIntMethod(inputStream, isRead, buffer)) > 0) {
|
||||
env->CallVoidMethod(baos, baosWrite, buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
jbyteArray classBytesArr = (jbyteArray)env->CallObjectMethod(baos, baosToByteArray);
|
||||
if (classBytesArr) {
|
||||
jsize byteLen = env->GetArrayLength(classBytesArr);
|
||||
jbyte* rawBytes = env->GetByteArrayElements(classBytesArr, nullptr);
|
||||
if (rawBytes) {
|
||||
jclass definedClass = env->DefineClass(className.c_str(), classLoader, rawBytes, byteLen);
|
||||
if (definedClass) {
|
||||
definedCount++;
|
||||
env->DeleteLocalRef(definedClass);
|
||||
} else {
|
||||
unresolvedCount++;
|
||||
}
|
||||
env->ExceptionClear();
|
||||
env->ReleaseByteArrayElements(classBytesArr, rawBytes, JNI_ABORT);
|
||||
}
|
||||
env->DeleteLocalRef(classBytesArr);
|
||||
}
|
||||
env->DeleteLocalRef(baos);
|
||||
env->DeleteLocalRef(inputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
env->DeleteLocalRef(nameStr);
|
||||
}
|
||||
env->DeleteLocalRef(entry);
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(buffer);
|
||||
env->CallVoidMethod(jarObj, jarClose);
|
||||
env->DeleteLocalRef(jarObj);
|
||||
|
||||
Logger::Log(L"defined %zu new payload classes in the game class loader; %zu unresolved", definedCount, unresolvedCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PayloadLoader::LaunchBootstrap(JNIEnv* env, jobject classLoader, const MinecraftInfo& mcInfo, HMODULE hModule) {
|
||||
jclass bootstrapClass = nullptr;
|
||||
|
||||
if (classLoader) {
|
||||
jclass clClass = env->GetObjectClass(classLoader);
|
||||
jmethodID loadClassMethod = env->GetMethodID(clClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||
if (loadClassMethod) {
|
||||
jstring className = env->NewStringUTF("dev.slinky.inject.Bootstrap");
|
||||
bootstrapClass = (jclass)env->CallObjectMethod(classLoader, loadClassMethod, className);
|
||||
env->DeleteLocalRef(className);
|
||||
env->ExceptionClear();
|
||||
}
|
||||
env->DeleteLocalRef(clClass);
|
||||
}
|
||||
|
||||
if (!bootstrapClass) {
|
||||
bootstrapClass = env->FindClass("dev/slinky/inject/Bootstrap");
|
||||
env->ExceptionClear();
|
||||
}
|
||||
|
||||
if (!bootstrapClass) {
|
||||
Logger::Log(L"resolve Bootstrap.start failed: class not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
jmethodID startMethod = env->GetStaticMethodID(bootstrapClass, "start", "(Ljava/lang/String;Ljava/lang/String;)V");
|
||||
if (!startMethod) {
|
||||
Logger::Log(L"resolve Bootstrap.start failed: method not found");
|
||||
env->DeleteLocalRef(bootstrapClass);
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t dllPath[MAX_PATH] = { 0 };
|
||||
GetModuleFileNameW(hModule, dllPath, MAX_PATH);
|
||||
int u8Len = WideCharToMultiByte(CP_UTF8, 0, dllPath, -1, nullptr, 0, nullptr, nullptr);
|
||||
std::vector<char> u8DllPath(u8Len);
|
||||
WideCharToMultiByte(CP_UTF8, 0, dllPath, -1, u8DllPath.data(), u8Len, nullptr, nullptr);
|
||||
|
||||
jstring jMapping = env->NewStringUTF(mcInfo.mappingName.c_str());
|
||||
jstring jDllPath = env->NewStringUTF(u8DllPath.data());
|
||||
|
||||
Logger::Log(L"Bootstrap.start calling with mapping=%hs", mcInfo.mappingName.c_str());
|
||||
env->CallStaticVoidMethod(bootstrapClass, startMethod, jMapping, jDllPath);
|
||||
|
||||
env->DeleteLocalRef(jMapping);
|
||||
env->DeleteLocalRef(jDllPath);
|
||||
env->DeleteLocalRef(bootstrapClass);
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
jthrowable ex = env->ExceptionOccurred();
|
||||
env->ExceptionClear();
|
||||
if (ex) {
|
||||
jclass exClass = env->GetObjectClass(ex);
|
||||
jmethodID toString = env->GetMethodID(exClass, "toString", "()Ljava/lang/String;");
|
||||
if (toString) {
|
||||
jstring msg = (jstring)env->CallObjectMethod(ex, toString);
|
||||
if (msg) {
|
||||
const char* chars = env->GetStringUTFChars(msg, nullptr);
|
||||
if (chars) {
|
||||
Logger::Log(L"Bootstrap.start failed: %hs", chars);
|
||||
env->ReleaseStringUTFChars(msg, chars);
|
||||
}
|
||||
env->DeleteLocalRef(msg);
|
||||
}
|
||||
}
|
||||
env->DeleteLocalRef(exClass);
|
||||
env->DeleteLocalRef(ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace SlinkyNative
|
||||
Reference in new issue
Block a user