# C++ DLL in VB 6.0



## ibo (30. August 2004)

Hallo leute,

ich hab da ein kleines problemchen!

Undzwar hab ich in C++ eine DLL geschrieben,  die eine funktion getData() enthält!

Jetzt versuche ich es in VB mit Private Declare Function getData Lib "C:\....." () As TLGData einzubinden
aber es funktioniert nicht!

TLGData ist eine struktur die einpaar int und double variablen beeinhaltet!

Hier mein code der DLL:

TLGData WINAPI getData()
{	
	TLGData pData[1];
	LPCTSTR Archiv ="Prozesswertarchiv";
	LPCTSTR Variable ="OP_MID_Q_l/s";
                     SYSTEMTIME Start;
	SYSTEMTIME Stop;
	PTLG_ARCHIVDATARAW pDaten;
	DWORD Anzahl = 1;
	DWORD Meldung = 0;
	CMN_ERROR Error;
	HWND hwndp = NULL;

	TLGConnect (hwndp, &Error);

	memset (&pDaten, 0, sizeof pDaten);
	memset (&Error, 0, sizeof (Error));

		Start.wYear = 2004;
		Start.wMonth = 8;
		Start.wDay = 26;
		Start.wHour = 15;
		Start.wMinute = 37;
		Start.wSecond = 0;		

		Stop.wYear = 2004;
		Stop.wMonth = 8;
		Stop.wDay = 26;
		Stop.wHour = 15;
		Stop.wMinute = 39;
		Stop.wSecond = 0;


	TLGGetArchivDataEx(Archiv, Variable, &Start, &Stop, &pDaten, &Anzahl, &Meldung, &Error);

	pData[0].Jahr = pDaten->stTime.wYear;
	pData[0].Monat = pDaten->stTime.wMonth;
	pData[0].Tag = pDaten->stTime.wDay;
	pData[0].Stunde = pDaten->stTime.wHour;
	pData[0].Minute = pDaten->stTime.wMinute;
	pData[0].Sekunde = pDaten->stTime.wSecond;
	pData[0].Flag =	pDaten->dwFlags;
	pData[0].Value = pDaten->doValue;

	TLGDisconnect(&Error);

	return pData[0];
}

BOOL APIENTRY DllMain( HANDLE, DWORD , LPVOID)
{


	return (TRUE);
}

Und in VB rufe ich es so auf:


Private Sub Form_Load

Dim x(1) As TLGData

x(0)= getData()

End Sub



Und er bringt mir den Fehler DLL-Einsprungspunkt getData nicht gefunden!


Was muss ich machen, damit er es findet

danke


----------



## MAN (30. August 2004)

Vielleicht hilft dir das weiter:

http://www.shadoware.de/vb/tutorials/cpp_in_vb.html

oder auch:

http://www.mvps.org/EDais/Tutorials/CDLL/CDLLch1b.html

sowie:

http://www.c-plusplus.de/forum/viewtopic.php?t=82340

Irgendwas wird schon weiterhelfen 


mfG,
MAN


----------



## ibo (1. September 2004)

Danke MAN... 

jetzt hab ich aber ein anderes problem...

ich hab in meiner funktion die in der dll steht einen zeiger  in der parameter liste

bool getData (String, String, Time, Time, pointer) 

so...
der pointer ist von einem selbst definierten Datentyp der Drei membervariablen enthält!

jetzt hab ich in VB
genau den gleichen Datentyp erstellt!
und rufe diesen als einen array in meiner parameterliste auf!
was ja angeblich in VB gehen soll!?

Und das sieht so aus

x = getData(String, String, Time, Time, MeinDatentyp(10))

Jetzt habe ich es  geschaft das er syntax mäsig und von wegen geht nicht mit byval oder byref  nicht mehr rummotzen kann

Aber jetzt strürtz VB jedes mal beim kompilieren ab!
 

und ich habe keine ahnung warum!

hab ihr ne ahnung an was es legen könnte

danke

mfg 

ibo


----------



## MAN (1. September 2004)

Dann hast du jetzt anscheinend noch das Problem mit dem bool Rückgabewert in der C++-Dll. Boolwerte sehen in C++ anders aus als in VB.

Nimm lieber bei beiden den Datentyp long und setz den Wert entweder auf 0 oder 1, dann passt es auch bei beiden.

