1

我正在尝试将文本写入 Win32 资源,但我失败了。

这是写完文本后的 图像1 样子:它应该是这样的: 图像1

这是我的代码:

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        WriteResourceStr(Target.Text, "hello")
        End Sub

#Region "Second"
    <DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Private Shared Function UpdateResource(ByVal hUpdate As IntPtr, ByVal lpType As String, ByVal lpName As String, ByVal wLanguage As UShort, ByVal lpData As IntPtr, ByVal cbData As UInteger) As Boolean
    End Function
    <DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Private Shared Function BeginUpdateResource(ByVal pFileName As String, <MarshalAs(UnmanagedType.Bool)> ByVal bDeleteExistingResources As Boolean) As IntPtr
    End Function
    <DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Private Shared Function EndUpdateResource(ByVal hUpdate As IntPtr, ByVal fDiscard As Boolean) As Boolean
    End Function

    Public Function WriteResourceStr(ByVal filename As String, ByVal bytes As String) As Boolean

        Try
            Dim handle As IntPtr = BeginUpdateResource(filename, False)
            Dim file1 As String = bytes
            Dim fileptr As IntPtr = ToPtr(file1)
            Dim res As Boolean = UpdateResource(handle, "RCData", "CONFIG", 1, fileptr, System.Convert.ToUInt16(file1.Length))
            EndUpdateResource(handle, False)
        Catch ex As Exception
            Return False
        End Try
        Return True

    End Function

    Private Function ToPtr(ByVal data As Object) As IntPtr
        Dim h As GCHandle = GCHandle.Alloc(data, GCHandleType.Pinned)
        Dim ptr As IntPtr
        Try
            ptr = h.AddrOfPinnedObject()
        Finally
            h.Free()
        End Try
        Return ptr

    End Function
#End Region

所以似乎它不写ANSI,而是用Unicode。如何改变它?

希望有人回复。

4

1 回答 1

0

最简单的方法是重载 UpdateResource 并让 Windows 为您进行 Unicode 到 ANSI 的转换:

<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Ansi)> _
Private Shared Function UpdateResource(ByVal hUpdate As IntPtr, _
    ByVal lpType As String, ByVal lpName As String, ByVal wLanguage As UShort, 
    ByVal lpData As String, ByVal cbData As Integer) As Boolean
End Function

请注意更改的 lpData 类型和更改的 CharSet。现在调用简单地变成:

    Dim handle As IntPtr = BeginUpdateResource(filename, False)
    If handle = IntPtr.Zero Then Throw New Win32Exception
    Dim res As Boolean = UpdateResource(handle, "RCData", "CONFIG", 1, _
       bytes, bytes.Length)
    If Not EndUpdateResource(handle, False) Then Throw New Win32Exception

我将不得不重申电话的荒谬性质。RCData 是一个编号的资源类型,而不是一个字符串。使用 1 的语言 ID 没有什么意义,这是阿拉伯语,因此您不会期望资源中有拉丁字符串。无论应用程序读取此资源,都不太可能找到它。

正确执行此操作需要将 lpType 声明为 IntPtr 的重载,以便您可以为 RT_RCData 资源类型传递 CType(10, IntPtr)。ToPtr() 函数非常邪恶,它返回一个会导致随机数据损坏的悬空指针。只需让 pinvoke 编组器通过将 lpData 参数声明为 Byte() 来生成指针。然后,您将使用 Encoding.GetBytes() 来使用正确的 ANSI 转换。因此:

<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
Private Shared Function UpdateResource(ByVal hUpdate As IntPtr, _
    ByVal lpType As IntPtr, ByVal lpName As String, ByVal wLanguage As UShort, 
    ByVal lpData As Byte(), ByVal cbData As Integer) As Boolean
End Function

如果 lpName 是编号而不是命名资源,则需要额外的重载,请使用 IntPtr。

于 2013-10-17T17:27:35.687 回答