We don't seem to have done a good job in educating our customers on this topic, so thought I'd put this out there at least as a starting point and I'm sure we can also try and get better samples in the SDK.
One of the tricky things with setting custom fields for any entity (Project, Resource or Task - but also assignment or timesheet) is that you cannot always just call up the dataset, navigate to the custom field row and set the value. In many cases the row may not yet exist, so you need to add it, then set all the required properties and then update back through the PSI.
As an example if you create a project through the PSI it will have no project level custom field rows created by default, (except ones based on Lookup Tables with a default value forced) and any tasks will only have the "Health" special custom field set, and again- any with Lookup Table defaults. If you then open in Project Professional and just save again, you will then have added any calculated fields at the project level, along with any calculated fields at the task level. Also at this stage the project summary task (Task 0) is populated with any task level fields with roll up to summary level set.
As my server does not have all the possible combinations of fields I may be missing something here - but ProjTool is a great way to see just what is in the dataset at any time.
So whenever you are setting custom fields first see if the row already exists - and if not you will need to add a customfieldrow to whatever dataset you are working with. Then the next step is to set the appropriate properties - which will depend on the type of field you are setting (defined by FIELD_TYPE_ENUM), and the dataset you are adding it to. For instance a ProjectCustomFieldsRow will need the PROJ_UID. A TaskCustomFieldsRow will need the PROJ_UID and the TASK_UID. A Timesheet CustomFieldsRow will need the TS_UID to identify the timesheet and a TS_LINE_UID to identify the specific line. Then for any row you need to set a new GUID for the CUSTOM_FIELD_UID, the MD_PROP_UID and/or the MD_PROP_ID to identify the specific custom field and the actual value you want to set in the appropriate property as detailed in the following table.
Field Type ENUM Value Description Set field value in: COST 9 Value in 1/COST_MULTIPLIER dollars NUM_VALUE DATE 4 A date value. HIWORD contains days off set from 1/1/84. LOWORD contains minute off-set, ranging from 0 to 1440, from 12:00 A.M. (midnight) DATE_VALUE DURATION 6 Value in 1/DUR_MULTIPLIER minutes DUR_VALUE and DUR_FMT TEXT 21 A string value TEXT_VALUE FLAG 17 Index into yes/no string table FLAG_VALUE NUMBER 15 A number value NUM_VALUE (Lookup Table) GUID CODE_VALUE
FINISHDATE is also listed in the SDK but is not applicable to these custom fields. Lookup Table isn't specifically a custom field type - but I added it for completeness. If the custom field is based on a Lookup Table then the LT_STRUCT_UID of the specific entry in the Lookup Table is entered in the CODE_VALUE property. For those that accept multiple values there will be a row with each CODE_VALUE - not a single row with multiple CODE_VALUES.
Another property you will come across in the datasets is the INDICATOR_VALUE - which will hold the enumeration value for the indicator to be displayed based on the custom field settings.
No code sample just yet on this - but I will try and come up with some shortly. I am looking into a support incident where values are being set for summary tasks (or rather they are not) - these are likely to be read-only if "roll-up" is set, so be aware of that.
*** Update *** Finally got a sample together - hope it is worth the wait - http://blogs.msdn.com/b/brismith/archive/2010/08/25/project-server-adding-custom-fields-to-projects-and-tasks-using-the-psi.aspx
The ProjCFDlg.cs sample in ProjTool and the Add Project Custom Field option on the Project Details pane of ProjTool is a great place to look for an example that covers this well.
Other things to be aware of are that constraints applied to the custom fields will need to be adhered to. If the custom field only allows selection of codes with no subordinate value (leaf nodes) then the PSI cannot over-ride this.