感谢你花了很多时间来回答这个问题。
我正在尝试创建一个DLL,它在DLL中打开一个窗口。我用C#运行创建的DLL。 DLL是在VSC中创建的,而C#代码是用VSC#。
编译的通过调用C#中的Initalize(const char* title)
或Initalize(string title)
来激活窗口。无论我如何尝试这样做,创建的窗口都是创建的,运行的,但它的标题不是传递的字符串。我尝试使用const wchar_t*
,LPCSTR
,LPCWSTR
,System.String
,[MarshalAs(UnmanagedType.LPStr)]
,[MarshalAs(UnmanagedType.LPWStr)]
。我尝试将传递的字符串复制到动态分配的数组中,并使用new / delete和malloc / free进行分配。
我认为这是一个指针错误,但最让我感到高兴的是我的C ++代码中的printf("passed string: %s", title)
将正确的标题打印到控制台中,但我的窗口看起来像:
我的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();
}
}
我很难过,已经有一段时间了。
答案 0 :(得分:4)
您是否在C ++版本中定义了UNICODE
和_UNICODE
?你需要做到这一点,让C#像这样说话。
在C ++项目的Visual Studio属性中,在常规下,将字符集设置为使用Unicode字符集。仔细检查 C / C ++ /命令行页面上是否显示/D "UNICODE"
和/D "_UNICODE"
。
(相反的方法是将您的导出声明为ANSI,但这是一个较差的解决方案。您应该支持Unicode。)
答案 1 :(得分:1)
这可能是因为代码期望ANSI。
如果您尝试这样做会发生什么:
[DllImport(GameInterfaceFile, CharSet=CharSet.Ansi)] public extern static int Initalize(string title)