Getting Cocoa function from C++ - c++builder

In the answer to this question: get logged in user the accepted answer uses Delphi code that looks like this to get access to the Cocoa function NSUserName.
function NSUserName: Pointer; cdecl; external '/System/Library/Frameworks/Foundation.framework/Foundation' name _PU +'NSUserName';
How would you do this in C++Builder?

This answers the question and is worth the bounty
The solution is to import NSUserName in C++ by using dlopen and dlsym:
void* (*NSUserName)();
String UserName;
void *hLib = dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", RTLD_GLOBAL);
if(hLib)
{
NSUserName = (void*(*)())dlsym(hLib, "NSUserName");
CFStringRef srUserName = (CFStringRef)NSUserName();
if(srUserName)
{
UserName = CFStringGetCStringPtr(srUserName, 0);
}
dlclose(hLib);
}
It is possible to use NSString (Cocoa Type) directly in C++ Builder by adding a header file as:
#include <Macapi.Foundation.hpp> // note that this will cause 8080 warnings if you have this warning turned on (unused variables)
Now I can use NSString instead CFStringRef (Core Foundation Type):
UserName = TNSString::Wrap(NSUserName())->UTF8String();

Related

How to represent a C char array in Java with GraalVm

I'm consuming a C library in Java with GraalVm and I have this field (if_name) I don't know how to implement:
# define IFNAMSIZ 16
struct port_t
{
char if_name[IFNAMSIZ];
}
This is my current code:
#CStruct("port_t")
interface Port extends PointerBase {
#CField("if_name")
WordPointer getIfName();
#CField("if_name")
void setIfName(WordPointer ifName);
}
Using WordPointer I get the following error compiling:
Error: Type WordPointer has a size of 8 bytes, but accessed C value has a size of 16 bytes; to suppress this error, use the annotation #AllowNarrowingCast
I already tried with CCharPointer and CCharPointerPointer but those have fixed lengths to 8 bytes and I got a similar error when compiling.
Anyone can help?
Thanks in advance
As you already guessed, you'll need to get the address of this field to manipulate it.
You can use
#CStruct("port_t")
interface Port extends PointerBase {
#CFieldAddress("if_name")
CCharPointer addressOfIfName();
}
In this case it doesn't make sense to have a setter since you cannot change the address of this field. Instead you can use the read/write methods of CCharPointer.
You'll probably need
#CConstant
static native int IFNAMSIZ();
somewhere as well.
Then you can do things like
String foo(Port p, String newIfName) {
UnsignedWord size = WordFactory.unsigned(IFNAMSIZ());
String oldIfName = CTypeConversion.toJavaString(p.addressOfIfName(), size);
CTypeConversion.toCString(newIfName, p.addressOfIfName(), size);
return oldIfName;
}

declaring TBitmap globally

I would like to declare a TBitmap Globally.
I tried as follows:
Locally within a method, this works fine
std::auto_ptr<Graphics::TBitmap> RenderGraphic(new Graphics::TBitmap());
OR
Graphics::TBitmap * RenderGraphic = new Graphics::TBitmap;
So to declare it globally I tried this in the header file
Graphics::TBitmap *RenderGraphic;
And this in the constructor
__fastcall TShipGraphic::TShipGraphic(TComponent* Owner)
: TForm(Owner)
{
Graphics::TBitmap * RenderGraphic = new Graphics::TBitmap;
}
Which compiles fine but when running, throws an access violation exception at the first occurrence of
RenderGraphic->Canvas->Pen->Color = clBlack;
Please advise, tks in advance.
The reference source I was using is C++ Builder Graphics Introduction
which suggested the declaration in the constructor
You need to implement a singleton. Consider read-only case (bitmap is created once, no setter function).
In MyGraphics.h define accessor function
#include <vcl.h>
TBitmap* GetRenderGraphic();
Implementation in MyGraphics.cpp
static std::unique_ptr<TBitmap> renderGraphic(new TBitmap());
TBitmap* GetRenderGraphic()
{
return renderGraphic.get();
}
Use it (required including of MyGraphics.h)
GetRenderGraphic()->Canvas->Pen->Color = clBlack;

