diff --git a/build.xml b/build.xml
index cdf9631..b26bb88 100644
--- a/build.xml
+++ b/build.xml
@@ -83,7 +83,7 @@
-
+
@@ -114,11 +114,8 @@
-
-
-
diff --git a/nbproject/project.properties b/nbproject/project.properties
index 9681f1d..2aa0443 100644
--- a/nbproject/project.properties
+++ b/nbproject/project.properties
@@ -116,4 +116,4 @@ run.test.modulepath=\
${javac.test.modulepath}
source.encoding=UTF-8
src.dir=src
-test.src.dir=test
+test.src.dir=test
\ No newline at end of file
diff --git a/src/jdiskmark/App.java b/src/jdiskmark/App.java
index 5176eea..24edbf3 100644
--- a/src/jdiskmark/App.java
+++ b/src/jdiskmark/App.java
@@ -95,7 +95,21 @@ public enum Mode { CLI, GUI }
// benchmarks and operations
public static HashMap benchmarks = new HashMap<>();
public static HashMap operations = new HashMap<>();
+ //Cli Mode
+ public static boolean isCliMode = false;
+ public static boolean isWindows() {
+ return os != null && os.toLowerCase().contains("win");
+ }
+
+ public static boolean isLinux() {
+ return os != null && os.toLowerCase().contains("linux");
+ }
+
+ public static boolean isMac() {
+ return os != null && os.toLowerCase().contains("mac");
+ }
+
/**
* @param args the command line arguments
*/
@@ -160,29 +174,59 @@ public static String getVersion() {
/**
* Initialize the GUI Application.
*/
+ /**
+ * Initialize the GUI Application.
+ */
public static void init() {
-
+
+ // ========= SAFE ELEVATION CHECK (NETBEANS + EXE/JAR) ============
+ if (!UtilOs.isProcessElevated()) {
+
+ // Detect if running inside NetBeans (dev mode)
+ String classPath = System.getProperty("java.class.path");
+ boolean runningInNetBeans =
+ classPath != null && classPath.toLowerCase().contains("netbeans");
+
+ if (!runningInNetBeans) {
+ // Only elevate when running as packaged JAR/EXE
+ System.out.println("Restarting JDiskMark with Administrator privileges...");
+ UtilOs.restartAsAdmin();
+ return;
+ } else {
+ System.out.println("Running inside NetBeans — skipping elevation.");
+ }
+ }
+ // ================================================================
+
+
os = System.getProperty("os.name");
arch = System.getProperty("os.arch");
- processorName = Util.getProcessorName();
- jdk = Util.getJvmInfo();
-
+
+ // Processor name based on OS
+ if (os.startsWith("Windows")) {
+ processorName = UtilOs.getProcessorNameWindows();
+ } else if (os.startsWith("Mac OS")) {
+ processorName = UtilOs.getProcessorNameMacOS();
+ } else if (os.contains("Linux")) {
+ processorName = UtilOs.getProcessorNameLinux();
+ }
+
checkPermission();
if (!APP_CACHE_DIR.exists()) {
APP_CACHE_DIR.mkdirs();
}
-
+
if (mode == Mode.GUI) {
loadConfig();
}
-
+
// initialize data dir if necessary
if (locationDir == null) {
locationDir = new File(System.getProperty("user.home"));
dataDir = new File(locationDir.getAbsolutePath()
+ File.separator + DATADIRNAME);
}
-
+
if (mode == Mode.GUI) {
Gui.configureLaf();
Gui.mainFrame = new MainFrame();
@@ -193,25 +237,19 @@ public static void init() {
Gui.mainFrame.setLocationRelativeTo(null);
Gui.progressBar = Gui.mainFrame.getProgressBar();
}
-
+
if (App.autoSave) {
- // configure the embedded DB in .jdm
System.setProperty("derby.system.home", APP_CACHE_DIR_NAME);
loadBenchmarks();
}
if (mode == Mode.GUI) {
- // load current drive
Gui.updateDiskInfo();
Gui.mainFrame.setVisible(true);
- // save configuration on exit...
- Runtime.getRuntime().addShutdownHook(new Thread() {
- @Override
- public void run() { App.saveConfig(); }
- });
+ Runtime.getRuntime().addShutdownHook(new Thread(App::saveConfig));
}
}
-
+
public static void checkPermission() {
String osName = System.getProperty("os.name");
if (osName.contains("Linux")) {
diff --git a/src/jdiskmark/Benchmark.java b/src/jdiskmark/Benchmark.java
index 86f9c21..d1d606b 100644
--- a/src/jdiskmark/Benchmark.java
+++ b/src/jdiskmark/Benchmark.java
@@ -1,4 +1,3 @@
-
package jdiskmark;
import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -27,6 +26,8 @@
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.EnumType;
import java.util.UUID;
/**
@@ -184,6 +185,37 @@ public void serialize(UUID value, JsonGenerator gen, SerializerProvider serializ
BenchmarkType benchmarkType;
public BenchmarkType getBenchmarkType() { return benchmarkType; }
+ public enum CachePurgeMethod {
+ NONE,
+ DROP_CACHE,
+ SOFT_PURGE;
+
+ @Override
+ public String toString() {
+ return switch (this) {
+ case DROP_CACHE -> "Drop Cache (OS Flush)";
+ case SOFT_PURGE -> "Soft Purge (Read-Through)";
+ case NONE -> "None";
+ };
+ }
+ }
+
+ // ---------------------------------------------------
+ // Cache purge metadata (for read-after-write benchmarks)
+ // ---------------------------------------------------
+ @Column
+ boolean cachePurgePerformed;
+
+ @Column
+ long cachePurgeSizeBytes;
+
+ @Column
+ long cachePurgeDurationMs;
+
+ @Column
+ @Enumerated(EnumType.STRING)
+ CachePurgeMethod cachePurgeMethod;
+
// timestamps
@Convert(converter = LocalDateTimeAttributeConverter.class)
@Column(name = "startTime", columnDefinition = "TIMESTAMP")
@@ -194,7 +226,7 @@ public void serialize(UUID value, JsonGenerator gen, SerializerProvider serializ
@OneToMany(mappedBy = "benchmark", cascade = CascadeType.ALL, orphanRemoval = true)
- List operations;
+ List operations = new ArrayList<>();
public List getOperations() {
return operations;
@@ -252,16 +284,22 @@ public String toResultString() {
}
public Benchmark() {
- operations = new ArrayList<>();
startTime = LocalDateTime.now();
+ cachePurgePerformed = false;
+ cachePurgeSizeBytes = 0L;
+ cachePurgeDurationMs = 0L;
+ cachePurgeMethod = CachePurgeMethod.NONE;
appVersion = App.VERSION;
profileName = App.activeProfile.getName();
}
Benchmark(BenchmarkType type) {
- operations = new ArrayList<>();
startTime = LocalDateTime.now();
benchmarkType = type;
+ cachePurgePerformed = false;
+ cachePurgeSizeBytes = 0L;
+ cachePurgeDurationMs = 0L;
+ cachePurgeMethod = CachePurgeMethod.NONE;
appVersion = App.VERSION;
profileName = App.activeProfile.getName();
}
@@ -295,7 +333,24 @@ public String getDuration() {
long diffMs = Duration.between(startTime, endTime).toMillis();
return String.valueOf(diffMs);
}
-
+
+ // cache purge getters (for UI / JSON)
+ public boolean isCachePurgePerformed() {
+ return cachePurgePerformed;
+ }
+
+ public long getCachePurgeSizeBytes() {
+ return cachePurgeSizeBytes;
+ }
+
+ public long getCachePurgeDurationMs() {
+ return cachePurgeDurationMs;
+ }
+
+ public CachePurgeMethod getCachePurgeMethod() {
+ return cachePurgeMethod;
+ }
+
// utility methods for collection
@JsonIgnore
@@ -333,7 +388,7 @@ static int delete(List benchmarkIds) {
.setParameter("benchmarkIds", benchmarkIds)
.executeUpdate();
- // delete the parent BenchmarkOperation records
+ // delete the parent Benchmark records
String deleteBenchmarksJpql = "DELETE FROM Benchmark b WHERE b.id IN :benchmarkIds";
int deletedBenchmarksCount = em.createQuery(deleteBenchmarksJpql)
.setParameter("benchmarkIds", benchmarkIds)
@@ -347,4 +402,4 @@ static int delete(List benchmarkIds) {
em.getTransaction().commit();
return deletedBenchmarksCount;
}
-}
\ No newline at end of file
+}
diff --git a/src/jdiskmark/BenchmarkWorker.java b/src/jdiskmark/BenchmarkWorker.java
index 5404030..5039f6c 100644
--- a/src/jdiskmark/BenchmarkWorker.java
+++ b/src/jdiskmark/BenchmarkWorker.java
@@ -64,6 +64,7 @@ public static int[][] divideIntoRanges(int startIndex, int endIndex, int numThre
protected Benchmark doInBackground() throws Exception {
if (App.verbose) {
+ msg(">>> USING CUSTOM PURGE BUILD (V1)");
msg("*** starting new worker thread");
msg("Running readTest " + App.isReadEnabled() + " writeTest " + App.isWriteEnabled());
msg("num samples: " + App.numOfSamples + ", num blks: " + App.numOfBlocks
@@ -238,13 +239,77 @@ protected Benchmark doInBackground() throws Exception {
App.wIops = wOperation.iops;
Gui.mainFrame.refreshWriteMetrics();
}
+
+ System.out.println(">>> BenchmarkWorker: ENTERING CACHE PURGE SECTION");
+
+ // ------------------------------------------------------------
+ // Cache Purge Step (only for Read-after-Write scenario)
+ // ------------------------------------------------------------
+ if (App.isWriteEnabled() && App.isReadEnabled() && !isCancelled()) {
+
+ long purgeStartNs = System.nanoTime();
+ benchmark.cachePurgePerformed = true;
+ benchmark.cachePurgeMethod = App.isAdmin
+ ? Benchmark.CachePurgeMethod.DROP_CACHE
+ : Benchmark.CachePurgeMethod.SOFT_PURGE;
+
+ // Detect purge size roughly equal to the full test data footprint
+ long estimatedBytes = (long) App.numOfSamples * (long) App.numOfBlocks *
+ ((long) App.blockSizeKb * 1024L);
+ benchmark.cachePurgeSizeBytes = estimatedBytes;
+
+ Gui.msg("⚡ Starting cache purge (" + benchmark.cachePurgeMethod +
+ ", ~" + (estimatedBytes / (1024*1024)) + " MB)");
+
+ if (App.isAdmin) {
+ // ==========================
+ // ADMIN MODE: Use drop-cache
+ // ==========================
+
+ System.out.println(">>> BenchmarkWorker: ADMIN purge path selected");
+ System.out.println(">>> BenchmarkWorker: Calling UtilOs.dropOsCache() ...");
+
+ try {
+ boolean ok = UtilOs.dropOsCache();
+
+ System.out.println(">>> BenchmarkWorker: dropOsCache() returned = " + ok);
+
+ if (!ok) {
+ System.out.println(">>> BenchmarkWorker: dropOsCache FAILED — fallback to SOFT purge");
+ Gui.msg("⚠ drop-cache failed — switching to soft purge.");
+
+ System.out.println(">>> BenchmarkWorker: Starting SOFT purge (fallback)");
+ Util.readPurge(estimatedBytes, pct -> setProgress(Math.min(99, pct)));
+ System.out.println(">>> BenchmarkWorker: Soft purge completed.");
+ }
+ } catch (Exception ex) {
+ System.out.println(">>> BenchmarkWorker: EXCEPTION in dropOsCache — fallback to read purge");
+ ex.printStackTrace();
+ Gui.msg("⚠ Exception during drop-cache, fallback to read purge.");
+ Util.readPurge(estimatedBytes, pct -> setProgress(Math.min(99, pct)));
+ }
- // TODO: review renaming all files to clear catch
- if (App.isReadEnabled() && App.isWriteEnabled() && !isCancelled()) {
- // TODO: review refactor to App.dropCache() & Gui.dropCache()
- Gui.dropCache();
+ } else {
+ // ==========================
+ // USER MODE: Soft purge
+ // ==========================
+ System.out.println(">>> BenchmarkWorker: Starting SOFT purge (readPurge)");
+ Gui.msg("Performing soft cache purge (read-through)…");
+
+ Util.readPurge(estimatedBytes, pct -> setProgress(Math.min(99, pct)));
+
+ System.out.println(">>> BenchmarkWorker: Soft purge completed.");
+ }
+
+ long purgeEndNs = System.nanoTime();
+ long purgeDurationMs = (purgeEndNs - purgeStartNs) / 1_000_000L;
+
+ benchmark.cachePurgeDurationMs = purgeDurationMs;
+
+ Gui.msg("✔ Purge finished in " + purgeDurationMs + " ms");
}
+
if (App.isReadEnabled()) {
BenchmarkOperation rOperation = new BenchmarkOperation();
rOperation.setBenchmark(benchmark);
@@ -369,7 +434,11 @@ protected void process(List sampleList) {
case Sample.Type.WRITE -> Gui.addWriteSample(s);
case Sample.Type.READ -> Gui.addReadSample(s);
}
- });
+ });
+ if (App.isCliMode) {
+ int pct = this.getProgress();
+ printCliProgress(pct);
+ }
}
@Override
@@ -380,4 +449,17 @@ protected void done() {
App.state = App.State.IDLE_STATE;
Gui.mainFrame.adjustSensitivity();
}
+
+ private void printCliProgress(int pct) {
+ int bars = pct / 5; // 20-bar progress
+ int spaces = 20 - bars;
+
+ String bar = "[" + "#".repeat(bars) + "-".repeat(spaces) + "] " + pct + "%";
+
+ System.out.print("\r" + bar);
+
+ if (pct >= 100) {
+ System.out.println();
+ }
+ }
}
diff --git a/src/jdiskmark/Gui.java b/src/jdiskmark/Gui.java
index 89c18f7..972a8aa 100644
--- a/src/jdiskmark/Gui.java
+++ b/src/jdiskmark/Gui.java
@@ -49,6 +49,11 @@ public static enum Palette { CLASSIC, BLUE_GREEN, BARD_COOL, BARD_WARM };
public static XYLineAndShapeRenderer bwRenderer;
public static XYLineAndShapeRenderer msRenderer;
+ public static void msg(String s) {
+ App.msg(s);
+ }
+
+
/**
* Setup the look and feel
*/
@@ -298,6 +303,7 @@ static public void updateDiskInfo() {
* GH-2 need solution for dropping catch
*/
static public void dropCache() {
+ App.msg(">>> Dropping OS cache...");
String osName = System.getProperty("os.name");
if (osName.contains("Linux")) {
if (App.isRoot) {
diff --git a/src/jdiskmark/RunBenchmarkCommand.java b/src/jdiskmark/RunBenchmarkCommand.java
index 227fa24..0d09303 100644
--- a/src/jdiskmark/RunBenchmarkCommand.java
+++ b/src/jdiskmark/RunBenchmarkCommand.java
@@ -76,6 +76,9 @@ public Integer call() {
return 0; // Return 0 (Success) immediately after help is printed
}
try {
+
+ App.isCliMode = true;
+
// 1. Apply CLI parameters to the global App state
App.setLocationDir(locationDir);
App.benchmarkType = benchmarkType;
diff --git a/src/jdiskmark/RunDetailsPanel.java b/src/jdiskmark/RunDetailsPanel.java
new file mode 100644
index 0000000..2351e97
--- /dev/null
+++ b/src/jdiskmark/RunDetailsPanel.java
@@ -0,0 +1,63 @@
+package jdiskmark;
+
+import java.awt.GridLayout;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.border.TitledBorder;
+
+public class RunDetailsPanel extends JPanel {
+
+ private final JLabel modeLabel = new JLabel("-");
+ private final JLabel samplesLabel = new JLabel("-");
+ private final JLabel blocksLabel = new JLabel("-");
+ private final JLabel threadsLabel = new JLabel("-");
+ private final JLabel avgLabel = new JLabel("-");
+ private final JLabel minMaxLabel = new JLabel("-");
+ private final JLabel accLabel = new JLabel("-");
+
+ // --- NEW purge metadata labels ---
+ private final JLabel purgeMethodLabel = new JLabel("-");
+ private final JLabel purgeSizeLabel = new JLabel("-");
+ private final JLabel purgeDurationLabel = new JLabel("-");
+
+ public RunDetailsPanel() {
+ setLayout(new GridLayout(0, 2));
+ setBorder(new TitledBorder("Run Details"));
+
+ add(new JLabel("Mode:")); add(modeLabel);
+ add(new JLabel("Samples:")); add(samplesLabel);
+ add(new JLabel("Blocks:")); add(blocksLabel);
+ add(new JLabel("Threads:")); add(threadsLabel);
+ add(new JLabel("Avg Speed (MB/s):")); add(avgLabel);
+ add(new JLabel("Min/Max (MB/s):")); add(minMaxLabel);
+ add(new JLabel("Access Time (ms):")); add(accLabel);
+
+ // --- PURGE METADATA ---
+ add(new JLabel("Purge Method:")); add(purgeMethodLabel);
+ add(new JLabel("Purge Size (MB):")); add(purgeSizeLabel);
+ add(new JLabel("Purge Duration (ms):")); add(purgeDurationLabel);
+ }
+
+ /**
+ * Populate details for a selected benchmark operation.
+ *
+ * @param op the BenchmarkOperation to load into the panel
+ */
+ public void load(BenchmarkOperation op) {
+ if (op == null) return;
+
+ Benchmark b = op.getBenchmark();
+
+ modeLabel.setText(op.getModeDisplay());
+ samplesLabel.setText(String.valueOf(op.numSamples));
+ blocksLabel.setText(op.getBlocksDisplay());
+ threadsLabel.setText(String.valueOf(op.numThreads));
+ avgLabel.setText(String.valueOf(op.bwAvg));
+ minMaxLabel.setText(op.getBwMinMaxDisplay());
+ accLabel.setText(op.getAccTimeDisplay());
+
+ purgeMethodLabel.setText(b.cachePurgeMethod.toString());
+ purgeSizeLabel.setText(String.valueOf(b.cachePurgeSizeBytes / (1024 * 1024)));
+ purgeDurationLabel.setText(String.valueOf(b.cachePurgeDurationMs));
+ }
+}
diff --git a/src/jdiskmark/Util.java b/src/jdiskmark/Util.java
index abfa4b8..786a923 100644
--- a/src/jdiskmark/Util.java
+++ b/src/jdiskmark/Util.java
@@ -12,6 +12,11 @@
import java.util.List;
import java.util.Random;
import javax.swing.filechooser.FileSystemView;
+import java.io.RandomAccessFile;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.lang.management.ManagementFactory;
+import com.sun.management.OperatingSystemMXBean;
/**
* Utility methods for JDiskMark
@@ -41,6 +46,42 @@ static public boolean deleteDirectory(File path) {
return (path.delete());
}
+ public static void readPurge(long estimatedBytes, java.util.function.IntConsumer progressCallback) {
+ try {
+ int block = 1024 * 1024; // 1MB chunks
+ long toRead = Util.getRecommendedPurgeSize(estimatedBytes);
+
+ System.out.println(">>> Soft purge dynamic size = " + (toRead / (1024*1024)) + " MB");
+
+ byte[] buf = new byte[block];
+ long read = 0;
+
+ File f = App.testFile;
+
+ if (f != null && f.exists()) {
+ try (RandomAccessFile raf = new RandomAccessFile(f, "r")) {
+ while (read < toRead) {
+ int r = raf.read(buf, 0, block);
+ if (r == -1) break;
+
+ read += r;
+
+ // ✔ NEW: progress callback
+ int pct = (int)((read * 100) / toRead);
+ progressCallback.accept(pct);
+ }
+ }
+ }
+
+ } catch (Exception ex) {
+ Logger.getLogger(Util.class.getName())
+ .log(Level.WARNING, "Soft cache purge failed: " + ex.getMessage(), ex);
+
+ System.out.println(">>> Util.readPurge: EXCEPTION during soft purge");
+ ex.printStackTrace(System.out);
+ }
+ }
+
/**
* Returns a pseudo-random number between min and max, inclusive.
* The difference between min and max can be at most
@@ -63,6 +104,24 @@ public static int randInt(int min, int max) {
return randomNum;
}
+ public static long getRecommendedPurgeSize(long estimatedBytes) {
+ try {
+ OperatingSystemMXBean osBean =
+ (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
+
+ long totalRam = osBean.getTotalPhysicalMemorySize(); // system RAM in bytes
+ long twentyPercent = (long)(totalRam * 0.20); // use 20% of RAM
+ long minSafe = 128L * 1024 * 1024; // never below 128MB
+
+ long dynamicCap = Math.max(minSafe, twentyPercent);
+
+ return Math.min(estimatedBytes, dynamicCap);
+ } catch (Throwable t) {
+ // If anything fails, fall back to old 512MB cap
+ return Math.min(estimatedBytes, 512L * 1024 * 1024);
+ }
+ }
+
/*
* Not used kept here for reference.
*/
diff --git a/src/jdiskmark/UtilOs.java b/src/jdiskmark/UtilOs.java
index 0d8d26c..b72c40e 100644
--- a/src/jdiskmark/UtilOs.java
+++ b/src/jdiskmark/UtilOs.java
@@ -40,6 +40,101 @@ static public void readPhysicalDriveWindows() throws FileNotFoundException, IOEx
System.out.println("content " + Arrays.toString(content));
}
+ public static boolean isProcessElevated() {
+ try {
+ String groups = System.getProperty("user.name");
+ Process p = Runtime.getRuntime().exec("net session");
+ p.waitFor();
+ return p.exitValue() == 0;
+ } catch (Exception ex) {
+ return false;
+ }
+ }
+
+ public static void restartAsAdmin() {
+ try {
+ String os = System.getProperty("os.name").toLowerCase();
+
+ // -------------------------------------------------------------------
+ // WINDOWS
+ // -------------------------------------------------------------------
+ if (os.contains("win")) {
+
+ String javaBin = System.getProperty("java.home") + "\\bin\\java.exe";
+ String jarPath = new File(App.class.getProtectionDomain()
+ .getCodeSource().getLocation().toURI()).getPath();
+
+ String cmd = "powershell -Command \"Start-Process '" + javaBin +
+ "' -ArgumentList '-jar \"" + jarPath +
+ "\"' -Verb RunAs\"";
+
+ Runtime.getRuntime().exec(cmd);
+ System.exit(0);
+ return;
+ }
+
+ // -------------------------------------------------------------------
+ // MAC / LINUX
+ // -------------------------------------------------------------------
+ App.msg("⚠ Restart-as-admin is only supported on Windows.");
+ System.out.println(">>> restartAsAdmin(): unsupported OS = " + os);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ App.msg("Failed to restart as Admin.");
+ }
+ }
+
+ /**
+ * Attempts to purge the OS filesystem cache.
+ *
+ * OS Behavior Summary:
+ * ---------------------
+ * WINDOWS:
+ * - Admin user: uses EmptyStandbyList.exe to drop standby lists.
+ * - Non-admin: cannot drop OS cache; BenchmarkWorker falls back
+ * to soft purge (single-pass read).
+ *
+ * LINUX:
+ * - drop-cache requires root ("sync; echo 3 > /proc/sys/vm/drop_caches").
+ * - JDiskMark does NOT attempt privileged Linux cache purge.
+ * - Always falls back to soft purge.
+ *
+ * MACOS:
+ * - No supported user-mode drop-cache command.
+ * - Always falls back to soft purge.
+ *
+ * The caller (BenchmarkWorker) must detect user privilege and select
+ * either admin purge (Windows only) or soft purge.
+ */
+
+ public static boolean dropOsCache() {
+ System.out.println(">>> DROP CACHE CALLED inside UtilOs"); // DEBUG
+ try {
+ if (App.isWindows()) {
+ // Windows requires EmptyStandbyList.exe
+ File exe = new File(App.ESBL_EXE);
+ if (!exe.exists()) {
+ return false;
+ }
+ Process p = new ProcessBuilder(exe.getAbsolutePath(), "standbylist").start();
+ p.waitFor();
+ return true;
+ } else if (App.isLinux() || App.isMac()) {
+ // Attempt typical Linux drop cache
+ Process p = new ProcessBuilder("sync").start();
+ p.waitFor();
+ p = new ProcessBuilder("sudo", "sh", "-c", "echo 3 > /proc/sys/vm/drop_caches").start();
+ p.waitFor();
+ return true;
+ } else {
+ return false;
+ }
+ } catch (Exception ex) {
+ return false;
+ }
+ }
+
/**
* This method became obsolete with an updated version of windows 10.
* A newer version of the method is used.