1

感谢您花费大量时间尝试回答这个问题。

我正在尝试创建一个从 DLL 中打开一个窗口的 DLL。我正在使用 C# 运行创建的 DLL。DLL 在 VSC 中创建,C# 代码使用 VSC# 编译。

该窗口通过调用Initalize(const char* title)Initalize(string title)在 C# 中进行集成。无论我如何尝试,创建的窗口都会被创建、运行,但它的标题不是传递的字符串。我试过用const wchar_t*, LPCSTR, LPCWSTR, System.String, [MarshalAs(UnmanagedType.LPStr)], [MarshalAs(UnmanagedType.LPWStr)]. 我尝试将传递的字符串复制到一个动态分配的数组中,该数组使用 new/delete 和 malloc/free 进行分配。

我认为这是一个指针错误,但最让我感动的是,printf("passed string: %s", title)在我的 C++ 代码中,在控制台中打印了正确的标题,但我的窗口看起来像: 带有非英文文本的窗口

我的 C++ 代码是:

// GameInterface.cpp : Defines the exported functions for the DLL application.
//

#include "GameInterface.h"

#include <Windows.h>

      // OpenGL was origionally implimented into here, and removed to be asked on StackOverflow.

LRESULT WINAPI DLLWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

HINSTANCE   hInstance = NULL;
ATOM        wclAtom = NULL;
HWND        hWnd = NULL;
HDC         hDC = NULL;
HGLRC       hRC = NULL;
bool        running = false;

#if _DEBUG
    #include <stdio.h>
#endif

BOOL APIENTRY DllMain( HMODULE hModule,
           DWORD  ul_reason_for_call,
           LPVOID lpReserved
                     )
{
    #if _DEBUG
        printf("GameInterface.dll::DllMain()\n");
    #endif

    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
            hInstance = hModule;
            break;
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            Shutdown();
            break;
    }
    return TRUE;
}

GAMEINTERFACE_API int Initalize(const char* title)
{
    if (hWnd != NULL)
        return 0;

    #if _DEBUG
        printf("GameInterface.dll::Initalize(\"%s\")\n", title);
    #endif

    int length = strlen(title);
    char* name = new char[length+1];
    strcpy(name, title);

    WNDCLASSEXA wcl;
    wcl.cbSize        = sizeof(WNDCLASSEXA);
    wcl.style         = CS_OWNDC;
    wcl.lpfnWndProc   = DLLWindowProc;
    wcl.cbClsExtra    = 0;
    wcl.cbWndExtra    = 0;
    wcl.hInstance     = hInstance;
    wcl.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wcl.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wcl.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE;
    wcl.lpszMenuName  = NULL;
    wcl.lpszClassName = name;
    wcl.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    wclAtom = RegisterClassExA(&wcl);

    #if _DEBUG
        printf("  Registering Class\n");
    #endif

    if (!wclAtom)
    {
        #if _DEBUG
            printf("  Error: Could not Register Class.\nExiting with error: %i\n", GetLastError() );
        #endif

        return 1;
    }

    #if _DEBUG
        printf("  Creating Window\n");
    #endif

    hWnd = CreateWindowExA(0,
                          (LPCSTR)wclAtom,
                          (LPCSTR)name,
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          512, 512,
                          NULL, NULL,
                          hInstance, NULL);

    if (hWnd == NULL)
    {
        #if _DEBUG
            printf("  Error: Window could not be created.\nExiting with error: %i\n", GetLastError() );
        #endif

        return 2;
    }

    #if _DEBUG
        printf("  Displaying Window\n");
    #endif

                // to reduce size removed the code to initalize an OpenGL 3.1 context

    ShowWindow(hWnd, SW_SHOW);
    UpdateWindow(hWnd);

    running = true;

    delete [] name;

    #if _DEBUG
        printf("Returning from GameInterface.dll::Initalize(const char*) with errors: %i\n", GetLastError() );
    #endif

    return 0;
}

GAMEINTERFACE_API void Shutdown()
{
    if (running = false)
        return;

    #if _DEBUG
        printf("GameInterface.dll::Shutdown()\n");
    #endif

    running = false;

    wglMakeCurrent(NULL, NULL);
    if (hRC != NULL) wglDeleteContext(hRC);
    if (hDC != NULL) ReleaseDC(hWnd, hDC);

    hRC = NULL;
    hDC = NULL;

    DestroyWindow(hWnd);
    UnregisterClassA( (LPCSTR)wclAtom, hInstance);
    wclAtom = NULL;

    hWnd = NULL;

    running = false;
}

GAMEINTERFACE_API int Update()
{
    if ( (running == false) && (hWnd == NULL) )
        return 1;

    MSG msg;
    if ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    if (running == false)
        return 1;

    return 0;
}

GAMEINTERFACE_API void DrawFrame()
{
    // Contained some OpenGL code that has now been removed.
}

LRESULT WINAPI DLLWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_DESTROY:
            PostQuitMessage(0);
            running = false;
            break;

        // handle other messages.

        default: // anything we dont handle.
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }

    return 0; // just in case
}


// GameInterface.h : Outlines the exported functions for the DLL application.
//

#pragma once

#ifdef GAMEINTERFACE_EXPORTS
    #define GAMEINTERFACE_API __declspec(dllexport)
#else
    #define GAMEINTERFACE_API __declspec(dllimport)
#endif

extern "C"
{

GAMEINTERFACE_API int  Initalize(const char* title);
GAMEINTERFACE_API void Shutdown();
GAMEINTERFACE_API int  Update();
GAMEINTERFACE_API void DrawFrame();

};

和 C# 代码:

// GameInterface.cs
//

using System;
using System.Runtime.InteropServices;

class GameInterface
{
    const string GameInterfaceFile = "GameInterface_d.dll";

    [DllImport(GameInterfaceFile)] public extern static int  Initalize(string title);
    [DllImport(GameInterfaceFile)] public extern static void Shutdown();
    [DllImport(GameInterfaceFile)] public extern static int  Update();
    [DllImport(GameInterfaceFile)] public extern static void DrawFrame();
};


// Program.cs
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

class Program
{
    public static void Main()
    {
        string title = "OpenGL Window Title";
        if (GameInterface.Initalize(title) != 0)
            return;

        while ( GameInterface.Update() == 0 )
        {
            // game logic.
            GameInterface.DrawFrame();
        }

        GameInterface.Shutdown();
    }
}

我被难住了,已经有一段时间了。

4

2 回答 2

4

您是否正在定义UNICODE_UNICODE在您的 C++ 构建中?您需要这样,C# 才能像这样与它交谈。

在 C++ 项目的 Visual Studio 属性中,在General下,将Character Set 设置Use Unicode Character Set。仔细检查/D "UNICODE"/D "_UNICODE"显示在C/C++ / 命令行页面上。

(相反的方法是将您的导出声明为 ANSI,但这是一个较差的解决方案。您应该支持 Unicode。)

于 2013-03-19T18:46:59.493 回答
1

这可能是因为代码需要 ANSI。

如果你尝试这个会发生什么:

[DllImport(GameInterfaceFile, CharSet=CharSet.Ansi)] public extern static int  Initalize(string title)
于 2013-03-19T18:48:01.900 回答