private void _CollectSoftwareFeedback(string directory)
        {
            /*
             * Garbage Collection für Einträge, die älter als das
             * eingestellte Intervall sind.
             */
            _RemoveOutdatedAppsInfo();

            var userDBAppDrvs    = new Dictionary <string, DBAppDrvInfo>(StringComparer.Ordinal);
            var machineDBAppDrvs = new Dictionary <string, DBAppDrvInfo>(StringComparer.Ordinal);

            var installationTypesById = _GetIdMapping("InstallationType", "Ident_InstType", "UID_InstallationType");
            var operatingSystemsById  = _GetIdMapping("OS", "Ident_OS", "UID_OS");

            foreach (string currFileName in Directory.GetFiles(directory, "*.ia"))
            {
                SetProgressInfo(LanguageManager.Instance.FormatString("SDL_ProcessingFile", currFileName));

                try
                {
                    using (Transaction t = new Transaction(ConnectData.Connection))
                    {
                        // Hole Zeit der letzten Modifikation
                        DateTime lastModified = File.GetLastWriteTimeUtc(currFileName);

                        // cleanup hashtables
                        userDBAppDrvs.Clear();
                        machineDBAppDrvs.Clear();

                        // Befülle das ApplicationInfo-Objekt aus der Datei
                        FeedBackFile    currFeedBackFile = new FeedBackFile(currFileName);
                        ApplicationInfo appInformation   = currFeedBackFile.GetApplicationInfo();

                        // Hole den passenden Namespace
                        AccountNameSpace ns;

                        switch (appInformation.MachineNamespace.ToUpperInvariant())
                        {
                        case "ADS":
                            ns = new ADSNameSpace(ConnectData);
                            break;

                        default:
                            // Default: NT, LDAP
                            throw new NotSupportedException($"Namespace {appInformation.MachineNamespace} is not supported (anymore).");
                        }

                        // Hole den passenden User-Account zu den Informationen des ApplicationInfos.
                        ISingleDbObject userAccount = ns.GetUserAccount(appInformation);

                        if (userAccount == null)
                        {
                            Result.Messages.Add(LanguageManager.Instance["UserInformationNotSupported"]);
                        }

                        // Hole das Hardware-Objekt zu den Informationen des ApplicationInfos.
                        ISingleDbObject machineAccount = ns.GetMachine(appInformation);

                        if (machineAccount == null)
                        {
                            Result.Messages.Add(LanguageManager.Instance.FormatString("MachineInformationNotSupported", appInformation.MachineNamespace));
                        }

                        // nicht bei ClientAbbruch
                        if (appInformation.ErrorLevel != "4")
                        {
                            #region Client erfolgreich

                            if (ns.NewerInstallDataDoesExist(lastModified, userAccount, machineAccount))
                            {
                                /*
                                 * Es gibt bereits neuere Daten in der Datenbank.
                                 */
                                Result.Messages.Add(LanguageManager.Format("SDL_WarnNewerData", currFileName));
                            }
                            else
                            {
                                /*
                                 * Einsammeln der DB-Daten für die Nutzerapplikationen
                                 */
                                if (userAccount != null)
                                {
                                    _CollectDBAppInfos(
                                        appInformation.UserApplications,
                                        installationTypesById,
                                        operatingSystemsById,
                                        ns.GetAccountUID(userAccount),
                                        userDBAppDrvs,
                                        true);
                                }

                                /*
                                 * Einsammeln der DB-Daten für die Maschinenapplikationen
                                 */
                                if (machineAccount != null)
                                {
                                    _CollectDBAppInfos(
                                        appInformation.MachineApplications,
                                        installationTypesById,
                                        operatingSystemsById,
                                        machineAccount.GetValue("UID_Hardware").String,
                                        machineDBAppDrvs,
                                        false);
                                }

                                /*
                                 * Behandle die dem Nutzer zugeordneten Applikationen
                                 */
                                if (userAccount != null)
                                {
                                    foreach (DBAppDrvInfo currUserDbAppDrvInfo in userDBAppDrvs.Values)
                                    {
                                        // Applikationen sind deselektiert, wenn ein Nutzeranteil existiert,
                                        // aber kein Maschinenanteil.
                                        if (!machineDBAppDrvs.ContainsKey(currUserDbAppDrvInfo.UidAppDrv))
                                        {
                                            currUserDbAppDrvInfo.IsDeselected = true;
                                        }
                                    }

                                    // Führe die Über- bzw. Untermengenbehandlung in der DB
                                    // durch. Dabei werden AppsInfo-Einträge angelegt bzw. als
                                    // deinstalliert markiert.
                                    ns.SetUserInstallStateInDB(
                                        ns.GetAccountUID(userAccount),
                                        userDBAppDrvs,
                                        lastModified);
                                }

                                /*
                                 * Behandle die der Maschine zugeordneten Applikationen
                                 * und Treiber.
                                 */
                                if (machineAccount != null)
                                {
                                    _SetMachineInstallStateInDB(
                                        machineAccount.GetValue("UID_Hardware").String,
                                        machineDBAppDrvs,
                                        lastModified);
                                }
                            }

                            #endregion
                        }


                        if (_MaxAgeClientLog == 0)
                        {
                            // remove all associated client log entries
                            ns.RemoveClientLogEntries(machineAccount, userAccount);
                        }
                        else if (appInformation.InstallLog != null)
                        {
                            // create new client log entry
                            ns.CreateClientLogEntry(machineAccount, userAccount, lastModified,
                                                    appInformation);
                        }

                        t.Commit();
                    }

                    if (File.Exists(currFileName))
                    {
                        File.Delete(currFileName);
                    }
                }
                finally
                {
                    // rename response file, if still exists (to handle those files
                    // that caused error messages / exceptions)
                    if (File.Exists(currFileName))
                    {
                        File.Move(currFileName, string.Format("{0}_{1:yyyyMMddHHmmss}", currFileName, DateTime.Now));
                    }
                }
            }             // foreach file
        }
        /// <summary>
        /// Sammle die Informationen aus Sectionname und Driver zu unseren Feedback-Einträgen ein.
        /// </summary>
        /// <param name="appInfos">Liste von Feedback-Einträgen</param>
        /// <param name="installationTypesById">Mapping from ID to UID</param>
        /// <param name="operatingSystemsById">Mapping from ID to UID</param>
        /// <param name="uid">UID des zugehörigen Namespace-Objektes.</param>
        /// <param name="destination">Dictionary, das Einträge aufnehmen soll.</param>
        /// <param name="ignoreDrivers">Sollen Einträge für Treiber ignoriert werden?</param>
        private void _CollectDBAppInfos(
            IList <AppsDrvProfileInfo> appInfos,
            IDictionary <string, string> installationTypesById,
            IDictionary <string, string> operatingSystemsById,
            string uid,
            IDictionary <string, DBAppDrvInfo> destination,
            bool ignoreDrivers)
        {
            var f            = ConnectData.Connection.SqlFormatter;
            var exec         = ConnectData.Connection.CreateSqlExecutor(ConnectData.PublicKey);
            var sectionNames = new Dictionary <string, bool>(StringComparer.OrdinalIgnoreCase);

            /*
             * Hole die Liste der Sectionnames.
             */
            if (appInfos.Count > 0)
            {
                var sql = "select ident_sectionname, appsnotdriver from sectionname where " +
                          f.InClause("ident_sectionname", ValType.String, appInfos.Select(a => a.SectionName));

                using (var rd = exec.SqlExecute(sql))
                {
                    while (rd.Read())
                    {
                        sectionNames[rd.GetString(0)] = rd.GetBoolean(1);
                    }
                }
            }

            /*
             * Teile die Info-Objekte in Applikationen und
             * Treiber auf.
             */
            var appsBySectionName    = new Dictionary <string, AppsDrvProfileInfo>(sectionNames.Count, StringComparer.OrdinalIgnoreCase);
            var driversBySectionName = new Dictionary <string, AppsDrvProfileInfo>(sectionNames.Count, StringComparer.OrdinalIgnoreCase);

            foreach (AppsDrvProfileInfo info in appInfos)
            {
                if (!sectionNames.ContainsKey(info.SectionName))
                {
                    // Der SectionName existiert nicht
                    Result.Messages.Add(string.Format(LanguageManager.Instance.GetString("SDL_WarnSectionNameNotFound"),
                                                      info.SectionName));
                }
                else
                {
                    if (sectionNames[info.SectionName])
                    {
                        appsBySectionName[info.SectionName] = info;
                    }
                    else
                    {
                        driversBySectionName[info.SectionName] = info;
                    }
                }
            }

            /*
             * Erzeuge die zugehörige DBAppDrvInfo-Objekte,
             * das die Daten aus Application und den
             * Accout-Schlüssel enthält.
             */
            if (appsBySectionName.Count > 0)
            {
                string sql = "select ident_sectionname, uid_application, namefull from application where " +
                             f.InClause("ident_sectionname", ValType.String, appsBySectionName.Values.Select(i => i.SectionName));

                using (IDataReader rd = exec.SqlExecute(sql))
                {
                    while (rd.Read())
                    {
                        AppsDrvProfileInfo info;

                        var sectionName = rd.GetString(0);

                        if (appsBySectionName.TryGetValue(sectionName, out info))
                        {
                            // Entferne den Eintrag, um auf fehlende Einträge zu testen.
                            appsBySectionName.Remove(sectionName);

                            string uidInstallationType;
                            string uidOperatingSystem;

                            if (!installationTypesById.TryGetValue(info.InstallType, out uidInstallationType))
                            {
                                Result.Messages.Add(LanguageManager.Format("SDL_WarnInstallationTypeNotFound", info.InstallType));
                                continue;
                            }

                            if (!operatingSystemsById.TryGetValue(info.OS, out uidOperatingSystem))
                            {
                                Result.Messages.Add(LanguageManager.Format("SDL_WarnOSNotFound", info.OS));
                                continue;
                            }

                            var dbinfo = new DBAppDrvInfo(
                                info,
                                rd.GetString(1),
                                uid,
                                rd.GetString(2),
                                uidInstallationType,
                                uidOperatingSystem,
                                true);

                            destination.Add(dbinfo.UidAppDrv, dbinfo);
                        }
                    }
                }
            }

            foreach (AppsDrvProfileInfo info in appsBySectionName.Values)
            {
                // Für die übrigen gibt es keinen Apps-Eintrag
                Result.Messages.Add(
                    LanguageManager.Instance.FormatString(
                        "SDL_WarnNoAppsEntry",
                        info.SectionName,
                        "Application"));
            }

            /*
             * Erzeuge die zugehörige DBAppDrvInfo-Objekte,
             * die die Daten aus Driver und den
             * Accout-Schlüssel enthalten.
             */

            if (!ignoreDrivers)
            {
                if (driversBySectionName.Count > 0)
                {
                    string sql = "select ident_sectionname, uid_driver, namefull from driver where " +
                                 f.InClause("ident_sectionname", ValType.String, driversBySectionName.Values.Select(i => i.SectionName));

                    using (IDataReader rd = exec.SqlExecute(sql))
                    {
                        while (rd.Read())
                        {
                            AppsDrvProfileInfo info;

                            var sectionName = rd.GetString(0);

                            if (driversBySectionName.TryGetValue(sectionName, out info))
                            {
                                // Entferne den Eintrag, um auf fehlende Einträge zu testen.
                                driversBySectionName.Remove(sectionName);

                                string uidInstallationType;
                                string uidOperatingSystem;

                                if (!installationTypesById.TryGetValue(info.InstallType, out uidInstallationType))
                                {
                                    Result.Messages.Add(LanguageManager.Format("SDL_WarnInstallationTypeNotFound", info.InstallType));
                                    continue;
                                }

                                if (!operatingSystemsById.TryGetValue(info.OS, out uidOperatingSystem))
                                {
                                    Result.Messages.Add(LanguageManager.Format("SDL_WarnOSNotFound", info.OS));
                                    continue;
                                }

                                var dbinfo = new DBAppDrvInfo(
                                    info,
                                    rd.GetString(1),
                                    uid,
                                    rd.GetString(2),
                                    uidInstallationType,
                                    uidOperatingSystem,
                                    false);

                                destination.Add(dbinfo.UidAppDrv, dbinfo);
                            }
                        }
                    }
                }

                foreach (AppsDrvProfileInfo info in driversBySectionName.Values)
                {
                    // Für die übrigen gibt es keinen Apps-Eintrag
                    Result.Messages.Add(
                        LanguageManager.Instance.FormatString(
                            "SDL_WarnNoAppsEntry",
                            info.SectionName,
                            "Driver"));
                }
            }
        }