0

我有一个未管理的 MFC dll 的 C++ .net 包装器。这个包装器由 vb.net dll 使用,在我的 c# 代码中调用。在运行时,有时包装器会抛出异常尝试读取或写入受保护的内存。

System.AccessViolationException: Attempted to read or write protected memory. 
This is often an indication that other memory is corrupt

它似乎在我的“While”循环中随机发生。有时它在开始时抛出,有时在中间抛出,有时什么也不抛出。

工作原理:我的程序需要一个 MFC dll。我的程序中有一个 wrapper.dll(c++) 和一个 myVbDll.dll(vb.net) 。我还添加了 MFC dll 作为内容,因为它不是有效的 COM 组件。这就是它的工作原理:

myProgramm.exe->myVbDll.dll->wrapper.dll->myMFC.dll->myMFCfunction

信息:如果我field = "WHATSOEVER";之前设置调用 MyWrappedFunction,则永远不会抛出错误!

更新:经过多次更改,问题仍然存在。我看看这次将 unicode 字符串转换为 Ansi。可能有一些东西可以找到......因为当你在上面写一个字符串中的文本时,它可以工作,但是当使用 ToString 函数时,它就不起作用了。

有人能说出为什么会发生这种情况。

我在 c# 中的程序的一部分(使用 TextFieldParser 从 .csv 文件中读取 5000 行以获取字段):

string[] fields;
string field ;
string temp = "";

TextFieldParser parser = new TextFieldParser(textbox_csv.Text, System.Text.Encoding.UTF8);
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(";");

while (!parser.EndOfData)
{
    fields = parser.ReadFields();
    field = fields[0];
    temp = field.ToUpper();
    field = myVbDll.MyWrappedFunction(ref temp, false);
}

VB.net Dll 的一部分,由我的 c# 程序调用:

Public Class myVbDll

Public Declare Auto Function MyWrappedFunction Lib "myWrapper.dll" (ByVal name As String, ByVal opt As Boolean) As String

End Class

MFC 包装器的一部分,由 VB.net Dll 调用(错误肯定不在 MFC dll 中):

typedef void (*MYFUNCTION)(CString&, CString&, BYTE);
MYFUNCTION Myfunction;

LPWSTR _stdcall MyWrappedFunction(LPWSTR ValInput, BYTE opt)
{
    HINSTANCE gLibtestDLL=NULL;
    CString S_ValInput(ValInput);
    CString S_resultat;

    gLibtestDLL = AfxLoadLibrary(TEXT(".\\test.dll"));
    if(gLibtestDLL == NULL)
    {
        MessageBox(NULL, TEXT("unable to load test.DLL"), TEXT("Error"),MB_OK | MB_ICONINFORMATION);
        return NULL;
    }

    Myfunction = (MYFUNCTION)GetProcAddress(gLibtestDLL, "Myfunction");
    if (Myfunction == NULL)
    {
        MessageBox(NULL, TEXT("Can't find Myfunction."), TEXT("Error"),MB_OK | MB_ICONINFORMATION);

        return NULL;
    }
    //******************************************************************

    S_resultat.LockBuffer();
    S_resultat.Format("%64c", ' ');
    Myfunction(S_ValInput , S_resultat , opt);
    S_resultat.ReleaseBuffer();

    S_resultat.LockBuffer();
    S_resultat.TrimRight();
    S_resultat.ReleaseBuffer();

    // CString To UNICODE
    USES_CONVERSION;
    S_resultat.LockBuffer();
    LPWSTR C_tmp= A2OLE(S_resultat.GetBuffer(S_resultat.GetLength()));
    S_resultat.ReleaseBuffer();

    AfxFreeLibrary(gLibtestDLL);

    LPWSTR C_resultat=C_tmp;
    //******************************************************************

    return C_resultat;

}
4

2 回答 2

2
LPWSTR C_tmp= A2OLE(S_resultat.GetBuffer(S_resultat.GetLength()));

这是您的 C++ 代码中的一个非常严重的错误。您正在返回局部变量的地址。A2OLE() 创建的缓冲区。这会在 C++ 代码中调用未定义的行为。当您从 C++ 代码调用此函数时,这往往会意外地起作用,您有可能不会有另一个函数调用覆盖该局部变量曾经所在的堆栈地址。当您 pinvoke 函数时,这些几率变为零,堆栈地址被 pinvoke marshaller 函数调用删除。如果这本身不会导致崩溃,那么 pinvoke 编组器将确保它在尝试使用 CoTaskMemFree() 释放字符串时崩溃。

