After being told in this question that my preferred solution was impossible, I'm now trying to implement a workaround. Instead of declaring my interface that inherits from IClosable in C++/CX, I'm declaring it in raw IDL. But that doesn't seem to work either.
I've created an IDL file FooSpace.idl containing
import "inspectable.idl";
import "Windows.Foundation.idl";
namespace FooSpace
{
[uuid(01234567-89AB-CDEF-FEDC-BA9876543210)]
[version(42)]
interface Foo : IInspectable requires Windows.Foundation.IClosable
{
}
}
and generate Windows Runtime metadata from it with
midlrt /nomidl /metadata_dir "C:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral" FooSpace.idl
The generated FooSpace.winmd looks alright when I disassemble it with ildasm -- in particular, Foo appears to inherit from IClosable in just the same way IInputStream does in the system-provided Windows.winmd.
However, when I try to use it from C++/CX -- not even implement it, just pretending for the time being that someone else has implemented it with WRL or whatever -- it doesn't seem to work. Here's my test C++/CX source file:
void works(Windows::Storage::Streams::IInputStream^ istream) {
Platform::IDisposable^ local = istream ;
}
void doesnt(FooSpace::Foo^ foo) {
Platform::IDisposable^ local = foo ;
}
which produces an error for Foo but not for IInputStream:
C:\cygwin\tmp>cl /nologo /c /ZW /FU FooSpace.winmd testit.cpp
testit.cpp
testit.cpp(5) : error C2440: 'initializing' : cannot convert from 'FooSpace::Foo ^' to 'Platform::IDisposable ^'
No user-defined-conversion operator available, or
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
What am I doing wrong here?
On the other hand the equivalent C# code seems to compile fine:
public class Whatever {
public static void Works(Windows.Storage.Streams.IInputStream istream) {
System.IDisposable local = istream ;
}
public static void AlsoWorks(FooSpace.Foo foo) {
System.IDisposable local = foo ;
}
}
If you add a call to mdmerge to your cmds it should work:
midlrt /nomidl /metadata_dir "C:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral" FooSpace.idl
mdmerge -metadata_dir "C:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral" -i "." -o "merged" -v -partial
cl /nologo /c /ZW /FU merged\FooSpace.winmd /EHsc testit.cpp
With the 'merged' winmd file I am able to compile code like:
namespace ClosableTest
{
ref class Test sealed
: FooSpace::Foo
{
public:
virtual ~Test()
{
FooSpace::Foo^ f = nullptr;
Platform::IDisposable^ d = f;
}
};
}
The original FooSpace.winmd file that is generated by midlrt references Windows.Foundation (C:\Windows\system32\WinMetadata\Windows.Foundation.winmd) while the mdmerge output references Windows (C:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral\Windows.winmd).
It is interesting that you were able to reference the mildrt-output winmd file in a c# project without problems because in the blog post How to reference C++ WRL Components from a .NET project Kevin Stumpf describes that he had some problem when not using mdmerge first.
Related
I have a project which i have made into a fatjar. Gradle pus this into the /build/libs
I have gone to this directory and invoked the fatjar with a file as a param.
steps
cd /build/libs
java -jar .jar --execute script.groovy
this launches the Main-Class - a launcher class that reads the args from command line.
however what you get as the file name is 'script.groovy' and thats intended to be from the same directory as i have the jar file
Inside the class /fatjar however if you look at
System.getProperty("user.dir")
or
Path path = FileSystems.getDefault().getPath(".").toAbsolutePath()
they all report the path as the projectRoot directory - and not where the jar itself was run from (/build/libs)
inside your class, inside the fatjar, how do you determine the directory where the fatjar actually is when invoked from the command line?
I struggled a bit on this as well. You can find some hints in StartupInfoLogger.java from spring. I am using 2.1.5 spring boot version.
Here is some sample code.
public class MyTestFatJarMainClass {
public static void main(String[] args) {
SpringApplication.run(MyTestFatJarMainClass.class, args);
// The needed code start below
// The class is MyTestFatJarMainClass.class, but it can be any class in your app
ApplicationHome home = new ApplicationHome(MyTestFatJarMainClass.class);
String path = (home.getSource() != null) ? home.getSource().getAbsolutePath() : "";
// Now you got the path, it contains the jar file itself.
System.out.println("DINDA " + s + " path " + path);
}
}
You could also read String property = System.getProperty("user.dir");
Check which one of them can be useful for you.
I'm trying to update a small Flex AS3 "project" consisting of one main file and an imported AS3 class. Unfortunately during compile I get the error 1120:Access of undefined property DEBUG. and the compilation fails. I've used mxmlc from Flex SDK 4.6 and Flash Builder 4.5 and get the same failure.
Flex isn't my strong suit so I hope someone can point out the error. From what I understand this source code compiled fine in 2011 using mxmlc.
Relevant code from the imported file:
package {
public class krpano_as3_interface {
public static var instance:krpano_as3_interface = null;
.
.
static public const STARTDEBUGMODE : int = 0xFF;
static public const DEBUG : int = 0;
And From the main AS3 file:
package {
.
import krpano_as3_interface;
public class soundinterface extends Sprite {
static public var krpano : krpano_as3_interface = null;
.
public function soundinterface() {
if (stage == null){
}else{
txt.htmlText = "krpano " + DEBUG::version + "\n\n" +
"<b>soundinterface plugin</b>" +
"\n\n(build " + DEBUG::builddate + ")";
}
}
If I rename or move the imported file the compiler complains that it is missing. The class where the constant DEBUG is defined should be being imported so why isn't it working?
The class where the constant DEBUG is defined should be being imported so why isn't it working?
Because they have nothing to do with each other.
DEBUG::version
and
static public const DEBUG : int = 0;
Are two unrelated parts of your code.
There are two hints in the syntax:
the :: name qualifier operator stands after a namespace, so whatever DEBUG is, it is a namespace, which the public static const is not (it's an int)
A property version is accessed. The public static const does not
have such a property.
What you are looking at is conditional compilation, which (among other things) allows you to specify values and pass them to the compiler to perform the compilation process.
You can also pass Strings and Numbers to the application and use them as inline constants
In your case, you want to define a version constant in the compiler arguments. Something like this:
-define+=DEBUG::version,"5"
This is probably because the version number is maintained by some build script (make, ant, whatever) and therefore passes this information to the compiler.
I highly recommend that you get in contact with the developer who worked on this project before to understand how the build process of this project is supposed to work.
I'm starting to get the hang of SWIG, and the latest version(v3.0) of SWIG seems to handle just about everything I need out of the box, including C++11 features, but I have hit a snag when it comes to using shared_ptr with my director classes.
I have been able to get shared_ptr to work with normal proxy classes great, but now on my directors, it seems to not be supported out of the box. It is giving me the auto-generated type like SWIGTYPE_p_std__shared_ptrT_MyDataType_t and is generating a broken interface because it isn't using the same types that the proxy classes use.
I have a simplified example of what I'm trying to do (run with swig -c++ -java Test.i on swig 3.0):
Test.i
%module(directors="1") test
%{
%}
%include <std_shared_ptr.i>
%shared_ptr(MyDataType)
class MyDataType {
public:
int value;
};
class NonDirectorClass {
public:
std::shared_ptr<MyDataType> TestMethod();
};
%feature("director") CallbackBaseClass;
class CallbackBaseClass {
public:
virtual ~CallbackBaseClass() {};
virtual std::shared_ptr<MyDataType> GetDataFromJava() {};
};
Basically what I'm going to be doing is extending the CallbackBaseClass in Java and I want to be able to pass around my shared_ptr wrapped types. The non-director class generates the shared_ptr types just fine. The director class proxy files get generated correctly, but the SwigDirector_ methods in the wrapper reference the incorrect types.
It seems like I could manually repair the files by changing the type of SWIGTYPE_p_std__shared_ptrT_MyDataType_t to MyDataType everywhere, but I'm hoping someone with more swig knowledge can answer the question so this can be generated correctly.
The best clue I have is here, but I'm still trying to figure out how to correctly use these type maps, especially for shared_ptr and not basic primitives.
UPDATE:
The documentation says:
Note: There is currently no support for %shared_ptr and the director feature.
Though it gives no indication as to why. I'd like to know if this is an impossibility with swig directors, if there is a good reason why not to use shared_ptr in directors. It seems like it makes sense to use the same types you use everywhere else. I hope the answer is it is still possible.
The latest version of the SWIG documentation now reads:
"There is somewhat limited support for %shared_ptr and the director feature and the degress of success varies among the different target languages. Please help to improve this support by providing patches with improvements."
To make your example work we seem to need to add four missing typemaps, directorin, directorout, javadirectorin and javadirectorout:
%module(directors="1") test
%include <std_shared_ptr.i>
%{
#include <memory>
#include <iostream>
%}
%shared_ptr(MyDataType)
%feature("director") CallbackBaseClass;
%typemap(javadirectorin) std::shared_ptr<MyDataType> "new $typemap(jstype, MyDataType)($1,true)";
%typemap(directorin,descriptor="L$typemap(jstype, MyDataType);") std::shared_ptr<MyDataType> %{
*($&1_type*)&j$1 = new $1_type($1);
%}
%typemap(javadirectorout) std::shared_ptr<MyDataType> "$typemap(jstype, MyDataType).getCPtr($javacall)";
%typemap(directorout) std::shared_ptr<MyDataType> %{
$&1_type tmp = NULL;
*($&1_type*)&tmp = *($&1_type*)&$input;
if (!tmp) {
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "Attempt to dereference null $1_type");
return NULL;
}
$result = *tmp;
%}
%inline %{
class MyDataType {
public:
int value;
};
class NonDirectorClass {
public:
std::shared_ptr<MyDataType> TestMethod() { return std::make_shared<MyDataType>(); }
};
class CallbackBaseClass {
public:
virtual ~CallbackBaseClass() {};
virtual std::shared_ptr<MyDataType> GetDataFromJava() = 0;
};
void frobinate(CallbackBaseClass& cb) {
std::cout << "In C++: " << cb.GetDataFromJava()->value << "\n";
}
%}
Even though you only ever use the directorout case in your sample the directorin typemap is still required to make the lookup in director_connect succeed, because it depends upon having the correct descriptor.
These four typemaps are equivilent to the in, javain and javaout typemaps in functionality, but reversed because of their role in directors.
They're not complete enough to handle all cases, but they work in your example. The $typemap call inside the descriptor needs a version of SWIG 3 newer than the one included in Ubuntu 14.04 - in the form I wrote it the only version I tested with was checked out from the trunk. You can write the descriptor by hand (which would just be descriptor="LMyDataType;"), but clearly that's less generic. The advantage of writing it as above is that it will handle %rename directives correctly too. This won't handle packages properly though either so you would have to write it manually again in that case too.
I was able to test and run the example, I added the following run.java:
public class run extends CallbackBaseClass {
public MyDataType GetDataFromJava() {
MyDataType val = new MyDataType();
val.setValue(123);
return val;
}
public static void main(String[] argv) {
System.loadLibrary("test");
run r = new run();
System.out.println("In Java: " + r.GetDataFromJava().getValue());
test.frobinate(r);
}
}
And compiled and ran it with:
~/swig-trunk/preinst-swig -Wall -c++ -java test.i
clang++-3.6 -stdlib=libc++ -Wall -Wextra -std=c++1y test_wrap.cxx -o libtest.so -I/usr/lib/jvm/default-java/include/ -I/usr/lib/jvm/default-java/include/linux -shared -fPIC
javac run.java
LD_LIBRARY_PATH=. java run
Which when ran gave:
In Java: 123
In C++: 123
I would guess that in the case of Java with shared_ptr+directors the subtleties around getting the descriptor right are probably the main blocker to having this "just work" out the box.
I am working for a large company that changes slowly. We are deploying to a Weblogic 10.2 environment, and are stuck with java 1.5. That is not a problem with GWT libraries, but the downloaded version of gwt-maps-3.0.2b.gwt22.jar we have pulled down was built with a 1.6 compiler. Does anyone know if a 1.5 built version is available?
Baring that, is it possible to rebuild with the 1.5 compiler, since the source is in the jar? If so, does anyone have a build script to do so?
-- Some additional info
We are trying to upgrade some existing code, This is the first error that they ran into offshore. The compile error tat they got was:
o Error: “class file has wrong version 50.0, should be 49.0”
I checked the jar file using the following method.
built the following program:
import java.io.*;
public class CheckVersion {
public static void main(String[] args) throws IOException {
for (int i=0; i < args.length; ++i) {
checkVersion(args[i]);
}
}
private static void checkVersion(String classFileName) throws IOException {
DataInputStream in = new DataInputStream(new FileInputStream(classFileName));
int magicNo = in.readInt();
if (magicNo != 0xCAFEBABE) {
System.err.println(classFileName + " is not a valid class file name");
return;
}
int minor = in.readUnsignedShort();
int major = in.readUnsignedShort();
System.out.println(classFileName + ": " + major +"." + minor);
in.close();
}
}
extracted the jar file eg. "jar xvf gwt-maps3-0.2b.jar"
ran the following command: "find . -name *.class | xargs java CheckVersion | cut -d':' -f2 | sort -u"
You have to download sources from google code :
http://code.google.com/p/gwt-google-maps-v3/source/checkout
-- No this does not work. All versions on the page were built with 1.6
I was able to resolve this by downloading the source, commenting out the #Override annotations which in 1.5 require that method in the parent have an implementation, and recompiling the module.
This code seems to compile fine in the IDE, but the command-line compiler (SDK 4.5 mxmlc.exe) reports "Parameter initializer unknown or is not a compile-time constant."
senocular gives a good explanation and a maybe-workaround, but I'm hoping for something more elegent (like a command-line instruction).
package {
public class Constants {
public static const CONSTANT : int = 0;
}
}
package {
public interface IInterface {
function foo( param : int = Constants.CONSTANT ) : void;
}
}
package
{
public class Concrete implements IInterface
{
public function foo(param:int=Constants.CONSTANT):void
{
}
}
}
According to Senocular, it's all about the compilation order. There's no explicit way to set this order.
You could define inline constants using the define compiler option to avoid this problem.
Another way would be to create a library containing the constants. Libraries are included before user classes.
To create a library use the component compiler:
compc -output lib\Constants.swf -source-path src -include-classes Constants
When compiling the application, include that library:
mxmlc -include-libraries lib\Constants.swf -- src\Main.as
Just don't forget to recompile the library when the constants change, or use a build script that takes care of that.
A short comment on the example code:
The interface doesn't need to use that constant, any value will do and have the same effect on implementing classes.
Programming AS3 - Interfaces
A method that implements such a function declaration must have a default parameter value that is a member of the same data type as the value specified in the interface definition, but the actual value does not have to match.