Używanie bibliotek dll w C#

0

Witam, Mam drobny problem z używaniem bibliotek dll napisanych w niezarządzanym c++. Konkretnie piszę taką prostą klasę w c++:

ifndef SOME_DLL_H
#define SOME_DLL_H

#ifdef DLLTEST_LIB_EXPORTS
#define MY_DLL __declspec(dllexport)
#else
#define MY_DLL __declspec(dllexport)
#endif

#pragma once

class MY_DLL TestClass
{
	int number;
public:
	TestClass(void);
	~TestClass(void);
	Driver(int _nbr);

	int GetNumber();
};

#endif

Taka trywialna klasa. Teraz w C# chcę użyć tej klasy, więc piszę:

[DllImport("SOME_DLL.dll")]
TestClass testClass;

Ale taki zapis powoduje pojawienie się błędów:

Error 1 The type or namespace name 'TestClass' could not be found (are you missing a using directive or an assembly reference?)

Może ktoś potłumaczyć jak sprawnie dołączyć taką bibliotekę?

1

Nie da się importować całych klas w ten sposób. Musisz swoją niezarządzaną klasę z kodem zarządzanym połączyć ręcznie. Poprzez wystawienie niezarządzanego interfejsu C (pojedyncze funkcje), interfejsu COM bądź wystawienie zarządzanej klasy za pomocą C++/CLI.

0

Czyli jedynym wyjściem jest napisanie wrappera? Możesz trochę to opisać lub znasz może jakiś dobry i czytelny poradnik/tutorial? Trochę szukałem ale nie udało mi się znaleźć czegoś wystarczająco klarownego.

0

Tak, pozostaje wrapper. Słabo z ogólnymi poradnikami na ten temat, jak będziesz miał konkretne problemy pod względem konwersji typów między zarządzalnym kodem, a niezarządzalnym to pisz, mam w tym pewne doświadczenie (pisałem biblioteki szyfrujące w języku C, wykorzystywane z poziomu aplikacji .NETowych)

0

I chciałem tym samym zrobić uniwersalne narzędzie do łączenia się z tą drugą biblioteką.
To zrób interfejs tej swojej biblioteki jako funkcje globalne (extern "C") a nie klasy i będzie dobrze.

0

Odkopię swój problem, ponieważ jest to rzecz, której nie potrafię aktualnie rozwiązać. Otóż tworzę solution a w nim dwa projekty - jeden to biblioteka dll jako CLR->Class Library, drugi to prosta aplikacja wykorzystująca zbudowaną bibliotekę dll. Bibliotekę ładuję na dwa sposoby i na moim komputerze wszystko działa jak należy, natomiast jeśli przeniosę aplikację na inny komputer to otrzymuje informację o błędzie ładowania biblioteki. Wszystkie mają zainstalowane .Nety do wersji 4, i nawet środowiska VS a mimo to dostaję monit o błędzie. Oto sposoby:

  1. Jeśli bibliotekę próbuję załadować poprzez Add References to u mnie wszystko działa jak należy. Po przeniesieniu aplikacji na inny komputer otrzymuję błąd:

Każde odwołanie do tej biblioteki to pojawienie się komunikatu (we właściwościach tej referencji zaznaczyłem aby plik został skopiowany do katalogu z exekiem):

System.IO.FileNotFoundException: Could not load file or assembly 'TestDLL.dll' or one of its dependencies. Nie można odnaleźć określonego modułu.
File name: 'TestDLL.dll'

  1. Drugi sposób to poprzez użycie Assembly.Load:

