Fixes for Windows and MSCOM implementation

Still can't pass Java objects to COM
This commit is contained in:
Norbi Peti 2020-08-11 19:00:00 +02:00
parent 586ab05033
commit 580d48d7d0
15 changed files with 295 additions and 22 deletions

View file

@ -9,6 +9,7 @@
<version>2.1-SNAPSHOT</version> <version>2.1-SNAPSHOT</version>
</parent> </parent>
<build> <build>
<finalName>VirtualComputer</finalName>
<plugins> <plugins>
<plugin> <plugin>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
@ -36,6 +37,14 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
<dependencies> <dependencies>
@ -55,7 +64,7 @@
<version>2.1-SNAPSHOT</version> <version>2.1-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>sznp.virtualcomputer</groupId> <groupId>io.github.NorbiPeti</groupId>
<artifactId>VirtualComputer-MSCOM</artifactId> <artifactId>VirtualComputer-MSCOM</artifactId>
<version>2.1-SNAPSHOT</version> <version>2.1-SNAPSHOT</version>
</dependency> </dependency>
@ -87,7 +96,7 @@
<artifactSet> <artifactSet>
<excludes> <excludes>
<exclude>org.virtualbox:VirtualBox-MSCOM</exclude> <exclude>org.virtualbox:VirtualBox-MSCOM</exclude>
<exclude>sznp.virtualcomputer:VirtualComputer-MSCOM</exclude> <exclude>io.github.NorbiPeti:VirtualComputer-MSCOM</exclude>
</excludes> </excludes>
</artifactSet> </artifactSet>
<!-- <minimizeJar>true</minimizeJar> --> <!-- <minimizeJar>true</minimizeJar> -->
@ -130,7 +139,7 @@
<artifactSet> <artifactSet>
<excludes> <excludes>
<exclude>org.virtualbox:VirtualBox</exclude> <exclude>org.virtualbox:VirtualBox</exclude>
<exclude>sznp.virtualcomputer:VirtualComputer-XPCOM</exclude> <exclude>io.github.NorbiPeti:VirtualComputer-XPCOM</exclude>
</excludes> </excludes>
</artifactSet> </artifactSet>
</configuration> </configuration>

View file

