I'm using the JNA to call the Windows API. I want to start a process (doesn't matter which) as a specific user. The two API calls I use are:
LogonUserW
CreateProcessAsUserW
LogonUserW succeeds, but CreateProcessAsUserW fails with Error 6. According to the Windows System Error Codes Doc, this corresponds to "ERROR_INVALID_HANDLE".
As far as I can tell, the only handle I pass in is the user handle. I don't see what could be wrong with that. According to the LogonUserW doc,
In most cases, the returned handle is a primary token that you can use in calls to the CreateProcessAsUser function. However, if you specify the LOGON32_LOGON_NETWORK flag, LogonUser returns an impersonation token that you cannot use in CreateProcessAsUser unless you call DuplicateTokenEx to convert it to a primary token.
However, I don't use LOGON32_LOGON_NETWORK.
Some of the struct parameters have handles, but I either pass NULL or they are populated by the API call instead of by me.
Here's the meat of my code:
final PointerByReference userPrimaryToken =
new PointerByReference();
System.out.printf(
"ptr.peer = %d\n",
Pointer.nativeValue(userPrimaryToken.getValue())
);
final boolean logonOk = MyWinBase.INSTANCE.LogonUserW(
toCString(<my-username>), // hidden
toCString("ANT"),
toCString(<my-password>), // hidden
/* This logon type is intended for batch servers, where
processes may be executing on behalf of a user without their
direct intervention. This type is also for higher
performance servers that process many plaintext
authentication attempts at a time, such as mail or web
servers.*/
WinBase.LOGON32_LOGON_BATCH,
WinBase.LOGON32_PROVIDER_DEFAULT,
userPrimaryToken
);
System.out.printf("ok = %b\n", logonOk);
System.out.printf(
"ptr.peer = %d\n",
Pointer.nativeValue(userPrimaryToken.getValue())
);
final STARTUPINFOW.ByReference startupInfoW =
new STARTUPINFOW.ByReference();
startupInfoW.cb = startupInfoW.size();
startupInfoW.lpReserved = Pointer.NULL;
startupInfoW.lpDesktop = Pointer.NULL;
startupInfoW.lpTitle = Pointer.NULL;
startupInfoW.dwFlags
= startupInfoW.dwX = startupInfoW.dwY
= startupInfoW.dwXSize = startupInfoW.dwYSize
= startupInfoW.dwXCountChars = startupInfoW.dwYCountChars
= startupInfoW.dwFillAttribute
= startupInfoW.wShowWindow
= 0;
startupInfoW.cbReserved2 = 0;
startupInfoW.lpReserved2 = Pointer.NULL;
startupInfoW.hStdInput = startupInfoW.hStdOutput
= startupInfoW.hStdError
= Pointer.NULL;
final PROCESS_INFORMATION.ByReference processInformation =
new PROCESS_INFORMATION.ByReference();
processInformation.hProcess = processInformation.hThread
= Pointer.NULL;
processInformation.dwProcessId = processInformation.dwThreadId
= 0;
final boolean createProcessOk = MyProcessThreadsApi.INSTANCE
.CreateProcessAsUserW(
userPrimaryToken.getPointer(),
toCString("C:\\Windows\\System32\\cmd.exe"),
// execute and terminate
toCString("/c whoami > whoami.txt"),
Pointer.NULL,
Pointer.NULL,
false,
WinBase.CREATE_UNICODE_ENVIRONMENT,
new PointerByReference(),
Pointer.NULL,
startupInfoW,
processInformation
);
System.out.printf("ok = %b\n", createProcessOk);
System.out.printf(
"dwProcessId = %d\n", processInformation.dwProcessId
);
System.out.printf(
"last err code = %d\n",
ErrHandlingApi.INSTANCE.GetLastError()
);
Here's my output:
ptr.peer = 0
ok = true
ptr.peer = 1040
ok = false
dwProcessId = 0
last err code = 6
Any suggestions?
Looking at this piece of code:
final PointerByReference userPrimaryToken = ...;
Online documentation says it represents a pointer to pointer, C notation void**
https://java-native-access.github.io/jna/4.2.1/com/sun/jna/ptr/PointerByReference.html
On documentation for LogonUser it expects a PHALDLE pointer to a HANDLE, which is similar to a pointer to pointer, since HANDLE is similar to pointer (it is declared as typedef void *HANDLE;).
https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-logonuserw
BOOL LogonUserW(
....
DWORD dwLogonProvider,
PHANDLE phToken
);
But in documentation to CreateProcessAsUser is specified that this function accepts a HANDLE, not a PHANDLE
https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessasuserw
BOOL CreateProcessAsUserW(
HANDLE hToken,
LPCWSTR lpApplicationName,
....
);
So I would expect you to pass rather getValue than getPointer. By using getPointer you get the pointer itself, which is most probably the pointer to pointer in your case. I don't know JNA, but expectances are from knowledge of WinAPI
final boolean createProcessOk = MyProcessThreadsApi.INSTANCE
.CreateProcessAsUserW(
userPrimaryToken.getValue(),
....
);
Related
We work with a serial device that is attached to a Mac on USB and need to configure the DTR/RTS-line settings. Technically this involves usage of open(3), ioctl(3).
We implemented this in C and it worked. Below is a very simplified snippet showing the core part.
Then we migrated the code to Java/JNA and run into the problem that the ported code did not work, though it is basically a line-by-line conversion of the C code.
The question is where do we go wrong?
Symptom of the failure in Java is errno=25 'Inappropriate ioctl for device' returned from the call to ioctl(). Since it works in C it seems that we do somwthing wrong in JNA.
What we did:
Checked the values from the header constants. Note that the C-code generates Java-compatible constant definitions that are used in the Java code.
Checked the signature of ioctl(). Seems to be right according to the man-page and include files.
Guessed that the problem is that the ioctl code for TIOCMSET is not properly passed since it is negative.
We use JNA 5.5.0.
Here comes the C code. The snippet simply reads the settings of the lines and writes them back unmodified for demo purposes. Here's the code (note the hard-coded device name).
int main(int argc, char **argv)
{
// Print constant values.
printf( "long TIOCMGET = 0x%x;\n", TIOCMGET );
printf( "long TIOCMSET = 0x%x;\n", TIOCMSET );
printf( "int O_RDWR = 0x%x;\n", O_RDWR );
printf( "int O_NDELAY = 0x%x;\n", O_NDELAY );
printf( "int O_NOCTTY = 0x%x;\n", O_NOCTTY );
int value = O_RDWR|O_NDELAY|O_NOCTTY;
printf( "value=%x\n", value );
int portfd = open("/dev/tty.usbmodem735ae091", value);
printf( "portfd=%d\n", portfd );
int lineStatus;
printf( "TIOCMGET %x\n", TIOCMGET );
int rc = ioctl( portfd, TIOCMGET, &lineStatus );
printf( "rc=%d, linestatus=%x\n", rc, lineStatus );
rc = ioctl( portfd, TIOCMSET, &lineStatus );
printf( "rc=%d, linestatus=%x\n", rc, lineStatus );
if ( rc == -1 )
printf( "Failure\n" );
else
printf( "Success\n" );
if ( portfd != -1 )
close( portfd );
return 0;
}
Output of the above is:
long TIOCMGET = 0x4004746a;
long TIOCMSET = 0x8004746d;
int O_RDWR = 0x2;
int O_NDELAY = 0x4;
int O_NOCTTY = 0x20000;
value=20006
portfd=3
TIOCMGET 4004746a
rc=0, linestatus=6
rc=0, linestatus=6
Success
Here's the Java implementation:
public class Cli
{
/**
* Java mapping for lib c
*/
public interface MacCl extends Library {
String NAME = "c";
MacCl INSTANCE = Native.load(NAME, MacCl.class);
int open(String pathname, int flags);
int close(int fd);
int ioctl(int fd, long param, LongByReference request);
String strerror( int errno );
}
private static final MacCl C = MacCl.INSTANCE;
private static PrintStream out = System.err;
public static void main( String[] argv )
{
long TIOCMGET = 0x4004746a;
long TIOCMSET = 0x8004746d;
int O_RDWR = 0x2;
int O_NDELAY = 0x4;
int O_NOCTTY = 0x20000;
int value = O_RDWR|O_NDELAY|O_NOCTTY;
out.printf( "value=%x\n", value );
int portfd = C.open(
"/dev/tty.usbmodem735ae091",
value );
out.printf( "portfd=%d\n", portfd );
LongByReference lineStatus = new LongByReference();
int rc = C.ioctl( portfd, TIOCMGET, lineStatus );
out.printf(
"rc=%d, linestatus=%d\n", rc, lineStatus.getValue() );
rc = C.ioctl( portfd, TIOCMSET, lineStatus );
out.printf(
"rc=%d errno='%s'\n",
rc,
C.strerror( Native.getLastError() ) );
if ( rc == -1 )
out.print( "Failure." );
else
out.print( "Success." );
if ( portfd != -1 )
C.close( portfd );
}
}
Java output is:
value=20006
portfd=23
rc=0, linestatus=6
rc=-1 errno='Inappropriate ioctl for device'
Failure.
A review of the ioctl.h header file for the commands you are using reveals that it expects an int as the third argument:
#define TIOCMSET _IOW('t', 109, int) /* set all modem bits */
#define TIOCMGET _IOR('t', 106, int) /* get all modem bits */
You correctly define a 4-byte int in your C code and pass a reference to it, which works:
int lineStatus;
int rc = ioctl( portfd, TIOCMGET, &lineStatus );
rc = ioctl( portfd, TIOCMSET, &lineStatus );
However, in your Java code, you define an 8-byte long reference to pass:
LongByReference lineStatus = new LongByReference();
int rc = C.ioctl( portfd, TIOCMGET, lineStatus );
rc = C.ioctl( portfd, TIOCMSET, lineStatus );
The "get" appears to work because the native code is only filling in 4 of the 8 bytes and it happens to be the low order bytes, but you may be corrupting the stack with the overallocation.
As #nyholku points out in the comments, in addition from switching from long to int you may need to pass the int (rather than the pointer) to the TIOCMSET version of the command. There is conflicting documentation but the examples I see in the wild favor your pointer implementation.
So your code should include:
IntByReference lineStatus = new IntByReference();
int rc = C.ioctl( portfd, TIOCMGET, lineStatus );
// Possible, per the page #nyholku linked:
rc = C.ioctl( portfd, TIOCMSET, lineStatus.getValue() );
// Probable, per the man pages and other examples:
rc = C.ioctl( portfd, TIOCMSET, lineStatus );
You do say the C version without the pointer "works" but only in the sense that it does not throw an error. To confirm what "works", you should read the bytes again to make sure whatever you set actually stuck.
We checked many times the third argument. Must a pointer be passed or not? The docs we found -- Man page man -s 4 tty on the Mac -- really documents to pass a pointer. So there seem to be differences between Unix implementations.
Finally we found the solution by printing the passed value using printf( "%xl", ... );. and the resulting value was 0xffffffff8004746d. So we got an unexpected sign extension.
And the problem is the line
long TIOCMSET = 0x8004746d;
The literal constant is defined as an int literal that gets implicitly converted to long with sign extension. Since 0xffffffff8004746d is not equal to 0x8004746d' this explains the error message inappropriate ioctl for device. When we changed the line above to
long TIOCMSET = 0x8004746dL; // Note the 'L' at the end.
everything worked perfectly. On other Unixes we did not have the problem because the TIO... constants happened to be positive.
I have written a SNMP listener in Java using the TNM4J library which uses the SNMP4J library.
The listener is able to read received traps, except for traps that appear to be indexed in a table.
The listener is listening to traps from an Ericsson object, which means I am using the ERICSSON-ALARM-MIB and the MIB imports it needs. The trap I am receiving is the eriAlarmActiveManagedObject with OID .1.3.6.1.4.1.193.183.4.1.3.5.1.5, but I also tested it locally with the other traps in the table and the same error occurs
If one looks at https://mibs.observium.org/mib/ERICSSON-ALARM-MIB/ :
All the traps that are from a table like this can not be read by the listener.
It gives an index out of bound exception from a extractIndexes method in MibbleIndexExtractor.java in the TNM4J library.
#Override
public IndexDescriptor[] extractIndexes(String instanceOid) {
String oid = symbol.getValue().toString();
String suboid = instanceOid.substring(oid.length() + 1);
int[] components = oidToArray(suboid);
int offset = 0;
IndexDescriptor[] descriptors = new IndexDescriptor[indexes.length];
for (int i = 0; i < indexes.length; i++) {
SnmpIndex index = indexes[i];
MibValueSymbol indexSymbol = symbol.getMib().getSymbolByOid(index.getValue().toString());
MibType indexType = ((SnmpObjectType) indexSymbol.getType()).getSyntax();
int length = fixedLength(indexType);
boolean implied = length != -1 || index.isImplied();
if (length == -1) {
length = variableLength(indexType, components, offset, index.isImplied());
}
int[] encoded = new int[length];
System.arraycopy(components, offset, encoded, 0, length);
descriptors[i] = new MibbleIndexDescriptor(indexSymbol, encoded, implied);
offset += length;
}
return descriptors;
}
I have debugged it and this happens because the oid String and instanceOid String are identical which of course causes an exception where the suboid String is being created.
However on all other traps it never calls this extractIndexes method, but just works finely and prints out the trap and oid name correctly.
Any suggestion on how to fix this issue?
After being in contact with the developer of TNM4J he made some fixes to his library.
After that the Ericsson oids was being correctly translated. There was a few missing translations from oids, which was because of the loading order of the MIBs.
Re-adjusting these made it work.
For anyone interested the troubleshooting process with the developer can view it here:
https://github.com/soulwing/tnm4j/issues/9
I am integrating window based application with java application and want to capture window events in java.
I found in google J-Interop is the library thorugh this can be achived.
i did some POC wih below code but facing issue while locating the service i.e WbemScripting.SWbemLocator
import java.io.IOException;
import java.util.logging.Level;
import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.common.JISystem;
import org.jinterop.dcom.core.JIComServer;
import org.jinterop.dcom.core.JIProgId;
import org.jinterop.dcom.core.JISession;
import org.jinterop.dcom.core.JIString;
import org.jinterop.dcom.core.JIVariant;
import org.jinterop.dcom.impls.JIObjectFactory;
import org.jinterop.dcom.impls.automation.IJIDispatch;
public class EventLogListener
{
private static final String WMI_DEFAULT_NAMESPACE = "ROOT\\CIMV2";
private static String domainName = "domain";
private static String userName="user";
private static String password="psswd";
private static String hostIP ="127.0.0.1";
private static JISession configAndConnectDCom( String domain, String user, String pass ) throws Exception
{
JISystem.getLogger().setLevel( Level.OFF );
try
{
JISystem.setInBuiltLogHandler( false );
}
catch ( IOException ignored )
{
;
}
// JISystem.setAutoRegisteration( true );
JISession dcomSession = JISession.createSession( domain, user, pass );
dcomSession.useSessionSecurity( true );
return dcomSession;
}
private static IJIDispatch getWmiLocator( String host, JISession dcomSession ) throws Exception
{
//HKEY_CLASSES_ROOT\CLSID\{76A64158-CB41-11D1-8B02-00600806D9B6}
//WbemScripting.SWbemLocator
JIComServer wbemLocatorComObj = new JIComServer( JIProgId.valueOf( "76A64158-CB41-11D1-8B02-00600806D9B6" ), host, dcomSession );
System.out.println("com objected created");
return (IJIDispatch) JIObjectFactory.narrowObject( wbemLocatorComObj.createInstance().queryInterface( IJIDispatch.IID ) );
}
private static IJIDispatch toIDispatch( JIVariant comObjectAsVariant ) throws JIException
{
return (IJIDispatch) JIObjectFactory.narrowObject( comObjectAsVariant.getObjectAsComObject() );
}
public static void main( String[] args )
{
String domain = domainName;//args[ 0 ];
String host = hostIP;//args[ 1 ];
String user = userName;//args[ 2 ];
String pass = password;//args[ 3 ];
JISession dcomSession = null;
try
{
// Connect to DCOM on the remote system, and create an instance of the WbemScripting.SWbemLocator object to talk to WMI.
dcomSession = configAndConnectDCom( domain, user, pass );
IJIDispatch wbemLocator = getWmiLocator( host, dcomSession );
// Invoke the "ConnectServer" method on the SWbemLocator object via it's IDispatch COM pointer. We will connect to
// the default ROOT\CIMV2 namespace. This will result in us having a reference to a "SWbemServices" object.
JIVariant results[] =
wbemLocator.callMethodA( "ConnectServer", new Object[] { new JIString( host ), new JIString( WMI_DEFAULT_NAMESPACE ),
JIVariant.OPTIONAL_PARAM(), JIVariant.OPTIONAL_PARAM(), JIVariant.OPTIONAL_PARAM(), JIVariant.OPTIONAL_PARAM(), new Integer( 0 ),
JIVariant.OPTIONAL_PARAM() } );
IJIDispatch wbemServices = toIDispatch( results[ 0 ] );
// Now that we have a SWbemServices DCOM object reference, we prepare a WMI Query Language (WQL) request to be informed whenever a
// new instance of the "Win32_NTLogEvent" WMI class is created on the remote host. This is submitted to the remote host via the
// "ExecNotificationQuery" method on SWbemServices. This gives us all events as they come in. Refer to WQL documentation to
// learn how to restrict the query if you want a narrower focus.
final String QUERY_FOR_ALL_LOG_EVENTS = "SELECT * FROM __InstanceCreationEvent WHERE TargetInstance ISA 'Win32_NTLogEvent'";
final int RETURN_IMMEDIATE = 16;
final int FORWARD_ONLY = 32;
JIVariant[] eventSourceSet =
wbemServices.callMethodA( "ExecNotificationQuery", new Object[] { new JIString( QUERY_FOR_ALL_LOG_EVENTS ), new JIString( "WQL" ),
new JIVariant( new Integer( RETURN_IMMEDIATE + FORWARD_ONLY ) ) } );
IJIDispatch wbemEventSource = (IJIDispatch) JIObjectFactory.narrowObject( ( eventSourceSet[ 0 ] ).getObjectAsComObject() );
// The result of the query is a SWbemEventSource object. This object exposes a method that we can call in a loop to retrieve the
// next Windows Event Log entry whenever it is created. This "NextEvent" operation will block until we are given an event.
// Note that you can specify timeouts, see the Microsoft documentation for more details.
System.out.println("listner statred");
while ( true )
{
System.out.println("vinod");
// this blocks until an event log entry appears.
JIVariant eventAsVariant = (JIVariant) ( wbemEventSource.callMethodA( "NextEvent", new Object[] { JIVariant.OPTIONAL_PARAM() } ) )[ 0 ];
IJIDispatch wbemEvent = toIDispatch( eventAsVariant );
// WMI gives us events as SWbemObject instances (a base class of any WMI object). We know in our case we asked for a specific object
// type, so we will go ahead and invoke methods supported by that Win32_NTLogEvent class via the wbemEvent IDispatch pointer.
// In this case, we simply call the "GetObjectText_" method that returns us the entire object as a CIM formatted string. We could,
// however, ask the object for its property values via wbemEvent.get("PropertyName"). See the j-interop documentation and examples
// for how to query COM properties.
JIVariant objTextAsVariant = (JIVariant) ( wbemEvent.callMethodA( "GetObjectText_", new Object[] { new Integer( 1 ) } ) )[ 0 ];
String asText = objTextAsVariant.getObjectAsString().getString();
System.out.println( asText );
}
}
catch ( Exception e )
{
e.printStackTrace();
}
finally
{
if ( null != dcomSession )
{
try
{
JISession.destroySession( dcomSession );
}
catch ( Exception ex )
{
ex.printStackTrace();
}
}
}
}
}
Error:
org.jinterop.dcom.common.JIException: The system cannot find the file specified. Please check the path provided as parameter. If this exception is being thrown from the WinReg package, please check if the library is registered properly or do so using regsvr32. [0x00000002]
at org.jinterop.winreg.smb.JIWinRegStub.winreg_OpenKey(JIWinRegStub.java:195)
at org.jinterop.dcom.core.JIProgId.getIdFromWinReg(JIProgId.java:129)
at org.jinterop.dcom.core.JIProgId.getCorrespondingCLSID(JIProgId.java:160)
at org.jinterop.dcom.core.JIComServer.<init>(JIComServer.java:428)
at com.stg.commons.behave.reporting.EventLogListener.getWmiLocator(EventLogListener.java:49)
at com.stg.commons.behave.reporting.EventLogListener.main(EventLogListener.java:81)
Caused by: org.jinterop.dcom.common.JIRuntimeException: The system cannot find the file specified. Please check the path provided as parameter. If this exception is being thrown from the WinReg package, please check if the library is registered properly or do so using regsvr32. [0x00000002]
at org.jinterop.winreg.IJIWinReg$openKey.read(IJIWinReg.java:938)
at ndr.NdrObject.decode(NdrObject.java:36)
at rpc.ConnectionOrientedEndpoint.call(ConnectionOrientedEndpoint.java:137)
at rpc.Stub.call(Stub.java:113)
at org.jinterop.winreg.smb.JIWinRegStub.winreg_OpenKey(JIWinRegStub.java:189)
... 5 more
This is the clue:
"If this exception is being thrown from the WinReg package, please
check if the library is registered properly or do so using regsvr32."
It seems the necessary library of your Windows application is not properly registered yet. From the command prompt (in admin mode), you can use regsvr32 to do that:
regsvr32 yourlib.dll
References:
There is a similar thread here
How to register a DLL using regsvr32 can be found here
Been stumped on this for a while and pulling what is left of my hair out.
Sending non-nested Protobufs from Python to Java and Java to Python without
an issue with WebSockets. My problem is sending a nested version over a WebSocket. I believe my issue is on
the Python encoding side.
Your guidance is appreciated.
.proto file
message Response {
// Reflect back to caller
required string service_name = 1;
// Reflect back to caller
required string method_name = 2;
// Who is responding
required string client_id = 3;
// Status Code
required StatusCd status_cd = 4;
// RPC response proto
optional bytes response_proto = 5;
// Was callback invoked
optional bool callback = 6 [default = false];
// Error, if any
optional string error = 7;
//optional string response_desc = 6;
}
message HeartbeatResult {
required string service = 1;
required string timestamp = 2;
required float status_cd = 3;
required string status_summary = 4;
}
A Heartbeat result is supposed to get sent in the reponse_proto field
of the Response Protobuf. I am able to do this in Java to Java but Python
to Java is not working.
I've included two variations of the python code. Neither of which works.
def GetHeartbeat(self):
print "GetHeartbeat called"
import time
ts = time.time()
import datetime
st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
heartbeatResult = rpc_pb2.HeartbeatResult()
heartbeatResult.service = "ALERT_SERVICE"
heartbeatResult.timestamp = st
heartbeatResult.status_cd = rpc_pb2.OK
heartbeatResult.status_summary = "OK"
response = rpc_pb2.Response()
response.service_name = ""
response.method_name = "SendHeartbeatResult"
response.client_id = "ALERT_SERVICE"
response.status_cd = rpc_pb2.OK
response.response_proto = str(heartbeatResult).encode('utf-8')
self.sendMessage(response.SerializeToString())
print "GetHeartbeat finished"
def GetHeartbeat2(self):
print "GetHeartbeat called"
import time
ts = time.time()
import datetime
st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
heartbeatResult = rpc_pb2.HeartbeatResult()
heartbeatResult.service = "ALERT_SERVICE"
heartbeatResult.timestamp = st
heartbeatResult.status_cd = rpc_pb2.OK
heartbeatResult.status_summary = "OK"
response = rpc_pb2.Response()
response.service_name = ""
response.method_name = "SendHeartbeatResult"
response.client_id = "ALERT_SERVICE"
response.status_cd = rpc_pb2.OK
response.response_proto = heartbeatResult.SerializeToString()
self.sendMessage(response.SerializeToString())
print "GetHeartbeat finished"
Errors on the Java server side are:
(GetHeartbeat) Protocol message end-group tag did not match expected tag
and
(GetHeartbeat2)
Message: [org.java_websocket.exceptions.InvalidDataException: java.nio.charset.MalformedInputException: Input length = 1
at org.java_websocket.util.Charsetfunctions.stringUtf8(Charsetfunctions.java:80)
at org.java_websocket.WebSocketImpl.deliverMessage(WebSocketImpl.java:561)
at org.java_websocket.WebSocketImpl.decodeFrames(WebSocketImpl.java:328)
at org.java_websocket.WebSocketImpl.decode(WebSocketImpl.java:149)
at org.java_websocket.server.WebSocketServer$WebSocketWorker.run(WebSocketServer.java:593)
Caused by: java.nio.charset.MalformedInputException: Input length = 1
at java.nio.charset.CoderResult.throwException(CoderResult.java:277)
at java.nio.charset.CharsetDecoder.decode(CharsetDecoder.java:798)
at org.java_websocket.util.Charsetfunctions.stringUtf8(Charsetfunctions.java:77)
Solution
Also posted this question on protobuf group
Credit to Christopher Head and Ilia Mirkin for providing input on the google group
https://groups.google.com/forum/#!topic/protobuf/Cp7zWiWok9I
response.response_proto = base64.b64encode(heartbeatResult.SerializeToString())
self.sendMessage(response.SerializeToString())
FYI, Ilia also suggested base64 encoding the entire message but this seems to be working at the moment.
Am trying to convert a VBScript to java using JACOB - Java COM bridge library.
'Create' method in VBScript accepts a [out] param in it's method and it sets it upon method execution and i couldn't figure out how to retrieve it back via JACOB.
VBScript in question:
Function CreateProcess(strComputer, strCommand)
Dim objWMIService, objProcess
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set objProcess = objWMIService.Get("Win32_Process")
errReturn = objProcess.Create (strCommand, Null, Null, intProcessID)
Set objWMIService = Nothing
Set objProcess = Nothing
CreateProcess = intProcessID
End Function
intProcessID is [out] param set after method execution. (Create API contract)
Converted java code(incomplete and modified slightly for demonstration):
public static void createProcess() {
String host = "localhost";
String connectStr = String
.format("winmgmts:{impersonationLevel=impersonate}!\\\\%s\\root\\CIMV2",
host);
ActiveXComponent axWMI = new ActiveXComponent(connectStr);
Variant vCollection = axWMI.invoke("get", new Variant("Win32_Process"));
Dispatch d = vCollection.toDispatch();
Integer processId = null;
int result = Dispatch.call(d, "Create", "notepad.exe", null, null, processId)
.toInt();
System.out.println("Result:" + result);
// WORKS FINE until here i.e. notepad launches properly, however processId still seems to be null. Following commented code is wrong - doesn't work
//Variant v = Dispatch.get(d, "processId"); // even ProcessId doesn't work
//int pId = v.getInt();
//System.out.println("process id:"
// + pId);
// what is the right way to get the process ID set by 'Create' method?
}
Would be great if you could provide some pointers or relevant code. Ask me more if needed. Thanks in advance.
Replacing
Integer processId = null;
with
Variant processId = new Variant(0, true);
should solve the problem. You should then have process ID of the notepad.exe process in the processId variant, and it can be fetched by
processId.getIntRef()