Żeby program chociaż się uruchomił to poniższy kod wrzuciłem pod przycisk (bibliotekę kopiuję ręcznie):

            try
            {
                myAssembly = Assembly.LoadFrom("TestLibrary.dll");

                myType = myAssembly.GetType("TestLibrary.SimpleMath");

                WorkingObject = Activator.CreateInstance(myType);

                foreach (MethodInfo info in myType.GetMethods())
                {
                    Console.WriteLine("Metody: {0}", info.Name);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                GB_Test.Enabled = true;
            }

Błąd:

Could not load file or assembly 'TestLibrary.dll' or one of its dependencies. Nie można odnaleźć określonego modułu.

Zawartość biblioteki dll:

//
//    PLIK .h
//
#pragma once

using namespace System;
using namespace std;

namespace TestLibrary {

	public ref class SimpleMath
	{
	public:
		SimpleMath();
		int Multiply(int _value);
	};
}

//
//    PLIK .cpp
//
#include "stdafx.h"

#include "TestLibrary.h"

using namespace TestLibrary;

SimpleMath::SimpleMath()
{
}

int SimpleMath::Multiply(int _value)
{
	return _value * 100;
}

Biblioteka jak widać prosta i prostsza już być nie może. Nie wykorzystuję tutaj żadnych dodatkowych cudów. Ot taki prosty twór. Po zbudowaniu u mnie działa poprawnie a na innym komputerze nie działa.

Niestety potrzebuję napisać tą bibliotekę w C++ dlatego męczę się z tym i nie widzę rozwiązania.

0

Możesz podesłać gotowe binarki?

0

Dodaję cały folder Debug stworzony w VS razem z plikiem dll.

EDIT:

Napisałeś skompilowane binarki więc program + biblioteka. Zatem dodałem plik dll oraz exe...

0

A dlaczego dystrybuujesz biblioteki skompilowane jako Debug?

1

Strzelam, że program w C# odpalany jest jako x64, a biblioteka to 32-bit. W preferencjach projektu C# np. platform target ustaw na "x86".

0

Dzisiaj ustawiłem Platform target na x86 i dalej to samo (wcześniej było wybrane any platform). Rev, Tobie udało się podlinkować tą bibliotekę?

EDIT:

już na wszelki wypadek wyłączyłem prekompilowane nagłówki. I dalej ten sam efekt - aby nie było przy każdym budowaniu aplikacji daję clear i dopiero buduję.

0

@Rev udało Ci się w jakiś sposób rozwiązać ten problem?

0

Podpiąłem tę DLL'kę do pustego projektu ale nie da się wywołać z niej metody SimpleMatch(). Wali błędem o problemach z ładowaniem. Możesz zapakować całe przykładowe solution i tu podeslac? Coś mi się wydaje, że Twoje TestLibrary jest od czegoś jeszcze zależne.

0

Ale osso hozi?

  1. Visual Studio 2012, Windows 7 32-bit
  2. tworzę nowy projekt (C# Console)
  3. dodaję referencję do TestLibrary.dll
  4. piszę
class Program
{
    static void Main(string[] args)
    {
        var sm = new TestLibrary.SimpleMath();
        int i = sm.Multiply(4);
        System.Console.WriteLine(i);
    }
}
  1. odpalam (Ctrl+F5)
  2. dostaję 400

jakie problemy z ładowaniem? ;-)

a) dopilnuj jednakowej wersji .NET w dll-ce i w programie
b) dopilnuj jednakowej architektury w obu projektach (najlepiej unikać AnyCPU jeśli którakolwiek biblioteka jest natywna)

1

Masz system x64 czy 32 bit?
Jeśli ładujesz jako 64 bit, nie da rady wczytać 32bitowej dll.

Jesteś pewien że zmieniłeś target? Jeśli masz system 64bit, to uruchom program i sprawdź czy w menadżerze zadań ma taką (*) gwiazdkę koło nazwy.

0

Mimo, że komputer przyjąłby system 64bitowy to wszystko mam zainstalowane w wersji 32 bity.

Azarien, tak skompilowany program przenieść na inny komputer. Dalej będzie sie wykonywał? Na moim komputerze program działa nad wyraz sprawnie. Problem jest podczas przenoszenia.

