Setting a 64bit FILETIME PT_SYSTIME property using pywin32's SetProps() - 64-bit

I am using pywin32 mapi routines to interact with my outlook contacts store. I am trying to set the PT_BIRTHDAY property and have the following code for doing that:
The conversion from and to FILETIME values is from filetimes.py available at: http://reliablybroken.com/b/wp-content/filetimes.py
dt = datetime.strptime('1980-01-01','%Y-%m-%d')
filetime = filetimes.dt_to_filetime(dt)
msg.SetProps([(mapitags.PR_BIRTHDAY, filetime)])
I get an OverflowError: Python int too large to convert to c long
I am on a 32 bit machine, and I understand FILETME is a 64 bit value. I am at a loss. How can I set the underlying MAPI property using this library? Is there a workaround?

Related

My segmented picker has normal Int values as tags, How is this passed to and from CoreData?

My SwiftUI segmented control picker uses plain Int ".tag(1)" etc values for its selection.
CoreData only has Int16, Int32 & Int64 options to choose from, and with any of those options it seems my picker selection and CoreData refuse to talk to each other.
How is this (??simple??) task achieved please?
I've tried every numeric based option within CoreData including Int16-64, doubles and floats, all of them break my code or simply just don't work.
Picker(selection: $addDogVM.gender, label: Text("Gender?")) {
Text("Boy ♂").tag(1)
Text("?").tag(2)
Text("Girl ♀").tag(3)
}
I expected any of the 3 CoreData Int options to work out of the box, and to be compatible with the (standard) Int used by the picker.
Each element of a segmented control is represented by an index of type Int, and this index therefore commences at 0.
So using your example of a segmented control with three segments (for example: Boy ♂, ?, Girl ♀), each segment is represented by three indexes 0, 1 & 2.
If the user selects the segmented control that represents Girl ♀, then...
segmentedControl.selectedSegmentIndex = 2
When storing a value using Core Data framework, that is to be represented as a segmented control index in the UI, I therefore always commence with 0.
Everything you read from this point onwards is programmer preference - that is and to be clear - there are a number of ways to achieve the same outcome and you should choose one that best suits you and your coding style. Note also that this can be confusing for a newcomer, so I would encourage patience. My only advice, keep things as simple as possible until you've tested and debugged and tested enough to understand the differences.
So to continue:
The Apple Documentation states that...
...on 64-bit platforms, Int is the same size as Int64.
So in the Core Data model editor (.xcdatamodeld file), I choose to apply an Integer 64 attribute type for any value that will be used as an Int in my code.
Also, somewhere, some time ago, I read that if there is no reason to use Integer 16 or Integer 32, then default to the use of Integer 64 in object model graph. (I assume Integer 16 or Integer 32 are kept for backward compatibility.) If I find that reference I'll link it here.
I could write about the use of scalar attribute types here and manually writing your managed object subclass/es by selecting in the attribute inspector Class Codegen = Manual/None, but honestly I have decided such added detail will only complicate matters.
So your "automatically generated by Core Data" managed object subclass/es (NSManagedObject) will use the optional NSNumber? wrapper...
You will therefore need to convert your persisted/saved data in your code.
I do this in two places... when I access the data and when I persist the data.
(Noting I assume your entity is of type Dog and an instance exists of dog i.e. let dog = Dog())
// access
tempGender = dog.gender as? Int
// save
dog.gender = tempGender as NSNumber?
In between, I use a "temp" var property of type Int to work with the segmented control.
// temporary property to use with segmented control
private var tempGender: Int?
UPDATE
I do the last part a little differently now...
Rather than convert the data in code, I made a simple extension to my managed object subclass to execute the conversion. So rather than accessing the Core Data attribute directly and manipulating the data in code, now I instead use this convenience var.
extension Dog {
var genderAsInt: Int {
get {
guard let gender = self.gender else { return 0 }
return Int(truncating: gender)
}
set {
self.gender = NSNumber(value: newValue)
}
}
}
Your picker code...
Picker(selection: $addDogVM.genderAsInt, label: Text("Gender?")) {
Text("Boy ♂").tag(0)
Text("?").tag(1)
Text("Girl ♀").tag(2)
}
Any questions, ask in the comments.

Using .NET HashTable Return Type in VBA

