#pragma once

#include <string>
#include <vector>
#include <thread>
#include <mutex>
#include "tsk/auto/sqlite3.h"
#include "UnManagedFileInfo.h"
#include <shared_mutex>
#include <queue>
#include <condition_variable>
#include <functional>

namespace TSKWrapper
{
    /// <summary>
    /// 存放文件信息的索引类
    /// </summary>
    public class InvertedIndex
    {
    private:
        sqlite3* db;
        std::string dbFilePath;
        mutable std::shared_mutex indexMutex;
        std::queue<std::function<void()>> taskQueue;
        std::vector<std::thread> workerThreads;
        std::mutex queueMutex;
        std::condition_variable condition;
        bool stop = false;

    public:
        InvertedIndex(const std::string& filePath) : dbFilePath(filePath)
        {
            if (int rc = sqlite3_open(":memory:", &db))
            {
                throw std::runtime_error("Can't open database: " + std::string(sqlite3_errmsg(db)));
            }
            createTable();
            initializeThreadPool(5); // 初始化线程池
        }

        ~InvertedIndex()
        {
            {
                std::unique_lock<std::mutex> lock(queueMutex);
                stop = true;
            }
            condition.notify_all();
            for (std::thread& worker : workerThreads)
                worker.join();
            sqlite3_close(db);
        }

        void createTable() const
        {
            const char* sql = "CREATE TABLE IF NOT EXISTS Files ("
                "Name TEXT NOT NULL, "
                "Path TEXT NOT NULL, "
                "Type INTEGER NOT NULL, "
                "Size INTEGER NOT NULL, "
                "ModificationDate TEXT NOT NULL, "
                "Flag INTEGER NOT NULL, "
                "IsRecycleBinFile INTEGER NOT NULL, "
                "OriginalFilePath TEXT NOT NULL, "
                "OriginalFileName TEXT NOT NULL);";
            char* errMsg = nullptr;
            int rc = sqlite3_exec(db, sql, nullptr, nullptr, &errMsg);
            if (rc != SQLITE_OK)
            {
                std::string errorMsg = "SQL error: " + std::string(errMsg);
                sqlite3_free(errMsg);
                throw std::runtime_error(errorMsg);
            }

            // 创建索引
            const char* indexSql = "CREATE INDEX IF NOT EXISTS idx_name ON Files(Name);";
            rc = sqlite3_exec(db, indexSql, nullptr, nullptr, &errMsg);
            if (rc != SQLITE_OK)
            {
                std::string errorMsg = "SQL error: " + std::string(errMsg);
                sqlite3_free(errMsg);
                throw std::runtime_error(errorMsg);
            }
        }

        /// <summary>
        /// 添加索引
        /// </summary>
        /// <param name="word"></param>
        /// <param name="fileInfo"></param>
        void addWord(const std::string& word, const UnManagedFileInfo& fileInfo) const
        {
            std::unique_lock lock(indexMutex);

            // SQL语句模板
            const char* sql = "INSERT INTO Files (Name, Path, Type, Size, ModificationDate, Flag, IsRecycleBinFile, OriginalFilePath, OriginalFileName) "
                "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);";

            sqlite3_stmt* stmt;
            int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
            if (rc != SQLITE_OK)
            {
                throw std::runtime_error("SQL prepare error: " + std::string(sqlite3_errmsg(db)));
            }

            // 绑定参数
            sqlite3_bind_text(stmt, 1, word.c_str(), -1, SQLITE_STATIC);
            sqlite3_bind_text(stmt, 2, fileInfo.Path.c_str(), -1, SQLITE_STATIC);
            sqlite3_bind_int(stmt, 3, static_cast<int>(fileInfo.Type));
            sqlite3_bind_int64(stmt, 4, fileInfo.Size);
            sqlite3_bind_text(stmt, 5, fileInfo.ModificationDate.c_str(), -1, SQLITE_STATIC);
            sqlite3_bind_int(stmt, 6, static_cast<int>(fileInfo.Flag));
            sqlite3_bind_int(stmt, 7, fileInfo.IsRecycleBinFile ? 1 : 0);
            sqlite3_bind_text(stmt, 8, fileInfo.OriginalFilePath.c_str(), -1, SQLITE_STATIC);
            sqlite3_bind_text(stmt, 9, fileInfo.OriginalFileName.c_str(), -1, SQLITE_STATIC);

            // 执行语句
            rc = sqlite3_step(stmt);
            if (rc != SQLITE_DONE)
            {
                throw std::runtime_error("SQL execution error: " + std::string(sqlite3_errmsg(db)));
            }

            // 清理
            sqlite3_finalize(stmt);
        }

