c# Winforms के बिना ClassLibrary में ActiveX घटक का उपयोग कैसे करें



wpf com (1)

क्लास लायब्रेरी टाइप प्रोजेक्ट में एक ActiveX नियंत्रण का उपयोग कैसे किया जा सकता है?

मैं इसे बाद में WPF अनुप्रयोग से कॉल करने का इरादा रखता हूं, लेकिन मैं फॉर्म पर कहीं भी एक नियंत्रण नहीं रखना चाहता, इसलिए मैं WindowsFormsHost का उपयोग नहीं करना चाहता हूं; मुख्यतः क्योंकि मैं कंसोल ऐप और विंडोज सर्विस में मेरी लाइब्रेरी का उपयोग करना चाहूंगा।

इस स्थिति में, मैं ActiveX नियंत्रण का उपयोग करना चाहता हूं एक वीडियो विश्लेषण घटक है। इसके अतिरिक्त मैं चाहता हूं कि मेरा घटक खुद को तैनात परिवेश में पंजीकृत करे।


मुझे लगता है कि सामान्य ज्ञान यह है कि आपको ActiveX नियंत्रण का उपयोग करने के लिए Winforms की आवश्यकता है। ठीक है, पूरी तरह से सही नहीं। आपको winforms की तरह संदेश लूप और STAThread की आवश्यकता है।

मेरे समाधान के डिजाइन को प्रस्तुत करते हुए शुरू करते हैं। मैं कुछ अलग से परतों को अलग करना पसंद करता हूं, जब कुछ अज्ञात से निपटने की आवश्यकता होती है, तो आपको कुछ परतें बेमानी हो सकती हैं मैं आपको संतुलन को खोजने के लिए समाधान को बेहतर बनाने में मदद करने के लिए प्रोत्साहित करता हूं।

यदि आवश्यक हो तो सभी बाह्य परतों में IDisposable इंटरफ़ेस को लागू करने की आवश्यकता के बारे में याद रखें

ActiveXCore - एक निजी क्षेत्र के रूप में घोषित ActiveX नियंत्रण वाला वर्ग। इस वर्ग में आप केवल कोड का उपयोग करते हैं जैसे आप Winforms में

CoreAPI - एक आंतरिक एपीआई वर्ग जो कि ActiveXCore के तरीकों को उजागर करता है मुझे पता चला कि [STAThreadAttribute] साथ तरीकों को चिह्नित करना अच्छा है क्योंकि मुझे इसके बिना कुछ समस्या थी, हालांकि यह केवल इस मामले के लिए विशिष्ट है।

PublicAPI - मेरे मुख्य पुस्तकालय वर्ग को संदर्भित परियोजनाओं में बुलाया जाएगा।

अब, ActiveXCore में वास्तव में कोई दिशानिर्देश नहीं हैं CoreAPI में नमूना विधि होगी

[STAThreadAttribute]
internal bool Init()
{
    try
    {
        _core = new ActiveXCore();
        //...

        return true;
    }
    catch (System.Runtime.InteropServices.COMException)
    {
        //handle the exception
    }
    return false;
}

इन्हें ठीक से चलाने में सक्षम होने के लिए आपको Winforms जैसे संदेश पाश की ज़रूरत होगी जैसे कि (desing मेरे बिल्कुल नहीं है, मैंने कोड को थोड़ी सी में बदल दिया है)। आपको विनफॉर्म प्रोजेक्ट प्रकार की आवश्यकता नहीं है, लेकिन आपको सिस्टम

public class MessageLoopApartment : IDisposable
{
    public static MessageLoopApartment Apartament
    {
        get
        {
            if (_apartament == null)
                _apartament = new MessageLoopApartment();
            return _apartament;
        }
    }

    private static MessageLoopApartment _apartament;
    private Thread _thread; // the STA thread

    private TaskScheduler _taskScheduler; // the STA thread's task scheduler

    public TaskScheduler TaskScheduler { get { return _taskScheduler; } }

