Create a CFTree in Objective C - iphone

I want to create a basic CFTree with some string info in Objective-C.
This is my code
//CFtree attempt
NSString *info;
CFTreeContext ctx;
NSString *treeString = [[NSString alloc] initWithFormat:#"the tree string"];
info = treeString;
ctx.info = info;
CFTreeRef myTree = CFTreeCreate(NULL, &ctx);
I get an "EXC_BAD_ACESS" error on the last line.
Can someone please tell me how to configure this properly.

It seems that ctx should be initialized.
ctx.version = 0;
ctx.info = info;
ctx.retain = CFRetain;
ctx.release = CFRelease;
ctx.copyDescription = CFCopyDescription;

You may want to initialize the ctx struct to 0 before using it since there are members in it that otherwise may cause erratic behavior as the CFTreeCreate thinks they are pointing to something relevant.
see

Related

Is there a way to view COM entries by traversing a TLB file in .NET?

I'm converting an application to use registration free COM. There are a few 3rd party COM dll's that would normally have regsvr32 called on them. I tested that I can create objects from these 3rd party dlls by making a side-by-side manifest.
I used the OLE/COM viewer built into Windows to get this information. However I would like to make a program that could do this for me manually, as these 3rd party libraries have lots of classes I need to put in the manifest.
Does anyone know of a way to programatically traverse a type library?
I took Hans' advice and used LoadTypeLib.
For anyone looking for example code, this should be a great starting point.
I wrote it this morning and was able to get xml that I needed.
Forgive me for not releasing the objects! I don't have time to fully flesh out the rest of this answer right now. Edits are welcome.
[DllImport("oleaut32.dll", PreserveSig = false)]
public static extern ITypeLib LoadTypeLib([In, MarshalAs(UnmanagedType.LPWStr)] string typelib);
public static void ParseTypeLib(string filePath)
{
string fileNameOnly = Path.GetFileNameWithoutExtension(filePath);
ITypeLib typeLib = LoadTypeLib(filePath);
int count = typeLib.GetTypeInfoCount();
IntPtr ipLibAtt = IntPtr.Zero;
typeLib.GetLibAttr(out ipLibAtt);
var typeLibAttr = (System.Runtime.InteropServices.ComTypes.TYPELIBATTR)
Marshal.PtrToStructure(ipLibAtt, typeof(System.Runtime.InteropServices.ComTypes.TYPELIBATTR));
Guid tlbId = typeLibAttr.guid;
for(int i=0; i< count; i++)
{
ITypeInfo typeInfo = null;
typeLib.GetTypeInfo(i, out typeInfo);
//figure out what guids, typekind, and names of the thing we're dealing with
IntPtr ipTypeAttr = IntPtr.Zero;
typeInfo.GetTypeAttr(out ipTypeAttr);
//unmarshal the pointer into a structure into something we can read
var typeattr = (System.Runtime.InteropServices.ComTypes.TYPEATTR)
Marshal.PtrToStructure(ipTypeAttr, typeof(System.Runtime.InteropServices.ComTypes.TYPEATTR));
System.Runtime.InteropServices.ComTypes.TYPEKIND typeKind = typeattr.typekind;
Guid typeId = typeattr.guid;
//get the name of the type
string strName, strDocString, strHelpFile;
int dwHelpContext;
typeLib.GetDocumentation(i, out strName, out strDocString, out dwHelpContext, out strHelpFile);
if (typeKind == System.Runtime.InteropServices.ComTypes.TYPEKIND.TKIND_COCLASS)
{
string xmlComClassFormat = "<comClass clsid=\"{0}\" tlbid=\"{1}\" description=\"{2}\" progid=\"{3}.{4}\"></comClass>";
string comClassXml = String.Format(xmlComClassFormat,
typeId.ToString("B").ToUpper(),
tlbId.ToString("B").ToUpper(),
strDocString,
fileNameOnly, strName
);
//Debug.WriteLine(comClassXml);
}
else if(typeKind == System.Runtime.InteropServices.ComTypes.TYPEKIND.TKIND_INTERFACE)
{
string xmlProxyStubFormat = "<comInterfaceExternalProxyStub name=\"{0}\" iid=\"{1}\" tlbid=\"{2}\" proxyStubClsid32=\"{3}\"></comInterfaceExternalProxyStub>";
string proxyStubXml = String.Format(xmlProxyStubFormat,
strName,
typeId.ToString("B").ToUpper(),
tlbId.ToString("B").ToUpper(),
"{00020424-0000-0000-C000-000000000046}"
);
//Debug.WriteLine(proxyStubXml);
}
}
return;
}
}

Where to locate srandom (time(null))

