3

为了更好地学习 vb.net 和 C#,我正在进行一个项目(在 SourceForge 上找到 TreeViewAdv)并尝试将其代码转换为 VB。虽然我希望能够手动转换代码(因为这是一个学习项目),但我目前正在使用 C# 到 VB 代码转换器(在 www.DeveloperFusion.com 上找到)来让球滚动和一些先基本了解。我转换的代码大部分没有问题,但有一个问题(可能是 2 个)。见代码:

C#

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;

namespace Aga.Controls
{
public static class BitmapHelper
{
    [StructLayout(LayoutKind.Sequential)]
    private struct PixelData
    {
        public byte B;
        public byte G;
        public byte R;
        public byte A;
    }

    public static void SetAlphaChanelValue(Bitmap image, byte value)
    {
        if (image == null)
            throw new ArgumentNullException("image");
        if (image.PixelFormat != PixelFormat.Format32bppArgb)
            throw new ArgumentException("Wrong PixelFormat");

        BitmapData bitmapData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height),
                                 ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
        unsafe
        {
            PixelData* pPixel = (PixelData*)bitmapData.Scan0;
            for (int i = 0; i < bitmapData.Height; i++)
            {
                for (int j = 0; j < bitmapData.Width; j++)
                {
                    pPixel->A = value;
                    pPixel++;
                }
                pPixel += bitmapData.Stride - (bitmapData.Width * 4);
            }
        }
        image.UnlockBits(bitmapData);
    }
}
}

VB.Net(转换后)

Imports System.Collections.Generic
Imports System.Text
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Drawing.Imaging

Namespace Aga.Controls

Public NotInheritable Class BitmapHelper

    Private Sub New()
    End Sub

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure PixelData
        Public B As Byte
        Public G As Byte
        Public R As Byte
        Public A As Byte
    End Structure


    Public Shared Sub SetAlphaChanelValue(ByVal image As Bitmap, ByVal value As Byte)
        If image Is Nothing Then
            Throw New ArgumentNullException("image")
        End If
        If image.PixelFormat <> PixelFormat.Format32bppArgb Then
            Throw New ArgumentException("Wrong PixelFormat")
        End If

        Dim bitmapData As BitmapData = image.LockBits(New Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
        Dim pPixel As Pointer(Of PixelData) = DirectCast(bitmapData.Scan0, Pointer(Of PixelData))
        For i As Integer = 0 To bitmapData.Height - 1
            For j As Integer = 0 To bitmapData.Width - 1
                pPixel.A = value
                pPixel += 1
            Next
            pPixel += bitmapData.Stride - (bitmapData.Width * 4)
        Next
        image.UnlockBits(bitmapData)
    End Sub

End Class

End Namespace

我相信,问题中的代码行是: C#

PixelData* pPixel = (PixelData*)bitmapData.Scan0;

在VB中转换为这个

Dim pPixel As Pointer(Of PixelData) = DirectCast(bitmapData.Scan0, Pointer(Of PixelData))

Intellisense 告诉我Pointer(Of PixelData)有问题

我的问题: 让上面的 VB 代码像 C# 代码一样运行的最佳方法是什么(结果不是方法),以及为什么解决方案有效(我希望了解其中的原因)?

回答或评论时应牢记的事项:

1) 我已经了解 CRL 或托管编程语言不使用指针

2) 我不是想在 vb.net 中找到一种使用指针或不安全代码的方法,我知道这是不可能的。

3) 我不打算放弃 VB,也不希望简单地将 C# 代码保存在单独的程序集中并从 VB 中引用它。我知道它有局限性,但这是一个学习项目,所以当我去面试时,他们问我,“你能在 VB 中做 X吗?” 我可以自信地说是的。

4)同样,这里最重要的不是我走哪条路,而是目的地。我知道通过 C# 到目的地的路更短,但我希望通过 VB。

对于加分,我期待声明

pPixel += 1

不能在 VB 端工作(因为 pPixel 是一个结构,见上文),但它在 C# 端构建得很好。为什么这(工作/不工作)在各自的语言中。这不是关于安全/不安全代码块的问题,就像代码实际运行并且由于不适当的转换/类型使用(int 1 --> struct pPixel)而不会引发错误时一样,为什么?

4

2 回答 2

5

VB.NET 没有指针支持,需要回退到框架支持函数。Marshal.WriteByte 符合要求:

    Dim pPixel = bitmapData.Scan0
    For y As Integer = 0 To bitmapData.Height - 1
        For x As Integer = 0 To bitmapData.Width - 1
            Marshal.WriteByte(pPixel, 4 * x + 3, value)
        Next
        pPixel += bitmapData.Stride
    Next

当然,永远不要忽视 .NET 支持的出色语言互操作性。VB.NET 程序可以很容易地使用 C# 类库项目。

于 2013-10-31T19:18:20.733 回答
1

不幸的是,VB.Net 不支持通过指针直接操作数据。与 C# 相比,这是 VB 的显着缺点之一 - 在需要时无法访问不安全的代码。

在这种情况下,绕过它的方法实际上是从 复制IntPtr到字节数组,执行您的操作,然后复制回来。这可以通过Marshal.Copy方法完成。

MSDN for VB 上的Bitmap.LockBits示例代码显示了整个过程,以及如何从 VB 操作位图的像素数据。

于 2013-10-31T18:23:29.820 回答