C# i wywołanie funkcji z biblioteki napisanej w asemblerze

0

Witam! Mam problem - napisałem niewielką bibliotekę do konwertowania plików bmp do png, która wiem że działa (skompilowałem jako exe i śmiga bez problemu). Potem stworzyłem dllkę, wrzuciłem do katalogu z projektem w C# i tutaj mam problem:

Nagłówek funkcji w asemblerze:

konwertujASM proc zrodlo:dword,cel:dword,fake:dword

Wywołanie funkcji:

fn konwertujASM,"C:\Release\plik.bmp","C:\plik.png",1

Jak widać, pierwsze dwa parametry przechowują stringi (a raczej adresy) plików, gdzie mają być umieszczone. Nie wiem jednak, jak to opisać w c# - jak dołączyć bibliotekę (czy to byłoby ok?)

[DllImport("konwertujASM.dll")]
public static extern void konwertujASM(IntPtr plik,IntPtr docelowy,Int32 fake);

i jak funkcję potem wywoływać. Robiłem już na milion sposobów - konwersja do tablicy bajtów, Marshal do IntPtr, nic z tego.

Za każdym razem wywala mi błąd "An unhandled exception of type 'System.DllNotFoundException' occurred in ProjektJA.exe

Additional information: Unable to load DLL 'konwertujASM.dll': Nieprawidłowy dostęp do komórki pamięci. (Exception from HRESULT: 0x800703E6)"

Z góry dziękuję za pomoc.

1

Masz system 32 czy 64 bitowy? Nie jestem pewien czy IntPtr to najlepszy pomysł.

Mógłbyś gdzieś wrzucić tą bibliotekę albo przykładową bibliotekę z funkcją mającą taką samą sygnaturę (żeby potestować i sprawdzić czy wywołanie zadziała)?

0

Vista 32bit. Oto biblioteka (korzysta z GDIplus): http://hotfile.com/dl/102354603/6f5ba33/konwertujASM.dll.html

[edit]Pomoże ktoś? Nawet wskazówka byłaby ok. Char* - czyli

konwertujASM([MarshalAs(UnmanagedType.LPArray)] byte[] plik, [MarshalAs(UnmanagedType.LPArray)] byte[] docelowy, Int32 fake);

i wywołanie

konwertujASM(Encoding.ASCII.GetBytes(openFD.FileName), Encoding.ASCII.GetBytes(FN), 1);

Nie działają.

0

Bez źródeł tej biblioteki nic ci nie pomożemy.

0

Zawartość pliku konwertujASM:

.586p
.mmx			
.model flat, stdcall
option casemap :none

include				\masm32\include\windows.inc
include				\masm32\include\kernel32.inc
include				\masm32\include\gdi32.inc
include				\masm32\include\masm32.inc
include 			\masm32\include\gdiplus.inc
include				\masm32\macros\macros.asm

includelib			\masm32\lib\kernel32.lib
includelib			\masm32\lib\gdi32.lib
includelib			\masm32\lib\masm32.lib
includelib 			\masm32\lib\gdiplus.lib

; struktury potrzebne do obslugi GDI+ 
GDIstart STRUCT
	GdiplusVersion           DWORD ?
	DebugEventCallback       DWORD ?
	SuppressBackgroundThread DWORD ?
	SuppressExternalCodecs   DWORD ?
GDIstart ENDS

PNGinfo STRUCT
	ClassID           	CLSID <>
	FormatID          	GUID <>
	CodecName         	DWORD ?
	DllName           	DWORD ?
	FormatDescription 	DWORD ?
	FilenameExtension 	DWORD ?
	MimeType          	DWORD ?
	Flags             	DWORD ?
	Version           	DWORD ?
	SigCount          	DWORD ?
	SigSize           	DWORD ?
	SigPattern        	DWORD ?
	SigMask           	DWORD ?
PNGinfo ENDS



konwertujASM	PROTO :DWORD,:DWORD

.code

konwertujASM proc uses esi edi ebx 	zrodlo:dword,cel:dword
	
	LOCAL uni_zrodlo[1024]		:BYTE
	LOCAL uni_cel[1024]			:BYTE
	LOCAL uni_mime[64]			:BYTE
	
	LOCAL zet               	:DWORD
	LOCAL obraz               	:DWORD
	LOCAL enkoder         		:DWORD
	LOCAL rozmiarPNGinfo  		:DWORD
	LOCAL wskPNGinfo     		:DWORD
	LOCAL gdipsi				:GDIstart
	
	
	;inicjalizacja
	fn RtlZeroMemory,addr gdipsi,sizeof GDIstart
	mov gdipsi.GdiplusVersion,1	
	
	mov zet,0
	mov obraz,0
	mov enkoder,0
	mov rozmiarPNGinfo,0
	mov wskPNGinfo,0
	
	
	; konwersja do Unicode (ze wzgledu na GDI+)
	fn MultiByteToWideChar,0,MB_PRECOMPOSED,zrodlo,-1,addr uni_zrodlo,sizeof uni_zrodlo
	fn MultiByteToWideChar,0,MB_PRECOMPOSED,cel,-1,addr uni_cel,sizeof uni_cel
	
	mov edx,chr$("obraz/png")
	
	fn MultiByteToWideChar,0,MB_PRECOMPOSED,edx,-1,addr uni_mime,sizeof uni_mime
	
	
	
	; obsluga GDI+
	fn GdiplusStartup,addr zet,addr gdipsi, NULL
	
	fn GdipLoadImageFromFile,addr uni_zrodlo,addr obraz
	
	fn GdipGetImageEncodersSize,addr enkoder,ADDR rozmiarPNGinfo
	
	mov wskPNGinfo,alloc(rozmiarPNGinfo)
	
	fn GdipGetImageEncoders,enkoder,rozmiarPNGinfo,wskPNGinfo
	
	
	xor ebx,ebx
	mov esi,wskPNGinfo
	
