Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.118.184.237] |
|
Страницы: (3) [1] 2 3 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Приветствую!
Вот уже неделю (а то и больше) не могу разрешить следующую проблему: есть библиотека, написанная в 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. Извините за такой объём, но иначе нельзя объяснить проблему. Спасибо за вимание. |
Сообщ.
#2
,
|
|
|
А почему нельзя использовать System.Collections.ArrayList? Скорее всего он использует оптимальные алгоритмы, и не особо уступает в скорости написанному.
Или почему бы не сделать библиотеку managed dll? А гонять библиотеку под отладчиком пробовал? Именно библиотеку, а не программу. |
Сообщ.
#3
,
|
|
|
Здравствуйте!
Дело в том, что стандартный класс работает медленно. Я тестировал и стандартный и мною написанный в среде VB.NET класс, хороших результатов это не дало. А на С++ я программу отлаживал и она работает. Неужели указатели в библиотеке не сохраняются? Как это может быть? |
Сообщ.
#4
,
|
|
|
1. Если используешь VS2003 - имеет смысл переписать на MC++ и не париться. А то можешь на интеропе потерять больше.
2. Указатели маршалятся как IntPtr а не как Integer. Этот тип специально для этого и создан. Может баг еще где, извини, это просто в глаза бросилось.. времени нет |
Сообщ.
#5
,
|
|
|
То есть ты хочешь сказать, что необходимо поменять:
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 ??? |
Сообщ.
#6
,
|
|
|
Угу
|
Сообщ.
#7
,
|
|
|
Спасибо за ответ, все понятно. Но:
- Как мне послылать тогда массив 32-х битных значений? - А в самой библиотеке тоже надо получать как IntPtr? - И как его там конвертить в массив интов? Большое спасибо. С уважением, neutrino. |
Сообщ.
#8
,
|
|
|
Цитата neutrino, 22.07.03, 20:06:15 Спасибо за ответ, все понятно. Но: - Как мне послылать тогда массив 32-х битных значений? - А в самой библиотеке тоже надо получать как IntPtr? - И как его там конвертить в массив интов? Большое спасибо. С уважением, neutrino. В библиотеке у тебя обычные указатели. А про передачу массивов прочитай здесь. (последний ответ) |
Сообщ.
#9
,
|
|
|
Привет еще раз. Надеюсь я вас не замучил...
Ссылка оказалась на самом деле полезной. После того, как я ее прочитал, нашел и у себя в МСДН подходящий топик. Назревает вопрос: а надо ли мне маршалить массив, если библиотеку я тоже написал в .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) ??? ??? ??? |
Сообщ.
#10
,
|
|
|
Так понятно, прочитай-ка про C++ with managed extensions. Особенно обрати внимание на __gc arrays. Возможно у тебя отпадет куча вопросов и надобность в интеропе заодно.
|
Сообщ.
#11
,
|
|
|
Большое спасибо господину kl за исчерпывающий ответ и помощь.
|
Сообщ.
#12
,
|
|
|
Я немного поторопился с выводами...
У меня ничего не вышло с этими __gc. Все время синтаксические ошибки. Вот так я писал: double Distance __gc[,]; void SetDistancesMatrix(double M __gc[,]) { Distance=M; } Да и такое определение не прокатывает: void SetData(unsigned int CitiesData __gc[], unsigned int Pos, unsigned int N) Как же нужно правильно писать? |
Сообщ.
#13
,
|
|
|
Приведи ошибки-то, нет времени компилить.
Я надеюсь, ты с опцией /clr компилил? |
Сообщ.
#14
,
|
|
|
Ну Ё! Ты хоть МСДН почитай что-ли!
__gc это storage класс, как static или register. Соответственно его надо указывать там где ДОЛЖЕН появляться storage-класс. Или, для __gc arrays ПЕРЕД словом new при выделении памяти: <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++ |
Сообщ.
#15
,
|
|
|
Цитата andrey, 30.07.03, 23:26:44 Ну Ё! Ты хоть МСДН почитай что-ли! __gc это storage класс, как static или register. Соответственно его надо указывать там где ДОЛЖЕН появляться storage-класс. Или, для __gc arrays ПЕРЕД словом new при выделении памяти: <br>double array[]= __gc new double[100]<br> __gc - это ключевое слово, говорящее о том, что объект будет размещен в управляемой куче (куче CLR). И синтаксис должен выглядеть вот так: <br>double array __gc[] = new double __gc[100];<br> А причем тут например static я так и не понял |