Я работаю над проектом, который имитирует дейтеранопию (тип нарушения цветового зрения) с использованием комбинации C# и языка ассемблера (ASM). Код ASM создает DLL, которая обрабатывает данные изображения, и у меня возникает ошибка System.AccessViolationException с сообщением: «Попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена».
Подробности проекта:
Языки программирования: C# для основного приложения и язык ассемблера (ASM) для обработка изображений.
Функциональность: приложение позволяет пользователям загружать изображение, обрабатывать его (с помощью модуля asm или модуля C#) для имитации дейтеранопии и сохранять обработанное изображение.
Вот краткий обзор соответствующего кода:
Код ASM (ModuleAsm.asm):
.code
DeuteranopiaAsm proc
SimulateDeuteranopiaASM:
; Save registers
push rbp
mov rbp, rsp
sub rsp, 32
mov r9, rdx ; pixelCount
mov r8d, edi ; threadCount (passed through edi)
mov rdx, rcx ; pointer to original image (originalImage)
mov rcx, rdi ; pointer to processed image (processedImage)
; Calculate the portion size for each thread
xor rax, rax ; Clear rax before division
mov eax, r9d ; Move pixelCount to eax (32-bit register for division)
xor edx, edx ; Clear edx (higher part of rax)
div r8d ; Divide eax by r8d (threadCount in r8d, 32-bit register)
mov r10d, eax ; Store the result (portion size) in r10d
; Parallel processing
mov eax, r10d
mov r11, rdx ; pointer to original image
mov rdx, rcx ; pointer to processed image
ProcessLoop:
cmp r9d, 0
je Done
; Load original pixel data using 8-bit registers
movzx eax, byte ptr [r11] ; Load red channel (R) into eax (extended to 32-bit register)
movzx ecx, byte ptr [r11 + 1] ; Load green channel (G) into ecx (extended to 32-bit register)
movzx edx, byte ptr [r11 + 2] ; Load blue channel (B) into edx (extended to 32-bit register)
; Simulate deuteranopia (green color blindness)
imul eax, eax, 625 ; Transform red channel
imul ecx, ecx, 375 ; Transform green channel
add eax, ecx
shr eax, 10 ; Divide by 1024
mov [rdx + 2], al ; Save transformed red channel to processed image
imul ecx, ecx, 7 ; Further transform green channel
shr ecx, 3 ; Divide by 8
mov [rdx + 1], cl ; Save transformed green channel
imul edx, edx, 8 ; Transform blue channel
shr edx, 3 ; Divide by 8
mov [rdx], dl ; Save transformed blue channel
; Move to the next pixel
add r11, 3 ; Move pointer in original image to the next pixel
add rdx, 3 ; Move pointer in processed image to the next pixel
dec r9d ; Decrement pixel count
jmp ProcessLoop ; Repeat loop
Done:
; Restore registers
add rsp, 32
pop rbp
ret
DeuteranopiaAsm endp
end
using System;
using System.Windows;
using System.Windows.Input;
using Microsoft.Win32;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace Projekt
{
public partial class MainWindow : Window
{
// Importing the ASM function (updated with the correct path)
[DllImport(@"C:\Users\kacpe\Desktop\home\Programing\studia\ASM-SEM-5\Projekt\x64\Debug\ModuleAsm.dll")]
public static extern void DeuteranopiaAsm(IntPtr originalImage, IntPtr processedImage, int pixelCount, int stride, int threadCount);
private Bitmap _originalImage;
private Bitmap _processedImage;
public MainWindow()
{
InitializeComponent();
int processorThreads = Environment.ProcessorCount;
threadSlider.Value = processorThreads;
threadCount.Text = $"Selected threads: {processorThreads}";
}
private void Exit_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ButtonState == MouseButtonState.Pressed)
{
this.DragMove();
}
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.WindowStartupLocation = WindowStartupLocation.Manual;
var screenWidth = SystemParameters.PrimaryScreenWidth;
var screenHeight = SystemParameters.PrimaryScreenHeight;
this.Left = (screenWidth - this.Width) / 2;
this.Top = (screenHeight - this.Height) / 2;
}
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
{
if (threadCount != null)
{
int threadValue = (int)threadSlider.Value;
threadCount.Text = $"Thread count: {threadValue}";
}
}
private void ChooseImage_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog
{
Filter = "Image files (*.jpg, *.png)|*.jpg;*.png",
Title = "Choose an image"
};
if (openFileDialog.ShowDialog() == true)
{
imagePathTextBox.Text = openFileDialog.FileName;
_originalImage = new Bitmap(openFileDialog.FileName);
MessageBox.Show("Image loaded successfully.");
}
}
private void ProcessImage_Click(object sender, RoutedEventArgs e)
{
if (_originalImage == null)
{
MessageBox.Show("Please select an image first.");
return;
}
int threadCount = (int)threadSlider.Value;
_processedImage = new Bitmap(_originalImage.Width, _originalImage.Height);
if (asmRadioButton.IsChecked == true)
{
Rectangle rect = new Rectangle(0, 0, _originalImage.Width, _originalImage.Height);
BitmapData originalData = _originalImage.LockBits(rect, ImageLockMode.ReadOnly, _originalImage.PixelFormat);
BitmapData processedData = _processedImage.LockBits(rect, ImageLockMode.WriteOnly, _processedImage.PixelFormat);
int pixelCount = _originalImage.Width * _originalImage.Height;
int stride = originalData.Stride;
IntPtr originalPtr = originalData.Scan0;
IntPtr processedPtr = processedData.Scan0;
// Call to the ASM function
DeuteranopiaAsm(originalPtr, processedPtr, pixelCount, stride, threadCount);
_originalImage.UnlockBits(originalData);
_processedImage.UnlockBits(processedData);
MessageBox.Show("Image processed in ASM.");
}
else if (cSharpRadioButton.IsChecked == true)
{
_processedImage = SimulateDeuteranopia(_originalImage, threadCount);
MessageBox.Show("Image processed in C#.");
}
}
private void SaveImage_Click(object sender, RoutedEventArgs e)
{
if (_processedImage == null)
{
MessageBox.Show("Please process the image first.");
return;
}
SaveFileDialog saveFileDialog = new SaveFileDialog
{
Filter = "Image files (*.jpg, *.png)|*.jpg;*.png",
Title = "Save image"
};
if (saveFileDialog.ShowDialog() == true)
{
_processedImage.Save(saveFileDialog.FileName);
MessageBox.Show("Image saved successfully.");
}
}
public static Bitmap SimulateDeuteranopia(Bitmap original, int threads)
{
int width = original.Width;
int height = original.Height;
Bitmap simulatedImage = new Bitmap(width, height, original.PixelFormat);
Rectangle rect = new Rectangle(0, 0, original.Width, original.Height);
BitmapData originalData = original.LockBits(rect, ImageLockMode.ReadOnly, original.PixelFormat);
BitmapData simulatedData = simulatedImage.LockBits(rect, ImageLockMode.WriteOnly, simulatedImage.PixelFormat);
int bytesPerPixel = Image.GetPixelFormatSize(original.PixelFormat) / 8;
int stride = originalData.Stride;
IntPtr originalScan0 = originalData.Scan0;
IntPtr simulatedScan0 = simulatedData.Scan0;
byte[] originalPixels = new byte[stride * height];
byte[] simulatedPixels = new byte[stride * height];
Marshal.Copy(originalScan0, originalPixels, 0, originalPixels.Length);
Parallel.For(0, threads, threadIndex =>
{
int partitionSize = height / threads;
int start = threadIndex * partitionSize;
int end = (threadIndex == threads - 1) ? height : start + partitionSize;
for (int y = start; y < end; y++)
{
for (int x = 0; x < width; x++)
{
int pixelIndex = y * stride + x * bytesPerPixel;
byte originalB = originalPixels[pixelIndex];
byte originalG = originalPixels[pixelIndex + 1];
byte originalR = originalPixels[pixelIndex + 2];
// Simulate color transformation for deuteranopia
int newR = (int)(originalR * 0.625 + originalG * 0.375);
int newG = (int)(originalG * 0.7);
int newB = (int)(originalB * 0.8);
newR = Clamp(newR, 0, 255);
newG = Clamp(newG, 0, 255);
newB = Clamp(newB, 0, 255);
simulatedPixels[pixelIndex] = (byte)newB;
simulatedPixels[pixelIndex + 1] = (byte)newG;
simulatedPixels[pixelIndex + 2] = (byte)newR;
}
}
});
Marshal.Copy(simulatedPixels, 0, simulatedScan0, simulatedPixels.Length);
original.UnlockBits(originalData);
simulatedImage.UnlockBits(simulatedData);
return simulatedImage;
}
public static int Clamp(int value, int min, int max)
{
if (value < min) return min;
if (value > max) return max;
return value;
}
}
}
Описание проблемы:
Исключение AccessViolationException обычно возникает, когда код пытается получить доступ к запрещенной памяти. Я подозреваю, что это может быть связано с тем, как указатели и память управляются между кодом C# и ASM. Я правильно блокирую фрагменты изображений, но мне интересно, есть ли какие-либо проблемы с выравниванием памяти или могут ли проблемы быть вызваны манипуляциями с пикселями.
Дополнительная информация:
Я использую .NET Framework и ориентируюсь на архитектуру x64.
DLL загружается правильно, но на этапе обработки изображения происходят сбои. .
Буду признателен за любую информацию об распространенных ошибках, которые могут привести к этому исключению, особенно в сценариях взаимодействия между C# и ASM.
Я пробовал реструктуризировать, но это ни к чему не приводит...
Я работаю над проектом, который имитирует дейтеранопию (тип нарушения цветового зрения) с использованием комбинации C# и языка ассемблера (ASM). Код ASM создает DLL, которая обрабатывает данные изображения, и у меня возникает [b]ошибка System.AccessViolationException[/b] с [b]сообщением: «Попытка чтения или записи защищенной памяти[/b]. Это часто указывает на то, что другая память повреждена». Подробности проекта: Языки программирования: C# для основного приложения и язык ассемблера (ASM) для обработка изображений. Функциональность: приложение позволяет пользователям загружать изображение, обрабатывать его (с помощью модуля asm или модуля C#) для имитации дейтеранопии и сохранять обработанное изображение. Вот краткий обзор соответствующего кода: Код ASM (ModuleAsm.asm): [code].code DeuteranopiaAsm proc
SimulateDeuteranopiaASM: ; Save registers push rbp mov rbp, rsp sub rsp, 32
mov r9, rdx ; pixelCount mov r8d, edi ; threadCount (passed through edi) mov rdx, rcx ; pointer to original image (originalImage) mov rcx, rdi ; pointer to processed image (processedImage)
; Calculate the portion size for each thread xor rax, rax ; Clear rax before division mov eax, r9d ; Move pixelCount to eax (32-bit register for division) xor edx, edx ; Clear edx (higher part of rax) div r8d ; Divide eax by r8d (threadCount in r8d, 32-bit register) mov r10d, eax ; Store the result (portion size) in r10d
; Parallel processing mov eax, r10d mov r11, rdx ; pointer to original image mov rdx, rcx ; pointer to processed image
ProcessLoop: cmp r9d, 0 je Done
; Load original pixel data using 8-bit registers movzx eax, byte ptr [r11] ; Load red channel (R) into eax (extended to 32-bit register) movzx ecx, byte ptr [r11 + 1] ; Load green channel (G) into ecx (extended to 32-bit register) movzx edx, byte ptr [r11 + 2] ; Load blue channel (B) into edx (extended to 32-bit register)
; Simulate deuteranopia (green color blindness) imul eax, eax, 625 ; Transform red channel imul ecx, ecx, 375 ; Transform green channel add eax, ecx shr eax, 10 ; Divide by 1024 mov [rdx + 2], al ; Save transformed red channel to processed image
imul ecx, ecx, 7 ; Further transform green channel shr ecx, 3 ; Divide by 8 mov [rdx + 1], cl ; Save transformed green channel
imul edx, edx, 8 ; Transform blue channel shr edx, 3 ; Divide by 8 mov [rdx], dl ; Save transformed blue channel
; Move to the next pixel add r11, 3 ; Move pointer in original image to the next pixel add rdx, 3 ; Move pointer in processed image to the next pixel dec r9d ; Decrement pixel count jmp ProcessLoop ; Repeat loop
Done: ; Restore registers add rsp, 32 pop rbp ret DeuteranopiaAsm endp end
[/code] Код C# (MainWindow.xaml.cs): [code]using System; using System.Windows; using System.Windows.Input; using Microsoft.Win32; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; using System.Threading.Tasks;
namespace Projekt { public partial class MainWindow : Window { // Importing the ASM function (updated with the correct path) [DllImport(@"C:\Users\kacpe\Desktop\home\Programing\studia\ASM-SEM-5\Projekt\x64\Debug\ModuleAsm.dll")] public static extern void DeuteranopiaAsm(IntPtr originalImage, IntPtr processedImage, int pixelCount, int stride, int threadCount);
public static Bitmap SimulateDeuteranopia(Bitmap original, int threads) { int width = original.Width; int height = original.Height; Bitmap simulatedImage = new Bitmap(width, height, original.PixelFormat);
Rectangle rect = new Rectangle(0, 0, original.Width, original.Height); BitmapData originalData = original.LockBits(rect, ImageLockMode.ReadOnly, original.PixelFormat); BitmapData simulatedData = simulatedImage.LockBits(rect, ImageLockMode.WriteOnly, simulatedImage.PixelFormat);
int bytesPerPixel = Image.GetPixelFormatSize(original.PixelFormat) / 8; int stride = originalData.Stride; IntPtr originalScan0 = originalData.Scan0; IntPtr simulatedScan0 = simulatedData.Scan0;
byte[] originalPixels = new byte[stride * height]; byte[] simulatedPixels = new byte[stride * height];
public static int Clamp(int value, int min, int max) { if (value < min) return min; if (value > max) return max; return value; } } }
[/code] Описание проблемы: Исключение AccessViolationException обычно возникает, когда код пытается получить доступ к запрещенной памяти. Я подозреваю, что это может быть связано с тем, как указатели и память управляются между кодом C# и ASM. Я правильно блокирую фрагменты изображений, но мне интересно, есть ли какие-либо проблемы с выравниванием памяти или могут ли проблемы быть вызваны манипуляциями с пикселями. Дополнительная информация:[list] [*]Я использую .NET Framework и ориентируюсь на архитектуру x64. [*]DLL загружается правильно, но на этапе обработки изображения происходят сбои. . [*]Буду признателен за любую информацию об распространенных ошибках, которые могут привести к этому исключению, особенно в сценариях взаимодействия между C# и ASM. [/list]Я пробовал реструктуризировать, но это ни к чему не приводит...