skok:	cmp ebx, enkoder
		jae dalej2
		fn ucCmp,[esi].PNGinfo.MimeType,addr uni_mime
		cmp eax, 0
		je dalej1
		fn GdipSaveImageToFile,obraz,addr uni_cel,esi,NULL
		
dalej1:	add esi, SIZEOF PNGinfo
		inc ebx
		jmp skok

dalej2:	fn GdipDisposeImage, obraz
		fn GdiplusShutdown, zet
	
	free wskPNGinfo
	
	ret
konwertujASM endp
	
end konwertujASM 

plik .def:

LIBRARY "konwertujASM"
EXPORTS
konwertujASM

Paczka z projektem w radasm:

http://hotfile.com/dl/102474561/9fedde2/konwertujASM.zip.html

Próbowałem wywołać ją poprzez

public static extern void konwertujASM([MarshalAs(UnmanagedType.AnsiBStr)]String plik, [MarshalAs(UnmanagedType.AnsiBStr)]String docelowy);

, bez rezultatu.

1

Patrzyłem na to już wcześniej, ale nie zdążyłem zrobić dokładnej analizy. Teraz też nie, więc piszę co mam na razie:

Co do źródła, IDA już mi to wszystko powiedziała :P

Problem nie leży w sygnaturze wywołania, raczej w bibliotece (jesteś na 100% pewny że dokładnie ta sama biblioteka działała na dokładnie tym samym komputerze?) - Program 'wywala' się w momencie rozruchu maszyny wirtualnej - gdyby wina była w źle zadeklarowanej sygnaturze, błąd byłby niewykrywany, ale występowałby w momencie wywołania tej funkcji.
Teraz nie zdążę, ale gdybyś mógł (albo ktokolwiek) sprawdzić czy ta biblioteka w programie napisanym w C++ działa...?

Potancjalnie najciekawsze: DllEntryPoint ma ten sam adres co konwertujASM (0x10001000). DllEntryPoint to procedura wejścia biblioteki, wywoływana w momencie wczytania programu do pamięci. To może znaczyć że twoje konwertujASM jest wywoływane ze śmieciowymi parametrami przy ładowaniu - świetnie pasowałoby to w takim razie do objawów (konwersja niczego do niczego nie może działać poprawnie ;) ). Nie wiem co za kompilator/linker by jednak zrobił takie coś bez ostrzeżenia...

0

Dzięki, sprawdzę. Napiszę program w cpp korzystający z tej biblioteki i zobaczę jak tam będzie śmigać.

A, co do tego dllentrypoint - program się krzaczy tylko podczas manualnego wywołania z menu aplikacji w C# - dlaczego miałoby się wtedy źle załadować?

Co do biblioteki - skopiowałem tą skompilowaną i wrzuciłem do każdego katalogu w projekcie z C# (bo mnie to wkurzyło:D) więc raczej tak, pewny jestem.

0
#include "stdafx.h"
#include <windows.h>
 
typedef void (*fun)(DWORD,DWORD);

int _tmain(int argc, _TCHAR* argv[])
{
	LPCWSTR str = TEXT("konwertujASM.dll");
	HMODULE hModule = LoadLibrary (str);
	if (hModule == NULL) return 1; //sprawdzenie, czy moduł faktycznie został załadowany
		fun hFun = (fun)GetProcAddress (hModule, "konwertujASM");
		if (hFun == NULL) return 2; //tak dla pewności sprawdźmy czy nasza funkcja także została odnaleziona
		hFun (*"plik.bmp",*"plik.png");
		FreeLibrary (hModule);

return 0;
}

Napisałem program do sprawdzenia czy dll'ka śmiga - i co ciekawe program zawsze wyskakuje mi z wartością 1 (biblioteka się nie ładuje). Robię coś źle czy po prostu biblioteka nie chce się załadować?

0

zobacz co po LoadLibrary zwraca ci GetLastError.

1 użytkowników online, w tym zalogowanych: 0, gości: 1