        /// <summary>
        /// 根据输入在索引中查询文件信息
        /// </summary>
        /// <param name="word"></param>
        /// <param name="onBatchResult"></param>
        /// <returns></returns>
        void search(const std::string& word, std::function<void(std::vector<UnManagedFileInfo>)> onBatchResult)
        {
            try
            {
                //测试不可以正常调用
                std::vector<UnManagedFileInfo> result;
                onBatchResult(result);

                std::shared_lock lock(indexMutex);

                // 获取总记录数
                int totalRecords = getTotalRecords();
                if (totalRecords == 0) return;

                // 计算每个线程的查询范围
                int recordsPerBatch = 500;
                int numBatches = (totalRecords + recordsPerBatch - 1) / recordsPerBatch;

                for (int i = 0; i < 1; ++i)
                {
                    int offset = i * recordsPerBatch;
                    int limit = (std::min)(recordsPerBatch, totalRecords - offset);

                    enqueueTask([this, word, limit, offset, onBatchResult]() 
                        {
	                        std::vector<UnManagedFileInfo> result = singleThreadSearch(word, limit, offset);
	                        onBatchResult(result);
                        });
                }
            }
            catch (std::exception e)
            {
                throw e;
            }
        }

        std::vector<UnManagedFileInfo> singleThreadSearch(const std::string& word, int limit, int offset = 0) const
        {
            std::vector<UnManagedFileInfo> result;

            // SQL语句模板
            const char* sql = "SELECT * FROM Files WHERE Name LIKE ? LIMIT ? OFFSET ?;";

            sqlite3_stmt* stmt;
            int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
            if (rc != SQLITE_OK)
            {
                throw std::runtime_error("SQL prepare error: " + std::string(sqlite3_errmsg(db)));
            }

            // 绑定参数
            std::string searchPattern = "%" + word + "%";
            sqlite3_bind_text(stmt, 1, searchPattern.c_str(), -1, SQLITE_STATIC);
            sqlite3_bind_int(stmt, 2, limit);
            sqlite3_bind_int(stmt, 3, offset);

            // 执行语句
            while ((rc = sqlite3_step(stmt)) == SQLITE_ROW)
            {
                UnManagedFileInfo fileInfo;
                fileInfo.Name = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
                fileInfo.Path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
                fileInfo.Type = static_cast<TSK_FS_META_TYPE_ENUM>(sqlite3_column_int(stmt, 2));
                fileInfo.Size = sqlite3_column_int64(stmt, 3);
                fileInfo.ModificationDate = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4));
                fileInfo.Flag = static_cast<TSK_FS_META_FLAG_ENUM>(sqlite3_column_int(stmt, 5));
                fileInfo.IsRecycleBinFile = sqlite3_column_int(stmt, 6) != 0;
                fileInfo.OriginalFilePath = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 7));
                fileInfo.OriginalFileName = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 8));
                result.push_back(fileInfo);
            }

            // 清理
            sqlite3_finalize(stmt);

            return result;
        }

        int getTotalRecords() const
        {
            const char* sql = "SELECT COUNT(*) FROM Files;";
            sqlite3_stmt* stmt;
            int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
            if (rc != SQLITE_OK)
            {
                throw std::runtime_error("SQL prepare error: " + std::string(sqlite3_errmsg(db)));
            }

            int totalRecords = 0;
            if (sqlite3_step(stmt) == SQLITE_ROW)
            {
                totalRecords = sqlite3_column_int(stmt, 0);
            }

            sqlite3_finalize(stmt);
            return totalRecords;
        }

        void saveDatabase() const
        {
            sqlite3* fileDb;
            if (sqlite3_open(dbFilePath.c_str(), &fileDb) != SQLITE_OK) {
                throw std::runtime_error("Cannot open file database");
            }

            if (sqlite3_backup* backup = sqlite3_backup_init(fileDb, "main", db, "main"))
            {
                sqlite3_backup_step(backup, -1);
                sqlite3_backup_finish(backup);
            }

            if (sqlite3_errcode(fileDb) != SQLITE_OK) {
                sqlite3_close(fileDb);
                throw std::runtime_error("Backup failed: " + std::string(sqlite3_errmsg(fileDb)));
            }

            sqlite3_close(fileDb);
        }

        void loadDatabase() const
        {
            sqlite3* fileDb;
            int rc = sqlite3_open(dbFilePath.c_str(), &fileDb);
            if (rc)
            {
                std::cerr << "Cannot open database: " << sqlite3_errmsg(fileDb) << std::endl;
                return;
            }

            char* attachSql = sqlite3_mprintf("ATTACH DATABASE '%q' AS filedb;", dbFilePath.c_str());
            rc = sqlite3_exec(db, attachSql, nullptr, nullptr, nullptr);
            sqlite3_free(attachSql);
            if (rc != SQLITE_OK)
            {
                std::cerr << "Attach database error: " << sqlite3_errmsg(fileDb) << std::endl;
                sqlite3_close(fileDb);
                return;
            }

            rc = sqlite3_exec(db, "BEGIN;", nullptr, nullptr, nullptr);
            if (rc != SQLITE_OK)
            {
                std::cerr << "Begin transaction error: " << sqlite3_errmsg(fileDb) << std::endl;
                sqlite3_close(fileDb);
                return;
            }

            rc = sqlite3_exec(db, "INSERT INTO Files SELECT * FROM filedb.Files;", nullptr, nullptr, nullptr);
            if (rc != SQLITE_OK)
            {
                std::cerr << "Insert error: " << sqlite3_errmsg(fileDb) << std::endl;
                sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr);
                sqlite3_close(fileDb);
                return;
            }

            rc = sqlite3_exec(db, "COMMIT;", nullptr, nullptr, nullptr);
            if (rc != SQLITE_OK)
            {
                std::cerr << "Commit transaction error: " << sqlite3_errmsg(fileDb) << std::endl;
                sqlite3_close(fileDb);
                return;
            }

            sqlite3_close(fileDb);
        }

    private:
        void initializeThreadPool(int numThreads)
        {
            for (int i = 0; i < numThreads; ++i)
            {
                workerThreads.emplace_back([this]() {
                    while (true)
                    {
                        std::function<void()> task;
                        {
                            std::unique_lock<std::mutex> lock(queueMutex);
                            condition.wait(lock, [this]() { return stop || !taskQueue.empty(); });
                            if (stop && taskQueue.empty())
                                return;
                            task = std::move(taskQueue.front());
                            taskQueue.pop();
                        }
                        task();
                    }
                    });
            }
        }

        void enqueueTask(std::function<void()> task)
        {
            {
                std::unique_lock<std::mutex> lock(queueMutex);
                taskQueue.push(std::move(task));
            }
            condition.notify_one();
        }
    };
}
#pragma once