Ich hatte selbst mal sowas in der Arbeit geschrieben, war auch kurz vor dem verzweifeln, aber letztendlich hat alles geklappt.

Ein Tipp: Pass auch mit Int und Long bei VB und C++ auf, die unterscheiden sich gänzlich! Hier dazu auch noch ein gutes Script: http://www.activevb.de/rubriken/kolumne/kol_4/cpptovbtypen.html


mfG,
MAN


----------



## ibo (2. September 2004)

Danke.....

Die Seite ist super!
ich werds probieren!
hoffentlich hab ich erfolg!

wenn noch fragen auftauchen sollten... auf dich ist ja verlass MAN
! 

Dankeschön!


----------



## MAN (2. September 2004)

Danke für das Kompliment 

mfG,
MAN


----------



## ibo (2. September 2004)

MAN ich hab noch ein problem!

Auf der Site steht zwar wie die funktionen aussehen müssen!
Ich machs auch genau so wie dort!

Also in der DLL hab ich ne struktur die so aussieht

typedef struct  _STIME
{   long Jahr;
    long Monat;
    long Tag;
    long Stunde;
    long Minute;
    long Sekunde;
} STIME;


und ich benutze diese struktur in meiner Funktionn als Parameter

long getData( LPCTSTR, LPCTSTR, STIME Sta)

ok? so weit ist doch alles klar oder?

in VB sieht die Struktur so aus:

Private Type STIME
 Jahr As Long
Monat As Long
Tag As Long
Stunde As Long
Minute As Long
Sekunde As Long
End Type

So jetz hab ich diese funktion in VB implementiert mit:

Private Declare Funktion getData Lib"C:\DLL" (ByVal s1 As Strin, ByVal s2 As String, sta As STIME)

und in:

Private Sub Form_Load

Dim x As long
Dim sta As STIME

s1="Blah"
s2 ="BlahBlah"

sta.Jahr=2004
sta.Monat=9
sta.Tag =2
.....usw...



x=getData(s1, s2, sta)



Debug.Print getData(s1, s2, sta);

End Sub


Und wenn ichs Kompilieren will bringt er mir den Fehler:

Fasche DLL-Aufrufkonvention
Und zeigt auf die Zeile mit dem x= getData.(.....)

Warum
wenn ich in meiner struktur STIME nur eine Variable habe gehts einwandfrei
aber schon bei zwei kommt dieser verda.... te fehler!:  :eek

Dringenst hilfe
danke!


----------



## MAN (2. September 2004)

Das liegt ganz einfach daran, dass deine deklarierte Funktion in VB kein Rückgabewert hat.

Das:

```
Private Declare Funktion getData Lib"C:\DLL" (ByVal s1 As Strin, ByVal s2 As String, sta As STIME)
```
mit dem:

```
x=getData(s1, s2, sta)
```
passt nicht ganz  

Versuchs mit:

```
Private Declare Funktion getData Lib "C:\DLL" _
(ByVal s1 As String, ByVal s2 As String, sta As STIME) As Long
```


mfG,
MAN


----------



## ibo (3. September 2004)

oh 


Doch meine funktion hat schon ein rückgabewert, aber ich hab vergessen ihn hinzuschreiben!

Und weißt du ob man von der c++ dll die werte in den Parametern zurückgeben kann?

also das was in den klammern steht


----------



## MAN (3. September 2004)

Eine Variable übergeben, also sozusagen referenzieren kannst du auch ganz einfach:

In deiner C++-DLL schreibst du das dann so:


```
__declspec(dllexport) long __stdcall getData( long* uebergabeParam1, long* uebergabeParam2 )
{
   (*uebergabeParam1) = 1234;
   (*uebergabeParam2) = 5678;

   return 1;
}
```
In VB definierst du dann die Funktion folgendermaßen:

```
Private Declare Funktion getData Lib "C:\DLL" _
(ByRef uebergabeParam1 As Long, ByRef uebergabeParam1 As Long) As Long

Private Sub Form_Load()
   Dim x As Long
   Dim param1 As Long
   Dim param2 As Long

   x = getData(param1, param2)

   MsgBox "Datenuebergabe der Funktion: param1 = " & param1 & "  |  param2 = " & param2
End Sub
```
Dies sollte dir dann eine MessageBox mit dem Text *Datenuebergabe der Funktion: param1 = 1234  |  param2 = 5678* ausgeben.

Ich hoffe ich konnte dir damit helfen!


mfG,
MAN


