Número de série do volume, como descobrir?

:scrambleup: Gente, já Googleei isso, já busquei em todo canto, mas ainda não consegui achar algo concreto pra fazer o que quero. Primeiro o que eu quero: quero buscar o id do disco da máquina local (ou volume serial number, número de série do volume, volume id, ou do que você quiser chamar). A máquina que vai rodar esta aplicação estará, com certeza absoluta, rodando Windows. O que eu vi como solução durante minhas buscas incansáveis no Google e no Java Technology Forums:

:arrow: Uma tal de Servertec Foundation Classes que eu não tenho certeza se vai rolar, pois lá não diz se funciona com FAT32 por exemplo (além de, segundo o pessoal do Technology Forums, ser pago).
:arrow: Uma porcalhada que seria abrir o cmd.exe, chamar vol e depois capturar a saída (cara, isso é muito feio!)
:arrow: Me virar e criar minha própria dll pra chamá-la via JNI
:arrow: Um bando de gente dizendo pra eu esquecer o serial numer e usar mac.

Problemas: não sei muito de C e nunca escrevi nada pra JNI. Não quero usar cmd.exe, isso é muito porco. Não posso usar mac, além um zilhão de problemas que foram apontados por um zilhão de pessoas na internet toda, falando mal de usar essa solução, eu não posso usar porque o chefe quer o serial.

Eu preciso: de uma outra API pra me ajudar, code samples e/ou uma solução mágica… É só pra Windows mesmo, não se importem com portabilidade extra-Windows… Funcionando no 98 e na família NT (ou seja, tudo quanto é Windows que foi lançado depois do 3.11 :wink: ) tá ótimo.

Ola

[quote=“martui”]
:arrow: Uma porcalhada que seria abrir o cmd.exe, chamar vol e depois capturar a saída [/quote]

Cara, isso NÃO é feio, é a única maneira que vc sabe. E funciona direitinho. O que vc quer: solução ou elegância?

Esquece isto se você não sabe C.

Qual o seu problema? MAC identifica univocamente a placa de rede e o número serial do HD não é um identificador único. Qual deles realmente precisa?

Escreva o código que sabe fazer pegando as informações da linha de comando, considerando as várias versões do Windows e as diversas línguas onde ele vai rodar. No futuro, depois de conhecer C e JNI, vai poder usar coisas melhores.

[]s
Luca

:scrambleup: É claro que, em primeiro lugar, o objetivo é funcionalidade, mas o que eu andava a procurar com a elegância era facilidade de manutenção (e não ter que cuidar, manualmente, das várias línguas que podem ser usadas com o Windows) e quem sabe, uma solução menos trabalhosa…

Meu problema 1 com o MAC é que, segundo um mooooooooooooooooooooooooooooooo…ooooooooooonte de gente ele é um dado não-acessível em todas as máquinas (muitas vezes citado o caso de máquinas da IBM). O problema 2 é que não fui eu que defini o que deve ser usado… Eu só tenho é que fazer… :cry:

Mas, valeu assim mesmo, velho! :wink:

Este é um programa C++ que mostra o “volume serial number” do disco C:
Na minha máquina o “volume serial number” é CAFE-BABE e este programa imprime “CAFEBABE”.

Para compilar: copie o código abaixo para um arquivo “teste.cpp”, rode o script “vcvars32.bat” (que normalmente está em “\arquivos de programas\microsoft visual studio .net 2003\vc7\bin\vcvars32.bat”), e use o comando “cl teste.cpp”. Estou supondo que você tem o Visual Studio .NET 2003; se tiver alguma outra versão mais velha, é sempre uma batch com esse nome (vcvars32.bat) que você deve rodar.

