diff --git a/src/StarfaceOutlookSync/Services/OutlookContactsService.cs b/src/StarfaceOutlookSync/Services/OutlookContactsService.cs
index db34ecc9..da7d78eb 100644
--- a/src/StarfaceOutlookSync/Services/OutlookContactsService.cs
+++ b/src/StarfaceOutlookSync/Services/OutlookContactsService.cs
@@ -2,46 +2,62 @@ using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using StarfaceOutlookSync.Models;
-using Outlook = Microsoft.Office.Interop.Outlook;
namespace StarfaceOutlookSync.Services
{
+ ///
+ /// Zugriff auf Outlook-Kontakte per dynamic COM.
+ /// Funktioniert mit jeder Outlook Classic Version (2013-2024)
+ /// ohne Abhaengigkeit von einer bestimmten Interop-DLL.
+ ///
public class OutlookContactsService : IDisposable
{
- private Outlook.Application _outlookApp;
+ private dynamic _outlookApp;
private bool _weStartedOutlook;
- // Marshal.GetActiveObject existiert nicht in .NET 8, daher P/Invoke
+ // OlDefaultFolders.olFolderContacts = 10
+ private const int OlFolderContacts = 10;
+ // OlItemType.olContactItem = 2
+ private const int OlContactItem = 2;
+
[DllImport("oleaut32.dll", PreserveSig = false)]
- private static extern void GetActiveObject([MarshalAs(UnmanagedType.LPStruct)] Guid rclsid, IntPtr pvReserved, [MarshalAs(UnmanagedType.IUnknown)] out object ppunk);
+ private static extern void GetActiveObject(
+ [MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
+ IntPtr pvReserved,
+ [MarshalAs(UnmanagedType.IUnknown)] out object ppunk);
private static object GetActiveComObject(string progId)
{
- var clsid = Type.GetTypeFromProgID(progId, true).GUID;
- GetActiveObject(clsid, IntPtr.Zero, out var obj);
+ var type = Type.GetTypeFromProgID(progId, false);
+ if (type == null) return null;
+ GetActiveObject(type.GUID, IntPtr.Zero, out var obj);
return obj;
}
- private Outlook.Application GetOutlookApp()
+ private dynamic GetOutlookApp()
{
if (_outlookApp != null) return _outlookApp;
// Versuch 1: Laufende Outlook-Instanz finden
try
{
- _outlookApp = (Outlook.Application)GetActiveComObject("Outlook.Application");
- _weStartedOutlook = false;
- return _outlookApp;
+ var obj = GetActiveComObject("Outlook.Application");
+ if (obj != null)
+ {
+ _outlookApp = obj;
+ _weStartedOutlook = false;
+ return _outlookApp;
+ }
}
catch { }
// Versuch 2: Outlook per COM starten
try
{
- var outlookType = Type.GetTypeFromProgID("Outlook.Application");
+ var outlookType = Type.GetTypeFromProgID("Outlook.Application", false);
if (outlookType != null)
{
- _outlookApp = (Outlook.Application)Activator.CreateInstance(outlookType);
+ _outlookApp = Activator.CreateInstance(outlookType);
_weStartedOutlook = true;
return _outlookApp;
}
@@ -65,18 +81,21 @@ namespace StarfaceOutlookSync.Services
var app = GetOutlookApp();
var ns = app.GetNamespace("MAPI");
- // Alle Stores durchgehen (jedes Konto, jede PST-Datei etc.)
- foreach (Outlook.Store store in ns.Stores)
+ // Alle Stores durchgehen
+ var stores = ns.Stores;
+ for (int i = 1; i <= (int)stores.Count; i++)
{
try
{
+ var store = stores[i];
var rootFolder = store.GetRootFolder();
FindContactFoldersRecursive(rootFolder, folders);
Marshal.ReleaseComObject(rootFolder);
+ Marshal.ReleaseComObject(store);
}
catch (Exception ex)
{
- System.Diagnostics.Debug.WriteLine($"Error scanning store '{store.DisplayName}': {ex.Message}");
+ System.Diagnostics.Debug.WriteLine($"Error scanning store {i}: {ex.Message}");
}
}
@@ -85,121 +104,141 @@ namespace StarfaceOutlookSync.Services
{
try
{
- var defaultFolder = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);
- folders.Add(defaultFolder.FolderPath);
+ var defaultFolder = ns.GetDefaultFolder(OlFolderContacts);
+ folders.Add((string)defaultFolder.FolderPath);
Marshal.ReleaseComObject(defaultFolder);
}
catch { }
}
+ Marshal.ReleaseComObject(stores);
Marshal.ReleaseComObject(ns);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Error getting folders: {ex.Message}");
+ throw;
}
return folders;
}
- private void FindContactFoldersRecursive(Outlook.MAPIFolder folder, List paths)
+ private void FindContactFoldersRecursive(dynamic folder, List paths)
{
try
{
- // Kontaktordner erkennen: DefaultItemType ODER Ordnername enthaelt "Kontakt"/"Contact"
- if (folder.DefaultItemType == Outlook.OlItemType.olContactItem)
+ if ((int)folder.DefaultItemType == OlContactItem)
{
- if (!paths.Contains(folder.FolderPath))
- paths.Add(folder.FolderPath);
+ string path = folder.FolderPath;
+ if (!paths.Contains(path))
+ paths.Add(path);
}
- // Alle Unterordner durchsuchen
- foreach (Outlook.MAPIFolder sub in folder.Folders)
+ var subFolders = folder.Folders;
+ for (int i = 1; i <= (int)subFolders.Count; i++)
{
try
{
+ var sub = subFolders[i];
FindContactFoldersRecursive(sub, paths);
- }
- catch { }
- finally
- {
Marshal.ReleaseComObject(sub);
}
+ catch { }
}
+ Marshal.ReleaseComObject(subFolders);
}
catch (Exception ex)
{
- System.Diagnostics.Debug.WriteLine($"Error scanning folder '{folder.Name}': {ex.Message}");
+ System.Diagnostics.Debug.WriteLine($"Error scanning folder: {ex.Message}");
}
}
- private Outlook.MAPIFolder GetFolderByPath(string folderPath)
+ private dynamic GetFolderByPath(string folderPath)
{
var app = GetOutlookApp();
var ns = app.GetNamespace("MAPI");
- // Standard-Kontaktordner als Fallback
if (string.IsNullOrEmpty(folderPath))
- return ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);
+ return ns.GetDefaultFolder(OlFolderContacts);
try
{
- // Pfad durchlaufen
var parts = folderPath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
- Outlook.MAPIFolder current = null;
+ dynamic current = null;
- foreach (Outlook.Store store in ns.Stores)
+ var stores = ns.Stores;
+ for (int i = 1; i <= (int)stores.Count; i++)
{
- if (store.GetRootFolder().Name == parts[0] ||
- store.GetRootFolder().FolderPath.TrimStart('\\') == parts[0])
+ var store = stores[i];
+ var root = store.GetRootFolder();
+ string rootName = root.Name;
+
+ if (rootName == parts[0])
{
- current = store.GetRootFolder();
+ current = root;
break;
}
+ Marshal.ReleaseComObject(root);
+ Marshal.ReleaseComObject(store);
}
+ Marshal.ReleaseComObject(stores);
if (current == null)
- return ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);
+ return ns.GetDefaultFolder(OlFolderContacts);
for (int i = 1; i < parts.Length; i++)
{
bool found = false;
- foreach (Outlook.MAPIFolder sub in current.Folders)
+ var subFolders = current.Folders;
+ for (int j = 1; j <= (int)subFolders.Count; j++)
{
- if (sub.Name == parts[i])
+ var sub = subFolders[j];
+ if ((string)sub.Name == parts[i])
{
current = sub;
found = true;
break;
}
+ Marshal.ReleaseComObject(sub);
}
+ Marshal.ReleaseComObject(subFolders);
+
if (!found)
- return ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);
+ return ns.GetDefaultFolder(OlFolderContacts);
}
return current;
}
catch
{
- return ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);
+ return ns.GetDefaultFolder(OlFolderContacts);
}
}
public List GetContacts(string folderPath)
{
var contacts = new List();
-
try
{
var folder = GetFolderByPath(folderPath);
var items = folder.Items;
- foreach (var item in items)
+ for (int i = 1; i <= (int)items.Count; i++)
{
- if (item is Outlook.ContactItem ci)
+ dynamic item = null;
+ try
{
- contacts.Add(MapFromOutlook(ci));
- Marshal.ReleaseComObject(ci);
+ item = items[i];
+ // Nur ContactItems verarbeiten (Class = 40 = olContact)
+ if ((int)item.Class == 40)
+ {
+ contacts.Add(MapFromOutlook(item));
+ }
+ }
+ catch { }
+ finally
+ {
+ if (item != null) Marshal.ReleaseComObject(item);
}
}
@@ -219,7 +258,8 @@ namespace StarfaceOutlookSync.Services
try
{
var folder = GetFolderByPath(folderPath);
- var ci = (Outlook.ContactItem)folder.Items.Add(Outlook.OlItemType.olContactItem);
+ var items = folder.Items;
+ dynamic ci = items.Add(OlContactItem);
MapToOutlook(contact, ci);
ci.Save();
@@ -227,6 +267,7 @@ namespace StarfaceOutlookSync.Services
contact.OutlookEntryId = ci.EntryID;
Marshal.ReleaseComObject(ci);
+ Marshal.ReleaseComObject(items);
Marshal.ReleaseComObject(folder);
return contact;
@@ -244,7 +285,7 @@ namespace StarfaceOutlookSync.Services
{
var app = GetOutlookApp();
var ns = app.GetNamespace("MAPI");
- var ci = (Outlook.ContactItem)ns.GetItemFromID(entryId);
+ dynamic ci = ns.GetItemFromID(entryId);
MapToOutlook(contact, ci);
ci.Save();
@@ -267,7 +308,7 @@ namespace StarfaceOutlookSync.Services
{
var app = GetOutlookApp();
var ns = app.GetNamespace("MAPI");
- var ci = (Outlook.ContactItem)ns.GetItemFromID(entryId);
+ dynamic ci = ns.GetItemFromID(entryId);
ci.Delete();
Marshal.ReleaseComObject(ci);
@@ -282,36 +323,46 @@ namespace StarfaceOutlookSync.Services
}
}
- private UnifiedContact MapFromOutlook(Outlook.ContactItem ci)
+ private UnifiedContact MapFromOutlook(dynamic ci)
{
return new UnifiedContact
{
- OutlookEntryId = ci.EntryID ?? "",
- FirstName = ci.FirstName ?? "",
- LastName = ci.LastName ?? "",
- Company = ci.CompanyName ?? "",
- JobTitle = ci.JobTitle ?? "",
- Email = ci.Email1Address ?? "",
- EmailSecondary = ci.Email2Address ?? "",
- PhoneWork = ci.BusinessTelephoneNumber ?? "",
- PhoneMobile = ci.MobileTelephoneNumber ?? "",
- PhoneHome = ci.HomeTelephoneNumber ?? "",
- Fax = ci.BusinessFaxNumber ?? "",
- Street = ci.BusinessAddressStreet ?? "",
- City = ci.BusinessAddressCity ?? "",
- PostalCode = ci.BusinessAddressPostalCode ?? "",
- State = ci.BusinessAddressState ?? "",
- Country = ci.BusinessAddressCountry ?? "",
- Website = ci.WebPage ?? "",
- Notes = ci.Body ?? "",
- Salutation = ci.Title ?? "",
- Title = ci.Suffix ?? "",
- Birthday = ci.Birthday != DateTime.MinValue && ci.Birthday.Year > 1900
- ? ci.Birthday.ToString("yyyy-MM-dd") : ""
+ OutlookEntryId = (string)(ci.EntryID ?? ""),
+ FirstName = (string)(ci.FirstName ?? ""),
+ LastName = (string)(ci.LastName ?? ""),
+ Company = (string)(ci.CompanyName ?? ""),
+ JobTitle = (string)(ci.JobTitle ?? ""),
+ Email = (string)(ci.Email1Address ?? ""),
+ EmailSecondary = (string)(ci.Email2Address ?? ""),
+ PhoneWork = (string)(ci.BusinessTelephoneNumber ?? ""),
+ PhoneMobile = (string)(ci.MobileTelephoneNumber ?? ""),
+ PhoneHome = (string)(ci.HomeTelephoneNumber ?? ""),
+ Fax = (string)(ci.BusinessFaxNumber ?? ""),
+ Street = (string)(ci.BusinessAddressStreet ?? ""),
+ City = (string)(ci.BusinessAddressCity ?? ""),
+ PostalCode = (string)(ci.BusinessAddressPostalCode ?? ""),
+ State = (string)(ci.BusinessAddressState ?? ""),
+ Country = (string)(ci.BusinessAddressCountry ?? ""),
+ Website = (string)(ci.WebPage ?? ""),
+ Notes = (string)(ci.Body ?? ""),
+ Salutation = (string)(ci.Title ?? ""),
+ Birthday = GetBirthdayString(ci)
};
}
- private void MapToOutlook(UnifiedContact contact, Outlook.ContactItem ci)
+ private string GetBirthdayString(dynamic ci)
+ {
+ try
+ {
+ DateTime bday = ci.Birthday;
+ if (bday.Year > 1900 && bday != DateTime.MinValue)
+ return bday.ToString("yyyy-MM-dd");
+ }
+ catch { }
+ return "";
+ }
+
+ private void MapToOutlook(UnifiedContact contact, dynamic ci)
{
ci.FirstName = contact.FirstName;
ci.LastName = contact.LastName;
@@ -348,7 +399,7 @@ namespace StarfaceOutlookSync.Services
{
try { _outlookApp.Quit(); } catch { }
}
- Marshal.ReleaseComObject(_outlookApp);
+ try { Marshal.ReleaseComObject(_outlookApp); } catch { }
_outlookApp = null;
}
}
diff --git a/src/StarfaceOutlookSync/StarfaceOutlookSync.csproj b/src/StarfaceOutlookSync/StarfaceOutlookSync.csproj
index acce1f2d..7cf75307 100644
--- a/src/StarfaceOutlookSync/StarfaceOutlookSync.csproj
+++ b/src/StarfaceOutlookSync/StarfaceOutlookSync.csproj
@@ -19,7 +19,6 @@
-