----------



## ibo (6. September 2004)

Du bist der Größte MAN!


Jetzt nur noch eine frage!

undzwar:

Wie kann ich ein ganzes array übergeben und in Visual basic wieder alle einträge ausgeben


Also zum beispiel: long WINAPI getData( long uebergabeparam[10]);

wie muss ich das in VB deklarieren


Danke

Du bist echt gut MAN! respekt!


Mfg 

ibo


----------



## MAN (6. September 2004)

In C++ tust du es folgendermaßen definieren:

```
__declspec(dllexport) long __stdcall getData( long* uebergabeparam );
{
	uebergabeparam[0] = 123;
	uebergabeparam[1] = 456;
	uebergabeparam[2] = 789;
	.....
}
```
In VB schaut es dann so aus:

```
Private Declare Function getData Lib "C:\DLL.dll" (ByRef uebergabeparam As Long) As Long
```
Und zugreifen tust du dann in VB folgendermaßen:

```
Dim myArray(10) As Long

getData( myArray(0) )

MsgBox myArray(0) & " - " & myArray(1) & " - " & myArray(2)
```
ergibt dann eine MessageBox mit dem Text *"123 - 456 - 789"*


mfG,
MAN


----------



## ibo (8. September 2004)

MAN!

You'r the man 

Super

Alles funktioniert!

Und sogar so wie ichs willl!

Danke für alles!

Du bist einfach der checker!


mfg ibo


----------



## MAN (8. September 2004)

Das ehrt mich 

Fragen zu beantworten, von dene ich Ahnung habe macht mir auch sehr viel Spass, vor allem, wenns um Programmiertechnisches geht im Bereich VB, bzw C(C++).

Wenn du weiterhin noch wo anders Fragen haben solltest kannst du gerne wieder fragen! 

so long,


mfG,
MAN


----------



## ibo (14. September 2004)

*neues problem.... neue frage!*

hi MAN,

also das is wahrscheinlich ne einfache frage für nen super Checker wie dich:

Ich will in VB ein Datei öffnen dialog machen!
gibts da auch so was wie in C++ das CFileDialog?

oder muss ich mir selber ein dialog basteln mit diesen ganzen ordnerboxen usw


----------



## MAN (14. September 2004)

Hi!

So etwas wie den CFileDialog in C++ gibt es durchaus in VB, hier heißt er nur anders, und zwar "CommonDialog".

Um diesen nutzen zu können must du aber erst eine Komponente den vorhandenen Steuerelementen hinzufügen, und zwar folgendes:

"Microsoft Common Dialog Control"

Wenn du dies dann hast, ziehst du es ganz einfach auf deine Form und per

```
CommonDialog1.ShowOpen()
```
bekommst du auch schon einen Öffnen-Dialog hin.

Falls du dazu noch Fragen haben solltest, wie man mit diesem Control umgeht, frag einfach nochmal nach 


mfG,
MAN


----------



## ibo (15. September 2004)

Danke...
klappt wunderbar!

ich kanns nicht oft genug sagen!

Du bist der beste MAN


----------



## ibo (16. September 2004)

hi MAN

Ich hab schon wieder ein Problem mit VB

Und zwar will ich ein Form das im Rahmen oben zwar diesen Minimieren Button hat aber nicht das Ausschalt button

Also die Frage ist jetzt, wie kann ich diesen Fenster Schließen Button deaktivieren 
oder ganz entfernen, ohne das ich mein Minimieren Button entferne


Danke


----------



## MAN (16. September 2004)

Das X oben rechts wegzubekommen geht nur mit API-Aufrufen und zwar folgendermaßen:

```
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function GetSystemMenu Lib "user32" (ByVal hwnd As Long, ByVal bRevert As Long) As Long
Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Private Declare Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long

Const MF_BYPOSITION = &H400
Const MF_REMOVE = &H1000

'Button um das Programm doch noch beenden zu können
Private Sub Command1_Click()
   End
End Sub

Private Sub Form_Load()
   Dim hMenu As Long
   Dim nPosition As Long
   
   hMenu = GetSystemMenu(Me.hwnd, 0)
   
   nPosition = GetMenuItemCount(hMenu)
   
   Call RemoveMenu(hMenu, nPosition - 1, MF_REMOVE Or MF_BYPOSITION)
   Call RemoveMenu(hMenu, nPosition - 2, MF_REMOVE Or MF_BYPOSITION)
   Call DrawMenuBar(Me.hwnd)
End Sub
```