I have created a .NET library in VB.NET and there is a function that returns an object of HashTable.
I have been searching for how to access the elements in the HashTable object in Excel VBA but can't find a solution. I am new to VBA so pardon me. I have searched but can't find a way out.
For instance, after something like this, I don't know how to access the data.
Dim hashData As Object
Set hashData = obj.getHashData
Please help
Dim hashData As Object
Set hashData = obj.getHashData
If getHashData is returning a HashTable, then hashData is a late-bound HashTable, and you can invoke its members, including its Item property:
Dim value As Variant
value = hashData.Item("key")
You're not getting compile-time validation on the late-bound member calls against Object, so you need to be particularly careful for typos, because Option Explicit cannot save you when late binding is involved. Refer to the HashTable documentation linked above for what members you can invoke.
Adding a reference to mscorlib.tlb (you'll find it under C:\Windows\Microsoft.NET\Framework\v4.0.30319, or reference the equivalent from \Framework64 if your Excel is 64-bit - bitness of the library needs to match the bitness of the host application) would normally allow for early binding, but while this library is COM-visible, it's intended to be used from managed (.net) code, so you're accessing these objects from interfaces - the concrete types don't expose any members directly:
Knowing that Hashtable implements the IDictionary interface, we can use early binding and get compile-time validation and IntelliSense if we declare hashData As IDictionary:
Dim hashData As mscorlib.IDictionary
Set hashData = New mscorlib.Hashtable
hashData.Add "foo", 42
Debug.Print hashData.Item("foo") 'prints 42
Note that the Item property is exposed as the default member:
This means you can have the Item member call implicit, exactly as you could do with any standard VBA collection object:
Dim hashData As mscorlib.IDictionary
Set hashData = New mscorlib.Hashtable
hashData.Add "foo", 42
Debug.Print hashData("foo") 'prints 42
Early-bound code is much easier to write, especially when you're not familiar with the types involved. However if the project is referencing the 64-bit framework and your macros need to run on 32-bit Excel, you'll want to stick to late binding to avoid binding issues.
Also note, iterating the Hashtable object with a For Each loop isn't going to work, because of how enumerators work in VBA vs how they work in .NET; the Keys and Values collections are objects implementing the ICollection interface, so iterating them will be non-trivial as well: a For Each loop won't work, and while you can set up a For i = 0 To hashData.Keys.Count - 1, you can't get the item at index i from an ICollection.
But we know that ICollection inherits IEnumerable, and IEnumerable does work with For Each, so we can cast the Keys collection to IEnumerable, and iterate all keys and values like so:
Dim hashData As mscorlib.IDictionary
Set hashData = obj.getHashData
Dim hashKeys As mscorlib.IEnumerable
Set hashKeys = hashData.Keys
Dim k As Variant
For Each k In hashKeys
Debug.Print k, hashData(k) 'outputs the key and its associated value
Next
The problem is that you can't cast to IEnumerable with late-bound code or without a reference to mscorlib.tlb, and late binding somehow won't see the GetEnumerator member, so this raises error 438:
Dim hashKeys As Object
Set hashKeys = hashData.Keys
Dim k As Variant
For Each k In hashKeys ' error 438, hashKeys isn't exposing the enumerator
Debug.Print k, hashData(k)
Next
Conclusion: if you need the VBA code to run on both 32 and 64 bit hosts, you'll have to jump through hoops to get late-bound code to work. I would recommend working early-bound with the 64-bit framework if you're on a 64-bit host, and distributing a separate copy of the macro that references the 32-bit framework for 32-bit hosts. A bit of a pain to distribute, but less painful than getting late bound code to work.

Excel VBA - How to convert an Object into a String

I like to convert an Object into a string. I found this topic but I can not get it to work in Excel 2010 ("Cast.xxx", "CArray()" and "Array()" seems to be unknown to Excel?)
I know how to convert a variant e.g. "toString = CStr(x)" but not how to do it the best way for an object
Function toString(ByVal x As Variant) As String
If TypeOf x Is Object Then
toString = ???
Else
toString = CStr(x)
End If
End Function
any suggestions?
Are you referring to the IFormattable interface. For example in VB.NET?
Excel VBA isn't a language that will provide you with a ToString method since it doesn't support inheritance.
In your example, you are simply converting whatever the variant is to a string, but an object in VBA wont support this directly.
If you have an external COM object, this would need to be exposed in the interface to access this method to call it from VBA.
For your own classes, you could implement your own IFormattable interface for your objects, but you would have assign to that interface before being able to call the objects ToString method - possible with a helper method. You could of course just supply a ToString method for every class which will through the class interface, but if you want to include this functionality for all objects, then an interface is probably the way to go.
Hope that helps.

XXX doesn't contain a definition and no extension method

I need to access some methods and properties of a third party unmanaged DLL from my VS2010 C# project. One property in particular “disappears” when trying to access it after I added the DLL to the reference. I am using MS VS2010 and the target platform is an XP SP3 x86.
From the .NET VB, the Item property is shown as
Item([Object], [Object]) As Object
or
ReadOnly Default Property Item(Optional ByVal Name As Object = Nothing, Optional ByVal Index As Object = Nothing) As Object
I can use it with no problem.
However, in C#, this property disappears and the closest one I can find become
this[[object], [object]]
or
dynamic this[[object Name = System.Type.Missing], [object Index = System.Type.Missing]] { get; }
How do I access this property in my C# project? Thanks.
The Item property in VB.NET is the indexer in C#.
So, the following VB.NET and C# codes are equivalent:
/* VB.NET */
yourObject.Item(o1, o2)
/* C# */
yourObject[o1, o2];
this is an indexer and can be accessed like this.
var yourObj = new SomeObject();
var item = yourObj[value1,value2];
In other words you just use [] brackets after the object variable itself, rather than Item()

C++/CLI Managed Wrapper and ADODB::Recordset

I have a native C++ DLL that uses COM ADO Recordsets and am in need of converting it to the .NET variant (ADODB::Recordset). I have tried several approaches to tackling this problem without success.
The native C++ DLL dynamically creates and populates the COM Recordset. Ideally I'd do the same for the ADODB::Recordset within the managed wrapper, but the needed properties aren't accessible to me.
For example, when attempting to utilize the Fields collection in order to Append Columns (despite intellisense telling me otherwise), I receive:
error C2039: 'Fields' : is not a member of 'ADODB::Recordset'
ADODB::Recordset ^RS = gcnew ADODB::Recordset ();
RS->Fields->Append("ID", DataTypeEnum::adInteger, 1, FieldAttributeEnum::adFldKeyColumn);
My C++/CLI solution contains the ADODB reference (c:\Program Files\Microsoft.NET\Primary Interop Assemblies\adodb.dll) version 7.0.3300.0
I am using Visual Studio 2005 with .NET Framework 2.0.50727 SP2
I would appreaciate it if someone in the StackOverflow community can direct me to a sample that dynamically populates a .NET ADO Recordset using C++/CLI.
I think that the main difference between the raw COM Recordset and the one provided by the .Net wrapper classes is just that some things get renamed. It is simply a wrapper around the underlying COM object and not a new class in its own right.
To answer your immediate example, try
RS->default->Append(...);
You could try to run ILDASM over the adodb.dll you have to see what the API on the recordset class is.
You can do the following too:
//Create instance of a recordset
ADODB::RecordsetClass^ recordset;
recordset = gcnew ADODB::RecordsetClass();
//Set some options
recordset->CursorLocation = ADODB::CursorLocationEnum::adUseClient ;
recordset->CursorType = ADODB::CursorTypeEnum::adOpenDynamic;
recordset->LockType = ADODB::LockTypeEnum::adLockBatchOptimistic;
//Add columns
recordset->default->Append("Name", ADODB::DataTypeEnum::adWChar, 50, ADODB::FieldAttributeEnum::adFldFixed, nullptr);
recordset->default->Append("Number", ADODB::DataTypeEnum::adWChar, 20, ADODB::FieldAttributeEnum::adFldFixed, nullptr);
//Build an array of field names
fields = gcnew array<Object^>(2);
fields[0] = gcnew String("Name");
fields[1] = gcnew String("Number");
//Add values
array<Object^>^ values = gcnew array<Object^>(2);
values [0] = "some name";
values [1] = 1.2;
recordset->AddNew(fields, values);
//Get a value out again
recordset->MoveFirst();
ADODB::Field^ pNum= recordset->default[1];
double num = Convert::ToDouble((pNum->default));

Resources