将文本写入Win32资源

时间:2013-10-17 12:58:35

标签: vb.net string winapi unicode resources

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

这是在写完文本之后: img1 这是它应该是这样的: img1

这是我的代码:

    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。如何改变?

希望有人回复。

1 个答案:

答案 0 :(得分: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 marshaller通过将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。