2009-05-22 4 views
1

Ich habe eine VB-Anwendung beantragen eine Liste von Benutzern aus einem C-DLL:
VB fragt die DLL, wie viele Benutzer es gibt, und initialisieren Sie dann ein Array auf die entsprechende Größe.
VB wird dann sein Array durch Verweis auf eine DLL-Funktion übergeben, die es mit Benutzernamen füllen wird.Wie viele Sternchen sollte ich verwenden, wenn ich einen Zeiger auf ein Array von C-Strings deklariere?

Ich begann mit dem Schreiben der C-Funktion wie folgt: foo(char **bar);, die als ein Array von Strings behandelt werden würde. Aber dann wurde mir klar, dass ich jedes Element im Array auf eine andere C-Zeichenfolge (die char *username in der verknüpften Liste struct userlist) setzen werde, anstatt die Daten zu ändern, auf die bereits hingewiesen wurde. Das Array von Arrays wird nach Wert übergeben: eine Kopie einer Liste von Adressen, so dass die Adressen auf die ursprünglichen Daten zeigen, aber das Ändern der Adressen in dieser Kopie wird die Liste der Adressen des Aufrufers nicht ändern (denke ich jedenfalls)). Also, sollte ich es foo(char ***bar); deklarieren? Dies wäre ein Zeiger auf das Array von Zeichenfolgen, so dass, wenn ich die Zeichenfolgen ändere, auf die das Array zeigt, wird es das Array von Zeichenfolgen ändern, die der Aufrufer (VB) benutzt .... richtig?

Diese meine Nutzung ist bisher (habe es nicht getestet noch ... Ich bin Codierung gerade noch die DLL als der noch, es gibt keine VB-Front-End nennen es so weit)

EXPORT void __stdcall update_userlist(char ***ulist){ 

    int i = 0; 
    userlist *cur_user = userlist_head; //pointer to first item in linked list 

    for(; i < usercount_; ++i){ 
    *ulist[i] = cur_user->username; 
    cur_user = cur_user->next; 
    } 

} 

Antwort

4

Im Allgemeinen ist es nicht einfach ist, zu tun, was Sie fragen, weil VB einfach nicht C-Stil ASCIIZ Strings und Arrays verstehen.

Wenn Ihre DLL kein VB SafeArray von BSTR erwartet, werden Sie einige Schwierigkeiten haben, es zu füllen.

Es wäre einfach, VB in einem Array von Long (C int) durch Verweis auf das erste Element zu übergeben, und Sie könnten das mit den Zeigern zu einzelnen Zeichenfolgen füllen. Die VB-Seite könnte sie in VB-Strings kopieren. Aber in diesem Fall, wer hat die C-Saiten und wann?

Wenn Sie das VB-Array erstellen und es mit vordefinierten Strings füllen, müssen Sie immer noch mit einem SafeArray auf der C-Seite umgehen, da Sie kein einzelnes VB-String-Array-Element als Referenz übergeben und erwarten können um die restlichen im Speicher benachbarten Zeichenfolgen zu finden.

Die beste und sicherste Methode besteht darin, dass Ihre DLL ein SafeArray des sogenannten 'Ansi BSTR' erstellt und die Funktion in VB als Rückgabe eines Array von Strings deklariert. Dann brauchen Sie nicht zwei Aufrufe, weil die Array-Grenzen die ganze Geschichte erzählen.

===== ===== bearbeiten

Wenn VB ein String-Array auf eine deklarierte Funktion gibt es einige Voodoo hinter den Kulissen tut. Es konvertiert zuerst alle Zeichenfolgen von Unicode in eine Bastardform, die allgemein als "Ansi BSTR" bekannt ist. Nach C sehen diese aus und können wie ASCIIZ oder LPSTR behandelt werden, außer dass Sie sie nicht auf die normale C-Art erzeugen oder verlängern können, sondern nur ausfüllen können. Auf der C-Seite sieht das übergebene Array aus wie ppSA (SAFEARRAY **). Die Ansi-BSTR sind eine Reihe von Zeigern, auf die das pData-Member von SafeArray verweist.

Sie können absolut keine einzige Zeichenkette aus dem Array übergeben (als char *) und erwarten, dass die restlichen Zeichenketten, die im Speicher liegen, gefunden werden. Sie müssen das Array selbst übergeben und mit der SafeArray-API (oder der Kenntnis der SA-Struktur) manipulieren.

Deshalb ist die beste Option, insgesamt ist dies alles direkt in der DLL zu tun. Erstellen Sie das Array mit SafeArrayCreate, dann erstellen Sie Ansi BSTRs mit SysAllocStringByteLen und platzieren Sie diese Zeichenfolgen (die BSTR sind, also ein 4-Byte-Zeiger) in die Array-Slots. Bei der Rückkehr macht VB seinen Voodoo und konvertiert die Strings für Sie in Unicode.

In VB würde Ihre Funktion als Rückgabe eines String() deklariert werden.

+0

