private string GetKeyFileName(MSIComponent component) {
     string keyFileName;
     if ((component.attr & 4) != 0) {
         keyFileName = component.key.file;
     } else if (files.Contains(component.directory + "|" + component.key.file)) {
         keyFileName = (string)files[component.directory + "|" + component.key.file];
         if (keyFileName == "KeyIsDotNetAssembly") {
             throw new BuildException("Cannot specify key '" + component.key.file +
                 "' for component '" + component.name + "'. File has been detected as " +
                 "being a COM component or Microsoft.NET assembly and is " +
                 "being registered with its own component. Please specify " +
                 "a different file in the same directory for this component's key.");
         }
     } else {
         throw new BuildException("KeyFile \"" + component.key.file +
             "\" not found in Component \"" + component.name + "\".");
     }
     return keyFileName;
 }
        /// <summary>
        /// Adds a file record to the Files table.
        /// </summary>
        /// <param name="database">The MSI database.</param>
        /// <param name="directoryTable">The MSI database view.</param>
        /// <param name="Component">The Component's XML Element.</param>
        /// <param name="fileTable">The MSI database view.</param>
        /// <param name="ComponentDirectory">The directory of this file's component.</param>
        /// <param name="ComponentName">The name of this file's component.</param>
        /// <param name="Sequence">The installation sequence number of this file.</param>
        /// <param name="msiAssemblyTable">View containing the MsiAssembly table.</param>
        /// <param name="msiAssemblyNameTable">View containing the MsiAssemblyName table.</param>
        /// <param name="componentTable">View containing the Components table.</param>
        /// <param name="featureComponentTable">View containing the FeatureComponents table.</param>
        /// <param name="classTable">View containing the Class table.</param>
        /// <param name="progIdTable">View containing the ProgId table.</param>
        /// <param name="selfRegTable">View containing the SelfReg table.</param>
        /// <param name="modComponentTable">ModuleComponent table.</param>
        private void AddFiles(InstallerDatabase database, InstallerTable directoryTable, MSIComponent Component,
            InstallerTable fileTable, string ComponentDirectory, string ComponentName, 
            ref int Sequence, InstallerTable msiAssemblyTable, InstallerTable msiAssemblyNameTable,
            InstallerTable componentTable, InstallerTable featureComponentTable, InstallerTable classTable, InstallerTable progIdTable,
            InstallerTable selfRegTable, InstallerTable modComponentTable) {

            XmlElement fileSetElem = (XmlElement)((XmlElement)_xmlNode).SelectSingleNode(
                "nant:components/nant:component[@id='" + Component.id + "']/nant:fileset", NamespaceManager);

            FileSet componentFiles = (FileSet) Element.InitializeBuildElement(
                task, fileSetElem, new FileSet(), typeof(FileSet));

            /*
            if (componentFiles.BaseDirectory == null) {
                componentFiles.BaseDirectory = new DirectoryInfo(Project.BaseDirectory);
            }
            */

            string basePath = componentFiles.BaseDirectory.FullName;
            Hashtable dirMap = new Hashtable();
            Hashtable componentMap = new Hashtable();

            foreach (string filePath in componentFiles.FileNames) {
                // Insert the File
                string fileName = Path.GetFileName(filePath);
                string dirPath = Path.GetDirectoryName(filePath);

#region Build the subdirectory structure -- Component.keepsubdirs == true
                if (Component.keepsubdirs) {
                    // foreach file, add intermediate directory records as needed
                    //    foreach directory record added that has at least one file
                    //       add a component record
                    //       hook the component record up to the feature
                    // add the file
                    string tmpDirPath = dirPath;

                    // Add intermediate directory records to the directory table
                    // List of sub directory names.  
                    ArrayList subdirList = new ArrayList();
                    if (basePath.EndsWith(Path.DirectorySeparatorChar.ToString()) || basePath.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
                        basePath = basePath.Substring(0, basePath.Length - 1);

                    while (tmpDirPath != basePath) {
                        subdirList.Insert(0, Path.GetFileName(tmpDirPath));
                        tmpDirPath = Path.GetDirectoryName(tmpDirPath);
                    }

                    tmpDirPath = basePath;
                    string parentDir = Component.directory;
                    string relativeDirId = Component.directory;
                    foreach (string folderName in subdirList) {
                        tmpDirPath = Path.Combine(tmpDirPath, folderName);
                        relativeDirId += "_" + folderName.ToUpper();

                        // Directory column is an identifier: identifiers may
                        // contain the ASCII characters A-Z (a-z), digits, 
                        // underscores (_), or periods (.). However, every
                        // identifier must begin with either a letter or an 
                        // underscore.

                        relativeDirId = relativeDirId.Replace(" ","_");

                        if (!dirMap.ContainsKey(tmpDirPath)) {
                            // Add entry to directory table
                            dirMap[tmpDirPath] = relativeDirId;

                            string path = GetShortPath(tmpDirPath) + "|" + folderName;
                        
                            // Insert the directory record
                            directoryTable.InsertRecord(relativeDirId, parentDir, path);
                            parentDir = relativeDirId;
                        } else {
                            parentDir = (string)dirMap[tmpDirPath];
                        }
                    }

                    tmpDirPath = dirPath;

                    if (tmpDirPath != basePath && !componentMap.ContainsKey(tmpDirPath)) {
                        // Create a component for this path.

                        string name = "C_" + CreateIdentityGuid();
                        componentMap[tmpDirPath] = name;
                        string newCompId = CreateRegistryGuid();
                        string directoryRef = (string)dirMap[tmpDirPath];

                        // Add a record for a new Component
                        componentTable.InsertRecord(name, newCompId, directoryRef, Component.attr, Component.condition, null);

                        // The null GUID is authored into any field of a msm database that references a feature.  It gets replaced
                        // with the guid of the feature assigned to the merge module.
                        string feature = "{00000000-0000-0000-0000-000000000000}";
                        if (featureComponents[ComponentName] != null) {
                            feature = (string)featureComponents[ComponentName];
                        }

                        // Map the new Component to the existing one's Feature (FeatureComponents is only used in MSI databases)
                        featureComponentTable.InsertRecord(feature, name);                        
                    }
                }
#endregion

                MSIFileOverride fileOverride = null;

                if (Component.forceid != null) {
                    foreach (MSIFileOverride curOverride in Component.forceid) {
                        if (curOverride.file == fileName) {
                            fileOverride = curOverride;
                            break;
                        }
                    }
                }

                string fileId = fileOverride == null ?
                    CreateIdentityGuid() :
                    fileOverride.id;

                // If the user specifies forceid & specified a file attribute, use it.  Otherwise use the
                // fileattr assigned to the component.
                int fileAttr = ((fileOverride == null) || (fileOverride.attr == 0)) ? Component.fileattr : fileOverride.attr;

                if (Component.keepsubdirs && dirMap.ContainsKey(dirPath)) {
                    // The file is down a subdirectory path
                    string dirValue = (string)dirMap[dirPath];
                    files.Add(dirValue + "|" + fileName, fileId);
                } else {
                    // Used to determine the keyfile
                    files.Add(Component.directory + "|" + fileName, fileId);
                }

                string fileSize;

                try {
                    fileSize = new FileInfo(filePath).Length.ToString();
                } catch (Exception ex) {
                    throw new BuildException(String.Format(CultureInfo.InvariantCulture, "Could not open file {0}", filePath), Location, ex);
                }

                Log(Level.Verbose, "\t" + filePath);

                // If the file is an assembly, create a new component to contain it,
                // add the new component, map the new component to the old component's
                // feature, and create an entry in the MsiAssembly and MsiAssemblyName
                // table.
                //
                bool isAssembly = false;
                Assembly fileAssembly = null;
                string fileVersion = string.Empty;
                try {
                    FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(filePath);
                    fileVersion = string.Format(CultureInfo.InvariantCulture, 
                        "{0}.{1}.{2}.{3}", fileVersionInfo.FileMajorPart, 
                        fileVersionInfo.FileMinorPart, fileVersionInfo.FileBuildPart, 
                        fileVersionInfo.FilePrivatePart);
                } catch {}

                try {
                    fileAssembly = Assembly.LoadFrom(filePath);
                    fileVersion = fileAssembly.GetName().Version.ToString();
                    isAssembly = true;
                } catch {}

                // Set the file version equal to the override value, if present
                if ((fileOverride != null) && (fileOverride.version != null) && (fileOverride.version != string.Empty)) {
                    fileVersion = fileOverride.version;
                }

                if (!IsVersion(ref fileVersion)) {
                    fileVersion = null;
                }

                string componentFieldValue = Component.name;

                if (isAssembly || filePath.EndsWith(".tlb")) {
                    // The null GUID is authored into any field of a msm database that references a feature.  It gets replaced
                    // with the guid of the feature assigned to the merge module.
                    string feature = "{00000000-0000-0000-0000-000000000000}";
                    if (featureComponents[ComponentName] != null)
                        feature = (string)featureComponents[ComponentName];

                    string asmCompName = ComponentName;

                    if ((componentFiles.FileNames.Count > 1) && !fileName.ToLower().Equals(Component.key.file.ToLower())) {
                        asmCompName = "C_" + fileId;
                        componentFieldValue = asmCompName;
                        string newCompId = CreateRegistryGuid();

                        // Add a record for a new Component
                        componentTable.InsertRecord(asmCompName, newCompId, ComponentDirectory, Component.attr, Component.condition, fileId);

                        if (modComponentTable != null) {
                            AddModuleComponentVirtual(database, modComponentTable, asmCompName);
                        }
                        else {
                            // Map the new Component to the existing one's Feature (FeatureComponents is only used in MSI databases)
                            featureComponentTable.InsertRecord(feature, asmCompName);                        
                        }
                    }

                    if (isAssembly) {
                        bool installToGAC = ((fileOverride == null) || (fileOverride.installtogac == false)) ? Component.installassembliestogac : fileOverride.installtogac;
                        // Add a record for a new MsiAssembly
                        if (installToGAC) {
                            msiAssemblyTable.InsertRecord(asmCompName, feature, fileId, null, 0);
                        }
                        else {
                            msiAssemblyTable.InsertRecord(asmCompName, feature, fileId, fileId, 0);
                        }

                        AddAssemblyManifestRecords(fileAssembly, msiAssemblyNameTable, asmCompName);

                        bool checkInterop = Component.checkinterop;

                        if (fileOverride != null) {
                            checkInterop = fileOverride.checkinterop;
                        }

                        if (checkInterop) {
                            CheckAssemblyForCOMInterop(
                                database, filePath, fileAssembly, ComponentName,
                                asmCompName, classTable, progIdTable);
                        }

                        // File can't be a member of both components
//                        if (componentFiles.FileNames.Count > 1) {
//                            files.Remove(ComponentDirectory + "|" + fileName);
//                            files.Add(ComponentDirectory + "|" + fileName, "KeyIsDotNetAssembly");
//                        }
                    } else if (filePath.EndsWith(".tlb")) {
                        typeLibComponents.Add(
                            Path.GetFileName(filePath),
                            asmCompName);
                    }
                }

                if (filePath.EndsWith(".dll") || filePath.EndsWith(".ocx")) {
                    int hmod = LoadLibrary(filePath);
                    if (hmod != 0) {
                        int regSvr = GetProcAddress(hmod, "DllRegisterServer");
                        if (regSvr != 0) {
                            Log(Level.Info, "Configuring '{0}' for COM Self Registration...",
                                Path.GetFileName(filePath));

                            // Add a record for a new Component
                            selfRegTable.InsertRecord(fileId, null);
                        }
                        FreeLibrary(hmod);
                    }

                    // Register COM .dlls with an embedded
                    // type library for self registration.
                }

                CopyToTempFolder(filePath, fileId);

//                if (!isAssembly && !filePath.EndsWith(".tlb")
//                    || componentFiles.FileNames.Count == 1) {
//                    componentFieldValue = Component.name;
//                }

                // propagate language (if available) to File table to avoid 
                // ICE60 verification warnings
                string language = GetLanguage(isAssembly, fileAssembly, filePath);

                Sequence++;

                if (Component.keepsubdirs && componentMap.ContainsKey(dirPath)) {
                    // Use the component for the file's path
                    componentFieldValue = (string)componentMap[dirPath];
                }

                fileTable.InsertRecord(fileId, componentFieldValue, GetShortFile(filePath) + "|" + fileName, 
                    fileSize, fileVersion, language, fileAttr, Sequence.ToString());
            }
        }