Yerel kodunuzdan .NET çalışma zamanını denetlemek için özel bir .NET konağı yazma

Tüm yönetilen kodlarda olduğu gibi .NET uygulamaları da bir konak tarafından yürütülür. Konak, çalışma zamanını başlatmak (JIT ve çöp toplayıcı gibi bileşenler dahil) ve yönetilen giriş noktalarını çağırmaktan sorumludur.

.NET çalışma zamanını barındırmak gelişmiş bir senaryodur ve .NET derleme işlemleri .NET uygulamalarını çalıştırmak için varsayılan bir konak sağladığından çoğu durumda .NET geliştiricilerinin barındırma konusunda endişelenmesi gerekmez. Ancak bazı özel durumlarda, yönetilen kodu yerel bir işlemde çağırmanın bir aracı olarak veya çalışma zamanının nasıl çalıştığı üzerinde daha fazla denetim elde etmek için .NET çalışma zamanını açıkça barındırmak yararlı olabilir.

Bu makalede yerel koddan .NET çalışma zamanını başlatmak ve içinde yönetilen kod yürütmek için gereken adımlara genel bir bakış verilmektedir.

Önkoşullar

Konaklar yerel uygulamalar olduğundan, bu öğretici .NET barındırmak için bir C++ uygulaması oluşturmayı kapsar. Bir C++ geliştirme ortamına (Visual Studio tarafından sağlanan ortam gibi) ihtiyacınız olacaktır.

Ayrıca konağı test etmek için bir .NET bileşeni oluşturmanız gerekir, bu nedenle .NET SDK'sını yüklemeniz gerekir. Bağlantı için gerekli üst bilgileri ve kitaplıkları içerir. Örnek olarak, .NET 8 SDK'sı ile Windows'ta dosyalar içinde C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\8.0.4\runtimes\win-x64\nativebulunabilir.

Barındırma API'leri

.NET çalışma zamanını .NET Core 3.0 ve üzerinde barındırma işlemi ve hostfxr kitaplıklarının API'leriyle nethost yapılır. Bu giriş noktaları, başlatma için çalışma zamanını bulma ve ayarlamanın karmaşıklığını ele alır ve hem yönetilen bir uygulama başlatmaya hem de statik yönetilen bir yönteme çağrılmasına izin verir.

.NET Core 3.0'ın öncesinde, çalışma zamanını barındırmak için tek seçenek API aracılığıylaydı coreclrhost.h . Bu barındırma API'si artık kullanım dışıdır ve .NET Core 3.0 ve üzeri çalışma zamanlarını barındırmak için kullanılmamalıdır.

ve kullanarak nethost.h konak oluşturma hostfxr.h

Aşağıdaki öğreticide açıklanan adımları gösteren örnek bir konak dotnet/samples GitHub deposunda bulunabilir. Örnekteki açıklamalar, bu öğreticideki numaralandırılmış adımları örnekte gerçekleştirdikleri yerle açıkça ilişkilendirir. İndirme yönergeleri için bkz . Örnekler ve Öğreticiler.

Örnek konağın öğrenme amacıyla kullanılması gerektiğini, dolayısıyla hata denetimine açık olduğunu ve verimlilik üzerinde okunabilirliği vurgulayan bir tasarıma sahip olduğunu unutmayın.

Aşağıdaki adımlar, yerel bir uygulamada .NET çalışma zamanını başlatmak ve yönetilen statik bir yönteme çağırmak için ve hostfxr kitaplıklarının nasıl kullanılacağını nethost ayrıntılı olarak açıklar. Örnekte üst bilgiler ve kitaplık coreclr_delegates.h ile .NET SDK'sı ile yüklenen ve hostfxr.h üst bilgileri kullanılırnethost.

1. Adım - Dışarı aktarılan barındırma işlevlerini yükleme hostfxr ve alma

Kitaplık, nethost kitaplığı bulmak hostfxr için işlevi sağlarget_hostfxr_path. Kitaplık, hostfxr .NET çalışma zamanını barındırmaya yönelik işlevleri kullanıma sunar. İşlevlerin tam listesi ve yerel barındırma tasarımı belgesinde hostfxr.hbulunabilir. Örnek ve bu öğreticide aşağıdakiler kullanılır:

  • hostfxr_initialize_for_runtime_config: Bir konak bağlamı başlatır ve belirtilen çalışma zamanı yapılandırmasını kullanarak .NET çalışma zamanını başlatmaya hazırlanır.
  • hostfxr_get_runtime_delegate: Çalışma zamanı işlevselliği için bir temsilci alır.
  • hostfxr_close: Konak bağlamını kapatır.