    /// <summary>MessageLoopApartment constructor</summary>
    public MessageLoopApartment()
    {
        var tcs = new TaskCompletionSource<TaskScheduler>();

        // start an STA thread and gets a task scheduler
        _thread = new Thread(startArg =>
        {
            EventHandler idleHandler = null;

            idleHandler = (s, e) =>
            {
                // handle Application.Idle just once
                Application.Idle -= idleHandler;
                // return the task scheduler
                tcs.SetResult(TaskScheduler.FromCurrentSynchronizationContext());
            };

            // handle Application.Idle just once
            // to make sure we're inside the message loop
            // and SynchronizationContext has been correctly installed
            Application.Idle += idleHandler;
            Application.Run();
        });

        _thread.SetApartmentState(ApartmentState.STA);
        _thread.IsBackground = true;
        _thread.Start();
        _taskScheduler = tcs.Task.Result;
    }

    /// <summary>shutdown the STA thread</summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_taskScheduler != null)
        {
            var taskScheduler = _taskScheduler;
            _taskScheduler = null;

            // execute Application.ExitThread() on the STA thread
            Task.Factory.StartNew(
                () => Application.ExitThread(),
                CancellationToken.None,
                TaskCreationOptions.None,
                taskScheduler).Wait();

            _thread.Join();
            _thread = null;
        }
    }

    /// <summary>Task.Factory.StartNew wrappers</summary>
    public void Invoke(Action action)
    {
        Task.Factory.StartNew(action,
            CancellationToken.None, TaskCreationOptions.None, _taskScheduler).Wait();
    }

    public TResult Invoke<TResult>(Func<TResult> action)
    {
        return Task.Factory.StartNew(action,
            CancellationToken.None, TaskCreationOptions.None, _taskScheduler).Result;
    }

    public Task Run(Action action, CancellationToken token)
    {
        return Task.Factory.StartNew(action, token, TaskCreationOptions.None, _taskScheduler);
    }

    public Task<TResult> Run<TResult>(Func<TResult> action, CancellationToken token)
    {
        return Task.Factory.StartNew(action, token, TaskCreationOptions.None, _taskScheduler);
    }

    public Task Run(Func<Task> action, CancellationToken token)
    {
        return Task.Factory.StartNew(action, token, TaskCreationOptions.None, _taskScheduler).Unwrap();
    }

    public Task<TResult> Run<TResult>(Func<Task<TResult>> action, CancellationToken token)
    {
        return Task.Factory.StartNew(action, token, TaskCreationOptions.None, _taskScheduler).Unwrap();
    }
}

और फिर आप इस तरह से तरीके प्रदान कर सकते हैं

public bool InitLib()
{   
    return MessageLoopApartment.Apartament.Run(() =>
    {
         ca = new CoreAPI();
         bool initialized = ca.Init();
    }, CancellationToken.None).Result;
}

यदि विधि शून्य होगी

public void InitLib()
{   
    MessageLoopApartment.Apartament.Run(() =>
    {
         ca = new CoreAPI();
         ca.Init();
    }, CancellationToken.None).Wait();
}

ऑटो पंजीकरण के लिए मैंने इस तरह से कुछ डिजाइन किया है (मैं इसे CoreAPI से CoreAPI )

internal static class ComponentEnvironment
{
    internal static void Prepare()
    {   
        CopyFilesAndDeps();

        if (Environment.Is64BitOperatingSystem) 
            RegSvr64();
        RegSvr32(); //you may notice no "else" here
        //in my case for 64 bit I had to copy and register files for both arch 
    }

    #region unpack and clean files

    private static void CopyFilesAndDeps()
    {
        //inspect what file you need
    }

    #endregion unpack and clean files

    #region register components

    private static void RegSvr32()
    {
        string dllPath = @"xxx\x86\xxx.dll";
        Process.Start("regsvr32", "/s " + dllPath);
    }

    private static void RegSvr64()
    {
        string dllPath = @"xxx\x64\xxx.dll";
        Process.Start("regsvr32", "/s " + dllPath);
    }

    #endregion register components
}

मैंने इस पुन: प्रयोज्य पैटर्न को डिजाइन करने के लिए कई दिन और रात बिताई इसलिए मुझे आशा है कि यह किसी को मदद करेगा





activex