@ -273,6 +273,7 @@ public final class Computer {
GPURenderer.update(new byte[1], 0, 0, 0, 0, 640, 480); //Black screen GPURenderer.update(new byte[1], 0, 0, 0, 0, 640, 480); //Black screen
stopEvents(); stopEvents();
MouseLockerPlayerListener.computerStop(); MouseLockerPlayerListener.computerStop();
if (framebuffer != null)
framebuffer.stop(); framebuffer.stop();
} }
@ -286,6 +287,7 @@ public final class Computer {
public void pluginDisable(CommandSender ccs) { public void pluginDisable(CommandSender ccs) {
stopEvents(); stopEvents();
if (framebuffer != null)
framebuffer.stop(); framebuffer.stop();
if (session.getState() == SessionState.Locked) { if (session.getState() == SessionState.Locked) {
if (session.getMachine().getState().equals(MachineState.Running)) { if (session.getMachine().getState().equals(MachineState.Running)) {

View file

@ -33,7 +33,7 @@ public class PluginMain extends JavaPlugin {
* Only used if {@link #direct} is false. * Only used if {@link #direct} is false.
*/ */
public static ByteBuffer allpixels; // It's set on each change public static ByteBuffer allpixels; // It's set on each change
private static ArrayList<IRenderer> renderers = new ArrayList<>(); private static final ArrayList<IRenderer> renderers = new ArrayList<>();
/* /*
* Only used if {@link #direct} is true. * Only used if {@link #direct} is true.
*/ */
@ -50,14 +50,23 @@ public class PluginMain extends JavaPlugin {
this.getCommand("computer").setExecutor(new Commands()); this.getCommand("computer").setExecutor(new Commands());
sendAll = getConfig().getBoolean("sendAll", true); sendAll = getConfig().getBoolean("sendAll", true);
ccs.sendMessage("§bInitializing VirtualBox..."); ccs.sendMessage("§bInitializing VirtualBox...");
String vbpath = System.getProperty("os.name").toLowerCase().contains("mac") String osname = System.getProperty("os.name").toLowerCase();
final boolean windows;
String vbpath;
{
boolean win = false;
vbpath = osname.contains("mac")
? "/Applications/VirtualBox.app/Contents/MacOS" ? "/Applications/VirtualBox.app/Contents/MacOS"
: (win = osname.contains("windows"))
? "C:\\Program Files\\Oracle\\VirtualBox"
: "/opt/virtualbox"; : "/opt/virtualbox";
windows = win;
}
//noinspection ConstantConditions //noinspection ConstantConditions
Predicate<File> notGoodDir= ff->!ff.isDirectory() || Arrays.stream(ff.list()).noneMatch(s -> s.contains("xpcom")); Predicate<File> notGoodDir = ff -> !ff.isDirectory() || (!windows && Arrays.stream(ff.list()).noneMatch(s -> s.contains("xpcom")));
if (notGoodDir.test(new File(vbpath))) if (notGoodDir.test(new File(vbpath)))
vbpath = "/usr/lib/virtualbox"; vbpath = "/usr/lib/virtualbox";
if(notGoodDir.test(new File(vbpath))) if (notGoodDir.test(new File(vbpath)))
error("Could not find VirtualBox! Download from https://www.virtualbox.org/wiki/Downloads"); error("Could not find VirtualBox! Download from https://www.virtualbox.org/wiki/Downloads");
if (System.getProperty("vbox.home") == null || System.getProperty("vbox.home").isEmpty()) if (System.getProperty("vbox.home") == null || System.getProperty("vbox.home").isEmpty())
System.setProperty("vbox.home", vbpath); System.setProperty("vbox.home", vbpath);
@ -66,10 +75,12 @@ public class PluginMain extends JavaPlugin {
System.setProperty("sun.boot.library.path", vbpath); System.setProperty("sun.boot.library.path", vbpath);
if (System.getProperty("java.library.path") == null || System.getProperty("java.library.path").isEmpty()) if (System.getProperty("java.library.path") == null || System.getProperty("java.library.path").isEmpty())
System.setProperty("java.library.path", vbpath); System.setProperty("java.library.path", vbpath);
Utils.addLibraryPath(vbpath); Utils.addLibraryPath(vbpath); //TODO: Jacob DLL must be in the server folder
final VirtualBoxManager manager = VirtualBoxManager.createInstance(getDataFolder().getAbsolutePath()); final VirtualBoxManager manager = VirtualBoxManager.createInstance(getDataFolder().getAbsolutePath());
VBoxLib vbl = LibraryLoader.create(VBoxLib.class).load("vboxjxpcom"); //TODO: Test for MSCOM if (!windows) {
VBoxLib vbl = LibraryLoader.create(VBoxLib.class).load("vboxjxpcom");
vbl.RTR3InitExe(0, "", 0); vbl.RTR3InitExe(0, "", 0);
}
IVirtualBox vbox = manager.getVBox(); IVirtualBox vbox = manager.getVBox();
(listener = new VBoxEventHandler()).registerTo(vbox.getEventSource()); (listener = new VBoxEventHandler()).registerTo(vbox.getEventSource());
new Computer(this, manager, vbox); //Saves itself new Computer(this, manager, vbox); //Saves itself
@ -80,12 +91,12 @@ public class PluginMain extends JavaPlugin {
for (short j = 0; j < MCY; j++) for (short j = 0; j < MCY; j++)
renderers.add(new GPURenderer((short) (j * 5 + i), Bukkit.getWorlds().get(0), i, j)); renderers.add(new GPURenderer((short) (j * 5 + i), Bukkit.getWorlds().get(0), i, j));
//pxc = LibraryLoader.create(PXCLib.class).search(getDataFolder().getAbsolutePath()).load("pxc"); //pxc = LibraryLoader.create(PXCLib.class).search(getDataFolder().getAbsolutePath()).load("pxc");
direct=true; direct = true;
ccs.sendMessage("§bUsing Direct Renderer, all good"); ccs.sendMessage("§bUsing Direct Renderer, all good");
} catch (NoClassDefFoundError | Exception e) { } catch (NoClassDefFoundError | Exception e) {
for (short i = 0; i < 20; i++) for (short i = 0; i < 20; i++)
renderers.add(new BukkitRenderer(i, Bukkit.getWorlds().get(0), i * 128 * 128 * 4)); renderers.add(new BukkitRenderer(i, Bukkit.getWorlds().get(0), i * 128 * 128 * 4));
direct=false; direct = false;
e.printStackTrace(); e.printStackTrace();
ccs.sendMessage("§6Compatibility error, using slower renderer"); ccs.sendMessage("§6Compatibility error, using slower renderer");
} }

View file

@ -1,5 +1,7 @@
package sznp.virtualcomputer.util; package sznp.virtualcomputer.util;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Arrays; import java.util.Arrays;
@ -11,6 +13,14 @@ public class Utils {
* @throws Exception * @throws Exception
*/ */
public static void addLibraryPath(String pathToAdd) throws Exception { public static void addLibraryPath(String pathToAdd) throws Exception {
try {
addLibraryPathOld(pathToAdd);
} catch (Throwable t) {
addLibraryPathNew(pathToAdd);
}
}
private static void addLibraryPathOld(String pathToAdd) throws Exception {
final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths"); final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths");
usrPathsField.setAccessible(true); usrPathsField.setAccessible(true);
@ -29,4 +39,14 @@ public class Utils {
newPaths[newPaths.length - 1] = pathToAdd; newPaths[newPaths.length - 1] = pathToAdd;
usrPathsField.set(null, newPaths); usrPathsField.set(null, newPaths);
} }
private static void addLibraryPathNew(String pathToAdd) throws Exception {
MethodHandles.Lookup cl = MethodHandles.privateLookupIn(ClassLoader.class, MethodHandles.lookup());
VarHandle sys_paths = cl.findStaticVarHandle(ClassLoader.class, "sys_paths", String[].class);
final String[] paths = (String[]) sys_paths.get();
final String[] newPaths = Arrays.copyOf(paths, paths.length + 1);
newPaths[newPaths.length - 1] = pathToAdd;
sys_paths.set((Object) newPaths);
}
} }

View file

@ -4,7 +4,6 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>sznp.virtualcomputer</groupId>
<artifactId>VirtualComputer-MSCOM</artifactId> <artifactId>VirtualComputer-MSCOM</artifactId>
<version>2.1-SNAPSHOT</version> <version>2.1-SNAPSHOT</version>
@ -22,6 +21,11 @@
<optional>true <optional>true
</optional> <!-- https://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html --> </optional> <!-- https://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html -->
</dependency> </dependency>
<dependency>
<groupId>net.sf.jacob-project</groupId>
<artifactId>jacob</artifactId>
<version>1.19</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View file

@ -0,0 +1,97 @@
package sznp.virtualcomputer;
import lombok.RequiredArgsConstructor;
import org.virtualbox_6_1.BitmapFormat;
import org.virtualbox_6_1.FramebufferCapabilities;
import org.virtualbox_6_1.IFramebufferOverlay;
import sznp.virtualcomputer.util.IMCFrameBuffer;
import java.util.Arrays;
@RequiredArgsConstructor
public class COMFrameBuffer {
private final IMCFrameBuffer frameBuffer;
public long getBitsPerPixel() {
return 32;
}
public long getBytesPerLine() {
return 640L;
}
public long[] getCapabilities(long[] arg0) {
try {
System.out.println("Capabilities queried");
System.out.println("Capabilities: " + Arrays.toString(arg0));
return new long[]{FramebufferCapabilities.UpdateImage.value()};
} catch (Exception e) {
e.printStackTrace();
return new long[]{};
}
}
public long getHeight() {
return 480;
}
public long getHeightReduction() {
return 0;
}
public IFramebufferOverlay getOverlay() {
return null;
}
public long getPixelFormat() {
return BitmapFormat.BGRA.value();
}
public long getVisibleRegion(byte arg0, long arg1) {
return 0;
}
public long getWidth() {
return 640;
}
public long getWinId() {
return 0; // Zero means no win id
}
public void notify3DEvent(long type, byte[] data) {
System.out.println("3D event! " + type + " - " + Arrays.toString(data));
}
public void notifyChange(long screenId, long xOrigin, long yOrigin, long width, long height) {
frameBuffer.notifyChange(screenId, xOrigin, yOrigin, width, height);
}
public void notifyUpdate(long x, long y, long width, long height) {
frameBuffer.notifyUpdate(x, y, width, height);
}
public void notifyUpdateImage(long arg0, long arg1, long arg2, long arg3, byte[] arg4) {
frameBuffer.notifyUpdateImage(arg0, arg1, arg2, arg3, arg4);
}
public void setVisibleRegion(byte arg0, long arg1) {
}
/**
* Posts a Video HW Acceleration Command to the frame buffer for processing.<br />
* <br />
* The commands used for 2D video acceleration (DDraw surface creation/destroying, blitting, scaling, color conversion, overlaying, etc.) are posted from quest to the host to be processed by the host hardware.
*
* @param command Pointer to VBOXVHWACMD containing the command to execute.
* @param enmCmd The validated VBOXVHWACMD::enmCmd value from the command.
* @param fromGuest Set when the command origins from the guest, clear if host.
*/ //https://www.virtualbox.org/browser/vbox/trunk/src/VBox/Frontends/VirtualBox/src/VBoxFBOverlay.cpp#L4645
public void processVHWACommand(byte command, int enmCmd, boolean fromGuest) {
}
public boolean videoModeSupported(long arg0, long arg1, long arg2) {
return true;
}
}

View file

@ -0,0 +1,32 @@
package sznp.virtualcomputer;
import org.virtualbox_6_1.IEvent;
import sznp.virtualcomputer.util.COMObjectBase;
import sznp.virtualcomputer.util.IEventHandler;
/**
* A Bukkit-like event system which calls the appropriate methods on an event.
*/
public final class EventHandler extends COMObjectBase {
private final IEventHandler handler;
private boolean enabled = true;
/**
* New MSCOM event handler.
*
* @param handler The handle method that handles what needs to be handled
*/
public EventHandler(IEventHandler handler) {
this.handler = handler;
}
public final void handleEvent(IEvent iEvent) {
if (!enabled)
return;
handler.handleEvent(iEvent);
}
public void disable() {
enabled = false;
}
}

View file

@ -0,0 +1,10 @@
package sznp.virtualcomputer.util;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
public abstract class COMObjectBase extends Dispatch {
public COMObjectBase() {
super("clsid:{67099191-32E7-4F6C-85EE-422304C71B90}");
}
}

View file

@ -0,0 +1,52 @@
package sznp.virtualcomputer.util;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.*;
import lombok.val;
import org.virtualbox_6_1.*;
import org.virtualbox_6_1.mscom.Helper;
import org.virtualbox_6_1.mscom.IUnknown;
import sznp.virtualcomputer.COMFrameBuffer;
import sznp.virtualcomputer.EventHandler;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public final class COMUtils {
private COMUtils() {
}
//public static void registerListener(IEventSource source, IEventListener listener, VBoxEventType... types) {
public static org.virtualbox_6_1.IEventListener registerListener(IEventSource source, IEventHandler listener, List<VBoxEventType> types) {
//new DispatchEvents(source.getTypedWrapped(), listener);
val ret = new org.virtualbox_6_1.IEventListener(new EventHandler(listener));
/*com.jacob.activeX.ActiveXComponent.createNewInstance("IEventListener");
new ActiveXComponent("");
source.registerListener(ret, types, true);*/
//registerListener(source, new EventHandler(listener), types, true);
System.out.println("Testing listener...");
ret.handleEvent(null);
System.out.println("Tested");
return ret;
//return null;
}
@SuppressWarnings("unchecked")
public static <T extends IEvent> T getEvent(IEvent event, Class<T> cl) {
try {
val method = cl.getMethod("queryInterface", IUnknown.class);
return (T) method.invoke(null, event);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
public static IFramebuffer gimmeAFramebuffer(IMCFrameBuffer frameBuffer) {
return new IFramebuffer(new Variant(new COMFrameBuffer(frameBuffer)).getDispatch());
}
public static void queryBitmapInfo(IDisplaySourceBitmap bitmap, long[] ptr, long[] w, long[] h, long[] bpp, long[] bpl, long[] pf) {
Dispatch.call(bitmap.getTypedWrapped(), "queryBitmapInfo", ptr, w, h, bpp, bpl, pf);
}
}

View file

@ -0,0 +1,7 @@
package sznp.virtualcomputer.util;
import org.virtualbox_6_1.IEvent;
public interface IEventHandler {
void handleEvent(IEvent iEvent);
}

View file

@ -0,0 +1,9 @@
package sznp.virtualcomputer.util;
public interface IMCFrameBuffer {
void notifyUpdate(long x, long y, long width, long height);
void notifyUpdateImage(long x, long y, long width, long height, byte[] image);
void notifyChange(long screenId, long xOrigin, long yOrigin, long width, long height);
}

View file

@ -15,8 +15,7 @@
<packaging>pom</packaging> <packaging>pom</packaging>
<name>VirtualComputer</name> <name>VirtualComputer</name>
<!-- FIXME change it to the project's website --> <url>https://github.com/NorbiPeti/VirtualComputer</url>
<url>http://www.example.com</url>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@ -75,12 +74,12 @@
<version>1.12-R0.1-SNAPSHOT</version> <version>1.12-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <!-- Not using anything from here directly so we're not that dependent on versions --> <!-- <dependency> !- Not using anything from here directly so we're not that dependent on versions -
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId> <artifactId>spigot</artifactId>
<version>1.16.1-R0.1-SNAPSHOT</version> <version>1.16.1-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency> -->
</dependencies> </dependencies>
<build> <build>

Binary file not shown.

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>net.sf.jacob-project</groupId>
<artifactId>jacob</artifactId>
<version>1.19</version>
<description>POM was created from install:install-file</description>
</project>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>net.sf.jacob-project</groupId>
<artifactId>jacob</artifactId>
<versioning>
<release>1.19</release>
<versions>
<version>1.19</version>
</versions>
<lastUpdated>20200811112851</lastUpdated>
</versioning>
</metadata>