#include "IObserver.h"
#include "TypeConverterHelper.h"
#include "tsk/auto/tsk_auto.h"
#include "InvertedIndex.h"
#include "UnManagedFileInfo.h"
#include <string>
#include <memory>
#include <vcclr.h> // 包含 gcroot
#include <functional>
#include <vector>

namespace TSKWrapper
{
    /// <summary>
    /// 全盘索引构建
    /// </summary>
    public class FullDiskIndexBuilder : public TskAuto
    {
    private:
        gcroot<IObserver^> m_observer;
        gcroot<IFilterStrategy^> m_filterStrategy;
        std::unique_ptr<InvertedIndex> m_index;
        typedef std::function<void(std::vector<UnManagedFileInfo>)> BatchSearchResultCallback;
        BatchSearchResultCallback _batchSearchResultCallback;
    public:
        /// <summary>
        /// 是否外部停止扫描
        /// </summary>
        bool IsScanStopped = false;

    public:
        /// <summary>
        /// 非托管构造函数
        /// </summary>
        FullDiskIndexBuilder() : m_observer(nullptr), m_filterStrategy(nullptr), m_index(nullptr)
        {
        }

        ~FullDiskIndexBuilder() override
        {
            m_index = nullptr;
        }

        /// <summary>
        /// 工厂方法，用于创建和初始化 FullDiskIndexBuilder 实例
        /// </summary>
        static FullDiskIndexBuilder* Create(IObserver^ observer, IFilterStrategy^ filterStrategy, const std::string& dbPath)
        {
            FullDiskIndexBuilder* builder = new FullDiskIndexBuilder();
            builder->Initialize(observer, filterStrategy, dbPath);
            return builder;
        }

