我正在考虑创建一个 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);
}
};
}
是的,您可以将托管代码包装在非托管函数中,然后按照以下步骤从托管项目中调用它,
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 级别处理异常也很重要,以免它们导致非托管代码崩溃。