您必须先修复您的 C++ 代码。不,只是将指针复制到 C_resultat 不是解决方法。

请注意,尝试挽救此功能没有多大意义。它不会做任何你在 C# 中做不到的事情。只需为“MyFunction”函数编写一个 [DllImport] 属性。

于 2013-07-31T18:43:33.133 回答
1

最后,我摆脱了这个问题!

问题的真正原因是编码字符串。以下是我为改进代码所做的所有更改。

如果您发现我做的可疑事情可以改进,请随时发表评论

我的主要应用程序:

private void processImport()
{
    string[] fields;
    string field ;
    string temp = "";
    byte[] tempByte;

    TextFieldParser parser = new TextFieldParser(textbox_csv.Text, System.Text.Encoding.UTF8);
    parser.TextFieldType = FieldType.Delimited;
    parser.SetDelimiters(";");

    while (!parser.EndOfData)
    {
        fields = parser.ReadFields();
        field = fields[0];
        temp = RemoveDiacritics(field).ToUpper();
        //this line is very important. It seems to change the Encoding of my string to Unicode.
        temp = temp.Normalize(NormalizationForm.FormC);
        field = myVbDll.MyWrappedFunction(temp, false);
    }
    parser.Close();
}

//Transforms the culture of a letter to its equivalent representation in the 0-127 ascii table, such as the letter 'é' is substituted by an 'e'
public string RemoveDiacritics(string s)
{
    string normalizedString = null;
    StringBuilder stringBuilder = new StringBuilder();
    normalizedString = s.Normalize(NormalizationForm.FormD);
    int i = 0;
    char c = '\0';

    for (i = 0; i <= normalizedString.Length - 1; i++)
    {
        c = normalizedString[i];
        if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
        {
            stringBuilder.Append(c);
        }
    }

    return stringBuilder.ToString().ToLower();
}

VB.net Dll 的一部分,由我的 c# 程序调用:

Public Class myVbDll
    <DllImport("Wrapper.dll", CharSet:=CharSet.Unicode)> Public Shared Function MyWrappedFunction (ByVal nom As String, ByVal opt As Boolean) As String
    End Function
End Class

C++ 包装器的一部分,由 VB.net Dll 调用:

typedef void (*MYFUNCTION)(CString&, CString&, BYTE);
MYFUNCTION Myfunction;

LPWSTR _stdcall MyWrappedFunction(LPWSTR ValInput, BYTE opt)
{
    HINSTANCE gLibtestDLL=NULL;
    CString S_ValInput(ValInput);
    CString S_resultat;

    gLibtestDLL = AfxLoadLibrary(TEXT(".\\test.dll"));
    if(gLibtestDLL == NULL)
    {
        MessageBox(NULL, TEXT("unable to load test.DLL"), TEXT("Error"),MB_OK | MB_ICONINFORMATION);
        return NULL;
    }

    Myfunction = (MYFUNCTION)GetProcAddress(gLibtestDLL, "Myfunction");
    if (Myfunction == NULL)
    {
        MessageBox(NULL, TEXT("Can't find Myfunction."), TEXT("Error"),MB_OK | MB_ICONINFORMATION);

        return NULL;
    }
    //******************************************************************

    S_resultat.Format("%64c", ' ');
    Myfunction(S_ValInput , S_resultat , opt);  //Run MFC function
    S_resultat.TrimRight();
    S_resultat.ReleaseBuffer();

    char* tmp = (char*) CoTaskMemAlloc((S_resultat.GetLength()*2)+1);
    memset(tmp,0,sizeof(tmp));
    strcpy_s(tmp, (S_resultat.GetLength()+1), S_resultat.GetBuffer(S_resultat.GetLength()));
    S_resultat.ReleaseBuffer();

    wchar_t wtext[1024];
    memset(wtext,0,sizeof(wtext));
    mbstowcs(wtext, tmp, strlen(tmp)+1);//Plus \0
    LPWSTR resultat = wtext;

    AfxFreeLibrary(gLibtestDLL);

    return resultat;
}
于 2013-08-01T18:29:59.867 回答