PInvoke C 函数调用分配内存的 Win32 函数时出现访问冲突错误

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

我用 C# 编写了一个库(运行良好)来运行 Win32 函数。例如 PInvoking CredUIPromptForWindowsCredentials、CredUnPackAuthenticationBuffer、CredPackAuthenticationBuffer,因此一个方法调用可以返回 NetworkCredentials,而无需您自己进行所有凭据打包/解包和错误检查。以及类似的类和方法,用于使用 NetUser... 和 NetGroup... 函数从计算机创建/列出/更改/删除本地用户和本地组

//ToolsCS.cs

public static class Credentials{
    public static NetworkCredential GetCredentials(string promtpCaption, string promptMessage, string inUsername, string inDomain, string inPassword){...}
    public static NetworkCredential GetCredentials(string promtpCaption, string promptMessage){...}
}
public class User{
    public static User[] GetUsers(string computername){...}
    public static bool Exists(string computername,string username){...}
    public static void Create(string computername,User user){...}
    public static void Delete(string computername,string username){...}
    public static void Set(string computername,string username,User user){...}
    public string Name;
    public string DisplayName;
    public string Description;
}

这一切都适用于调用它们的任何其他 C# 库或应用程序。 现在我正在用 C 语言编写几个应用程序,它们使用的功能与我刚刚为 C# 库创建的功能相同,所以为什么不在 C 语言中将其用于这些 C 应用程序,让编写应用程序本身更简单。

//ToolsC.c

extern "C" __declspec(dllexport) BOOL __stdcall AccGroupList(wchar_t* system,wchar_t** names,DWORD* count);
extern "C" __declspec(dllexport) BOOL __stdcall AccGroupExists(wchar_t* system,wchar_t* name);
extern "C" __declspec(dllexport) BOOL __stdcall AccGroupCreate(wchar_t* system,wchar_t* name);
extern "C" __declspec(dllexport) BOOL __stdcall AccGroupSet(wchar_t* system,wchar_t* name);
extern "C" __declspec(dllexport) BOOL __stdcall AccGroupRemove(wchar_t* system,wchar_t* name);
extern "C" __declspec(dllexport) BOOL __stdcall AccGroupAddMember(wchar_t* system,wchar_t* group,wchar_t* member);

这对我用 C 编写的应用程序来说非常有用。但是我遇到的麻烦是当我决定尝试调用我从 C# 编写的这些 C 函数时

//SomeApp.cs
class SomeClass{
    [DllImport(@"ToolsC.dll",SetLastError=true)]
    public static extern bool AccGroupList(
        [MarshalAs(UnmanagedType.LPWStr)]                       string system,
        [MarshalAs(UnmanagedType.LPArray,SizeParamIndex=2)] ref string[] names,
                                                            ref int count);
    ...
}

在调试 C# 代码时,它成功地进入了我导出的 C dll 函数,它在调用

NetGroupEnum
时崩溃并出现访问冲突错误(在文档中说系统分配了一个缓冲区,而不是调用者)相同当 C# 应用程序调用我的 C 函数调用
CredUIPromptForWindowsCredentials
(这也表示系统分配缓冲区)时,错误导致 C# 应用程序崩溃。 并不是 Win32 函数返回然后我在访问它给我的缓冲区时出错,而是调试器给我一个错误框而没有从该函数返回。 对于 AccGroupExists,它使用
NetUserGetInfo
函数,并且只获取用户名,返回而不会崩溃,这个函数填充你给它的缓冲区,而不是“系统分配的缓冲区”。

我已经尝试更改我导出的 C 函数以具有不同的参数类型,并在调用 Win32 函数之前分配 C 函数内的任何字符串并将传递的 C# 字符串复制到 wchar_t* 中。我尝试更改 PInvoke 参数类型。

所以看来我必须满足于为 C# 做 C#->Win32,为 C 做 C->Win32。但我不能使用 C#->C->Win32。

我可以在 C# 中做些什么,比如在调用我的 C dll 之前设置内存安全或进程访问权限,这将允许 Win32 函数分配内存而不会使应用程序崩溃?

编辑

这是 C 库中的一个函数,在另一个 C 应用程序中调用时它对我来说工作正常。但是在 C# 的

NetLocalGroupEnum
处失败。

extern "C" __declspec(dllexport) BOOL __stdcall AccGroupList(wchar_t* system,wchar_t** names,DWORD* count){
    GROUP_INFO_0* buffer;
    DWORD readcount=0;
    DWORD totalcount=0;
    DWORD size=0;
    error=NetLocalGroupEnum(system,0,(LPBYTE*)&buffer,MAX_PREFERRED_LENGTH,&readcount,&totalcount,NULL);
    if(error!=NERR_Success){
        SetLastError(error);
        return FALSE;}
    if((names=(wchar_t**)CoTaskMemAlloc(sizeof(wchar_t*)*readcount))==NULL){
        NetApiBufferFree(&buffer);
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        return FALSE;}
    for(int i=0;i<readcount;i++){
        size=wcslen(buffer[i].grpi0_name);
        if((names[i]=(wchar_t*)CoTaskMemAlloc(2*size))==NULL){
            for(int j=0;j<i;i++){
                size=wcslen(names[j]);
                wmemset(names[j],0,size);
                CoTaskMemFree(names[j]);}
            NetApiBufferFree(&buffer);
            CoTaskMemFree(names);
            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
            return FALSE;}
        
        wmemset(names[i],0,size);
        wcscpy(names[i],buffer[i].grpi0_name);}
    NetApiBufferFree(&buffer);
    *count=readcount;
    return TRUE;}
c# c winapi pinvoke
© www.soinside.com 2019 - 2024. All rights reserved.