Kitaplıkhostfxr, kitaplıktan nethost API kullanılarak get_hostfxr_path bulunur. Daha sonra yüklenir ve dışarı aktarmaları alınır.

// Using the nethost library, discover the location of hostfxr and get exports
bool load_hostfxr()
{
    // Pre-allocate a large buffer for the path to hostfxr
    char_t buffer[MAX_PATH];
    size_t buffer_size = sizeof(buffer) / sizeof(char_t);
    int rc = get_hostfxr_path(buffer, &buffer_size, nullptr);
    if (rc != 0)
        return false;

    // Load hostfxr and get desired exports
    void *lib = load_library(buffer);
    init_fptr = (hostfxr_initialize_for_runtime_config_fn)get_export(lib, "hostfxr_initialize_for_runtime_config");
    get_delegate_fptr = (hostfxr_get_runtime_delegate_fn)get_export(lib, "hostfxr_get_runtime_delegate");
    close_fptr = (hostfxr_close_fn)get_export(lib, "hostfxr_close");

    return (init_fptr && get_delegate_fptr && close_fptr);
}

Örnekte aşağıdakiler kullanılır:

#include <nethost.h>
#include <coreclr_delegates.h>
#include <hostfxr.h>

Bu dosyalar aşağıdaki konumlarda bulunabilir:

Veya Windows'a .NET 8 SDK'sını yüklediyseniz:

  • C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\8.0.4\runtimes\win-x64\native

2. Adım - .NET çalışma zamanını başlatma ve başlatma

hostfxr_initialize_for_runtime_config ve hostfxr_get_runtime_delegate işlevleri, yüklenecek yönetilen bileşen için çalışma zamanı yapılandırmasını kullanarak .NET çalışma zamanını başlatır ve başlatır. İşlev, hostfxr_get_runtime_delegate yönetilen derlemeyi yüklemeye ve bu derlemedeki statik bir yönteme işlev işaretçisi almaya olanak tanıyan bir çalışma zamanı temsilcisi almak için kullanılır.

// Load and initialize .NET Core and get desired function pointer for scenario
load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(const char_t *config_path)
{
    // Load .NET Core
    void *load_assembly_and_get_function_pointer = nullptr;
    hostfxr_handle cxt = nullptr;
    int rc = init_fptr(config_path, nullptr, &cxt);
    if (rc != 0 || cxt == nullptr)
    {
        std::cerr << "Init failed: " << std::hex << std::showbase << rc << std::endl;
        close_fptr(cxt);
        return nullptr;
    }

    // Get the load assembly function pointer
    rc = get_delegate_fptr(
        cxt,
        hdt_load_assembly_and_get_function_pointer,
        &load_assembly_and_get_function_pointer);
    if (rc != 0 || load_assembly_and_get_function_pointer == nullptr)
        std::cerr << "Get delegate failed: " << std::hex << std::showbase << rc << std::endl;

    close_fptr(cxt);
    return (load_assembly_and_get_function_pointer_fn)load_assembly_and_get_function_pointer;
}

3. Adım - Yönetilen derlemeyi yükleme ve yönetilen yönteme işlev işaretçisi alma

Yönetilen derlemeyi yüklemek ve yönetilen bir yönteme işlev işaretçisi almak için çalışma zamanı temsilcisi çağrılır. Temsilci, derleme yolunu, tür adını ve yöntem adını giriş olarak gerektirir ve yönetilen yöntemi çağırmak için kullanılabilecek bir işlev işaretçisi döndürür.

// Function pointer to managed delegate
component_entry_point_fn hello = nullptr;
int rc = load_assembly_and_get_function_pointer(
    dotnetlib_path.c_str(),
    dotnet_type,
    dotnet_type_method,
    nullptr /*delegate_type_name*/,
    nullptr,
    (void**)&hello);

Örnek, çalışma zamanı temsilcisini çağırırken temsilci türü adı olarak geçirerek nullptr yönetilen yöntem için varsayılan imzayı kullanır:

public delegate int ComponentEntryPoint(IntPtr args, int sizeBytes);

Çalışma zamanı temsilcisi çağrılırken temsilci türü adı belirtilerek farklı bir imza kullanılabilir.

4. Adım : Yönetilen kodu çalıştırın!

Yerel konak artık yönetilen yöntemi çağırabilir ve istenen parametreleri geçirebilir.

lib_args args
{
    STR("from host!"),
    i
};

hello(&args, sizeof(args));