I'm using function random()%some integer in a method of one of my app's classes and I have no idea where to put srandom (time (NULL)) to generate not pseudorandom but true random numbers. I have already put it in viewDidLoad and viewWillAppear but it doesn't help.
- (NSMutableDictionary *)getUsersFromServer
{
srand(time(NULL));
//here we're getting list of users from the server
NSMutableDictionary * users = [[[NSMutableDictionary alloc] init] autorelease];
for (int i = 0;i < 19;i++)
{
int wins = rand()%100; float f_wins = (float)wins;
int losses = rand()%100; float f_losses = (float)losses;
int withdr = rand()%100; float f_withdr = (float)withdr;
float win_per = f_wins / ((f_wins + f_losses + f_withdr) / 100.0);
[userresults setArray:[NSMutableArray arrayWithObjects:[NSNumber numberWithInt:wins],
[NSNumber numberWithInt:losses],
[NSNumber numberWithInt:withdr],
[ NSNumber numberWithFloat:win_per],
nil]];
[users setObject:userresults forKey:[NSString stringWithFormat:#"Pfeffer ID %i",i]];
}
[userresults release];
return users;
}
something like this... the code looks awful but its sense is understandable. rand() produces same numbers for each loop iteration. If I use arc4random() it changes nothing. still same numbers
I don't think this is a issue about randomness or seeds at all, I don't use Objective-C, but ...
// for each loop iteration:
[userresults setArray: .... ] // <-- modify object known as userresults?
[users setObject:userresults ....] // <-- isn't that the SAME userresults object?
That is, I believe you have the same object multiple times in users: shouldn't a new result object be created each iteration?
Also, see srand() — why call it only once? -- for why using srand at the top of this method might not be ideal. Alternatively, this post recommends arc4random as it does not require a manual seeding and is a "stronger" pseudo-random generator.
Happy coding.

How can I get a list of all the properties of an ABRecordRef?

I would like to obtain a list of all the properties of an ABPersonRef and ABGroupRef without having to use the iOS predefined keys of kABPersonFirstNameProperty, kABPersonLastNameProperty... I'm playing with the address book and I'd like to iterate over all values for a particular person. I know there are predefined keys but Apple could very well add new ones in the future so I'd like to do something like:
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *allPeople = (NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
for (int i = 0; i < [allPeople count]; ++i) {
ABRecordRef person = [allPeople objectAtIndex:i];
// This is the line that I can't figure out.
NSArray *allProperties = (NSArray *)ABRecordCopyArrayOfAllProperties(person);
}
I know that I'll encounter multivalue items that I'll have to loop though later, but the goal is to obtain a list of keys that I can iterate over for the single value properties. I don't care what the returned class is, NSArray, NSDictionary... whatever.
I greatly appreciate any advice!
You can try the following:
With ARC:
NSDictionary* dictionaryRepresentationForABPerson(ABRecordRef person)
{
NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
for ( int32_t propertyIndex = kABPersonFirstNameProperty; propertyIndex <= kABPersonSocialProfileProperty; propertyIndex ++ )
{
NSString* propertyName = CFBridgingRelease(ABPersonCopyLocalizedPropertyName(propertyIndex));
id value = CFBridgingRelease(ABRecordCopyValue(person, propertyIndex));
if ( value )
[dictionary setObject:value forKey:propertyName];
}
return dictionary;
}
We using the localized name of the property - in different locales will have different keys.
The number of properties may change in the next version of iOS.
Maybe it makes sense to go through to the number of properties as long as the propertyName does not become UNKNOWN_PROPERTY
Aliaksandr's solution is not safe: for example if you attempt to create ABPerson records in a specific ABSource, and use this approach, you might find that contacts do not sync to that source properly.
I simply copied the list of 25 ABPropertyIDs from ABPerson, stuck them in a simple int[], and iterated over them...
// Loop over all properties of this Person
// taken from Apple's ABPerson reference page on 9.12.13.
// URL: https://developer.apple.com/library/ios/documentation/AddressBook/Reference/ABPersonRef_iPhoneOS/Reference/reference.html#//apple_ref/c/func/ABPersonGetTypeOfProperty
// count = 25. All are type ABPropertyID
int propertyArray[25] = {
kABPersonFirstNameProperty,
kABPersonLastNameProperty,
kABPersonMiddleNameProperty,
kABPersonPrefixProperty,
kABPersonSuffixProperty,
kABPersonNicknameProperty,
kABPersonFirstNamePhoneticProperty,
kABPersonLastNamePhoneticProperty,
kABPersonMiddleNamePhoneticProperty,
kABPersonOrganizationProperty,
kABPersonJobTitleProperty,
kABPersonDepartmentProperty,
kABPersonEmailProperty,
kABPersonBirthdayProperty,
kABPersonNoteProperty,
kABPersonCreationDateProperty,
kABPersonModificationDateProperty,
kABPersonAddressProperty,
kABPersonDateProperty,
kABPersonKindProperty,
kABPersonPhoneProperty,
kABPersonInstantMessageProperty,
kABPersonSocialProfileProperty,
kABPersonURLProperty,
kABPersonRelatedNamesProperty
};
int propertyArraySize = 25;
for ( int propertyIndex = 0; propertyIndex < propertyArraySize; propertyIndex++ ) {
...code here
}

iphone - Make a tree class with cftree

I want to make a tree class like NSArray with CFTree.
(Actually NSTree doesn't exist so I'm trying to make 'NSTree like tree'.)
But CFTree seems to request certain type class.
I want to make a general class that can deal in various class like NSArray.
Here is iPhone dev site's example.
static CFTreeRef CreateMyTree(CFAllocatorRef allocator) {
MyTreeInfo *info;
CFTreeContext ctx;
info = CFAllocatorAllocate(allocator, sizeof(MyTreeInfo), 0);
info->address = 0;
info->symbol = NULL;
info->countCurrent = 0;
info->countTotal = 0;
ctx.version = 0;
ctx.info = info;
ctx.retain = AllocTreeInfo;
ctx.release = FreeTreeInfo;
ctx.copyDescription = NULL;
return CFTreeCreate(allocator, &ctx);
}
I want to use general class instead of "MyTreeInfo".
Is there any way?
Thanks.
Sure, CFTree can hold any data you want. If you want to store instances of CFType, then just set the retain and release of the context to CFRetain and CFRelease. You can also then set copyDescription to CFCopyDescription. Something like this:
static CFTreeRef CreateMyTree(CFTypeRef rootObject) {
CFTreeContext ctx;
ctx.version = 0;
ctx.info = rootObject;
ctx.retain = CFRetain;
ctx.release = CFRelease;
ctx.copyDescription = CFCopyDescription;
return CFTreeCreate(NULL, &ctx);
}
...
CFStringRef string = CFSTR("foo");
CFTreeRef tree = CreateMyTree(string);
NSLog(#"%#", tree);
CFRelease(tree);

What are the required parameters for CMBufferQueueCreate?

Reading the documentation about iOS SDK CMBufferQueueCreate, it says that getDuration and version are required, all the others callbacks can be NULL.
But running the following code:
CFAllocatorRef allocator;
CMBufferCallbacks *callbacks;
callbacks = malloc(sizeof(CMBufferCallbacks));
callbacks->version = 0;
callbacks->getDuration = timeCallback;
callbacks->refcon = NULL;
callbacks->getDecodeTimeStamp = NULL;
callbacks->getPresentationTimeStamp = NULL;
callbacks->isDataReady = NULL;
callbacks->compare = NULL;
callbacks->dataBecameReadyNotification = NULL;
CMItemCount capacity = 4;
OSStatus s = CMBufferQueueCreate(allocator, capacity, callbacks, queue);
NSLog(#"QUEUE: %x", queue);
NSLog(#"STATUS: %i", s);
with timeCallback:
CMTime timeCallback(CMBufferRef buf, void *refcon){
return CMTimeMake(1, 1);
}
and queue is:
CMBufferQueueRef* queue;
queue creations fails (queue = 0) and returns a status of:
kCMBufferQueueError_RequiredParameterMissing = -12761,
The callbacks variable is correctly initialized, at least the debugger says so.
Has anybody used the CMBufferQueue?
Presumably there is nothing wrong with the parameters. At least the same as what you wrote is stated in CMBufferQueue.h about the required parameters. But it looks like you are passing a null pointer as the CMBufferQueueRef* parameter. I have updated your sample as follows and it seems to create the message loop OK.
CMBufferQueueRef queue;
CFAllocatorRef allocator = kCFAllocatorDefault;
CMBufferCallbacks *callbacks;
callbacks = malloc(sizeof(CMBufferCallbacks));
callbacks->version = 0;
callbacks->getDuration = timeCallback;
callbacks->refcon = NULL;
callbacks->getDecodeTimeStamp = NULL;
callbacks->getPresentationTimeStamp = NULL;
callbacks->isDataReady = NULL;
callbacks->compare = NULL;
callbacks->dataBecameReadyNotification = NULL;
CMItemCount capacity = 4;
OSStatus s = CMBufferQueueCreate(allocator, capacity, callbacks, &queue);
NSLog(#"QUEUE: %x", queue);
NSLog(#"STATUS: %i", s);
The time callback is still the same.
It does not look like it helps topic starter, but I hope it helps somebody else.