mfG,
MAN


----------



## HotrenorTaak (17. September 2004)

HI,

auf der Suche nach einer Lösung zu genau diesem Problem,(Übergabe Array DLL/VB)  bin ich auf diesen Eintrag gestossen:



> _Original geschrieben von MAN _
> *In C++ tust du es folgendermaßen definieren:
> *
> 
> ...



Das habe ich genauso gemacht, nur ich bekomme immer den Fehler 9: "Index ausserhalb des gültigen Bereichs

Woran kann das liegen? Im Debugger von Access 2000 (im VB Editor) habe ich gesehen, dass die C++Dll das Array "kaputtschreibt, so das irgendeinmehrdimensionales(?) Array rauskommt.

Wär schön wenn da jemand was wüsste.

MfG

HT


----------



## MAN (17. September 2004)

Das liegt daran, dass dein definiertes Array zu klein ist.

Guck mal bei dieser Zeile:

```
Dim myArray(10) As Long
```
Da kannst du dann natürlich auch nur 10 Felder ansprechen mit dem C++-Code:

```
__declspec(dllexport) long __stdcall getData( long* uebergabeparam );
{
	uebergabeparam[0] = 123;
	uebergabeparam[1] = 456;
	.....
	uebergabeparam[9] = 789;
	// übergebenes Array für weitere Einträge zu klein
}
```

mfG,
MAN


----------



## HotrenorTaak (21. September 2004)

Hi,

ich hatte schon daran gedacht dass es ein ArrayIndexOutofBoundsError sein könnte.

Das ist leider nicht mein Problem, da ich in der C++ Dll die Indizes 0, 1, 2 fülle:


```
__declspec(dllexport) long __stdcall uebergabe( long* cArray)
{
cArray[0]  = 1;
cArray[1]  = 2;
cArray[2]  = 3;
return 0;
}
```

aber in VB ein  


```
Dim myAarray(10) As Long
```

habe.


----------



## MAN (21. September 2004)

Hast du es denn richtig deklariert und benutzt, so wie im folgenden Beispiel?

```
Private Declare Function uebergabe Lib "DLL.dll" (ByRef cArrayAs Long)

--------------------------------------------------------------------------------

Dim myArray(10) As Long

uebergabe(myArray(0))
```

mfG,
MAN


----------



## colblake (21. September 2004)

hi ,
hab mir gerade die Sache mit der DLL durchgelesen . 
Echt interesant, weiter so!
Mfg col.blake


----------



## HotrenorTaak (21. September 2004)

Zuerstmal: Danke für Deine Bemühungen. MAN.

Die Deklaration sieht folgendermassen aus:



```
Private Declare Function uebergebe Lib "E:\dbs\datdll.dll" Alias "_arrayTest@4" (ByRef Tarray As Long) As Long
```

und benutzt wird es mit:


```
Dim Tarray(10) As Long

uebergebe(Tarray(0))

MsgBox Tarray(0)
```

Ich kann da keinen Fehler erkennen.
Deshalb frage ich ja auch hier  

Ach ja vor dem Funktionsaufruf zeigt der Debugger:

Tarray: Long(0to10)

und nach uebergebe(Tarray(0))

Tarray : Long(-2147352572 to -2147352573, 10 to 9, 0 to 10) 

MfG

HT


----------



## MAN (21. September 2004)

Sauber....

Hm... hab' leider keinen blassen Schimmer, was das zu bedeuten hat!

Dann ist das auch mit "Index out of bounds" natürlich klar, wenn der das Array so "zersetzt".

Trotzdem wüßt ich nicht, was daran jetzt so falsch sein sollte, bei *ibo* hat das ja anscheinend auch ganz gut geklappt, warum dann bei dir nicht... 

Poste mal den kompletten Code der DLL und den Code in VB (oder auch per Mail), vielleicht liegt das Problem an einer ganz anderen Stelle!


mfG,
MAN


----------



## HotrenorTaak (22. September 2004)

HI,

ok, hier ist der komplette Code

arraydll.cpp:


```
extern "C" __declspec(dllexport) long _stdcall uebergebe(long* tArray)
{
	tArray[0] = 1;
	tArray[1] = 2;
	tArray[2] = 3;

	return 0;
}
```

und der vB Code:


