复制结构时,system.AccessVioLationException

System.AccessViolationException when copying a struct

本文关键字:system AccessVioLationException 结构 复制      更新时间:2023-10-16

i在C /Cli-project中具有此C 函数(非托管代码)。

    BMP Image;
    Image.ReadFromFile(filePath);
    HsvColor hsvPixel;
    RGBApixel startPixel;
    for (int i = 0; i < Image.TellWidth(); i++) {
        for (int j = 0; j < Image.TellHeight(); j++) {

            startPixel = *(Image(i, j));
            hsvPixel = RgbToHsv(startPixel);

            RGBApixel finalPixel = HsvToRgb(hsvPixel);
            *(Image(i, j)) = finalPixel;
        }
    }

(hsvcolor和rgbapixel都是无符号字符的结构。图像(i,j)将指针返回到rgbapixel。)

有问题的行是 hsvPixel = RgbToHsv(startPixel);

我有两个问题:

  1. 有时确实会导致系统。AccessviolationException,但并非总是如此。错误消息还显示,它已尝试写入受保护的内存中。当我使用调试器逐步执行代码时,RGBTOHSV函数返回一个值,然后将其转到我看不到的某个系统函数,然后在返回到此处发布的代码块之前崩溃。

  2. 它不会以正确的值初始化HSVPixel。我以调试模式遵循它,并且它确实返回具有正确值的hsvcolor对象,但是在执行该行后,HSVColor struct的无符号字符设置为与函数返回的值完全不同的值。

    <</p> <。/li>

我会非常感谢您的帮助。

我还尝试仅执行RGBTOHSV方法,而无需进行任何作业。当我这样做时,循环大部分时间都可以贯穿,但是有时会随着系统而崩溃。AccessViolationException,只是比将分配分配到HSVpixel时要稀有得多。

RGBAPIXEL的代码:

typedef struct RGBApixel {
    ebmpBYTE Blue;
    ebmpBYTE Green;
    ebmpBYTE Red;
    ebmpBYTE Alpha;
} RGBApixel; 

ebmpbyte是一种打字的无符号字符。

这两种方法的代码:

RGBApixel HsvToRgb(HsvColor hsv)
{
    RGBApixel rgb;
    unsigned char region, remainder, p, q, t;
    if (hsv.Saturation == 0)
    {
        rgb.Red = hsv.Value;
        rgb.Green = hsv.Value;
        rgb.Blue = hsv.Value;
        rgb.Alpha = 1;
        return rgb;
    }
    region = hsv.Hue / 43;
    remainder = (hsv.Hue - (region * 43)) * 6;
    p = (hsv.Value * (255 - hsv.Saturation)) >> 8;
    q = (hsv.Value * (255 - ((hsv.Saturation * remainder) >> 8))) >> 8;
    t = (hsv.Value * (255 - ((hsv.Saturation * (255 - remainder)) >> 8))) >> 8;
    switch (region)
    {
    case 0:
        rgb.Red = hsv.Value; rgb.Green = t; rgb.Blue = p;
        break;
    case 1:
        rgb.Red = q; rgb.Green = hsv.Value; rgb.Blue = p;
        break;
    case 2:
        rgb.Red = p; rgb.Green = hsv.Value; rgb.Blue = t;
        break;
    case 3:
        rgb.Red = p; rgb.Green = q; rgb.Blue = hsv.Value;
        break;
    case 4:
        rgb.Red = t; rgb.Green = p; rgb.Blue = hsv.Value;
        break;
    default:
        rgb.Red = hsv.Value; rgb.Green = p; rgb.Blue = q;
        break;
    }
    return rgb;
}
HsvColor RgbToHsv(RGBApixel rgb)
{
    HsvColor hsv;
    unsigned char rgbMin, rgbMax;
    rgbMin = rgb.Red < rgb.Green ? (rgb.Red < rgb.Blue ? rgb.Red : rgb.Blue) : (rgb.Green < rgb.Blue ? rgb.Green : rgb.Blue);
    rgbMax = rgb.Red > rgb.Green ? (rgb.Red > rgb.Blue ? rgb.Red : rgb.Blue) : (rgb.Green > rgb.Blue ? rgb.Green : rgb.Blue);
    hsv.Value = rgbMax;
    if (hsv.Value == 0)
    {
        hsv.Hue = 0;
        hsv.Saturation = 0;
        return hsv;
    }
    hsv.Saturation = 255 * long(rgbMax - rgbMin) / hsv.Value;
    if (hsv.Saturation == 0)
    {
        hsv.Hue = 0;
        return hsv;
    }
    if (rgbMax == rgb.Red)
        hsv.Hue = 0 + 43 * (rgb.Green - rgb.Blue) / (rgbMax - rgbMin);
    else if (rgbMax == rgb.Green)
        hsv.Hue = 85 + 43 * (rgb.Blue - rgb.Red) / (rgbMax - rgbMin);
    else
        hsv.Hue = 171 + 43 * (rgb.Red - rgb.Green) / (rgbMax - rgbMin);
    return hsv;
}

图像的实现(i,j):

RGBApixel* BMP::operator()(int i, int j)
{
 using namespace std;
 bool Warn = false;
 if( i >= Width )
 { i = Width-1; Warn = true; }
 if( i < 0 )
 { i = 0; Warn = true; }
 if( j >= Height )
 { j = Height-1; Warn = true; }
 if( j < 0 )
 { j = 0; Warn = true; }
 if( Warn && EasyBMPwarnings )
 {
  cout << "EasyBMP Warning: Attempted to access non-existent pixel;" << endl
       << "                 Truncating request to fit in the range [0,"
       << Width-1 << "] x [0," << Height-1 << "]." << endl;
 }  
 return &(Pixels[i][j]);
}

像素的声明(来自EasyBMP库):

RGBApixel** Pixels;

编辑:我使用调试器来查看RGBTOHSV函数如何执行。启动像素始终是循环运行的第一次(应该是)。但是,当我在Visual Studio中单击"步入"并查看代码在函数中的执行方式时,参数(" RGB")总是完全不同于Startpixel!我是调试的新手,所以我可能正在错误地解释事情。但是现在我更加困惑了。这是一张图片。

我还应该在该代码运行时提及。它输出图像,但输出图片只是随机的单颜色(例如,完全蓝色),而它应该与输入图片相同。

确切的问题是他的评论中描述的@hanspassant:

您可能正在与呼叫大会不匹配的斗争。C /CLI编译器编制的代码的默认值是__clrcall,那就是用__cdecl构建的C函数上的redrum。您必须让编译器知道其他代码不是以相同的方式构建的。我们看不到您使用的#INCLUDES,请考虑将#pragma托管(推开)放在他们面前,然后将#pragma托管(pop)之后。

我为解决该问题所做的工作是删除所有#pragma Unmanaged/#Pragma托管行,而是设置应在本机代码中编译的所有CPP文件,以不支持他在此处描述的CLR。