Hobby Chef
Good news for all .Net developers working with Exchange or willing to work with Exchange but have zero experience in the domain.
Exchange Team had been working so hard to reduce your efforts and improve your efficiency.
Check out these videos to see what EWS Managed API is capable of
http://channel9.msdn.com/pdc2008/BB46/
http://msexchangeteam.com/archive/2009/03/24/450892.aspx
Keep a watch on here as it will go live in few hours, be the first one to grab it - http://msdn.microsoft.com/exchange
I have been working on different SearchFolders cases lately where customers were trying to create SearchFolder using EWS. Working on those issues has uncovered a limitation of Outlook (I tested it on 2007, but may exist with earlier versions as well)
I created the search folder using the following XML
<?xml version="1.0"?> <CreateFolderType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <ParentFolderId xmlns="http://schemas.microsoft.com/exchange/services/2006/messages"> <DistinguishedFolderId Id="searchfolders" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" /> </ParentFolderId> <Folders xmlns="http://schemas.microsoft.com/exchange/services/2006/messages"> <SearchFolder xmlns="http://schemas.microsoft.com/exchange/services/2006/types"> <DisplayName>Employee Search</DisplayName> <SearchParameters Traversal="Deep"> <Restriction> <And> <IsNotEqualTo> <ExtendedFieldURI DistinguishedPropertySetId="PublicStrings" PropertyName="EmployeeID" PropertyType="String" /> <FieldURIOrConstant> <Constant Value="" /> </FieldURIOrConstant> </IsNotEqualTo> <Exists> <ExtendedFieldURI DistinguishedPropertySetId="PublicStrings" PropertyName="CustomPropertyName" PropertyType="String" /> </Exists> </And> </Restriction> <BaseFolderIds> <DistinguishedFolderId Id="inbox" /> </BaseFolderIds> </SearchParameters> </SearchFolder> </Folders> </CreateFolderType>
I have created an email with custom property and it has some value in there to meet the criteria. The search folder is created and visible in the Outlook but I still do not see any entries under that folder. I also tried with just "Exists" criteria for the custom property but still it does not list the item. Then I created another SearchFolder with specific words in subject and itemClass = IPM.NOTE and that works fine… surprised!!
I went ahead and tried to test the Search Folder from OWA, to further add to my surprise it was not even listed in OWA… strange!! So then I dig into support.microsoft.com and found the following KB - http://support.microsoft.com/kb/831400
Symptoms: When you create Search Folders in Microsoft Office Outlook 2007 and Microsoft Office Outlook 2003in a Microsoft Exchange profile, the Search Folders do not appear in Microsoft Outlook Web Access.
Cause: This behavior occurs when you use Outlook in Cached Exchange Mode. The local copy of your mailbox maintains a Finder folder. This folder is not synchronized with the Finder folder that is in your Microsoft Exchange mailbox.
Resolution: Switch to online mode, expand search folders, let it sync with server and then you should be able to see.
I followed the resolution steps and now I can see the items in OWA & also in Outlook… relief!!
Happy Debugging…
Here is a quick sample if you are looking at creating a search folder using EWS which will look for Custom Property.
Here we are looking for a custom property named “EmployeeID” and make sure that the property exist and does not have a blank value.
public static BaseFolderType CreateCustomPropSearchFolder() { //Base folder type FolderIdType folderID = new FolderIdType(); //create the request that will create a new searchfolder under the finder directory CreateFolderType folderType = new CreateFolderType(); // inherited type from FolderType SearchFolderType[] folderArray = new SearchFolderType[1]; folderArray[0] = new SearchFolderType(); folderArray[0].SearchParameters = new SearchParametersType(); // Go a Deep traversal and search every folder inside parent folder folderArray[0].SearchParameters.Traversal = SearchFolderTraversalType.Deep; // deep traversal folderArray[0].SearchParameters.TraversalSpecified = true; // must set it to true otherwise traversal will have no effect //Define the base folder to search under, in this case its Inbox folderArray[0].SearchParameters.BaseFolderIds = new DistinguishedFolderIdType[1]; DistinguishedFolderIdType dType = new DistinguishedFolderIdType(); dType.Id = new DistinguishedFolderIdNameType(); dType.Id = DistinguishedFolderIdNameType.inbox; // we are looking at Inbox only folderArray[0].SearchParameters.BaseFolderIds[0] = dType; folderArray[0].SearchParameters.Restriction = new RestrictionType(); PathToExtendedFieldType CustomPropPath = new PathToExtendedFieldType(); CustomPropPath.DistinguishedPropertySetId = DistinguishedPropertySetType.PublicStrings; CustomPropPath.DistinguishedPropertySetIdSpecified = true; CustomPropPath.PropertyName = "EmployeeID"; CustomPropPath.PropertyType = MapiPropertyTypeType.String; ExistsType existsType = new ExistsType(); existsType.Item = CustomPropPath; // First part where the IsNotEqualToType isNotEqualType = new IsNotEqualToType(); isNotEqualType.FieldURIOrConstant = new FieldURIOrConstantType(); //Actual value of property that we are looking at ConstantValueType customPropertyValue = new ConstantValueType(); customPropertyValue.Value = string.Empty; isNotEqualType.FieldURIOrConstant.Item = customPropertyValue; isNotEqualType.Item = CustomPropPath; // Create a AND EXPRESSION & add two condition to it AndType andTypeExpressions = new AndType(); andTypeExpressions.Items = new SearchExpressionType[] {isNotEqualType,existsType }; folderArray[0].SearchParameters.Restriction.Item = andTypeExpressions; folderArray[0].DisplayName = "Employee Search"; // Give your search folder a unique name folderType.Folders = folderArray; TargetFolderIdType targetFolder = new TargetFolderIdType(); //Create the searchfolder under the Finder Folder DistinguishedFolderIdType searchFolder = new DistinguishedFolderIdType(); searchFolder.Id = DistinguishedFolderIdNameType.searchfolders; // Saving it under searchfolders root targetFolder.Item = searchFolder; folderType.ParentFolderId = targetFolder; // Uncomment the following lines of code to make it a hidden search folder, can be consumed by other programs and not visible to users // folderArray[0].ExtendedProperty = new ExtendedPropertyType[1]; // folderArray[0].ExtendedProperty[0] = new ExtendedPropertyType(); // folderArray[0].ExtendedProperty[0].ExtendedFieldURI = new PathToExtendedFieldType(); // folderArray[0].ExtendedProperty[0].ExtendedFieldURI.PropertyTag="0x10F4"; //PR_ATTR_HIDDEN // folderArray[0].ExtendedProperty[0].ExtendedFieldURI.PropertyType = MapiPropertyTypeType.Boolean; // folderArray[0].ExtendedProperty[0].Item = "true"; //Create the search folder CreateFolderResponseType createFolderResponse = esb.CreateFolder(folderType); //Return the newly created search folder FolderInfoResponseMessageType folderInfo = (FolderInfoResponseMessageType)createFolderResponse.ResponseMessages.Items[0]; return folderInfo.Folders.Length == 0 ? null : folderInfo.Folders[0]; }
Ever copied a DLL from one system to another and registered it using RegSvr32.exe? or in other words ever created a DLL hell situation? Its easy and dirty at the same time to copy-paste DLL between systems and register them using regsvr32.exe
Often you copy-paste, register DLL from temporary folders or may be desktop and then later delete the DLL or move to other folder without unregistering/re-registering it. Stop right there!!! You are creating a problem for yourself.
Every time you register a DLL, if its self-registering DLL, will create entries in System’s Registry with its current location, ProgID, CLSID along with other information. This information is used by programs when they are doing late binding to find the DLL and load in memory.
If you move/delete a DLL without unregistering/re-registering the DLL you are leaving with an entry behind in the Registry which is pointing to “Invalid Path”. In this case any program which is using that DLL will fail and you may not realize what’s happening.
As a first step in a “Could not load <Image>/Error loading <Image>” error scenario I would always go to registry and verify that the DLL is registered properly. It could be tedious task and risky as well. You may just edit a registry entry by mistake and break other functionality as well.
I have come up with a VBScript which gives you the ease to quickly verify the Image path & current version on the basic of ProgID or CLSID. This script will prompt you to enter either ProgID or CLSID and give you the desired information.
Here we are looking for PROGID of CDOSYS.DLL
…and here are the results.
Similarly you could use CLSID to do reverse lookup for ProgID & Image Path
Here is the code that I used in this script…
On Error Resume Next Dim strProgId Dim strDescription Dim strCLSID Dim strInProcServer Dim strCurVer Dim strCurVerCLSID Dim strCurVerInProcServer Dim strVersionIndependentProgID Dim oShell Set oShell = CreateObject("WScript.Shell") Dim strOutput strProgId = UCase(Trim(InputBox("Enter the ProgID/CLSID:","ProgID Tool"))) If Len(strProgId)<=0 Then Msgbox "Invalid ProgID/CLSID" Else If Left(strProgId,1) = "{" Then strProgId = oShell.RegRead("HKEY_CLASSES_ROOT\CLSID\" & strProgId & "\ProgID\") strDescription = oShell.RegRead("HKEY_CLASSES_ROOT\" & strProgId & "\") strCLSID = oShell.RegRead("HKEY_CLASSES_ROOT\" & strProgId & "\CLSID\") strCurVer = oShell.RegRead("HKEY_CLASSES_ROOT\" & strProgId & "\CurVer\") strInProcServer = oShell.RegRead("HKEY_CLASSES_ROOT\CLSID\" & strCLSID & "\InprocServer32\") strVersionIndependentProgID = oShell.RegRead("HKEY_CLASSES_ROOT\CLSID\" & strCLSID & "\VersionIndependentProgID\") strOutput = strOutput & "ProgID: " & strProgId & vbCrLf strOutput = strOutput & "Description: " & strDescription & vbCrLf strOutput = strOutput & "Current Version: " & strCurVer & vbCrLf strOutput = strOutput & "VersionIndependentProgID: " & strVersionIndependentProgID & vbCrLf & vbCrLf strOutput = strOutput & strProgId & " CLSID: " & strCLSID & vbCrLf strOutput = strOutput & strProgId & " InProcServer: " & strInProcServer & vbCrLf & vbCrLf If (Len(strCurVer)>0) Then strCurVerCLSID = oShell.RegRead("HKEY_CLASSES_ROOT\" & strCurVer & "\CLSID\") strCurVerInProcServer = oShell.RegRead("HKEY_CLASSES_ROOT\CLSID\" & strCurVerCLSID & "\InprocServer32\") strOutput = strOutput & strCurVer & " CLSID: " & strCurVerCLSID & vbCrLf strOutput = strOutput & strCurVer & " InProcServer: " & strCurVerInProcServer & vbCrLf End If Msgbox strOutput,,"ProgId Tool" End If
Happy debugging….