Aha, nie podałem tego ale używam Visual Studio 2012 na Windows 8 32bit. Podczas tworzenia projektu wybierałem .NET 4 aby właśnie uniknąć takich problemów. Dodatkowo ustawiałem architektury 32 bit - ale przy any a x86 nie widzę różnicy w tym przypadku - działa u mnie, na innym komputerze nie działa.

0

W załączniku jest solution z dwoma projektami. Jeden to dll'ka a drugi to aplikacja wykorzystująca tą bibliotekę. Są to najbardziej podstawowe projekty i nie dokonywałem żadnych zmian w ustawieniach projektu - poza wybraniem platformy oraz wyłączeniem prekompilowanych nagłówków (choć to i tak nic w moim przypadku nie daje).

0

(opisuję stan obecny, nie Twoje intencje, ani historię mieszania w opcjach):

  1. DLL-ka jest ustawiona na x86, ale EXE na AnyCPU. źle.

  2. DLL-ka jest ustawiona by się nie budowała przy "Build All". źle, bo może powodować ciągłe uruchamianie się poprzedniej wersji.

  3. DLL-ka nie jest kopiowana do katalogu z exekiem. Jeśli tam jest, to znaczy że jakaś stara wersja, nie bieżący build (patrz też pkt 2).

Dodaj po ludzku referencję do DLL-ki: w projekcie EXEka wybierz PROJECT|Add Reference|Solution, tutaj.

@1&2, właściwości solucji powinny wyglądać tak (dla All Configurations):

bzzt.png

PS. w Platform masz kilka pozycji, które dodatkowo komplikują. zostaw tylko jedną, resztę pousuwaj w Configuration Manager.

0

Pomimo zmiany ustawień program generuje błąd. Nawet stworzyłem całkiem nowy projekt z takimi ustawieniami jakie zaleciłeś i to samo. Już nawet stworzyłem klasę z samym tylko konstruktorem... Może źle tworzę klasę? Już sam nie wiem.

Aha - projekty specjalnie sam kompilowałem i ręcznie przenosiłem do katalogu z binarką. To było celowe. Podobnie jest z ładowaniem biblioteki - próbowałem przez add reference oraz przez Assembly.LoadFrom(). I otrzymuję te same komunikaty.

0

@Azarien
u mnie wygląda to w ten sposób (podaję wszystko) w załączniku.
Możesz to sprawdzić? Wydaje mi się, że jest wszystko okej dopilnowałem platformę (x86) jest i wersję .NET.
O jakim All Build mówisz?

Program działa na moim komputerze jednakże nie działa jak przeniosę go na inny i to jest dziwne bo dopiero na innym nie potrafi wczytać tej dllki.

0

@metal_man
@DibbyDum
a u mnie działa tylko na kompie, na którym był skompilowany :P to jest rzeczywiście dziwne w tej chwili :D

0

No właśnie nie mam pojęcia dlaczego na wybranych komputerach się uruchamia. Coś w ustawieniach projektu?

0

Bo brakuje na nich runtime Visual C++ dla biblioteki?

0

@metal_man a z tym DllImport Ci działa?:P Bo mi nie haha :D Mam dokładnie to samo... poddaje sie powoli

0

Ciagle otrzymuję tą samą odpowiedź. Co do runtime Visual C++ - program ma problem z uruchomieniem nawet na deweloperskich maszynach, wyposażonych w Visual Studio.

0

@Azarien @Rev
albo ktoś inny dajcie krok po kroku instrukcje jak to zrobić - jak dla debili to moze zadziała

1

Rozwiązaniem jest prawidłowe ustawienie projektu. Tworzymy bibliotekę C++/CLI i najlepiej zanim zacznie się pisać - w opcjach projektu ustawić target na x86 i aby budowało się do wersji release. Tak zbudowana biblioteka nie ma prawa nie działać :) Do tego potrzebny jest Visual Studio Redistributable.

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