Bind TServerSocket to a specific IP address in C++ Builder (10.1.2)

I am still using deprecated TServerSocket component.
I would like to bind TServerSocket to a specific IP. This question has been previously asked before for Delphi in this site: How to Bind a TServerSocket to a specific IP address
However I couldn't make it work in C++ Builder.
My code is:
class ServerWrapper : private TServerSocket {
public:
ServerWrapper();
private:
};
ServerWrapper::ServerWrapper()
: TServerSocket (0)
{
//---
}
ServerWrapper* pServer =0;
//...
//..
//.
// And in a function:
pServer = new ServerWrapper;
pServer->Address = "192.168.0.1" ;
pServer->Active = true;
However it doesn't compile.
It says:
E2247 'TAbstractSocket::Address' is not accessible
I am using C++ Builder 10.1.2 Berlin by the way.
It doesn't work because you did not translate the Delphi code to C++ correctly.
For one thing, you are using private inheritance instead of public inheritance. So all public and protected members inherited from TServerSocket will be private in ServerWrapper. Delphi has no notion of protected/private inheritance, only public inheritance.
But more importantly, Delphi has a notion of implicit friendship. Within a unit, all classes have full access to private/protected members of other classes that are declared in the same unit. That includes inherited protected members. The Delphi example in the other question takes advantage of that feature, by declaring a local helper class to implicitly gain public access to the Address property for the unit that declares the helper.
But C++ has no notion of implicit friendship. To translate the Delphi example to C++, you have to explicitly promote access to the protected Address property.
A literal translation of the Delphi code would look like this in C++:
class TServerSocketAccess : public TServerSocket
{
public:
__property Address;
// or:
// using TServerSocket::Address;
};
((TServerSocketAccess*)ServerSocket1)->Address = "192.168.0.1";
ServerSocket1->Active = true;
Applied to your ServerWrapper class, it would look like this:
class ServerWrapper : public TServerSocket
{
public:
ServerWrapper();
__property Address;
// or:
// using TServerSocket::Address;
};
ServerWrapper::ServerWrapper()
: TServerSocket (0)
{
//---
}
ServerWrapper* pServer = 0;
//...
pServer = new ServerWrapper;
pServer->Address = "192.168.0.1";
pServer->Active = true;

Get hardware type in Unified API

How do I get the device hardware type in Unified API? Here's an example of how to do it in Classic API.. In that example, the "[DllImport(Constants.SystemLibrary)]" part doesn't compile. It seems that has changed in Unified API?
So this is the old Classic code. How do I do this in Unified after including "ObjCRuntime"?
[DllImport(MonoTouch.Constants.SystemLibrary)]
static internal extern int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string property, IntPtr output, IntPtr oldLen, IntPtr newp, uint newlen);
public DeviceHardware ()
{
var pStr = Marshal.AllocHGlobal(length);
sysctlbyname(HardwareProperty, pStr, pLen, IntPtr.Zero, 0);
string DeviceTypeString = Marshal.PtrToStringAnsi(pStr);
}
Solution below. I had to use "ObjCRuntime" instead of "MonoTouch"
[DllImport(ObjCRuntime.Constants.SystemLibrary)]
The Constants class is in the ObjCRuntime namespace, so you just need to add this using clause at the top of the file:
using ObjCRuntime;

Has anyone created a MonoTouch binding for the Nuance Dragon Mobile Speech SDK for iOS?

