1

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で書かれているようです。それを変更する方法は?

うまくいけば、誰かが答えます。

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 は番号付きのリソース タイプであり、文字列ではありません。言語 ID に 1 を使用してもほとんど意味がありません。これはアラビア語であるため、リソースにラテン語の文字列は期待できません。このリソースを読み取るアプリが何であれ、それを見つけることはまずありません。

これを正しく行うには、lpType を IntPtr として宣言するオーバーロードが必要になるため、RT_RCData リソース タイプに CType(10, IntPtr) を渡すことができます。ToPtr() 関数は非常に悪質で、ランダムなデータ破損の原因となるダングリング ポインターを返します。lpData 引数を Byte() として宣言することにより、pinvoke マーシャラーにポインターを生成させるだけです。次に、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 に答える