Dificuldade com Structure no JNA

4 respostas
O

Olá,
Tenho umas bibliotecas de um equipamento para utilizar e o problema que estou tendo é o seguinte:
Eu passo uma Structure (struct no nativo) ByReference como parâmetro para um método. E depois de fazer a chamada do método, ao fazer a leitura da Structure os valores obtidos não são os esperados.
São valores muito estranhos por sinal. Eu altero os valores no equipamento e chamo de novo a funcao para obter os parametros e muitos dos parametros nem chegam se alterar.
Nao estou entendendo qual o problema. Nao sei se é pelo fato de estar usando ByReference, estou obtendo na verdade o endereço de memória dos itens da Structure e não o valor realmente dos itens.
Abaixo seguem os códigos utilizados:

Eu tenho exemplos da utilização dos arquivos .os em C++, mas preciso operar isso em Java, devido a plataforma que estou utilizando.

//Nativo C++
//Struct a ser utilizada, se encontra em um arquivo header struct.h
#pragma pack(push,1)
typedef struct ST_SCANPARMS    
{
	unsigned char iCommand; // 1 ±íÊ?ÉèÖòÎÊý 2±íÊ?É?Ãè
	int sortype;			// 1 :GR169 2 :SR4731
	int scanmode;			//average scan
	int scanrange;			//60KM
	int avgtime;			//6s
	int wavelength;			//wave length 1310
	int pulsewidth;			//3000ns
	int ior; 
	double sensitivity;		//low
	double filberendloss;
	unsigned char crcLow;
	unsigned char crcHigh;
}SCANPARMS,*PSCANPARMS;
#pragma pack(pop)

//Assinatura do método para operação do .os, se encontra no arquivo header, nfosock.h. O arquivo .os se encontra nomeado nfosock.os
int GetParms(SCANPARMS *tRetParms ,char sIP[],short nPort);

//Chamada do método em um arquivo principal, nfo.cpp
int ret=-1;
SCANPARMS parms;
char arrIP[30] = {0};
short nPort = 0;
//...
//no código sao atribuidos os valores de ip e port necessarios e entao o métodos é chamado
//...
ret = GetParms(&parms ,arrIP ,nPort);

Ao utilizar a aplicação C++ o equipamento me retorna os valores dos parâmetros esperados.
Já em java nao obtive o mesmo exito.
Abaixo segue o código utilizado em Java:

public class SCANPARMS extends Structure{
		public static class ByReference extends SCANPARMS implements Structure.ByReference { }
		public char iCommand; // 1 ±íÊ?ÉèÖòÎÊý 2±íÊ?É?Ãè
		public int sortype;			// 1 :GR169 2 :SR4731
		public int scanmode;			//average scan
		public int scanrange;			//60KM
		public int avgtime;			//6s
		public int wavelength;			//wave length 1310
		public int pulsewidth;			//3000ns
		public int ior; 
		public double sensitivity;		//low
		public double filberendloss;
		public char crcLow;
		public char crcHigh;
	}

//As assinaturas do metodos me pareceu estranha, mas ao usar o comando "nm nfosock.os" foi assim que eu os obtive e assim eu venho obtendo a resposta esperada para outros métodos
public interface NFOSock extends Library{
	int _Z8GetParmsP12ST_SCANPARMSPcs(SCANPARMS.ByReference tRetParms,String sIP,short nPort);
	int _Z9GetDeviceP14ST_Device_Info(ST_Device_Info[] tDevice);
	String _Z13GetLibVersionv();	
}

//Codigo principal
public static void main(String args[]){
	NFOSock nfosock = (NFOSock)Native.loadLibrary("/home/pedro.carvalho/workspace/WwRadiantech/lib/nfosock.so", NFOSock.class);
	SCANPARMS.ByReference parms = new SCANPARMS.ByReference();
	short nPort = 4997; //porta que estou utilizando para comunicacao com o equipamento
	int ret = 0;
	String IP = "192.168.1.57"; //ip no qual se encontra o equipamento
	ret = nfosock._Z8GetParmsP12ST_SCANPARMSPcs(parms, IP, nPort);
	System.out.println("sorType: "+parms.sortype); //Exemplo de parametro que ao ser comparado é obtido errado
}

Espero ter sido claro na minha dúvida.
Obrigado antecipadamente,

4 Respostas

E

O char do C++ tem 1 byte e o do Java tem 2. Use byte em vez de char.
Não conheço JNA mas acredito que haja uma maneira de especificar o packing também.

O

Grato pela resposta rápida.
Mudei as variaveis char para byte, entretanto o problema continua.
E, por fim, nao sei o que você quer dizer com “packing”.

O

Alguém mais tem alguma idéia?
Tentei não usar o ByReference e na hora da chamada do método passar o Pointer com o método getPointer(), mas o obtido é ainda pior, não há alteração da Structure.
Ela permanece com seus valores zerados.
Grato,

O

Finalmente descobri qual era o problema. Era no que dizia a respeito do packing, como disse entanglement.
O padrão Java e C++ é segmentar a memória em blocos de 4 bytes, entretanto o código

#pragma pack(push,1)
#pragma pack(pop)

muda isso. Com o packing em 1, a memória passou a ser segmentada de um em um, o que fazia com o que era lido pelo Java parecia incorreto, entretanto, apenas o bytes errados estavam sendo lidos para cada variável.
Para que o Java não utilize o padrão de 4 bytes, basta mudar o mapping no construtor da Structure, como segue abaixo:

public SCANPARMS(){
			super(null, ALIGN_NONE);
		}

onde, SCANPARMS é o nome da Structure. Espero que tais informações sejam úteis para outras pessoas também.

Criado 26 de abril de 2011
Ultima resposta 10 de mai. de 2011
Respostas 4
Participantes 2