无法从C++代码中检索正确的字符串.是否有一种通用类型用于处理c#上的无符号字符*

Cant retrieve right string from C++ code. Is there a generic type for handling unsigned char* on c#?

本文关键字:类型 一种 用于 处理 字符 无符号 代码 C++ 检索 是否 字符串      更新时间:2023-10-16

这很令人困惑,但我会尽力解释!

我正试图在我的C#代码上运行一个C++DLL。

在这个DLL上,我有一个方法,应该返回一个20个字符的无符号字符*。表示4个字节的5个"单词"。(sha-1算法的输出)

我在C#项目中使用DLLIMPORT,如下所示:

    [DllImport("hashLibrary.dll", CharSet = CharSet.Ansi)]
    static private extern string CallReturnString(IntPtr pHashClassObject);

这应该返回5个WORDS字符串。

这是我的C++方法,应该给出字符串:

unsigned char* SHA1::Result(/*unsigned *message_digest_array*/)
{
int i;                                  // Counter
int j = 0;
static int s_chString[5];
static unsigned char s_out[20]; // 4 * 5 + 10 de bob
if (Corrupted)
{
    return false;
}
if (!Computed)
{
    PadMessage();
    Computed = true;
}
unsigned int a = 0;
a = H[0];
s_out[0] = (a >> (8*0)) & 0xff;
a = H[0];
s_out[1] = (a >> (8*1)) & 0xff;
a = H[0];
s_out[2] = (a >> (8*2)) & 0xff;
a = H[0];
s_out[3] = (a >> (8*3)) & 0xff;
a = H[1];
s_out[4] = (a >> (8*0)) & 0xff;
s_out[5] = (a >> (8*1)) & 0xff;
s_out[6] = (a >> (8*2)) & 0xff;
s_out[7] = (a >> (8*3)) & 0xff;
a = H[2];
s_out[8] = (a >> (8*0)) & 0xff;
s_out[9] = (a >> (8*1)) & 0xff;
s_out[10] = (a >> (8*2)) & 0xff;
s_out[11] = (a >> (8*3)) & 0xff;
a = H[3];
s_out[12] = (a >> (8*0)) & 0xff;
s_out[13] = (a >> (8*1)) & 0xff;
s_out[14] = (a >> (8*2)) & 0xff;
s_out[15] = (a >> (8*3)) & 0xff;
a = H[4];
s_out[16] = (a >> (8*0)) & 0xff;
s_out[17] = (a >> (8*1)) & 0xff;
s_out[18] = (a >> (8*2)) & 0xff;
s_out[19] = (a >> (8*3)) & 0xff;
s_out[20] = '';

return s_out;
}

在这段代码中,我试图从H中获取所有字节,并添加一个将传递给C#代码的字符。

H声明为:unsigned H[5];

它几乎可以工作,但出于某种原因,有些组合会给我带来疯狂的结果,比如C#上的22个成员字符串,并且值都是错误的。

我认为这与C#和C++上的一些不同类型的变量有关如果我只能像C++代码中那样从char*中获得所有字节,那就太棒了

有人知道怎么做吗?

谢谢大家!

编辑:

一般工作流程为:

  1. 我的Windows窗体应用程序从C++类创建一个新类:HashWrapper hash = new HashWrapper();
  2. 我的windows窗体应用程序向C++(它是SHA-1算法类)发送种子:hash.SendInput("abc");
  3. 我的windows窗体应用程序要求获得c++算法的结果:string output = hash.ReturnString();

在这里,我将把我调用的方法放在最上面:

 public HashWrapper()
    {
        // We have to Create an instance of this class through an exported function
        this.m_pNativeObject = CreateSHA1Class();
    }
public void SendInput(string inp )
    {
        CallInput(this.m_pNativeObject, inp, inp.Length);
    }
public string ReturnString()
    {
        string ans = CallReturnString(this.m_pNativeObject);
        return ConvertStringToHex(ans); // Converts to Hex
    }
 public string ConvertStringToHex(string asciiString)
    {
        string hex = "";
        foreach (char c in asciiString)
        {
            int tmp = c;
            hex += String.Format("{0:x2}", (uint)System.Convert.ToUInt32(tmp.ToString()));
        }
        return hex;
    }

不幸的是,您不能简单地根据返回值封送数组。如果你需要多次调用它,我会从自定义编组器开始:

private class ReturnArrayMarshaller : ICustomMarshaler
{
    public static ICustomMarshaler GetInstance(string cookie)
    {
        return new ReturnArrayMarshaller(cookie);
    }
    private readonly int byteCount;
    private ReturnArrayMarshaller(string cookie)
    {
        byteCount = int.Parse(cookie);
    }
    public void CleanUpManagedData(object ManagedObj) { throw new NotImplementedException(); }
    public void CleanUpNativeData(IntPtr pNativeData)
    {
        // release unmanaged return value if needed
    }
    public int GetNativeDataSize() { throw new NotImplementedException(); }
    public IntPtr MarshalManagedToNative(object ManagedObj) { throw new NotImplementedException(); }
    public object MarshalNativeToManaged(IntPtr pNativeData)
    {
        byte[] data = new byte[byteCount];
        Marshal.Copy(pNativeData, data, 0, data.Length);
        return data;
    }
}

并在签名声明中使用:

[DllImport(@"hashLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ReturnArrayMarshaller), MarshalCookie = "20")]
public static extern byte[] CallReturnString(IntPtr pHashClassObject);

不要忘记在DllImport中指定CallingConvention.Cdecl,因为您在C++代码中没有使用__stdcall修饰符。

附言:我认为您使用非托管库并不是因为SHA1哈希,而是因为大多数密码学都可以作为托管类使用。

不要重新设计轮子

你为什么不能使用Microsoft提供的类?您的答案中存在一些问题,例如重新创建memcpy函数,该函数允许您在大约6行代码中执行内存复制函数,或者试图将数据字符串封送为以null结尾的字符串。您应该只使用.NET提供的SHA1实现,除非有要求说您必须自己制作。

如何在.NET中解决您的问题

您试图解决的问题实际上需要.NET中的3行代码,除非您需要使用.NET来实现自己的SHA1,否则会更有意义。

public static byte[] HashString(string inputString)
{
    inputData = Encoding.ASCII.GetBytes("abc");
    var sha1 = new SHA1Managed();
    return sha1.ComputeHash(inputData);
}
相关文章: