I want to make some changes on active desktop wallpaper like adding watermark.
For that I need to get the path of the active wallpaper. Adding the watermark I can do.
This can be done using JNA library, but I can't access the file path.
The way to obtain the current desktop wallpaper could different based on the operating system, for windows 7 it can be obtained from following registry path,
HKEY_CURRENT_USER\Control Panel\Desktop\Wallpaper
to read the registry path you can use the method described in following question
read/write to Windows Registry using Java
As Low Flying Pelican and ee said,
HKEY_CURRENT_USER\Control Panel\Desktop
contains the key Wallpaper which has a pointer to the wallpaper. For the command prompt, you can use
reg query "HKEY_CURRENT_USER\Control Panel\Desktop" /v Wallpaper
to get the location, or using this for native java support:
Runtime.getRuntime().exec('reg query "HKEY_CURRENT_USER\Control Panel\Desktop" /v Wallpaper');
Using JNA library:
implementation("net.java.dev.jna:jna-platform:5.12.1")
I was able to get the current Wallpaper path like this (tested on Windows 11):
Java:
import com.sun.jna.platform.win32.*;
import com.sun.jna.platform.win32.WinReg.HKEYByReference;
public class Main {
public static final String REGISTRY_PATH = "Control Panel\\Desktop";
public static final String REGISTRY_Key = "WallPaper";
public static void main(String[] args) {
var hKey = new HKEYByReference();
var registryAccessResult = openRegistryKey(hKey);
validate(registryAccessResult);
var wallpaperPath = getWallpaperPath();
System.out.println(wallpaperPath);
}
public static int openRegistryKey(HKEYByReference hKey) {
return Advapi32.INSTANCE.RegOpenKeyEx(
WinReg.HKEY_CURRENT_USER,
REGISTRY_PATH,
0,
WinNT.KEY_READ,
hKey
);
}
public static void validate(int registryAccessResult) {
if (registryAccessResult != W32Errors.ERROR_SUCCESS) {
throw new Win32Exception(registryAccessResult);
}
}
public static String getWallpaperPath() {
return Advapi32Util.registryGetStringValue(
WinReg.HKEY_CURRENT_USER,
REGISTRY_PATH,
REGISTRY_Key
);
}
}
Kotlin:
const val REGISTRY_PATH = "Control Panel\\Desktop"
const val REGISTRY_Key = "WallPaper"
fun main() {
val hKey = HKEYByReference()
openRegistryKey(hKey).validate()
val wallpaperPath = getWallpaperPath()
println(wallpaperPath)
}
fun openRegistryKey(hKey: HKEYByReference) =
Advapi32.INSTANCE.RegOpenKeyEx(
WinReg.HKEY_CURRENT_USER,
REGISTRY_PATH,
0,
WinNT.KEY_READ,
hKey
)
fun RegistryAccessResult.validate() =
takeIf { it == W32Errors.ERROR_SUCCESS }
?: throw Win32Exception(this)
fun getWallpaperPath(): String =
Advapi32Util.registryGetStringValue(
WinReg.HKEY_CURRENT_USER,
REGISTRY_PATH,
REGISTRY_Key
)
You can also listen for wallpaper changes and get its new path:
waitForWallpaperChange(hKey).validate() // Waits until wallpaper is changed
val newWallpaper = getWallpaperPath()
fun waitForWallpaperChange(hKey: HKEYByReference) =
Advapi32.INSTANCE.RegNotifyChangeKeyValue(
hKey.value,
false,
WinNT.REG_NOTIFY_CHANGE_LAST_SET,
null,
false
)
Related
I have a smart contract deployed. Whenever I try to perform a transaction, the transaction starts, but that's it. The transaction never actually takes place (or "doesn't get mined" might be the right word).
For reference, my smart contract function has takes one parameter and gives no output. just stores it. It's not that complex.
I do have reason to believe this has something to do with the transaction manager that I have set and how it doesn't provide enough nonce for any miner to take into consideration, since that was one of the answers on another question. However, they never said what the method was to fix it. I tried my best to fix it using a static gasProvider in hopes that it might be enough.
I have two pieces of code below:
VoteContractDelegate - This is used by rest of the application to make requests.
VoteContractAccessor - This extends the contract class and is used to return remotecall requests.
Note: I am using the web3j library.
VoteContractDelegate
private const val TAG = "VoteContractDelegate"
class VoteContractDelegate() {
//-----------------------------------------------------------------------------contract-elements
// TODO: get this from data store
private val USER_PRIVATE_KEY =
"66c53799ee0c63f2564305e738ea7479d7aee84aed3aac4c01e54a7acbcc4d92"
private val ROPSTEN_INFURA_URL = "https://ropsten.infura.io/v3/c358089e1aaa4746aa50e61d4ec41c5c"
private val credentials = Credentials.create(USER_PRIVATE_KEY)
private lateinit var web3j: Web3j//--------------------------------------------works-as-intended
private lateinit var contract: VoteContractAccessor
// TODO: set correct value
private val gasPrice: BigInteger = Convert.toWei("40", Convert.Unit.GWEI).toBigInteger()
//this gas limit value is from deployment and has to be constant
private val gasLimit = BigInteger.valueOf(4000000)
private val gasProvider: ContractGasProvider = StaticGasProvider(gasPrice, gasLimit)
init {
instantiateWeb3J()
web3j.ethGetTransactionCount(credentials.address, DefaultBlockParameterName.LATEST)
initializeContract()
}
private fun instantiateWeb3J() {
Log.d(
TAG, try {
web3j = Web3j.build(HttpService(ROPSTEN_INFURA_URL))
"Connection Successful"
} catch (e: Exception) {
e.printStackTrace()
"Connection Unsuccessful, error : ${e.message}"
}
)
}
private fun initializeContract() {
Log.d(
TAG, try {
contract = VoteContractAccessor(
web3j,
RawTransactionManager(web3j, credentials, ChainIdLong.ROPSTEN),
newGasProvider, credentials
)
"Contract Initialized Successfully"
} catch (e: Exception) {
"Contract Initialization Error"
}
)
}
// TODO: this is the problem function...
fun casteVote(party: PartyEnum): String {
return try {
Log.d(TAG,"started casteVote")
/**
* this starts but never completes. No errors outputted.
* If you watch closely, You'll see a '9' inside the get.
* that is the timeout duration. This function times out
* before being executed. It keeps waiting for whole 9
* minutes and then outputs a timeout error
*/
"cost = " + (
contract
.putVote(party)
.sendAsync()
.get(9, TimeUnit.MINUTES)
.gasUsed
.toString()
)
/**
* returns null as a result.
*/
} catch (e: Exception) {
e.printStackTrace()
e.message.toString()
}
}
}
VoteContractAccessor:
private const val TAG = "VoteContractAccessor"
private const val CONTRACT_BINARY =
"608060405234801561001057600080fd5b506000600281905560038190556004556103be8061002f6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c8063449b6db21161005b578063449b6db2146100b8578063464d4a92146100db578063a483f4e1146100ee578063f5a31579146100f657600080fd5b8063068ea0eb146100825780630efcb43c1461008c57806342cff738146100a3575b600080fd5b61008a6100fe565b005b6004545b6040519081526020015b60405180910390f35b6100ab6101cb565b60405161009a9190610312565b3360009081526020819052604090205460ff16604051901515815260200161009a565b61008a6100e93660046102f9565b61022d565b600354610090565b600254610090565b3360009081526020819052604090205460ff16156101635760405162461bcd60e51b815260206004820152601b60248201527f596f75204861766520416c7265616479204265656e204164646564000000000060448201526064015b60405180910390fd5b336000818152602081905260408120805460ff191660019081179091558054808201825591527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf601805473ffffffffffffffffffffffffffffffffffffffff19169091179055565b6060600180548060200260200160405190810160405280929190818152602001828054801561022357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610205575b5050505050905090565b60048110801561023d5750600081115b6102af5760405162461bcd60e51b815260206004820152603960248201527f74686520676976656e206e756d62657220697320696e76616c6964206173207460448201527f6865206e756d626572206973206f7574206f662072616e676500000000000000606482015260840161015a565b80600114156102d057600280549060006102c88361035f565b919050555050565b80600214156102e957600380549060006102c88361035f565b600480549060006102c88361035f565b60006020828403121561030b57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156103535783516001600160a01b03168352928401929184019160010161032e565b50909695505050505050565b600060001982141561038157634e487b7160e01b600052601160045260246000fd5b506001019056fea264697066735822122036c7a6eb905bfb9bbcbf2436975878a32327f0fd4a8648f67281fd07be0ff4b064736f6c63430008070033"
private const val CONTRACT_ADDRESS = "0x84D46ba7aAac6221DF9038d3Ccf41F1cd46001aF"
class VoteContractAccessor(
private val web3obj: Web3j,
transactionManager: TransactionManager,
gasProvider: ContractGasProvider,
private val credentials: Credentials
) :
Contract(
CONTRACT_BINARY,
CONTRACT_ADDRESS,
web3obj,
transactionManager,
gasProvider
) {
//--------------------------------------------------------------------------------function-names
private val functionGetHasAlreadyVoted = "hasAlreadyVoted"
private val functionRegisterVote = "registerVote"
private val functionGetAddressValues = "getAddressValues"
private val functionGetPartyOneVotes = "getParty1Votes"
private val functionGetPartyTwoVotes = "getParty2Votes"
private val functionGetPartyThreeVotes = "getParty3Votes"
fun printBalance(): BigDecimal {
val balance =
Convert.fromWei(
web3obj.ethGetBalance(
credentials.address, DefaultBlockParameterName.LATEST
)
.send().balance.toString(),
Convert.Unit.ETHER
)
Log.d(TAG, "user balance = $balance")
return balance
}
fun putVote(party: PartyEnum): RemoteCall<TransactionReceipt> {
Log.d(TAG, "putVote\n\n\nstarted")
val function = Function(
functionRegisterVote,
listOf<Type<*>>(
Uint256(
when (party) {
PartyEnum.ONE -> 1
PartyEnum.TWO -> 2
PartyEnum.THREE -> 3
}
)
),
emptyList()
)
Log.d(TAG, "gas price = ${gasProvider.getGasPrice(functionRegisterVote)}")
return executeRemoteCallTransaction(function)
}
}
PartyEnum
enum class PartyEnum {
ONE, TWO, THREE
}
You can use the credentials provided if you want. It doesn't have any real ether anyway.
Instructions for if you want to look at the entire project...
if you want the entire project links, Github links -
Android studio project
Solidity project link
Once you open and run the android studio project, swipe right on the left side of the screen to open the drawer layout side menu (the navigation button for drawer layout doesn't work yet).
From there, open the contract interface option and then, you'll see the select party card on the top.
That is the function responsible for the voting transactions.
The back end for this card will be found in the directory named ui by the name ContractScreenFragment.
Then, somewhere at the top of that file you can find the onclick listener for the select party to vote card.
Here's what it would look like-
casteVoteButton.setOnClickListener {
viewModel.transactionCost.value = transactionInProgress
CoroutineScope(Dispatchers.IO).launch {
val cost = voteContractDelegate.casteVote(partyEnum)
Log.d(TAG, "transaction output:-\n$cost")
CoroutineScope(Dispatchers.Main).launch {
viewModel.transactionCost.value = cost
}
}
}
the rest of the functions have been mentioned above.
For a less complicated code, try checking the test button onclick listener at the end of the same file. That should be easier to understand.
That onclick listener is connected to the bottom card found inside the contract interface. you'll enter the gas price in Gwei in the edit text and then call the same function.
I would like to provide a search string for my program like:
cmd.execute("getDevices", "-h 1.2.3.4", "-p myPSW", "-u myUser", "-n red|blue&black,-nonprod");
I want to create predicates to search for hostNames that contain red OR blue AND Black, but NOT nonprod. It is unclear to me how to go about parsing this the logical operators along with the Strings in Picocli to create a Predicate. Is there a simple and Straight forward way to parse a String to a predicate?
My CLI is set up as follows:
#Command(name = "HostMagicCLI", mixinStandardHelpOptions = true,
version = "1.0",
description = "Do Stuff With Hosts"
,
subcommands = {TufinDevices.class}
)
public class HostMagicCLI implements Runnable {
public static void main(String[] args) {
CommandLine cmd = new CommandLine(new InterfaceMagicCLI());
cmd.setExecutionStrategy(new RunAll());
cmd.getHelpSectionMap().put(SECTION_KEY_COMMAND_LIST, new MyCommandListRenderer());
cmd.usage(System.out);
cmd.execute("getDevices", "-h1.2.3.4", "-p myPSW", "-u myUser", "-n red|blue&black");
}
#Override
public void run() {
System.out.println("Running..");
}
}
#Command(name = "getDevices", aliases = {"l"}, description = "SpecifyTufin Credentials", subcommands = {InterfaceCommand.class})
class TufinDevices implements Runnable {
.
.//Options to collect user,psw, host etc.
.
#CommandLine.Option(names = {"-n", "--n"}, split = ",", arity = "0..*", description = "Hostname Contains")
String[] hostNameContains;
private void filter(TufinDeviceCollection<TufinDevice> devices) {
if (hostNameContains != null) {
Predicate< ? super TufinDevice> deviceFilter = device -> Arrays.stream(hostNameContains)
.allMatch(input -> device.getHostName().toLowerCase().contains(input.toLowerCase()));
devices = devices.stream()
.sequential()
.filter(deviceFilter)
.collect(Collectors.toCollection(TufinDeviceCollection<TufinDevice>::new));
}
#Override
public void run() {
try {
TufinDeviceCollection<TufinDevice> FETCH_DEVICES = Tufin.FETCH_DEVICES(user.trim(), password.trim(), hostName.trim());
this.filter(FETCH_DEVICES);
} catch (IOException | NoSuchAlgorithmException | KeyManagementException | IPConverter.InvalidIPException ex) {
Logger.getLogger(TufinDevices.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I suspect you may want to use a library for parsing the string that the end user specifies as the filter expression (the -n parameter). It may be an idea to look at libraries like Spring Expression Language, OGNL, JXPath, there may be others. Alternatively, if it is easy to write such a filter in Groovy or BeanShell, these languages can be called from Java, so you can call that filter from the Java command.
CAUTION:
I notice the example passes parameter to the picocli parser like this:
cmd.execute("getDevices", "-h 1.2.3.4", "-p myPSW", "-u myUser", "-n red|blue&black,-nonprod");
This will probably give an error explaining that "there is no -p myPSW option defined".
In your testing, if you call the execute method directly, make sure to pass parameters separately like this:
cmd.execute("getDevices", "-h", "1.2.3.4", "-p", "myPSW", "-u", "myUser", "-n", "red|blue&black,-nonprod");
I have webapp in Vaadin Framework 8. I have Windows GUI app in C#.
The gui app is using WebBrowser component to display webapp. WebBrowser component is internally using IE11 core through ActiveX. I can successfully load and display the webapp in the gui app browser component.
I need to pass data from webapp to the gui app.
The webapp has many rows loaded on server side, only few are displayed in grid. I want to pass all data from webapp to gui app in some format (csv or json).
I have tryed some approaches, but I wasn't successfull.
[Approach 1]
Webapp: attach downloadable resource (csv) to Link with predefined id using FileDownloader. Download by user mouse click works fine, file save dialog pops up and data are downloaded successfully.
Link link = new Link("Data");
link.setId("myId");
StreamResource resource = getMyResource(data);
FileDownloader downloader = new FileDownloader(resource);
downloader.extend(link);
Page.getCurrent().getJavaScript().addFunction("test", new JavaScriptFunction() {
#Override
public void call(JsonArray arguments) {
Page.getCurrent().getJavaScript()
.execute("document.getElementById('myId').click()");
}
});
Gui app: raise onClick event on link and capture WebBrowser.FileDownload event, capture WebBrowser.Navigate event.
I have failed to raise onClick event from C# using:
HtmlElement el = webBrowser.Document.GetElementById("myId");
el.RaiseEvent("onClick");
el.InvokeMember("click");
webBrowser.Document.InvokeScript("document.getElementById('myId').click();", null);
webBrowser.Document.InvokeScript("test", null);
Result:
WebBrowser.FileDownload event doesn't work (is fired but can't capture url nor data), capture WebBrowser.Navigate event works partialy (can see resource url, but can't download data using byte[] b = new WebClient().DownloadData(e.Url);).
[Approach 2]
Similar to approach 1. I tryed to get resource url, put the direct url to Link and download the resource in c# using direct link. I can construct the same resource url as is used by browser to download data when user clicks the link.
Extended file downloader that keeps resource, key and connector:
public class ExtendedFileDownloader extends FileDownloader {
private String myKey;
private Resource myResource;
private ClientConnector myConnector;
public ExtendedFileDownloader(StreamResource resource, ClientConnector connector) {
super(resource);
myConnector = connector;
}
#Override
protected void setResource(String key, Resource resource) {
super.setResource(key, resource);
myKey = key;
myResource = resource;
}
public String getResourceUrl() {
ResourceReference ref =
ResourceReference.create(
myResource,
(myConnector != null) ? myConnector : this,
myKey);
String url = ref.getURL();
return url;
}
}
In view:
// fix app://path... urls to /<base-path>/path urls
private String fixResourceReferenceUrl(String resourceReferenceUrl) {
String resourceReferencePath = resourceReferenceUrl.replace("app://", "");
String uiBaseUrl = ui.getUiRootPath();
String fixedUrl = uiBaseUrl + "/" + resourceReferencePath;
return fixedUrl;
}
Link link2 = new Link("Data2");
link2.setId("myId2");
StreamResource resource = getMyResource(data);
ExtendedFileDownloader downloader = new ExtendedFileDownloader(resource, this);
String fixedResourceUrl = fixResourceReferenceUrl(downloader.getResourceUrl());
link2.setResource(new ExternalResource(fixedResourceUrl));
Result:
The data cannot be downloaded using this link, server error 410 or NotFound errors.
Any Ideas ? Any other approaches to try ?
I have finally solved the problem. The solution is very close to approach 2.
The resource url is passed in element with custom attribute. C# WebClient needs to set cookies from WebBrowser and Referer HTTP headers. The data can be successfully downloaded by C# app.
Element attribute in vaadin webapp can be set using Vaadin-addon Attributes.
Cookies in C# app can be retrieved using this solution.
// Fix resource urls begining with app://
public String fixResourceReferenceUrl(String resourceReferenceUrl) {
try {
String uiRootPath = UI.getCurrent().getUiRootPath();
URI location = Page.getCurrent().getLocation();
String appLocation = new URIBuilder()
.setScheme(location.getScheme())
.setHost(location.getHost())
.setPort(location.getPort())
.setPath(uiRootPath)
.build()
.toString();
String resourceReferencePath = resourceReferenceUrl.replace("app://", "");
String fixedUrl = appLocation + "/" + resourceReferencePath;
return fixedUrl;
}
catch (Exception e) {
return null;
}
}
In view (using ExtendedFileDownloader from above):
Link link = new Link("Data");
link.setId("myId");
StreamResource resource = getMyResource(data);
ExtendedFileDownloader downloader = new ExtendedFileDownloader(resource);
downloader.extend(link);
Attribute attr = new Attribute("x-my-data", fixResourceReferenceUrl(downloader.getResourceUrl()));
attr.extend(link);
link.setVisible(true);
In C# app:
[DllImport("wininet.dll", SetLastError = true)]
public static extern bool InternetGetCookieEx(
string url,
string cookieName,
StringBuilder cookieData,
ref int size,
Int32 dwFlags,
IntPtr lpReserved);
private const Int32 InternetCookieHttponly = 0x2000;
public static String GetUriCookies(String uri)
{
// Determine the size of the cookie
int datasize = 8192 * 16;
StringBuilder cookieData = new StringBuilder(datasize);
if (!InternetGetCookieEx(uri, null, cookieData, ref datasize, InternetCookieHttponly, IntPtr.Zero))
{
if (datasize < 0)
return null;
// Allocate stringbuilder large enough to hold the cookie
cookieData = new StringBuilder(datasize);
if (!InternetGetCookieEx(
uri,
null, cookieData,
ref datasize,
InternetCookieHttponly,
IntPtr.Zero))
return null;
}
return cookieData.ToString();
}
private void button_Click(object sender, EventArgs e)
{
HtmlElement el = webBrowser.Document.GetElementById("myId");
String url = el.GetAttribute("x-my-data");
String cookies = GetUriCookies(url);
WebClient wc = new WebClient();
wc.Headers.Add("Cookie", cookies);
wc.Headers.Add("Referer", WEB_APP_URL); // url of webapp base path, http://myhost/MyUI
byte[] data = wc.DownloadData(url);
}
The Java app I am developing is an internal tool for others to use to help our daily activities. When the tool is used (on a JButton press which calls the code below) I want it to open a new Outlook EMail for the user to see/edit.
At first I was developing this app in a 64 bit Eclipse and could not get SWT to open Outlook despite all my research. After I had some issues running 64bit versus 32bit SWT, I had the idea to check Outlook, and sure enough the company using is 32 bit. I loaded up a 32 bit eclipse, imported my project, switch SWT to 32 bit and it worked exactly as intended.
I noticed the process that was running was javaw.exe*32 but the 64bit Eclipse was using the process javaw.exe. I exported the JAR from the 32bit Eclipse and gave it a shot and no EMail showed up. I checked the JRE's installed and saw both 32bit and 64bit but my company had a policy that forced only the 64bit JRE in the Java Control Panel. I worked with some others and got both installed and enabled as seen here. Still the JAR fails to open the EMail. I even tried disabling the 64bit and it still does not work.
Is there anything that can be done to remedy this situation? Please let me know if I can elaborate better or provide more info!
package EDM_PKG;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.ole.win32.OLE;
import org.eclipse.swt.ole.win32.OleAutomation;
import org.eclipse.swt.ole.win32.OleClientSite;
import org.eclipse.swt.ole.win32.OleFrame;
import org.eclipse.swt.ole.win32.Variant;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class CreateEmail {
private static Display display = new Display();
public static void sendEMail(String env) {
//String currUser = System.getProperty("user.name");
String msg = getMessage(env);
String sub = getSubject(env);
Shell shell = new Shell(display);
OleFrame frame = new OleFrame(shell, SWT.NONE);
// This should start outlook if it is not running yet
//OleClientSite site = new OleClientSite(frame, SWT.NONE,"OVCtl.OVCtl");
//site.doVerb(OLE.OLEIVERB_INPLACEACTIVATE);
// Now get the outlook application
OleClientSite site2 = new OleClientSite(frame, SWT.NONE, "Outlook.Application");
OleAutomation outlook = new OleAutomation(site2);
OleAutomation mail = invoke(outlook, "CreateItem", 0 /* Mail item */).getAutomation();
setProperty(mail, "BodyFormat", 2 /* HTML */);
setProperty(mail, "Subject", sub);
setProperty(mail, "To", "example#gmail.com");
setProperty(mail, "HtmlBody", msg);
invoke(mail, "Display" /* or "Send" */);
display = null;
}
private static String getMessage(String env) {
String msg = "";
if (env.equalsIgnoreCase("quas")) {
msg = "<html><body>The <b>USER</b> excel has been migrated to <b>QUAS.</b><br><br> This email was generated by Excel Datatable Migrator.</body></html>";
} else if (env.equalsIgnoreCase("prod")) {
msg = "<html><body>The <b>QUAS</b> excel has been migrated to <b>PROD.</b><br><br>This email was generated by Excel Datatable Migrator.</body></html>";
} else {
msg = "Somthing happened with the automated message of EDM. Please contact the user with the eCode: "+System.getProperty("user.name")+".</body></html>";
}
return msg;
}
private static String getSubject(String env) {
String sub = "";
if (env.equalsIgnoreCase("quas")) {
sub = "EDM has been used to move USER to QUAS...";
} else if (env.equalsIgnoreCase("prod")) {
sub = "EDM has been used to move QUAS to PROD...";
} else {
sub = "Somthing didnt quite work right...";
}
return sub;
}
private static OleAutomation getProperty(OleAutomation auto, String name) {
Variant varResult = auto.getProperty(property(auto, name));
if (varResult != null && varResult.getType() != OLE.VT_EMPTY) {
OleAutomation result = varResult.getAutomation();
varResult.dispose();
return result;
}
return null;
}
private static Variant invoke(OleAutomation auto, String command,
String value) {
return auto.invoke(property(auto, command),
new Variant[] { new Variant(value) });
}
private static Variant invoke(OleAutomation auto, String command) {
return auto.invoke(property(auto, command));
}
private static Variant invoke(OleAutomation auto, String command, int value) {
return auto.invoke(property(auto, command),
new Variant[] { new Variant(value) });
}
private static boolean setProperty(OleAutomation auto, String name,
String value) {
return auto.setProperty(property(auto, name), new Variant(value));
}
private static boolean setProperty(OleAutomation auto, String name,
int value) {
return auto.setProperty(property(auto, name), new Variant(value));
}
private static int property(OleAutomation auto, String name) {
return auto.getIDsOfNames(new String[] { name })[0];
}
}
There's no need to use the heavyweight and difficult to use Ole classes.
If all you want is to send an email, just call this:
Program.launch("mailto:bla#blubb.com&subject=Subject&body=Message here");
This will work on all architectures and operating systems.
Background :
I started playing with Groovy recently and am trying to embed a groovy script engine in an eclipse plugin to let my customers develop their own GUI extensions inside my eclipse-based product. This is very similar to the success story published on codehaus's website.
Problem
The groovy script (let's call it "main_eclipse.groovy") run from the eclipse plugin by a GroovyScriptEngine throws when trying to load a groovy class ("SwtGuiBuilder"), with the following error :
BUG! Queuing new source whilst already iterating. Queued source is 'file:/home/nicolas/workspace/groovy-test/src/gui/SwtGuiBuilder.groovy'
Question
Did anyone run into the same problem ? How can it be fixed ?
Any help will be highly appreciated !
Some observations :
When using the groovy interpreter instead of a GroovyScriptEngine java object, I have no problem using my SwtGuiBuilder class (see script "main_groovy" here below).
My problem does not seem to be a classpath issue, since the file containing my SwtGuiBuilder class is mentioned in the thrown exception.
The error message is mentioned in two reported groovy bugs, GRECLIPSE-429 and GRECLIPSE-1037. I did not fully get the technicals details, but those bugs seemed to be related to performance issues when loading lots of classes, which is not relevant in my situation...
Details
SampleView.java
public class SampleView
{
public SampleView() { super(); }
public void createPartControl(Composite parent)
{
String groovyScript = null;
String [] groovyPath = null;
boolean shall_exit = false;
do
{ // ask user for params
GroovyLocationDialog groovyLocationDialog= new GroovyLocationDialog(parent.getShell() );
int return_code = groovyLocationDialog.open();
if ( return_code != Window.OK )
shall_exit = true;
else
{
groovyScript= groovyLocationDialog.getInputScriptName();
groovyPath = groovyLocationDialog.getInputScriptPath();
// run it
ScriptConnector scriptConnector = new ScriptConnector(parent);
try { scriptConnector.runGuiComponentScript( groovyPath, groovyScript); }
catch (Exception e) { e.printStackTrace(); }
System.out.println("script finished");
}
}
while ( ! shall_exit );
}
ScriptConnector.java
public class ScriptConnector
{
private String[] roots;
private Composite window;
private Binding binding;
public ScriptConnector( Composite window )
{
this.window = window;
Binding scriptenv = new Binding(); // A new Binding is created ...
scriptenv.setVariable("SDE", this);
scriptenv.setVariable("WINDOW", this.window); // ref to current window
this.binding = scriptenv;
}
public void runGuiComponentScript(final String[] groovyPath, final String scriptName)
{
GroovyScriptEngine gse = null;
this.roots = groovyPath;
try
{
// instanciating the script engine with current classpath
gse = new GroovyScriptEngine( roots, this.getClass().getClassLoader() );
gse.run(scriptName, binding); // ... and run specified script
}
catch (Exception e) { e.printStackTrace(); }
catch (Throwable t) { t.printStackTrace(); }
}
}
main_eclipse.groovy
package launcher;
import org.eclipse.swt.SWT
import org.eclipse.swt.widgets.*
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.RowLayout as Layout
// This import will fail...
import gui.SwtGuiBuilder;
WINDOW.layout = new Layout(SWT.VERTICAL);
def builder = new SwtGuiBuilder(WINDOW);
builder.Label ( style=SWT.NONE, text = 'Simple demo of Groovy and SWT')
builder.Button( style=SWT.PUSH, text = 'Click me' , action = { println "Click !" } )
SwtGuiBuilder.groovy
package gui;
import org.eclipse.swt.events.*
import org.eclipse.swt.widgets.Button
import org.eclipse.swt.widgets.Composite
import org.eclipse.swt.widgets.Label
class SwtGuiBuilder
{
private Composite _parent
public SwtGuiBuilder(Composite parent) { _parent = parent }
public void Button( style = SWT.PUSH, text= null, action = null )
{
def btn = new Button(_parent, style)
if ( text != null )
btn.text = text
if (action != null)
btn.addSelectionListener( new SelectionAdapter() { void widgetSelected( SelectionEvent event ) { action(); } } );
}
public void Label( style = SWT.NONE, text = '' )
{
def lbl = new Label(_parent, style)
lbl.text = text
}
}
main_groovy.groovy
package launcher;
import org.eclipse.swt.SWT
import org.eclipse.swt.widgets.*
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.RowLayout as Layout
// ... But this import is handled properly !
import gui.SwtGuiBuilder;
def display = new Display()
def WINDOW = new Shell(display)
WINDOW.text = 'Groovy / SWT Test';
WINDOW.layout = new Layout(SWT.VERTICAL);
def builder = new SwtGuiBuilder(WINDOW);
builder.Label ( style=SWT.NONE, text = 'Simple demo of Groovy and SWT')
builder.Button( style=SWT.PUSH, text = 'Click me' , action = { println "Ya clicked me !" } )
WINDOW.pack();
WINDOW.open();
while (!WINDOW.disposed) {
if (!WINDOW.display.readAndDispatch())
WINDOW.display.sleep();
}
Stack trace
BUG! Queuing new source whilst already iterating. Queued source is 'file:/home/nicolas/workspace/groovy-test/src/gui/SwtGuiBuilder.groovy'
at org.codehaus.groovy.control.CompilationUnit.addSource(CompilationUnit.java:460)
at org.codehaus.groovy.control.CompilationUnit.addSource(CompilationUnit.java:433)
at groovy.util.GroovyScriptEngine$ScriptClassLoader$3.findClassNode(GroovyScriptEngine.java:195)
at org.codehaus.groovy.control.ClassNodeResolver.resolveName(ClassNodeResolver.java:124)
at org.codehaus.groovy.control.ResolveVisitor.resolveToOuter(ResolveVisitor.java:863)
at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:377)
at org.codehaus.groovy.control.ResolveVisitor.visitClass(ResolveVisitor.java:1407)
at org.codehaus.groovy.control.ResolveVisitor.startResolving(ResolveVisitor.java:202)
at org.codehaus.groovy.control.CompilationUnit$1.call(CompilationUnit.java:713)
at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:1015)
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:647)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:596)
at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:279)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:258)
at groovy.util.GroovyScriptEngine$ScriptClassLoader.doParseClass(GroovyScriptEngine.java:247)
at groovy.util.GroovyScriptEngine$ScriptClassLoader.parseClass(GroovyScriptEngine.java:229)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:244)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:202)
at groovy.util.GroovyScriptEngine.loadScriptByName(GroovyScriptEngine.java:514)
at groovy.util.GroovyScriptEngine.createScript(GroovyScriptEngine.java:564)
at groovy.util.GroovyScriptEngine.run(GroovyScriptEngine.java:551)
My configuration :
Linux Ubuntu 14.04 x86
Groovy Version: 2.3.2
JVM: 1.7.0_55
Eclipse Kepler SR2 - Build 20140224-0627
Eclipse Groovy plugin v2.0.7
Instead of GroovyScriptEngine, I've used the GroovyShell class (groovy code below but easy enough to change back to java), CompilerConfiguration allows you to specify the classpath.
def config = new CompilerConfiguration(classpath: classpath)
def binding = new Binding()
def result = new GroovyShell(binding, config).evaluate("""
def foo='bar'
""")