gut, wenn ich die VB SAFEARRAY durch Verweis auf eine C-Funktion übergeben, die einen Zeiger erwartet, kann ich es so manipulieren, richtig? Und wenn ich sicherstelle, dass das VB-Array die richtige Anzahl von Elementen enthält, indem ich vorher die DLL nach dieser Nummer frage, dann kann ich einfach durch das Array iterieren und die Elemente ändern, oder? Wenn das, was Sie über ein VB-Array von Longs gesagt haben, einfach funktioniert, dann funktioniert auch ein Array von Strings, da BSTR wirklich nur char * ist. Ich denke, die Verwendung der regulären gefährlichen Array und zwei Anrufe ist besser für die Einfachheit dieses Programms geeignet, anstatt eine SAFEARRAY ... –

+0

... Mein Hauptproblem ist, dass ich die Zeichenfolgen in der VB-Array ändern kann, wenn Ich übergebe es an ein Char **, aber würde das nicht das tatsächliche Array nach Wert übergeben und nur die Strings durch Referenz? Dies würde es unmöglich machen, das Array so umzulenken, dass es auf verschiedene Strings zeigt, da ich nur die Kopie des Arrays ändern würde und nicht die Daten, auf die das Original und die Kopie zeigen. –

+0

nein, du hast Recht, es kann keine Strings übergeben, nur ganzzahlige Typen ...Danke –

1

zwei Asterixen ist der Weg zu gehen.

char* // is a pointer to a char 
char** // is a pointer to a char pointer 
char*** // is a pointer to a pointer to a char pointer - e.g. multi-dimensional array (err...) 

Ich habe mich verwirrt :)

+0

http://c2.com/cgi/wiki?ThreeStarProgrammer Es gibt nicht so etwas wie char *** (na ja, es ist, aber es ist sinnlos): Alles, was Sie mit einem char tun können ** * Sie können mit einem Char ** – Tordek

+0

http://c2.com/cgi/wiki?ThreeStarProgrammer – Dave

+0

Sie sollten auch beachten, dass Sie "gezackte Array" (ich denke, das ist der Begriff) tun können. So etwas wie {[1, 2, 3], [1, 2], [1, 2, 3, 4, 5]}! – nevets1219

0

Also lass mich das klarstellen. Ihre Funktion füllt ein Array von Strings aus Daten in einer verknüpften Liste?

Wenn Sie die Größe der Liste im Voraus kennen, können Sie einfach ein Zeichen ** übergeben, aber wenn Sie die Größe nicht kennen und in der Lage sein müssen, die Liste zu vergrößern, benötigen Sie ein Zeichen ***.

Aus in Ihrem Code suchen, scheinen Sie bereits über die Länge kennen, so dass Sie nur ein Array mit der richtigen Länge müssen zuweisen, bevor Sie die Funktion aufrufen. Hier ein Beispiel:

void update_userlist(char **ulist) 
{ 
    int i = 0; 
    userlist *cur_user = userlist_head; 

    for(; i < usercount_; ++i) 
    { 
     ulist[i] = cur_user->username; // I am assuming that username is a char * 
     cur_user = cur_user->next; 
    } 
} 

// This sets up the array and calls the function. 
char **mylist = malloc(sizeof(char*) * usercount_); 
update_userlist(mylist); 

Update: Hier ist der Unterschied zwischen den verschiedenen Ebenen der Zeiger:

  1. Leere func1 (char * data)
    Dies geht eine Kopie eines Zeigers zu einer C-Zeichenfolge. Wenn Sie den Zeiger so ändern, dass er auf eine andere Zeichenfolge zeigt, zeigt die aufrufende Funktion weiterhin auf die ursprüngliche Zeichenfolge.

  2. void func2 (char ** data)
    Dies übergibt eine Kopie eines Zeigers an ein Array von Zeigern auf C-Zeichenfolgen. Sie können den Zeiger auf eine beliebige Zeichenfolge im Array ersetzen, und das Array der aufrufenden Funktion wird geändert, da es keine Kopie des Arrays erstellt hat, sondern nur auf das Array des Aufrufers zeigt.

  3. void func3 (char *** data)
    Dies übergibt einen Zeiger auf einen Zeiger auf ein Array von Zeigern auf C-Zeichenfolgen. Damit können Sie das gesamte Array vollständig ersetzen. Sie benötigen diese Umleitungsebene nur, wenn Sie das Array erweitern müssen, da C-Arrays nicht neu skaliert werden können.

+0

die Funktion, die das Array ausgefüllt benötigt, ist in VB6, so dass ich nicht wirklich irgendwelche Zeiger vorher manipulieren kann. VB erhält die Anzahl der Strings und erstellt dann ein Array von Strings (ich denke, das ist äquivalent zu char ** in C, Zeug wird bei der Übergabe an DLL von COM weg konvertiert). –

+0

auch, wenn ich ulist [i] ändere, ändere ich nur die temporäre Reihe von Zeigern, die bestanden wurden, nicht wahr? Das ursprüngliche Array, das ich übergeben habe, wird nicht geändert, nur die Daten, auf die von * ulist [i] gezeigt wird, werden geändert ... oder? –

+0

Ein Zeichen ** ist ein Zeiger auf das Array. Wenn Sie also den Zeiger auf eine einzelne Zeichenfolge in diesem Array ändern, ändert sich das Original. Es wird keine Kopie des Arrays erstellt. –

Verwandte Themen