char* char** y VB6

Iniciado por ^[GS]^, 29 Mayo 2018, 10:08 AM

0 Miembros y 1 Visitante están viendo este tema.

^[GS]^

Hola, estoy con problema, hice una DLL (en Golang), que se compila en C, con los tipos de C, en la cual utilizo char* para enviar strings y char** para devolver strings, el problema es que no importa como lo declare en VB6 no logro poder usar estos métodos.

Las funciones se exportan con:
extern GoInt32 PrintHello(char* p0, char** p1);
extern GoInt32 PrintBye(char** p0);
extern GoInt32 LenString(char* p0);

Obviamente el tipo GoInt32 es propio de Golang, en VB6 lo puedo leer perfectamente como Long.

En teoría debería poder usar estos metodos en VB6 con la siguiente declaración:
Declare Function PrintHello Lib "testDLL.dll" (ByVal Nombre As String, ByRef Output As String) As Long
Declare Function PrintBye Lib "testDLL.dll" (ByRef Output As String) As Long
Declare Function LenString Lib "testDLL.dll" (ByVal Nombre As String) As Long


Pero no, no consigue otro mensaje que "Bad DLL calling convention". Hice otros métodos, que devuelven char* en lugar de GoInt32 (extern char* OutString();) y FUNCIONAN con VB6 como Strings (Declare Function OutString Lib "testDLL.dll" () As String), pero no como parámetro.

Gracias!!

Serapis

#1
Para que en vb6 puedas usar librerías externas, necesitas estas cosas:
+ la convención de llamadas tipo C: StdCall
+ Pasar la dirección de la cadena, que en vb luego el parámetro se declarará "ByRef elparametro as string"
+ La cadena de vb6 siempre acaba en un carácter null (0x), luego cuando proceda debes añadir un caracter 0 al final (si se recide desde la dll, porque vb6, lo adjuntará cuando se envíe a la dll). dicho carácter nunca cuenta como propio del tamaño del string.
+ Las cadenas en vb6 por defecto son Unicode (2 bytes por carácter), luego si las tienes de 1 byte por carácter o previamente haces una conversión en tu librería, o lo entregas como un array de bytes, ó como señalo a continuación...
Otra forma más laboriosa es pasar un tipo long que es la dirección de memoria donde se aloja la propia cadena (el primer carácter que interese), y en otro parámetro su longitud, en ese caso sabiendo la longitud (si se recibe en VB6), construyes una cadena de ese tamaño y luego copias el contenido desde aquella dirección a la dirección de tu cadena, la cantidad de bytes señalados. Aquí no importa si allí la tienes de 1 o 2 caracteres por byte (si siempre es igual, haces siempre una conversión en vb6 usando la función StrConv(x, a unicode/desde unicode). Si cada función de la dll, va atener sus propias características, entonces mejor señalar en un tercer parámetro si son 1 o dos bytes por caracter, por ejemplo ",Byval Unicode as boolean), =True para indicar que en origen tiene 2 bytes por caracter... o ",ByVal Unicode as byte)  1= ANSI, 2= UNICODE, 0 = indefinido (en destino debe resolverse).

Este método es el adecuado, si por ejemplo, quieres pasar una subcadena, o no quieres ajustar en origen un formato que entiendes que solo depende del 'destino'. Además de este modo, la cadena tomada en Vb6 es copia (byval), luego se usa también cuando no se quiere alterar la de origen...
Este método que copia contenido desde memoria, no precisa que en origen la cadena tenga un null al final (imagina el caso de una subcadena), dado que tu en Vb6 declaras y construyes una cadena del largo deseado, ya contiene el null final, al reservarse memoria para ella... luego tu solo copias los bytes (caracteres) en su nueva ubicación.

Si no terminas de aclararte, pásame copia de la dll, (con esas 3 funciones), tal cual la tienes ahora y veo de entender donde te has liado... y cual sería la solución menos costosa.

^[GS]^

Gracias NEBIRE, tu respuesta me aclaro bastantes dudas al respecto.

La DLL la esta creando Golang y por lo tanto me impide tener control sobre los "tipos de variable" finales que generará C. Así que no tengo forma de manipular el "mientras".

En teoría las llamadas son STDCALL pero no sabría como comprobarlo para estar seguro.

Estoy empezando a creer que tal vez el envió por memoria sea lo mas conveniente.