C++ 控制台应用程序调用 C++/CLI 静态库

问题描述 投票:0回答:1

我正在考虑创建一个 C++/CLI 静态库的想法,该库公开了许多用于托管 EventLogger 功能的静态函数。我当前的解决方案存在于

/clr
编译的 C++ 项目和 C++ 控制台应用程序中。

Visual Studio 告诉我 ConsoleApp 需要使用

/clr
参数进行编译,但这是我不想做的事情。有什么方法可以实现我在这里想要做的事情吗?

#### ConsoleApp.cpp

#include <iostream>
#include "../ClrEtwLogger/ClrEtwLogger.h"

int main()
{
    clr_etw_logger::etw_logger::etw_log();
}
#### ClrEtwLogger.h (/clr), static library

#pragma once

#using <system.dll>

using namespace System;
using namespace Diagnostics;

namespace clr_etw_logger
{
    public ref class etw_logger
    {
    public:
        static void etw_log()
        {
            const auto source = gcnew String("dotNet ClrEtwLogger");
            const auto log = gcnew String("EtwLogger");
            const auto event = gcnew String("Sample Event 1");

            if (!EventLog::SourceExists(source))
            {
                EventLog::CreateEventSource(source, log);
            }

            EventLog::WriteEntry(source, event);
            EventLog::WriteEntry(source, event, EventLogEntryType::Warning, 234);
        }
    };
}
c++ c++-cli
1个回答
0
投票

是的,您可以将托管代码包装在非托管函数中,然后按照以下步骤从托管项目中调用它,

1>创建一个空项目c++项目

2>Configuration -> Advanced 页面中将Common Language Runtime Support 设置为Common Language Runtime Support (/clr)

3> 在配置 > C++ > 命令行中,添加此文本以清除链接器错误 -> /Zc:twoPhase-

4> 将 .NET 版本设置为您在 .NET Framework 版本字段的 Configuration -> Advanced 页面中安装的版本,例如 4.8

5> 添加对必要 Dll 的引用

在我的示例中,我引用了以下程序集

System
System.Data
System.Windows.Forms
System.Drawing

6>Configuration->General页面,将Configuration Type改为静态库,

7>Configuration -> Advanced页面,将Target File Extension更改为.lib 在这个例子中,代码在没有头文件的 main.cpp 中编译

using namespace System;
using namespace System::Threading;
using namespace System::Windows::Forms;
using namespace System::Windows;

namespace MyApp
{
    public ref class MyForm : public Form
    {
    public:
        MyForm() {
            InitializeComponent();
        }

        ProgressBar^ GetProgressBar() {
            return pgb;
        }

    protected:
        ~MyForm() {

        }

    private:
        ProgressBar^ pgb;

        void InitializeComponent() {
            pgb = gcnew ProgressBar();
            SuspendLayout();
            // 
            // progressBar
            // 
            pgb->Dock = DockStyle::Fill;
            pgb->Location = Drawing::Point(0, 0);
            pgb->Name = "pgb";
            pgb->Size = Drawing::Size(200, 20);
            pgb->TabIndex = 0;
            // 
            // MyForm
            // 
            ClientSize = Drawing::Size(200, 20);
            Controls->Add(pgb);
            auto fs = Forms::FormBorderStyle::FixedSingle;
            this->FormBorderStyle = fs;
            MaximizeBox = false;
            MinimizeBox = false;
            Name = "MyForm";
            auto sp = FormStartPosition::CenterScreen;
            StartPosition = sp;
            Text = "My Form";
            ResumeLayout(false);
        }
    };
}
    void ShowProgress() {
        auto f = gcnew MyApp::MyForm();
        f->TopMost = true;
        f->Show();
        f->GetProgressBar()->Visible = true;
        f->GetProgressBar()->Minimum = 1;
        f->GetProgressBar()->Maximum = 100;
        f->GetProgressBar()->Value = 90;
        f->GetProgressBar()->Step = 1;

        auto fv = f->GetProgressBar()->Value;
        while (fv < 10)
        {
            f->GetProgressBar()->Value += 1;
            Thread::Sleep(1);
            f->Update();
        }

        f->Close();
    }

    void RunProgress() {
        try {
            auto ts = gcnew ThreadStart(ShowProgress);
            auto t = gcnew Thread(ts);
            t->SetApartmentState(ApartmentState::STA);
            t->Start();
            t->Join();
        }
        catch (Exception^ e) {
            // TODO: Handle any exceptions
        }
    }

    void ShowProgressBar()
    {
        MyApp::MyForm^ form = nullptr;
        form = gcnew  MyApp::MyForm();
        form->TopMost = true;
        form->Show();
        form->GetProgressBar()->Visible = true;
        form->GetProgressBar()->Minimum = 1;
        form->GetProgressBar()->Maximum = 100;
        form->GetProgressBar()->Value = 1;
        form->GetProgressBar()->Step = 1;
        auto i = 0;

        if (form)
        {
            while (form->GetProgressBar()->Value < 100)
            {
                form->GetProgressBar()->Value += 1;
                form->Update();
                Thread::Sleep(1);
            }
            form->Close();
        }
    }
     //this is the function to be exported
    extern "C" void RunProgressBar()
    {
        try
        {

            Thread^ progressBarThread = gcnew Thread(gcnew ThreadStart(ShowProgressBar));
            progressBarThread->SetApartmentState(ApartmentState::STA);
            progressBarThread->Start();
            progressBarThread->Join();

        }
        catch (System::Exception^ e)
        {

            // Your main application code here


        }
    }

然后你可以从你的非托管项目中调用代码 通过引用库并像这样定义导入函数

#pragma comment(lib, "RunProgressBarLib.lib") 
// Creates a progress bar for 
//a short amount of time
extern "C" void RunProgressBar();

您可以使用的 c++ 版本有一些限制,c++17 可能与 clr 不兼容,

在 .NET 级别处理异常也很重要,以免它们导致非托管代码崩溃。

© www.soinside.com 2019 - 2024. All rights reserved.