I am trying to bind a basic Objective-C library I have created to a Xamarin project. The .h file is:
#import <Foundation/Foundation.h>
#import UIKit;
#interface StarIOFunctions : NSObject {
}
+ (NSMutableData *)GetDataToSendToPrinter:(UIImage *)image;
#end
I have tried to create my binding with the following ApiDefinition:
using System;
using System.Drawing;
using MonoTouch.ObjCRuntime;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace BindingTake2
{
[BaseType (typeof (NSObject))]
interface StarIOFunctions {
[Export ("GetDataToSendToPrinter:image")]
NSMutableData GetDataToSendToPrinter (UIImage image);
}
}
Everything compiles, but when I run it in my application:
UIImage image = UIImage.FromBundle("image1.png");
StarIOFunctions functions = new StarIOFunctions ();
var output = functions.GetDataToSendToPrinter (image);
My application crashes with the following error:
Objective-C exception thrown. Name: NSInvalidArgumentException Reason: -[StarIOFunctions GetDataToSendToPrinter:image]: unrecognized selector sent to instance 0x7cdb50f0
Now, I think it has something to do with me sending an image, and not a pointer to the image - but I'm totally lost and can't work out what exactly I'm doing wrong.
It seems you're including the parameter names in the selector name, i.e.
[Export ("GetDataToSendToPrinter:image")]
should be:
[Export ("GetDataToSendToPrinter:")]
The last column ':' indicates that a parameter is needed - but you do not need to name it (in the selector) as the previous string should imply it.
Related
I've been trying to convert this WinRT interface from its C++ Origin Code, to C# based code:
IDL File:
namespace Windows.Internal.Security.Authentication.Web{
[version(1)]
[uuid(07650a66-66ea-489d-aa90-0dabc75f3567)]
interface ITokenBrokerInternalStatics : IInspectable {
HRESULT filler_GetTokenSilently();
HRESULT filler_GetSecureInputParameters();
HRESULT filler_ReportBackgroundCompletion();
HRESULT filler_FindAccount();
HRESULT filler_FindAccountForApp();
HRESULT filler_FindAccountForProvider();
HRESULT FindAllAccountsAsync(
[out][retval] Windows.Foundation.IAsyncOperation<Windows.Foundation.Collections.IVectorView<Windows.Security.Credentials.WebAccount > *> ** operation);
}
[version(1)]
[static(Windows.Internal.Security.Authentication.Web.ITokenBrokerInternalStatics, 1)]
[marshaling_behavior(agile)]
[threading(both)]
runtimeclass TokenBrokerInternal {
}
}
CPP File:
auto tokenBrokerStatics = get_activation_factory<TokenBrokerInternal, Windows::Foundation::IUnknown>();
auto statics = tokenBrokerStatics.as<ITokenBrokerInternalStatics>();
auto accounts = statics.FindAllAccountsAsync().get();
This is what I got so far:
using PInvoke;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Metadata;
using Windows.Internal.Security.Authentication.Web;
using Windows.Security.Credentials;
using GuidAttribute = System.Runtime.InteropServices.GuidAttribute;
namespace Windows.Internal.Security.Authentication.Web
{
[Version(1)]
[Guid("07650a66-66ea-489d-aa90-0dabc75f3567")]
[InterfaceType(ComInterfaceType.InterfaceIsIInspectable)]
public interface ITokenBrokerInternalStatics
{
Windows.Foundation.IAsyncOperation<IReadOnlyList<Windows.Security.Credentials.WebAccount>> FindAllAccountsAsync();
}
[Version(1)]
[MarshalingBehavior(MarshalingType.Agile)]
[Threading(ThreadingModel.Both)]
[Static(typeof(Windows.Internal.Security.Authentication.Web.ITokenBrokerInternalStatics), 1)]
public class TokenBrokerInternal { }
public static class TokenBrokerInternalAssist
{
public static ITokenBrokerInternalStatics GetTokenBrokerInternal()
{
var tokenBrokerStatics = WindowsRuntimeMarshal.GetActivationFactory(typeof(TokenBrokerInternal));
var statics = (ITokenBrokerInternalStatics)tokenBrokerStatics.ActivateInstance()
return statics;
}
}
}
However, I can't seem to get it to work despite my best efforts. Here's a couple of errors I've encountered while trying to get this working:
Casting Errors
Activation Factories Not Existing
Many Other Errors related to dumb mistakes
I'm pretty new at this WinRT stuff, but despite looking on multiple sites for answers to my problem, I've found myself at a dead-end, and I really just wanna convert this code to C# to avoid having to compile a C++ project twice to support Any CPU and the complicated compiling of my app. What am I doing wrong?
P.S. This is not a UWP app, so don't suggest WebAccountManager or anything UWP specific, please.
I have a main camera in my scene with a Sun Shafts (Script) ImageEffect on it.
(I'm using Medieval Environment asset.)
I'd like to disable this effect programmatically when main camera reaches a specific coordinate.
Here is my C# script's code:
using UnityEngine;
using System.Collections;
using System;
public class EnableComponents : MonoBehaviour
{
private SunShafts mySunShafts; //<<< Error CS0246 displays here (see below)
void Start ()
{
mySunShafts = GetComponent<SunShafts>();
}
void Update ()
{
foreach(Camera c in GameObject.FindObjectsOfType(typeof(Camera)))
{
if ((c.name == "Main Camera"))
{
if ((c.transform.position.x < -10))
{
mySunShafts.enabled = false;
}
}
}
}
Here is how SunShafts' code starts:
#script ExecuteInEditMode
#script RequireComponent (Camera)
#script AddComponentMenu ("Image Effects/Sun Shafts")
enum SunShaftsResolution {
Low = 0,
Normal = 1,
High = 2,
}
enum ShaftsScreenBlendMode {
Screen = 0,
Add = 1,
}
class SunShafts extends PostEffectsBase
{
public var resolution : SunShaftsResolution = SunShaftsResolution.Normal;
public var screenBlendMode : ShaftsScreenBlendMode = ShaftsScreenBlendMode.Screen;
...
...
...
When I try to debug the code, following errormessage displays:
"Error CS0246: The type or namespace name 'SunShafts' could not be found (are you missing a using directive or an assembly reference?) (CS0246) (Assembly-CSharp)"
Here you can see that SunShaft effect and the above written C# script belongs to the same camera. However (and this is my problem) the two scripts just "cannot see each other".
So what am I doing wrong? Why my C# script "cannot see" the Sun Shafts script written in JavaScript? How should I change my C# code to be able to disable the SunShafts effect on my camera in runtime?
======================== EDIT #1 ======================
C# script is already in Plugins folder:
and here is the errormessage:
===================== EDIT #2 ==============================
Here is the imported Standard Asset:
Now there's no problem with UnityStandardAssets.ImageEffects;
However I'm getting this error message:
Your code is missing the assembly import, therefore the compiler doesn't find the SunShaft class.
Place
using UnityStandardAssets.ImageEffects;
below
using System;
to import the assembly.
I want to enter the following command into the debugger
po [[UIWindow keyWindow] _autolayoutTrace]
How would I do that in Xamarin Studio?
Edit:
I saw this Objective-C code
NSLog(#"%#", [[UIWindow keyWindow] _autolayoutTrace]);
in programatically change autolayout on orientation change together with an interface definition for that.
// for debugging auto layout.
#interface UIWindow (AutoLayoutDebug)
+(UIWindow *)keyWindow;
-(NSString *)_autolayoutTrace;
#end
I'd like to know how this can be done in Xamarin iOS?
If you are using the unified API the solution posted by miguel.de.icaza doesn't work anymore, because you get
`ObjCRuntime.Messaging' is inaccessible due to its protection level
One has to use P/Invoke:
using System;
using System.Runtime.InteropServices;
using Foundation;
using UIKit;
using ObjCRuntime;
public static class UIViewAutolayoutTraceExtensions
{
[DllImport(Constants.ObjectiveCLibrary, EntryPoint="objc_msgSend")]
private static extern IntPtr IntPtr_objc_msgSend (IntPtr receiver, IntPtr selector);
public static NSString AutoLayoutTrace(){
return (NSString)Runtime.GetNSObject(IntPtr_objc_msgSend(UIApplication.SharedApplication.KeyWindow.Handle, new Selector ("_autolayoutTrace").Handle));
}
public static NSString RecursiveDescription(){
return (NSString)Runtime.GetNSObject(IntPtr_objc_msgSend(UIApplication.SharedApplication.KeyWindow.Handle, new Selector ("recursiveDescription").Handle));
}
}
Then you can use it like this:
Console.WriteLine(UIViewAutolayoutTraceExtensions.RecursiveDescription ());
One caveat though: You can only call this code after everything has been loaded. Otherwise KeyWindow will be null. So there is no possibility to set a breakpoint and then call this code. You can only call this code if you provide a button or something similar with which you trigger the action.
using MonoTouch.ObjCRuntime;
var str = new NSString (Messaging.IntPtr_objc_msgSend (UIApplication.SharedApplication.KeyWindow.Handle, new Selector ("_autolayoutTrace").Handle));
And "str" will contain the string that you can then use with Console.WriteLine
I've been trying to evaluate XSockets but it appears I've hit my first stumbling block pretty early. I can connect to Generic controller just fine but custom controllers do not seem to work at all - I get a custom message: "The handler name was not found in loaded plugins". A Google search shows one other person having this problem in SE, but their solution did not work for me.
I've created a console project and installed the latest XSockets 3.03 from NuGet. My code is below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XSockets.Core.Common.Socket;
using XSockets.Core.XSocket;
using XSockets.Core.XSocket.Helpers;
using XSockets.Core.Common.Socket.Event.Interface;
namespace XSockets2
{
class Program
{
static void Main(string[] args)
{
using (var server = XSockets.Plugin.Framework.Composable.GetExport<IXSocketServerContainer>())
{
Console.WriteLine("running!");
server.StartServers();
Console.ReadLine();
server.StopServers();
}
}
}
public class TestCont: XSocketController
{
public override void OnMessage(ITextArgs textArgs)
{
this.SendToAll(textArgs);
}
}
}
And my Javascript
function connect2() {
var host = "ws://localhost:4502/testcont";
var conn;
conn = new XSockets.WebSocket(host);
conn.on(XSockets.Events.open, function (clientInfo) {
message(clientInfo.ClientGuid); //appends message to textarea
console.log('Open', clientInfo);
});
conn.on('OnMessage', function (d) {
message(d);
console.log('Message', d);
});
conn.on(XSockets.Events.onError, function (err) {
message(err.CustomMessage);
console.log('Error', err);
});
conn.on(XSockets.Events.close, function () {
message('Closed');
console.log('Closed');
});
First of all the latest version is 3.0.2 (not 3.0.3) but that is not important :)
There is a well known and documented bug in the plugin framework for the latest version. The bug only affect you if you run a console application (or any other *.exe) project since xsockets by default only looks in *.dll and not *.exe.
The issue and work around is described here
But your code will not work anyway since you have an error (from what I can see).
Your controller is named "TestCont" but you connect to "testcont". The connectionstring is case sensitive.
EDIT: I also think you are missunderstanding the method OnMessage since you have added a subscription to that exact name.
Environment: c#.net VS 2010
Solution has the following two projects:
A dll with several tested methods I've added.
A test project
The only thing in the test project is a form with following code: (names changed for readability)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using DLL_PROJECT; //Yes I remembered to include the dll project
namespace DLL_PROJECT_Test
{
public partial class frmTest : Form
{
private Class_1 myClass_1; //this comes from the dll - no errors here
private Class_2 myClass_2 = new Class_2(); // no errors here either
public frmTest()
{
InitializeComponent();
//TransparencyKey = BackColor;
this.SetStyle(System.Windows.Forms.ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = System.Drawing.Color.FromArgb(0, System.Drawing.Color.Black);
myDebouncer = new Debouncer(this);
this.SetDragging(true); //THIS EXTENSION COMES FROM THE DLL AND WORKS FINE
this.RoundCorners(40, 80); //AS DOES THIS ONE
myClass_2 = new Class_2();
myClass_2.HoldStartEvent += new Class_2EventHandler(myClass_2_HoldStartEvent);
myClass_2.DragStartEvent += new Class_2EventHandler(myClass_2_DragStartEvent);
}
private void myClass_2_DragStartEvent(Class_2 sender)
{
myClass_2("DragStart") += 1; //THE ONLY ERROR IS HERE AS FOLLOWS
//ERROR: "The name 'myClass_2' does not exist in the current context"
// - Yes, the DLL is included
// - Yes, the project is .Net 4 (not client profile)
// - Yes xxx WRONG xxx, this exact syntax has been tested before on an instance of
// this class, it's just a default parameter.
// xxx should be [] instead of () for the indexer in c#. #VB_Fails
}
void myClass_2_HoldStartEvent(Class_2 sender)
{
this.Close();
}
}
}
This code:
myClass_2("DragStart") += 1;
... is using myClass_2 as if it were either the name of a method or a delegate instance.
Did you actually mean to use the indexer? That would be:
myClass_2["DragStart"] += 1;
What does "DragStart" mean here? Is it actually a property name? Perhaps you want:
myClass_2.DragStart += 1;
I very much doubt that "this exact syntax has been tested before on an instance of this class".
Admittedly the error message doesn't make much sense in this case. I think it's actually more likely that you've got a typo in your real code - a typo which isn't propagated here because you've changed the names. If you could reproduce this in a short but complete program, it would make life a lot simpler.