        /// <summary>
        /// 初始化方法
        /// </summary>
        void Initialize(IObserver^ observer, IFilterStrategy^ filterStrategy, std::string dbPath)
        {
            if (observer == nullptr || filterStrategy == nullptr)
            {
                throw std::invalid_argument("Observer and FilterStrategy cannot be null.");
            }

            m_observer = observer;
            m_filterStrategy = filterStrategy;
            m_index = std::make_unique<InvertedIndex>(dbPath);
        }

    protected:
        TSK_RETVAL_ENUM processFile(TSK_FS_FILE* fs_file, const char* path) override
        {
            if (IsScanStopped)
            {
                return TSK_STOP;
            }

            if (fs_file == nullptr)
            {
                return TSK_OK;
            }

            FileInfo^ fileInfo = TypeConverterHelper::ConvertToFileInfo(fs_file, path);
            std::string filePath = TypeConverterHelper::ConvertManagedStringToStdString(fileInfo->Path);
            std::string fileName = TypeConverterHelper::ConvertManagedStringToStdString(fileInfo->Name);
            TSK_FS_META_TYPE_ENUM fileType = static_cast<TSK_FS_META_TYPE_ENUM>(fileInfo->Type);
            int64_t fileSize = fileInfo->Size;
            std::string modificationDate = TypeConverterHelper::ConvertManagedStringToStdString(fileInfo->ModificationDate);
            TSK_FS_META_FLAG_ENUM fileFlag = static_cast<TSK_FS_META_FLAG_ENUM>(fileInfo->Flag);
            std::string originalName = TypeConverterHelper::ConvertManagedStringToStdString(fileInfo->OriginalFileName);
            std::string originalPath = TypeConverterHelper::ConvertManagedStringToStdString(fileInfo->OriginalFilePath);

            UnManagedFileInfo fileInfoObj(fileName, filePath, fileType, fileSize, modificationDate, fileFlag,
                fileInfo->IsRecycleBinFile, originalPath, originalName);

            m_index->addWord(fileName, fileInfoObj);

            bool filterConditionsAreMet = m_filterStrategy->ShouldInclude(fileInfo);
            m_observer->OnFileFound(fileInfo, filterConditionsAreMet);
            return TSK_OK;
        }

        uint8_t handleError() override
        {
            const std::vector<TskAuto::error_record> errorList = getErrorList();
            String^ managedError = TypeConverterHelper::ConvertErrorListToString(errorList);
            if (managedError != nullptr)
            {
                m_observer->OnError(managedError);
            }
            return TSK_OK;
        }

    public:
        void SetBatchSearchResultCallback(const BatchSearchResultCallback& callback)
        {
            _batchSearchResultCallback = callback;

            //测试可以正常调用
            std::vector<UnManagedFileInfo> result;
            _batchSearchResultCallback(result);
        }

        void search(const std::string& word) const
        {
            if (m_index)
            {
                m_index->search(word, _batchSearchResultCallback);
            }
        }

        void saveDatabase() const
        {
            if (m_index)
            {
                m_index->saveDatabase();
            }
        }

