На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
> Проблемы с подключением библиотеки
    Приветствую!

    Вот уже неделю (а то и больше) не могу разрешить следующую проблему: есть библиотека, написанная в Visual C++ .NET и проэкт, использующий ее, написанный в Visual Basic .NET. Библиотека предназначена для построения стрктуры данных в памяти (дву-связный список) по переданному ей массиву и работы с ним (перестановки и т.п.). Когда я вызываю процедуру построения этого списка, все вроде бы нормально и никаких ошибок не происходит. Но стоит мне вызвать хоть одну функцию работы со списком и вылетает ексепшн: NullReferenceException. Как будто указатель на начало списка укаывает в нуль, но из приведенного мной кода (см. ниже), явно видно, что такого быть не может. Тем более, когда я проверял все функции этой библиотеки в программе (без вызова их из DLL, они были описаны в той же программе) они работали и не происходило ошиок. Или я совсем ничего не понимаю, или все таки у DLL свой сегмент данных, и в нем должно все сохраняться. Вот код библиотеки (не весь, я указал лишь одну функцию работы со списком - Perform2OPT):

    Цитата

    #include <windows.h>

    typedef struct City {
         unsigned int Data;
         struct City *Next, *Prev;
    } TCity;

    // common functions
    void SetDistancesMatrix(double *M);
    void SetData(unsigned int *CitiesData, unsigned int Pos, unsigned int N);
    int GetData(unsigned int *CitiesData);
    void DestroyList();
    // heuristics
    bool Perform2OPT();
    ...
    ...
    ...

    //!!!!!!! These pointers raises exception ???
    TCity *Head=NULL, *Tail=NULL, *Last; // Pointer to the head and tail of list
    double *Distance; // Pointer to distances matrix
    int Num; // Number of cities

    void DestroyList() {
         TCity *C=Head, *T;
         while (C!=Tail) {
     T=C;
     C=C->Next;
     delete T;
         }
         delete C;
    }

    void SetDistancesMatrix(double *M) {
         Distance=M;
    }

    // Main DLL function. We do not use any initializatoins
    BOOL APIENTRY DllMain( HANDLE hModule,
                          DWORD  ul_reason_for_call,
                          LPVOID lpReserved
         )
    {
       return TRUE;
    }

    void SetData(unsigned int *CitiesData, unsigned int Pos, unsigned int N) {
         TCity *C;
         Num=N;
         Head=new TCity;  Tail=new TCity;  Last=Head;
         Head->Data=0;  Tail->Data=0;
         for (unsigned int i=Pos; i<Pos+Num; i++) {
     C=new TCity;
     C->Data=CitiesData[i];
     C->Prev=Last;
     Last->Next=C;
     Last=C;
         }
         Tail->Prev=Last;      Last->Next=Tail;
    }

    int GetData(unsigned int *CitiesData) {
         int Idx=0;
         TCity *C=Head->Next;
         while (C!=Tail) {
     CitiesData[Idx++]=C->Data;
     C=C->Next;
         }
         return Idx-1;
    }


    // Performs 2-OPT herustics
    bool Perform2OPT() {
         TCity *I1, *I2, *J1, *J2;
         unsigned int TempData;
         bool Result=false;
         int Cnt1=0, Cnt2=0, Cnt3=0;
    Next:
         I1=Head->Next;
         do {
     I2=I1->Next;
     J1=I2->Next;
     do {
             J2=J1->Next;
           if ((Distance[I1->Data*Num+J1->Data]+Distance[I2->Data*Num+J2->Data])<
       (Distance[I1->Data*Num+I2->Data]+Distance[J1->Data*Num+J2->Data]))
           {
       while (I2!=J1) {
             TempData=I2->Data;
             I2->Data=J1->Data;
             J1->Data=TempData;
             I2=I2->Next; J1=J1->Prev;
             if (J1->Next==I2) break;
       }
       Result=true;
       goto Next;
           }
           J1=J2;
     } while ((J1!=Tail->Prev)&&J1->Next);
     I1=I2;
         } while (I1!=Tail->Prev->Prev);
         return Result;
    }

    Так выглядит модуль объявлений функций в библиотеке (VB.NET):
    Цитата

    Module heuristics
       Declare Sub SetDistancesMatrix Lib "heuristics32.dll" (ByRef M As Double(,))
       Declare Sub SetData Lib "heuristics32.dll" (ByRef CitiesData As Integer(), ByVal Pos As Integer, ByVal N As Integer)
       Declare Function GetData Lib "heuristics32.dll" (ByRef CitiesData As Integer()) As Integer
       Declare Sub DestroyList Lib "heuristics32.dll" ()

       Declare Function Perform2OPT Lib "heuristics32.dll" () As Byte
    ...
    ...
    ...
    End Module


    А это класс-интерфейс для работы с библиотекой (собственно проэкт VB.NET):
    Цитата

    Module TSPClass
       Public Class HeuristicsClass
           Private FCitiesNum As Integer   'Number of cities
           Private FCities As Integer()      'Array of cities indexes
           Private DistancesMatrix As Double(,) 'Matrix with distances between cities
           Private FDBName As String      'File name of database with cities data
           Private FTableName As String    'Name of table in database
           Private FOptimized As Boolean   'Optimized flag

           Public ReadOnly Property CitiesCount() [COLOR=blue]As Integer
           Public Property DBName() As String
           Public Property TableName() As String
             Public ReadOnly Property Optimized() As Boolean
           Public Function GetTourPoints(ByRef Data As Short()) As Boolean
           Public Function SetTourPoints(ByRef Data As Short()) As Boolean

           'This method reads table (specifyed by TableName property) from source database (name specifyed by DBName property)
           'and loads data from it for optimization. Fields MUST BE named as follows: "Index", "X", "Y".
           'If function succeeds, returned value is true, otherwise - false

           Public Function ReadSource() As Boolean
               Dim Result As Boolean = True    'Return value
    'Всякие объявления
               Try
    'Здесь я считываю массив из базы данных (как раз то, что я спрашивал в соседнем топике)
    'А вот тут пошли вызовы из DLL:

                   Call SetDistancesMatrix(DistancesMatrix)    'Set pointer to distances matrix
                   Call SetData(FCities, 0, N)                 'Set current sequence for optimization
               Catch DllEx As DllNotFoundException
                   MsgBox(DllEx.Message, MsgBoxStyle.Critical, "Error")
                   FCitiesNum = 0
                   Result = False
               Catch ex As Exception                          'If error occured ...
                   FCitiesNum = 0                              'Clear number of cities
                   Result = False                              'Return result - false (failed)
               Finally
                   DataReader.Close()
                   Connection.Close()
               End Try
               Return
    Result
           End Function

    'А это, господа, и виновник всех неудач (как я с себя все свалил) :)
           Function Perform_2OPT() As Boolean
               Try

                   FOptimized = Perform2OPT()
               Catch DllEx As DllNotFoundException
                   MsgBox(DllEx.Message, MsgBoxStyle.Critical, "Error")
               Catch e As NullReferenceException
                   MsgBox("Che za hren'???"+e.Message)
               End Try
               Return
    FOptimized
           End Function
    ...
    ...
    ...
           Public Sub New(ByVal DBN As String, ByVal TN As String)
               Dim Response As MsgBoxResult = MsgBoxResult.Retry
               FOptimized = False
               FCitiesNum = 0
               FDBName = DBN
               FTableName = TN
               While (Not ReadSource()) And Response = MsgBoxResult.Retry
                   Response = MsgBox("Error reading database", MsgBoxStyle.RetryCancel, "ERROR")
              End While
           End Sub

           Protected Overrides Sub
    Finalize()
               MyBase.Finalize()
           End Sub
       End Class


    P.S. Извините за такой объём, но иначе нельзя объяснить проблему.

    Спасибо за вимание.
      А почему нельзя использовать System.Collections.ArrayList? Скорее всего он использует оптимальные алгоритмы, и не особо уступает в скорости написанному.

      Или почему бы не сделать библиотеку managed dll?

      А гонять библиотеку под отладчиком пробовал? Именно библиотеку, а не программу.
        Здравствуйте!
        Дело в том, что стандартный класс работает медленно. Я тестировал и стандартный и мною написанный в среде VB.NET класс, хороших результатов это не дало. А на С++ я программу отлаживал и она работает.

        Неужели указатели в библиотеке не сохраняются? Как это может быть?
          1. Если используешь VS2003 - имеет смысл переписать на MC++ и не париться. А то можешь на интеропе потерять больше.
          2. Указатели маршалятся как IntPtr а не как Integer. Этот тип специально для этого и создан.
          Может баг еще где, извини, это просто в глаза бросилось.. времени нет :)
          Сообщение отредактировано: kl -
            То есть ты хочешь сказать, что необходимо поменять:
               Declare Sub SetData Lib "heuristics32.dll" (ByRef CitiesData As Integer(), ByVal Pos As Integer, ByVal N As Integer)
               Declare Function GetData Lib "heuristics32.dll" (ByRef CitiesData As Integer()) As Integer

            На:

               Declare Sub SetData Lib "heuristics32.dll" (ByVal CitiesData As IntPtr, ByVal Pos As Integer, ByVal N As Integer)
               Declare Function GetData Lib "heuristics32.dll" (ByVal CitiesData As IntPtr) As Integer

            ???
              Угу
                Спасибо за ответ, все понятно. Но:
                - Как мне послылать тогда массив 32-х битных значений?
                - А в самой библиотеке тоже надо получать как IntPtr?
                - И как его там конвертить в массив интов?

                Большое спасибо.

                С уважением, neutrino.
                  Цитата neutrino, 22.07.03, 20:06:15
                  Спасибо за ответ, все понятно. Но:
                  - Как мне послылать тогда массив 32-х битных значений?
                  - А в самой библиотеке тоже надо получать как IntPtr?
                  - И как его там конвертить в массив интов?
                  Большое спасибо.
                  С уважением, neutrino.

                  В библиотеке у тебя обычные указатели.
                  А про передачу массивов прочитай здесь. (последний ответ)
                  Сообщение отредактировано: kl -
                    Привет еще раз. Надеюсь я вас не замучил...

                    Ссылка оказалась на самом деле полезной. После того, как я ее прочитал, нашел и у себя в МСДН подходящий топик.

                    Назревает вопрос: а надо ли мне маршалить массив, если библиотеку я тоже написал в .NET Framework? Странно получается... Или язык С++ по определению у них "Unsafe" из-за указателей или еще чего...

                    Кстати, из того, что я прочитал в МСДН следует, что определение должно выглядеть так:
                    Declare Sub SetData Lib "heuristics32.dll" (ByRef <MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)>  CitiesData As Integer(), ByVal Pos As Integer, ByVal N As Integer)
                    ??? ??? ???
                      Так понятно, прочитай-ка про C++ with managed extensions. Особенно обрати внимание на __gc arrays. Возможно у тебя отпадет куча вопросов  и надобность в интеропе заодно.
                      Сообщение отредактировано: kl -
                        Большое спасибо господину kl за исчерпывающий ответ и помощь.
                          Я немного поторопился с выводами...

                          У меня ничего не вышло с этими __gc. Все время синтаксические ошибки. Вот так я писал:

                          double Distance __gc[,];

                          void SetDistancesMatrix(double M __gc[,]) {
                               Distance=M;
                          }

                          Да и такое определение не прокатывает:

                          void SetData(unsigned int CitiesData __gc[], unsigned int Pos, unsigned int N)

                          Как же нужно правильно писать?
                            Приведи ошибки-то, нет времени компилить.
                            Я надеюсь, ты с опцией /clr компилил?
                              Ну Ё! Ты хоть МСДН почитай что-ли!
                              __gc это storage класс, как static или register. Соответственно его надо указывать там где ДОЛЖЕН появляться storage-класс. Или, для __gc arrays ПЕРЕД словом new при выделении памяти:
                              ExpandedWrap disabled
                                <br>double array[]= [b]__gc[/b] new double[100]<br>


                              Ссылки в MSDN:
                              ms-help://MS.VSCC.2003/MS.MSDNQTR.2003APR.1033/vcmxspec/html/vcManagedExtensionsSpec_4_5.htm  - это __gc arrays

                              ms-help://MS.VSCC.2003/MS.MSDNQTR.2003APR.1033/vcmxspec/html/vcManagedExtensionsSpec_4.htm  - это по поводу __gc вообще

                              ms-help://MS.VSCC.2003/MS.MSDNQTR.2003APR.1033/vcmex/html/vcconMCOverview.htm  - это всё про managed extensions for C++
                                Цитата andrey, 30.07.03, 23:26:44
                                Ну Ё! Ты хоть МСДН почитай что-ли!
                                __gc это storage класс, как static или register. Соответственно его надо указывать там где ДОЛЖЕН появляться storage-класс. Или, для __gc arrays ПЕРЕД словом new при выделении памяти:
                                ExpandedWrap disabled
                                  <br>double array[]= __gc new double[100]<br>




                                __gc - это ключевое слово, говорящее о том, что объект будет размещен в управляемой куче (куче CLR). И синтаксис должен выглядеть вот так:
                                ExpandedWrap disabled
                                  <br>double array __gc[] = new double __gc[100];<br>

                                А причем тут например static я так и не понял
                                  static это просто аналогия.
                                  Вот статья из MSDN:

                                  A __gc array is a dynamic array that is allocated on the common language runtime heap. The number of elements of the array is not part of the type. A single array variable may refer to arrays of different sizes.
                                  Example
                                  // __gc_arrays.cpp
                                  // compile with: /clr
                                  #using <mscorlib.dll>
                                  using namespace System;

                                  int main() {
                                    Int32 ia[] = __gc new Int32[100];
                                    ia = new Int32[200];
                                  }
                                  The indices of a __gc array are zero-based, as in standard C++. A __gc array is subscripted using ordinary C++ array brackets. Unlike standard C++, subscripting is not a synonym for pointer arithmetic, and is not commutative.
                                  Characteristics
                                  A __gc array shall be allocated using the managed operator __gc new.
                                  Using new to allocate a managed array defaults to __gc new.
                                  Constraints
                                  The type of an element of a __gc array shall only be a __value class, or a __gc pointer to a __gc class.
                                  __nogc new shall not be used to allocate an array of managed type.
                                  A __gc array variable definition shall not specify a size. The size of the array is given in the call to the managed operator __gc new.
                                  A __gc array is itself a __gc object. It is actually a pointer into the common language runtime heap. The indirection of the pointer has been factored into the subscripting operator. As a __gc object, it has the same restrictions as a __gc class (Section 4). Most notably, the element type cannot be an unmanaged C++ class that is not a POD type.
                                  All __gc arrays inherit from System::Array. Any method or property of System::Array can be applied directly to the array variable.
                                  Example
                                  // __gc_arrays2.cpp
                                  // compile with: /clr
                                  #using <mscorlib.dll>
                                  using namespace System;

                                  int main() {
                                    Int32 ia[] = __gc new Int32[100];
                                    Console::WriteLine(ia->Length);
                                  }
                                  Output
                                  100
                                    Кстати я в своём примере ошибся - нельзя использовать встроенный C++ класс double, нужно исползовать FCL класс Double
                                      Синтаксис допускает оба варианта
                                      Главное не забыть про /clr и разумеется не пытаться создавать __gc массивы на стеке
                                        Уважаемый господин Андрей, читал я МСДН и ничего там не понял.

                                        А для ключа /clr есть аналог в Options?
                                          Цитата andrey, 30.07.03, 23:26:44
                                          ... __gc это storage класс, как static или register. Соответственно его надо указывать там где ДОЛЖЕН появляться storage-класс. Или, для __gc arrays ПЕРЕД словом new при выделении памяти ...

                                          Мне не нужно выделять память для массива. Прочитайте мои вопрос внимательнее. Мне необходимо получить его в качестве параметра функции в библиотеке, которую вызывают из VB.NET. Именно поэтому существует проблема несоответствия типов данных.
                                            Цитата neutrino, 03.08.03, 20:32:17
                                            Уважаемый господин Андрей, читал я МСДН и ничего там не понял.
                                            А для ключа /clr есть аналог в Options?

                                            Есть там что-то типа Compile managed code.
                                            И приведи ты в конце-концов ошибки-то.
                                              Я никак не возьму в толк, тебе нужен ответ на вопрос или нет? Тогда напиши то что тебя просит модератор - то есть ошибки.

                                              Я попробовал так :
                                              C++ managed code class library:
                                              ExpandedWrap disabled
                                                <br>class sss{<br>...<br>      public : void PTest(Double arr[]){<br>                         Console::WriteLine(arr->ToString());<br>                   }<br>


                                              VB.NET windows forms application:
                                              ExpandedWrap disabled
                                                <br>    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load<br>        Dim ss As tst.sss<br>        ss = New tst.sss<br>        Dim mm() As Double<br>        mm = New Double(2) {2.2999999999999998, 5.5999999999999996, 5.2999999999999998}<br>        ss.PTest(mm)<br>    End Sub<br><br>


                                              У меня всё это работает
                                              Сообщение отредактировано: kl -
                                                Доброго времени суток.
                                                Вот вывод компилятора (команда вызова в самом начале):
                                                Цитата

                                                C:\Documents and Settings\neutrino\My Documents\Heuristics32>cl /clr Heuristics32.cpp
                                                Microsoft ® 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
                                                Copyright © Microsoft Corp 1984-1998. All rights reserved.

                                                Command line warning D4002 : ignoring unknown option '/clr'
                                                Heuristics32.cpp
                                                Heuristics32.cpp(37) : fatal error C1021: invalid preprocessor command 'using'

                                                C:\Documents and Settings\neutrino\My Documents\Heuristics32>

                                                То есть ни параметр '/clr' ни директиву препроцессора '#using' он не понял. Саму эту директиву, как

                                                написано в MSDN, надо указывать всегда при использовании Managed C++:
                                                Цитата

                                                #using <mscorlib.dll>

                                                Для полноты картины приведу релевантный кусок кода, который я пытался компилировать:
                                                Цитата

                                                #include <windows.h>
                                                #using <mscorlib.dll>

                                                typedef struct City {
                                                     unsigned int Data;
                                                     struct City *Next, *Prev;
                                                } TCity;

                                                TCity *Head=NULL, *Tail=NULL, *Last; // Pointer to the head and tail of list
                                                double Distance __gc[,]; // Pointer to distances matrix
                                                int Num; // Number of cities

                                                BOOL APIENTRY DllMain( HANDLE hModule,
                                                                      DWORD  ul_reason_for_call,
                                                                      LPVOID lpReserved
                                                                              )
                                                {
                                                   switch (ul_reason_for_call)
                                                     {
                                                           case DLL_PROCESS_ATTACH:
                                                           case DLL_THREAD_ATTACH:
                                                           case DLL_THREAD_DETACH:
                                                           case DLL_PROCESS_DETACH:
                                                                 break;
                                                     }
                                                   return TRUE;
                                                }

                                                void DestroyList() {
                                                     TCity *C=Head, *T;
                                                     while (C!=Tail) {
                                                           T=C;
                                                           C=C->Next;
                                                           delete T;
                                                     }
                                                     delete C;
                                                }

                                                void SetDistancesMatrix(double M __gc[,]) {
                                                     Distance=M;
                                                }

                                                void SetData(unsigned int CitiesData __gc[], unsigned int Pos, unsigned int N) {
                                                     TCity *C;
                                                     Num=N;
                                                     Head=new TCity;            Tail=new TCity;            Last=Head;
                                                     Head->Data=0;            Tail->Data=0;
                                                     for (unsigned int i=Pos; i<Pos+Num; i++) {
                                                           C=new TCity;
                                                           C->Data=CitiesData[i];
                                                           C->Prev=Last;
                                                           Last->Next=C;
                                                           Last=C;
                                                     }
                                                     Tail->Prev=Last;      Last->Next=Tail;
                                                }

                                                int GetData(unsigned int CitiesData __gc[]) {
                                                     int Idx=0;
                                                     TCity *C=Head->Next;
                                                     while (C!=Tail) {
                                                           CitiesData[Idx++]=C->Data;
                                                           C=C->Next;
                                                     }
                                                     return Idx-1;
                                                }

                                                .
                                                .
                                                .
                                                  Версия компилера не та, должна быть (у меня такая) 13.0.9466 for .NET Framework.
                                                  Это MC++ компилятор из MSVS.NET 2003. Если у тебя стоит MSVS.NET, то проверь PATH, может вызывается не тот компилер который надо.
                                                    Я понимаю, что это наглость, но не мог бы кто-нибудь откомпилировать мой проэкт библиотеки? Пожалуйста. Мне больше ничего не остается делать...

                                                    Зазипинный проэкт библиотеки: Heuristics.zip (362Kb)
                                                      Не качается.... Кинь мне на мыло andreyaz ____ @ ____ rol.ru (_ удалить)
                                                        Отправил.
                                                          Ээээ, размер файла =0.
                                                          О, зато теперь качается по ссылке!
                                                            Блин, там что сервак на модеме сидит?

                                                            Миллион ошибок.
                                                            Я отключил все RTC, Debug info, PCH

                                                            Всё вынесено в класс statics неймспейса ____Heuristics. Ко всему применён модификатор static. DllMain убит нафиг.
                                                            Количество размерностей массива Distance теперь 1 (при объявлении обявлялось 2, а потом в коде использовалась только 1, соответственно SetDistancesMatrix принимает только 1 мерный массив)

                                                            Вобщем работать может быть будет.

                                                            Самое главное: теперь это managed dll и LoadLibrary не катит!
                                                              Качай http://www.ve-2-00.ru/xxxx.rar
                                                                Странно, мне почему-то не удалось прочитать таблицу экспорта функций...
                                                                  Это managed-dll, там нет экспортируемых функций. RTFM, как уже неоднократно советовали!!!
                                                                    Цитата andrey, 25.08.03, 00:56:43
                                                                    Это managed-dll, там нет экспортируемых функций. RTFM, как уже неоднократно советовали!!!

                                                                    Тут согласен на 100\%. Это основы. Читай что такое метаданные в .NET
                                                                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                                    0 пользователей:


                                                                    Рейтинг@Mail.ru
                                                                    [ Script execution time: 0,1056 ]   [ 16 queries used ]   [ Generated: 27.04.24, 22:57 GMT ]