I have the Dragon Mobile SDK running nicely on Windows Phone 7 and I would like to get the equivalent functionality working for iOS. Since the SDK wraps the microphone, it's not really possible to use the .NET assemblies in my MonoTouch project (even if I did have the source). It appears that the best way to do this is to create a binding library (as Miguel describes here).
It sure seems like a lot of work though, and I would love to reuse as opposed to reinventing the wheel if someone's done it already...
Here are some more details for how I got this to work.
I downloaded the binding sample. You may be tempted to skip this step, but you really have to start with this project if you want to get this to work.
I created an objective-c library with Xcode (which I called SpeechKitLibrary) that has a dual purpose - one is to define the SpeechKitApplicationKey (which is an extern dependency that SpeechKit needs):
const unsigned char SpeechKitApplicationKey[] = {...};
and the other is to define a class which utilizes the SpeechKit framework, and links with it. (in Xcode, add the SpeechKit framework in the frameworks section of the project).
The .m file I wrote looks something like this... (you can figure out the .h file - super simple). I'm not 100% sure you need all of this, but I wanted to make sure the static archive library that came out of this step would import the right symbols. You may be able to avoid this somehow, but in my experiments I found that I needed to do something like this...
// the SpeechKitWrapper isn't actually used - rather, it is a way to exercise all the API's that
// the binding library needs from the SpeechKit framework, so that those can be linked into the generated .a file.
#implementation SpeechKitWrapper
#synthesize status;
- (id)initWithDelegate:(id <SKRecognizerDelegate>)delegate
{
self = [super init];
if (self) {
del = delegate;
[self setStatus:#"initializing"];
SpeechKit setupWithID:#"NMDPTRIAL_ogazitt20120220010133"
host:#"sandbox.nmdp.nuancemobility.net"
port:443
useSSL:NO
delegate:nil];
NSString *text = [NSString stringWithFormat:#"initialized. sessionid = %#", [SpeechKit sessionID]];
[self setStatus:text];
SKEarcon* earconStart = [SKEarcon earconWithName:#"beep.wav"];
[SpeechKit setEarcon:earconStart forType:SKStartRecordingEarconType];
voiceSearch = [[SKRecognizer alloc] initWithType:SKDictationRecognizerType
detection:SKLongEndOfSpeechDetection
language:#"en_US"
delegate:delegate];
text = [NSString stringWithFormat:#"recognizer connecting. sessionid = %#", [SpeechKit sessionID]];
[self setStatus:text];
}
return self;
}
#end
I then compiled/linked this static archive for the three different architectures - i386, arm6, and arm7. The Makefile in the BindingSample is the template for how to do this. But the net is that you get three libraries - libSpeechKitLibrary-{i386,arm6,arm7}.a. The makefile then creates a universal library (libSpeechKitLibraryUniversal.a) using the OSX lipo(1) tool.
Only now are you ready to create a binding library. You can reuse the AssemblyInfo.cs in the binding sample (which will show how to create an import on the universal library for all architectures - and will drive some compile flags)...
[assembly: LinkWith ("libSpeechKitLibraryUniversal.a", LinkTarget.Simulator | LinkTarget.ArmV6 | LinkTarget.ArmV7, ForceLoad = true)]
You compile the ApiDefinition.cs file with btouch as per the Makefile (I think I needed to repeat some of the info in StructsAndEnums.cs to make it work). Note - the only functionality I didn't get to work is the "SetEarcon" stuff - since this is an archive library and not a framework, I can't bundle a wav as a resource file... and I couldn't figure out how to get the SetEarcon method to accept a resource out of my app bundle.
using System;
using MonoTouch.Foundation;
namespace Nuance.SpeechKit
{
// SKEarcon.h
public enum SKEarconType
{
SKStartRecordingEarconType = 1,
SKStopRecordingEarconType = 2,
SKCancelRecordingEarconType = 3,
};
// SKRecognizer.h
public enum SKEndOfSpeechDetection
{
SKNoEndOfSpeechDetection = 1,
SKShortEndOfSpeechDetection = 2,
SKLongEndOfSpeechDetection = 3,
};
public static class SKRecognizerType
{
public static string SKDictationRecognizerType = "dictation";
public static string SKWebSearchRecognizerType = "websearch";
};
// SpeechKitErrors.h
public enum SpeechKitErrors
{
SKServerConnectionError = 1,
SKServerRetryError = 2,
SKRecognizerError = 3,
SKVocalizerError = 4,
SKCancelledError = 5,
};
// SKEarcon.h
[BaseType(typeof(NSObject))]
interface SKEarcon
{
[Export("initWithContentsOfFile:")]
IntPtr Constructor(string path);
[Static, Export("earconWithName:")]
SKEarcon FromName(string name);
}
// SKRecognition.h
[BaseType(typeof(NSObject))]
interface SKRecognition
{
[Export("results")]
string[] Results { get; }
[Export("scores")]
NSNumber[] Scores { get; }
[Export("suggestion")]
string Suggestion { get; }
[Export("firstResult")]
string FirstResult();
}
// SKRecognizer.h
[BaseType(typeof(NSObject))]
interface SKRecognizer
{
[Export("audioLevel")]
float AudioLevel { get; }
[Export ("initWithType:detection:language:delegate:")]
IntPtr Constructor (string type, SKEndOfSpeechDetection detection, string language, SKRecognizerDelegate del);
[Export("stopRecording")]
void StopRecording();
[Export("cancel")]
void Cancel();
/*
[Field ("SKSearchRecognizerType", "__Internal")]
NSString SKSearchRecognizerType { get; }
[Field ("SKDictationRecognizerType", "__Internal")]
NSString SKDictationRecognizerType { get; }
*/
}
[BaseType(typeof(NSObject))]
[Model]
interface SKRecognizerDelegate
{
[Export("recognizerDidBeginRecording:")]
void OnRecordingBegin (SKRecognizer recognizer);
[Export("recognizerDidFinishRecording:")]
void OnRecordingDone (SKRecognizer recognizer);
[Export("recognizer:didFinishWithResults:")]
[Abstract]
void OnResults (SKRecognizer recognizer, SKRecognition results);
[Export("recognizer:didFinishWithError:suggestion:")]
[Abstract]
void OnError (SKRecognizer recognizer, NSError error, string suggestion);
}
// speechkit.h
[BaseType(typeof(NSObject))]
interface SpeechKit
{
[Static, Export("setupWithID:host:port:useSSL:delegate:")]
void Initialize(string id, string host, int port, bool useSSL, [NullAllowed] SpeechKitDelegate del);
[Static, Export("destroy")]
void Destroy();
[Static, Export("sessionID")]
string GetSessionID();
[Static, Export("setEarcon:forType:")]
void SetEarcon(SKEarcon earcon, SKEarconType type);
}
[BaseType(typeof(NSObject))]
[Model]
interface SpeechKitDelegate
{
[Export("destroyed")]
void Destroyed();
}
[BaseType(typeof(NSObject))]
interface SpeechKitWrapper
{
[Export("initWithDelegate:")]
IntPtr Constructor(SKRecognizerDelegate del);
[Export("status")]
string Status { get; set; }
}
}
You now have an assembly that can be referenced by your monotouch application project. The important thing now is to remember to link with all the frameworks that are dependencies (not only SpeeckKit, but also SK's dependencies) - you do this by passing mtouch some additional arguments:
-gcc_flags "-F<insert_framework_path_here> -framework SpeechKit -framework SystemConfiguration -framework Security -framework AVFoundation -framework AudioToolbox"
That's all, folks! Hope this was helpful...
If anyone (kos or otherwise) gets the SetEarcon method to work, please post a solution :-)
Nuance's SDK Agreement is not permissive enough for anyone to even publish bindings for their iOS SDK for use with MonoTouch. But the library itself should work just fine.
That being said, the SDK has only a handful of types to map and would be fairly trivial to RE-do the work anyone else might have already done. You can check out how to bind assemblies using the reference guide here:
http://docs.xamarin.com/ios/advanced_topics/binding_objective-c_types
There's also a BindingSample project that helps users better understand how to bind native components using btouch:
https://github.com/xamarin/monotouch-samples/tree/master/BindingSample
Thanks again Anuj for your answer. I thought I'd leave a tip or two about how to do this. The binding library wasn't difficult to build (still tweaking it but it's not a difficult task).
The more obscure part was figuring out how to get the SpeechKit framework linked. The samples only show how to link a .a or .dylib. After spending a little time with the ld(1) man page on OSX, it looks like the correct ld (and therefore gcc) arguments for linking with a framework are the following:
-gcc_flags "-F<insert_framework_path_here> -framework SpeechKit"
You put this in a textbox in the project properties - under Build :: iPhone Build :: Additional mtouch arguments
Note that -L doesn't work because this isn't a library; also note that -force_load and -ObjC referenced here don't appear necessary because, again, this is a framework and not a library.

Resources