        void loadDatabase() const
        {
            if (m_index)
            {
                m_index->loadDatabase();
                m_index->search("", [this](const std::vector<UnManagedFileInfo>& results) {
                    for (const auto& result : results)
                    {
                        FileInfo^ managedFileInfo = gcnew FileInfo();
                        managedFileInfo->Name = TypeConverterHelper::ConvertStdStringToManagedString(result.Name);
                        managedFileInfo->Path = TypeConverterHelper::ConvertStdStringToManagedString(result.Path);
                        managedFileInfo->Type = static_cast<EnumFsMetaType>(result.Type);
                        managedFileInfo->Size = result.Size;
                        managedFileInfo->ModificationDate = TypeConverterHelper::ConvertStdStringToManagedString(result.ModificationDate);
                        managedFileInfo->Flag = static_cast<EnumFileMetaFlag>(result.Flag);
                        managedFileInfo->IsRecycleBinFile = result.IsRecycleBinFile;
                        managedFileInfo->OriginalFilePath = TypeConverterHelper::ConvertStdStringToManagedString(result.OriginalFilePath);
                        managedFileInfo->OriginalFileName = TypeConverterHelper::ConvertStdStringToManagedString(result.OriginalFileName);

                        bool filterConditionsAreMet = m_filterStrategy->ShouldInclude(managedFileInfo);
                        m_observer->OnFileFound(managedFileInfo, filterConditionsAreMet);
                    }
                    });
            }
        }
    };
}
#pragma once
#include "DriveScanner.h"
#include "FullDiskIndexBuilder.h"
#include "Event.h"
using namespace System;
using namespace System::Threading;
using namespace System::Collections::Generic;
namespace TSKWrapper
{
    /// <summary>
    /// 文件扫描类
    /// </summary>
    public ref class FullDiskIndexManager :public IObserver
    {
    private:
        Thread^ scanThread;
        FullDiskIndexBuilder* m_fullDiskIndexBuilder;
        Object^ m_statsLock;
        delegate void DelegateBatchSearchResult(std::vector<UnManagedFileInfo>);
        DelegateBatchSearchResult^ _batchSearchResult;

        void InitCallback();
        void OnBatchSearchResult(std::vector<UnManagedFileInfo> batchResult);
    public:
        /// <summary>
        /// 从磁盘扫描到文件事件
        /// </summary>
        event FileFoundEventHandler^ FileFound;
        /// <summary>
        /// 扫描文件出现错误事件
        /// </summary>
        event ErrorEventHandler^ ErrorOccurred;
        /// <summary>
        /// 索引完成事件
        /// </summary>
        event IndexCompleteHandler^ IndexCompleted;
        /// <summary>
        /// 流式返回结果事件
        /// </summary>
        event BatchSearchResultEventHandler^ BatchResult;
        /// <summary>
        /// 构造函数，接受数据库名作为参数
        /// </summary>
        FullDiskIndexManager();
        ~FullDiskIndexManager();
        void StartIndex(IFilterStrategy^ filterStrategy, bool rebuildIndex);
        void SearchFiles(String^ query);
    private:
        void ScanDrive();

    public:
        virtual void OnFileFound(FileInfo^ fileInfo, bool filterConditionsAreMet);
        virtual void OnError(String^ errorMessage);
        void StopScan();
    };
}
#include "FileInfo.h"
#include "FullDiskIndexManager.h"
#include <filesystem>
using namespace msclr::interop;
using namespace System::Collections::Generic;
namespace fs = std::filesystem;
namespace TSKWrapper
{
    FullDiskIndexManager::FullDiskIndexManager() :
        m_fullDiskIndexBuilder(nullptr),
        m_statsLock(gcnew Object())
    {
        
    }
    FullDiskIndexManager::~FullDiskIndexManager()
    {
        if (scanThread != nullptr && scanThread->IsAlive)
        {
            StopScan();
            scanThread->Abort();
            scanThread->Join();
        }

        if (m_fullDiskIndexBuilder != nullptr)
        {
            delete m_fullDiskIndexBuilder;
            m_fullDiskIndexBuilder = nullptr;
        }
    }
    void FullDiskIndexManager::StartIndex(IFilterStrategy^ filterStrategy, bool rebuildIndex)
    {
        if (m_fullDiskIndexBuilder != nullptr)
        {
            delete m_fullDiskIndexBuilder;
            m_fullDiskIndexBuilder = nullptr;
        }

        std::string dbFilePath = "FileRecoveryIndex.db";
        m_fullDiskIndexBuilder = FullDiskIndexBuilder::Create(this, filterStrategy, dbFilePath);
        InitCallback();
        if (rebuildIndex)
        {
            if (fs::exists(dbFilePath))
            {
                fs::remove(dbFilePath);
            }

            scanThread = gcnew Thread(gcnew ThreadStart(this, &FullDiskIndexManager::ScanDrive));
            scanThread->IsBackground = true;
            scanThread->Start();
        }
        else
        {
            if (fs::exists(dbFilePath))
            {
                m_fullDiskIndexBuilder->loadDatabase();
                IndexCompleted();
            }
            else
            {
                scanThread = gcnew Thread(gcnew ThreadStart(this, &FullDiskIndexManager::ScanDrive));
                scanThread->IsBackground = true;
                scanThread->Start();
            }
        }
    }