Modifique isto para JNI (para maiores detalhes, consulte o livro de Sheng Liang que pode ser baixado do site da Sun. Eu tinha um link para esse livro, não sei se ainda funciona: ftp://ftp.javasoft.com/docs/specs/jni.pdf )

[code]#include <windows.h>
#include <stdio.h>

main () {
HANDLE hFile = ::CreateFile (
"C:\",
FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
BY_HANDLE_FILE_INFORMATION fileInformation;
GetFileInformationByHandle(
hFile, &fileInformation);
printf ("%08X\n", fileInformation.dwVolumeSerialNumber);

CloseHandle &#40;hFile&#41;;

}[/code]

[quote=“thingol”] printf &#40;&quot;%08X&quot;, fileInformation.dwVolumeSerialNumber&#41;; &#125;[/quote]

:scrambleup: Que tipo de dados é retornado pela chamada fileInformation.dwVolumeSerialNumber? O número serial é um hexa, né? Qual seria a melhor forma de retornar isso pra Java: jstring ou jint (ou jlong)?

Boa sorte com o JNI!

Na API é definido como um DWORD (ou seja, um inteiro sem sinal de 32 bits). O jeito mais simples é retornar um jint (que é um inteiro com sinal de 32 bits) e converter o dado em Java mesmo. Só para você ter uma idéia (o programa abaixo deve imprimir “CAFE-BABE”):

[code]class Test112 {

static int minhaFalsaInformacaoDeVolume&#40;&#41; &#123;
    return 0xCAFEBABE;
&#125;

static String informacaoDeVolumeFormatada &#40;int dwVolumeSerialNumber&#41; &#123;
    String s = Long.toHexString &#40;&#40;minhaFalsaInformacaoDeVolume&#40;&#41; & 0xFFFFFFFFL&#41;|0x100000000L&#41;.substring&#40;1,9&#41;.toUpperCase&#40;&#41;;
    return s.substring&#40;0, 4&#41; + &quot;-&quot; + s.substring&#40;4, 8&#41;;
&#125;

public static void main&#40;String&#91;&#93; args&#41; &#123;
    System.out.println &#40;informacaoDeVolumeFormatada&#40;minhaFalsaInformacaoDeVolume&#40;&#41;&#41;&#41;;
&#125;

}[/code]

:scrambleup: Mas, que tipo de retorno eu devo definir para o método? Assim, ó: se o método Java declarado native retornar int, o método nativo deve retornar um jint (certo?). Por isso, eu tenho que, no código C, transformar esse hexa em alguma coisa que seja um jobject (nem que essa alguma coisa seja uma jstring), só pra que eu possa voltar algo compreensível para meu código Java. Como eu faria algo assim com esse DWORD? Eu não entendo muita coisa de C, por isso a pergunta.

:scrambleup: Realmente, eu vou precisar… Ah! O o link do livro que você recomendou ainda está funcionando sim!

Só mais uma chance :wink:

Digamos que você escreva uma classe Java exatamente assim:

package martui.utils;
public class InfoVolume &#123;
    public static native int getInfoVolume &#40;char drive&#41;;
&#125;

Por exemplo, InfoVolume.getInfoVolume(‘C’) retornaria para você 0xCAFEBABE, que você, com minha rotina, iria transformar para “CAFE-BABE” por exemplo.

Vamos compilar esse carinha, e rodar o JAVAH:

javac martuiutilsInfoVolume.java javah -d . -classpath . martui.utils.InfoVolume

Ele gerou um arquivo martui_utils_InfoVolume.h.

Ele vai criar o seguinte protótipo:

[code]/*

  • Class: martui_utils_InfoVolume
  • Method: getInfoVolume
  • Signature: (C)I
    */
    JNIEXPORT jint JNICALL Java_martui_utils_InfoVolume_getInfoVolume
    (JNIEnv *, jclass, jchar);[/code]

Então você vai criar uma função em C em um arquivo .C:

JNIEXPORT jint JNICALL Java_martui_utils_InfoVolume_getInfoVolume &#40;JNIEnv * env, jclass klass, jchar drive&#41; &#123; ... aqui, se não me engano, já escrevi uns 87% do código para você ... ... só se lembrar que jchar é o equivalente de um wchar_t em C, mas ... para o que você pretende fazer, é só fazer um cast ... para char &#40;ou seja, &#40;char&#41; drive&#41; e tudo está bem. &#125;

e vai retornar nesse jint o valor do dwAlgumaCoisa, nem lembro mais o nome da variável. Para o compilador não reclamar é só fazer

… return (jint) …dw…;

Não precisa retornar um jobject, jstring ou sei lá o que. Isso só complica as coisas para você. Retorne um int mesmo, que é mais fácil fazer as coisas em Java que em C (e já fiz, na verdade. )

Os detalhes sangrentos (como usar o compilador C, qual é a linha de comando e outras coisas) acho que dá para encontrar na Internet. Só uma dica - se for possível, use o compilador C do Microsoft Visual Studio 6.0 ou .NET 2003, e use a seguinte linha de comando:

  • Para setar as variáveis de ambiente:
    \Program Files\Microsoft Visual Studio .NET 2003\vc7\bin\vcvars32
    ou
    \Program Files\Microsoft Visual Studio\vc98\bin\vcvars32

  • Para rodar o compilador (obviamente meu JDK está instalado em j2sdk1.4.2_04, mude o nome do diretório conforme sua instalação…)

C> cl -MT -LD -I\j2sdk1.4.2_04\include -I\j2sdk1.4.2_04\include\win32 martui_utils_InfoVolume.c /link /libpath:\j2sdk1.4.2_04\lib /out:infovolume.dll

onde o arquivo de saída é “infovolume.dll”, supondo-se que seu arquivo .c seja chamado martui_utils_InfoVolume.c

Fiquei com preguiça de editar o tópico anterior inteiro, só vou então editar o seguinte:

javac martui\utils\InfoVolume.java javah -d . -classpath . martui.utils.InfoVolume

Este fórum fica achando que todos os backspaces são escapes…

:scrambleup: Aaahh, boooom… :o Beleza!! Agora sim! Vou seguir os passos que você disse pra seguir! E, logo depois eu mato :snipersmile:, destruo :2gunfire:, explodo :microwave:, extermino :robot:, acabo com a raça :evilbat: desse compilador C… :lol: Valeu! Qualquer coisa, eu volto a te encher!

:scrambleup: Ah! Sem essa de .NET… Minha máquina é limpinha… Vou usar o Visual C++ Toolkit 2003… Dá no mesmo, certo?

[quote=“thingol”]#include &lt;windows.h&gt; #include &lt;stdio.h&gt;[/quote]
:scrambleup: Onde eu acho windows.h? Ela não está em lugar nenhum! DROGA! ODEIO C! (não tanto quanto Assembly ou .NET, é verdade). Olha só:

[quote=“Saída do sistema”]fatal error C1083: Cannot
open include file: ‘windows.h’: No such file or directory[/quote]

Você está falando daquele compilador “gratuito” que pode ser baixado do site da Microsoft? Se for esse “gratuito”, parece que você tem só as coisas que eles deixam disponíveis “de graça”. Então você precisa montar as coisas aos poucos. Por exemplo, não sei se tem o <windows.h> lá nesse compilador.
Então você precisa baixar o Platform SDK (dica: é um monstro, se algum colega tiver em CD, dá quase um CD inteiro, e esse CD faz parte daquelas remessas do MSDN, não do Technet) que tem os arquivos windows.h, winbase.h, user32.lib, gdi32.lib e outras coisas .h e .lib que você precisa para esse programinha de 10 linhas funcionar.
Dica: vê se você tem um colega que tem o Visual Studio completo, “alugue” ele por um dia ou dois, faça o seu programa, e não se preocupe mais com essas coisas.
Dica 2: nunca nunca trabalhei em C++ no Windows com o GCC. Nem sei se o GCC consegue gerar DLLs JNI.
Dica 3: Parece que teve gente que conseguiu usar aquele compilador grátis da Borland, mas como eu te disse, não sei se ele vem com o <windows.h> e outras coisas que só podem ser obtidas com o compilador da Microsoft, ou licenciadas da Microsoft (como é o caso do compilador pago da Borland), ou baixadas com o Platform SDK.

:scrambleup: Não, não tem… Baixei o Dev C++ e compilei dentro dele. Não testei ainda com JNI… Não deu tempo… Depois conto o resultado…

:scrambleup: Funcionou! Beleza! Valeu, señor!

:arrow: Usei o Dev-C++ 5.0 beta 9 (4.9.9.0) with Mingw/GCC 3.3.1

Parabéns!