Can someone explain what the pid field in a PROPERTYKEY structure is? Microsoft says just don't use 0 or 1 and you're fine, but this doesn't help when I need to implement IPropertyStore in my code. Is the pid supposed to be part of the key, so multiple values with the same fmtid but different pid may be present? Or should it be ignored, so GetValue should return any value with a matching fmtid, ignoring pid?
This fmtid+pid combination is historically related to OLE (yes, that's pretty old).
At that time, the fmtid (format id) was like a category, and the pid (property id) was the property identifier in the category. For example, you have here the first FMTID defined: Predefined Property Set Format Identifiers. These properties are still used for Office documents (Author, Keywords, etc.) So you had many properties per category (so few fmtid for a lot of properties), but the combination of both fmtid and pid always make the property unique across space and galaxies.
Others FMTID appeared since, you can have a look at in in Windows SDK's propkey.h: FMTID_AudioSummaryInformation, FMTID_Volume, FMTID_ShellDetails, etc...
Today, for some new properties, the FMTID does not mean anything anymore. For example, the System.Contact.Birthday has a fmtid of 176DC63C-2688-4E89-8143-A347800F25E9 and an id of 47, but the fmtid has no special meaning, and is not defined specifically, so it in fact could be used solely for the key.
So, for a given property, you must consider the key is still the combination of both (hence the structure name: PROPERTYKEY), but you could define your own properties with pid as something greater or equal to 2 (as the official doc specifies) and fmtid as a new guid if you prefer. I personally still prefer to define one common FMTID for a group of properties.
Related
I'm writing some code in C# that matches a pattern from the subject and then ingests the email. To initialize my datastore, I go through the current Microsoft.Office.Interop.Outlook.Table.
while (!table.EndOfTable)
{
Row row = table.GetNextRow();
string entryId = row["EntryID"].ToString();
this.SaveInXML(entryId, row);
}
It seems pretty simple. Well, I also have an event (Application.ItemLoad) that I'm watching, too. I notice that in the event the MailItem's EntryID is completely different than the Table's EntryID. In fact, the string lengths are not even the same (See example below). Why is this? Shouldn't they be the same? The item has not moved folders, so I'd assume it's the same. Thank you, all.
Example code:
NameSpace ns = this.Folder.Application.GetNamespace("MAPI");
var mi = ns.GetItemFromID("EF0000003E65593F1D361C44AFBFA24E6F365D6E04782F00") as MailItem;
string entryId = mi.EntryID;
System.Diagnostics.Debug.WriteLine("EF0000003E65593F1D361C44AFBFA24E6F365D6E04782F00");
System.Diagnostics.Debug.WriteLine(entryId);
// Output Produced:
// EF0000003E65593F1D361C44AFBFA24E6F365D6E04782F00
// 000000003E65593F1D361C44AFBFA24E6F365D6E0700CC348F1AD97A224B9898503750437E4700000000010C0000CC348F1AD97A224B9898503750437E470000F59160590000
//
// Notice that the second WriteLine isn't even remotely close to the EntryID that I requested.
Entry identifiers come in two types: short-term and long-term.
Short-term entry identifiers are faster to construct, but their uniqueness is guaranteed only over the life of the current session on the current workstation.
Long-term entry identifiers have a more prolonged lifespan. Short-term entry identifiers are used primarily for rows in tables and entries in dialog boxes, whereas long-term entry identifiers are used for many objects such as messages, folders, and distribution lists.
Use the MailItem.EntryID property if you need to get a long-term entry identifiers.
Entry identifiers cannot be compared directly because one object can be represented by two different binary values. Use the NameSpace.CompareEntryIDs method to determine whether two entry identifiers represent the same object.
As Eugene noted, you have two kinds of entry ids - long term and short term. Even for long-term entry ids, they can be different depending on how the item was opened. Long term entry ids always start with "00000000". Short term entry ids can only be used in the current MAPI session and therefore should not be persisted to be used across different sessions.
You must treat entry id as black boxes and never compare them directly - always use Namespace.CompareEntryIDs.
I'm using Ruby scripts to to round-trip a SKOS vocabulary definition in Turtle format through to a spreadsheet (via CSV) and back to allow non-technical people to check and update the localised phrases. This then needs to be converted back into the Turtle format with as little non-significant churn and variation from the original as possible.
The spreadsheet has these columns (for the sake of this example):
vocab ID
term ID
property ID
value
EN
FR
...
vocab ID contains an abbreviated URI for the vocabulary, e.g. foo:bar.
property ID contains abbreviated URIs identifying a property of either the vocabulary itself or a term in it. (such as dcterm:created or dc:title for the former case; or skos:prefName or skos:altLabel for the latter). A special case of the former is base_uri, defining the vocab's base URI.
term ID contains IDs identifying a term in the vocabulary when appropriate - or it is blank for properties of the vocabulary itself.
value is an unlocalised string literal, or some other sort of literal (like a date), or an URI, as appropriate. It may be blank if the value is a localised string - the other columns then contain the translated versions of the property in various languages. The column name is the two-letter identifier for the language.
Creating the CSV is not the problem - what is a little tricky is reading back the literal values and recreating the correct literal values.
Here's the thing: I'd like to be able to infer the XSD datatype of the property from the RDF::Term for it. I can look the latter up from the abbreviated URI, using RDF::Vocab. However there seems to be no mapping I can find in these libraries to the XSD datatype (whether mandatory or merely suggested.)
This seems to mean I must create a mapping from property IDs to the XSD datatype myself if I'm to avoid ending up with all the values becoming string literals by default (which wouldn't preserve the original datatypes).
Can anyone advise if I'm correct here, or is there a way to infer the nominal XSD datatype to use using the Ruby RDF libraries?
I presume you mean an RDF::Vocabulary::Term instance, which typically is an IRI, but contains accessors for a related vocabulary definition.
The Documentation for RDF::Vocabulary::Term describes the generic accessors you can use, and for a term based on a property, you might look at either range or rangeIncludes accessors to get an idea of what the preferred values that might be used as the object of a triple using this term.
The built-in vocabularies are minimal, pretty much limited to RDF, RDFS, XSD, and OWL. Load the rdf-vocab gem, and many other vocabularies are loaded. You can also use the RDF::Vocabulary.from_graph class method to instantiate a new vocabulary, including its term definitions, from a graph.
For example, see the following:
require 'rdf/vocab'
RDF::Vocab::SCHEMA.name.rangeIncludes # => [RDF::Vocab::SCHEMA.Text]
RDF::Vocab::FOAF.name.range # => [RDF::RDFS.Literal]
Other common accessors correspond to basic RDFS, OWL, SKOS, and schema.org annotation properties. Or, you can access an arbitrary annotation property using #attribute_value and #properties accessors.
In some cases, property range may be more complex, take for example, the term definition for skos:member:
property :member,
definition: "Relates a collection to one of its members.".freeze,
domain: "http://www.w3.org/2004/02/skos/core#Collection".freeze,
isDefinedBy: "http://www.w3.org/2004/02/skos/core".freeze,
label: "has member".freeze,
range: term(
type: "http://www.w3.org/2002/07/owl#Class".freeze,
unionOf: list("http://www.w3.org/2004/02/skos/core#Concept".freeze, "http://www.w3.org/2004/02/skos/core#Collection".freeze)
),
type: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#Property".freeze, "http://www.w3.org/2002/07/owl#ObjectProperty".freeze]
Additionally, the rdf-reasoner gem can form entailments over vocabularies to provide additional domain and range (and other) information based on subProperty hierarchies (as well as class hierarchies for rdf:type).
Is there a way to temporarily override hashcode and equals in java ?
I have a User class with id, name and age attributes. The current equals compares the id, rightly so. So if two ids, are same then the Users are equal.
Now, I have two Lists of User and I want to find users with common names.
Other than looping every element of list1 over every element of list2, I have no other option (java 7). Is there a way, I can temporarily change the behaviour of equals ? In this case, where I am coding the logic for searching users with common names, I want to be able to say if name is same then the users are equal (even though its technically incorrect), without touching the actual User class's equal.
I am writing an extension to my companies existing SNMP MIB. I have a whole list of objects, with the same properties on each. I want to be able to get and set these through SNMP.
So for example, consider my object has name, desc, arg0, arg1. What I want is to be able to refer to these as:
fullpath.objects.ObjectA.name
fullpath.objects.ObjectA.desc
fullpath.objects.ObjectA.arg0
fullpath.objects.ObjectB.name
fullpath.objects.ObjectB.desc
fullpath.objects.ObjectB.arg0
However the leaf nodes appear to have to have unique names, so I am unable to define this.
I can use a SNMP table to produce:
fullpath.objects.table.name.1
fullpath.objects.table.desc.1
fullpath.objects.table.arg0.1
fullpath.objects.table.name.2
fullpath.objects.table.desc.2
fullpath.objects.table.arg0.2
But there is nowhere to look up that 2 means ObjectB. This leaves it open to user error looking up the wrong value and setting the wrong thing.
At the moment the best solution I can see is:
fullpath.objects.ObjectAName
fullpath.objects.ObjectADesc
fullpath.objects.ObjectAArg0
fullpath.objects.ObjectBName
fullpath.objects.ObjectBDesc
fullpath.objects.ObjectBArg0
which involves defining name for every object (there are 20 or so of them). The set of objects is fixed, so this is ok...just not very tidy.
Is there some way to define names for index in the table?
Is there some way of defining a container type?
Is there some way of allowing leaf nodes to be non-unique?
Any other ideas?
You should definitely use SNMP tables to accomplish what is required. This is the only way.
MIB Object names must be unique within entire MIB file.
You can easily use object of OCTET STRING type as Table index. So each byte/symbol/char of OCTET STRING value will be translated to corresponding numeric ASCII code in OID.
I ended up just using a naming convention and adding each of the settings directly into the MIB.
Not really the answer I wanted, but it means that all of the settings show up in the MIB, and that reduces the chance of users setting the wrong setting.
For example, key 1 will have values "A","B","C" but key 2 will have value "D". If I use
Map<String, List<String>>
I need to populate the List<String> even when I have only single String value.
What data structure should be used in this case?
Map<String,List<String>> would be the standard way to do it (using a size-1 list when there is only a single item).
You could also have something like Map<String, Object> (which should work in either Java or presumably C#, to name two), where the value is either List<String> or String, but this would be fairly bad practice, as there are readability issue (you don't know what Object represents right off the bat from seeing the type), casting happens during runtime, which isn't ideal, among other things.
It does however depend what type of queries you plan to run. Map<String,Set<String>> might be a good idea if you plan of doing existence checks in the List and it can be large. Set<StringPair> (where StringPair is a class with 2 String members) is another consideration if there are plenty of keys with only 1 mapped value. There are plenty of solutions which would be more appropriate under various circumstances - it basically comes down to looking at the type of queries you want to perform and picking an appropriate structure according to that.