    void FullDiskIndexManager::SearchFiles(String^ query)
    {
        if (m_fullDiskIndexBuilder != nullptr)
        {
            std::string stdQuery = TypeConverterHelper::ConvertManagedStringToStdString(query);
            m_fullDiskIndexBuilder->search(stdQuery);
        }
    }


    void FullDiskIndexManager::StopScan()
    {
        if (m_fullDiskIndexBuilder != nullptr)
        {
            m_fullDiskIndexBuilder->IsScanStopped = true;
        }
    }

    void FullDiskIndexManager::ScanDrive()
    {
        array<String^>^ driveLetters = TypeConverterHelper::GetAllDriveLetters();
        std::vector<const TSK_TCHAR*> images = TypeConverterHelper::PrepareImages(driveLetters);
        for (const auto& image : images)
        {
            const TSK_TCHAR* singleImageArray[1] = { image };
            uint8_t rv = m_fullDiskIndexBuilder->openImage(1, singleImageArray, TSK_IMG_TYPE_DETECT, 0);
            if (rv != 0)
            {
                String^ imagePath = TypeConverterHelper::ToManagedString(image);
                OnError("打开图像失败: " + imagePath);
                continue;
            }
            rv = m_fullDiskIndexBuilder->findFilesInImg();
            if (rv != 0)
            {
                String^ imagePath = TypeConverterHelper::ToManagedString(image);
                OnError("在图像中查找文件失败: " + imagePath);
            }
            m_fullDiskIndexBuilder->closeImage();
        }

        m_fullDiskIndexBuilder->saveDatabase();
        IndexCompleted();
    }

    void FullDiskIndexManager::InitCallback()
    {
        _batchSearchResult = gcnew DelegateBatchSearchResult(this, &FullDiskIndexManager::OnBatchSearchResult);
        IntPtr pvFun1 = Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(safe_cast<Delegate^>(_batchSearchResult));
        m_fullDiskIndexBuilder->SetBatchSearchResultCallback(static_cast<void(*)(std::vector<UnManagedFileInfo>)>(pvFun1.ToPointer()));
    }

    // ReSharper disable once CppMemberFunctionMayBeStatic
    // ReSharper disable once CppPassValueParameterByConstReference
    void FullDiskIndexManager::OnBatchSearchResult(std::vector<UnManagedFileInfo> batchResult)
    {
        List<FileInfo^>^ managedResults = gcnew List<FileInfo^>();
        for (const auto& result : batchResult)
        {
            FileInfo^ managedFileInfo = gcnew FileInfo();
            managedFileInfo->Name = TypeConverterHelper::ConvertStdStringToManagedString(result.Name);
            managedFileInfo->Path = TypeConverterHelper::ConvertStdStringToManagedString(result.Path);
            managedFileInfo->Type = static_cast<EnumFsMetaType>(result.Type);
            managedFileInfo->Size = result.Size;
            managedFileInfo->ModificationDate = TypeConverterHelper::ConvertStdStringToManagedString(result.ModificationDate);
            managedFileInfo->Flag = static_cast<EnumFileMetaFlag>(result.Flag);
            managedFileInfo->IsRecycleBinFile = result.IsRecycleBinFile;
            managedFileInfo->OriginalFilePath = TypeConverterHelper::ConvertStdStringToManagedString(result.OriginalFilePath);
            managedFileInfo->OriginalFileName = TypeConverterHelper::ConvertStdStringToManagedString(result.OriginalFileName);

            managedResults->Add(managedFileInfo);
        }
        BatchResult(managedResults);
    }

    void FullDiskIndexManager::OnFileFound(FileInfo^ fileInfo, bool filterConditionsAreMet)
    {
        if (filterConditionsAreMet)
        {
            FileFound(fileInfo);
        }
    }

    void FullDiskIndexManager::OnError(String^ errorMessage)
    {
        ErrorOccurred(errorMessage);
    }
}
以上代码为什么FullDiskIndexBuilder可以正常调用接受到回调：
//测试可以正常调用
std::vector<UnManagedFileInfo> result;
_batchSearchResultCallback(result);
InvertedIndex确不能正常回调到:
//测试不可以正常调用
std::vector<UnManagedFileInfo> result;
onBatchResult(result);