```
Option Compare Database
Option Explicit

Private Declare Function uebergebe Lib "E:\ArrayDll\arraydll.dll" Alias "_uebergebe@4" (ByRef tArray As Long) As Long

Sub test()

Dim tArray(10) As Long

uebergebe (tArray(0))

MsgBox (tArray(0))

End Sub
```

ich hoffe, das hilft Dir weiter.

MfG

HT


----------



## ibo (24. September 2004)

MAN ich brauch deine hilfe!

im MFC Forum hat mir keiner drauf geantwortet!

Also du kennst dich doch auch in C++ ein bisschen aus ne?

Ich muss aus einer Globalen Funktion eine Combobox von nem dialog füllen....

ich habs mit diesem Code Probiert


BOOL TLGEnumVariablesExCallback(PTLG_VARIABLE_INFO lpvi, LPVOID pUser)
{	
	CWinCCDataDlg h;

	TCHAR szText[256];
	sprintf(szText,"%s",lpvi->szVariableName);

	CComboBox* c = (CComboBox*) GetDlgItem (h,IDC_COMBO1); 
	c->InsertString(0,_T(szText));//geht net!

	return TRUE;
}


aber es geht nicht!
Da bekomme ich nen laufzeitfehler!
er springt mir ohne auf Return True zu kommen raus und bringt mir nen fehler

Siehst du zufällig was ich falsch mache?

Danke


----------



## MAN (24. September 2004)

Sieht eigentlich ganz gut aus die Zeile, aber poste doch noch bitte, was bei deiner Funktion die einzelnen Datentypen sind, denn mit *PTLG_VARIABLE_INFO* und *LPVOID* kann ich im Moment nichts anfangen. Vielleicht gibt es da bei den String-Konvertierungen Schwierigkeiten. 

Und was kommt denn da für eine Fehlermeldung? Kannst du dich weiter reindebuggen, oder bekommst du da gar keine weiteren Infos raus?

mfG,
MAN


----------



## ibo (24. September 2004)

PTLG_VARIABLE_INFO ist ein Struct mit zwei member Variablen!
eine Member ist ein Strin und der andere ein float!

Das problem ist, bis zum umkopieren des Strings ist kein fehler
also in szText steht das richtige drin..
bei der Zeile  wo ich den Zeiger auf die Combobox deklariere sagt er auch nichts..
nur die  zeile mit 
c->InsertString(0,szText)  und  return TRUE wird übersprungen!

Ich habe mal beim debuggen die Variablen alle durchgeschaut!
und das h, also mein Dialog ist immer 0!

Deswegen glaub ich, das das c->InsertString einfach das Dialog nicht findet


die fehlermeldung sieht dann so aus:
Unbehandelte Ausnahme bei 0x10023096 in WinCCData.exe: 0xC0000005: Zugriffsverletzung-Leseposition 0x00000010.

also ich weiß net!
Ich muss es einfach hinkriegen das mein Objekt h nicht mehr null ist! glaub ich!


----------



## MAN (24. September 2004)

schonmal statt:

```
CWinCCDataDlg h;
```
das versucht ?

```
CWinCCDataDlg h = new CWinCCDataDlg();
```
Das würde dann aber ein neues Formular der Klasse *CWinCCDataDlg* erstellen und kein Vorhandenes benutzen.

Wenn du dir dein Formular in deiner globalen Klasse (da wo du auch deine globale Funktion definiert hast) definierst, und in der Funktion drauf zugreifst, kannst du immer dieses eine benutzen, ein Beispiel:

```
CWinCCDataDlg form = new CWinCCDataDlg();  // globales Objekt

BOOL TLGEnumVariablesExCallback(PTLG_VARIABLE_INFO lpvi, LPVOID pUser)
{
   TCHAR szText[256];
   sprintf( szText, "%s", lpvi->szVariableName );

   CComboBox* c = (CComboBox*) GetDlgItem( form, IDC_COMBO1 );
   c->InsertString( 0, _T( szText ) );

   return TRUE;
}
```

mfG,
MAN


----------



## ibo (27. September 2004)

Hi MAN,
ich habs auch so probiert, immernoch der gleiche Fehler!
wenn ich die zeile mit c->InsertString(0, _T(szText)) weglasse
kommt kein fehler!

aber wenn sie drin ist kommt dieser fehler mit der Zugriffsverletzung!

also weiter fällt mir nichts ein wie ichs sonst machen könnte!


Mfg 

ibo


----------

