JNI para Aumentar o som do Windows vista/7

5 respostas
MarcosOLIVEIRA

Pessoal estou trabalhndo montando um dll que é acessada atraves de JNI para modificar o volume do windows pra isso montei primeiramente um executavel apartir de um exemplo do msdn que funcionou blz consegui aumentar baixar e “mutar” o volume do win.

Quando adptei a minha dll para adicionar as assinaturas do JNI e acessar atraves de uma pequena main apareceram os erros.

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
//

//
// EndpointVolumeChanger.cpp : Endpoint Volume Changing sample application.
//

#include "stdafx.h"
#include "volumeJNI.h"
#include <functiondiscoverykeys.h>
#include "EndpointVolume.h"


bool ShowHelp;
bool UseConsoleDevice;
bool UseCommunicationsDevice;
bool UseMultimediaDevice;
bool VolumeUp;
bool VolumeDown;
bool ToggleMute;
int VolumeValue = -1;
bool isDefaultDevice;
IAudioEndpointVolume *endpointVolume;
int result = 0;
wchar_t *OutputEndpoint;


LPWSTR GetDeviceName(IMMDeviceCollection *DeviceCollection, UINT DeviceIndex)
{
    IMMDevice *device;
    LPWSTR deviceId;
    HRESULT hr;

    hr = DeviceCollection->Item(DeviceIndex, &device);
    if (FAILED(hr))
    {
        printf("Unable to get device %d: %x\n", DeviceIndex, hr);
        return NULL;
    }
    hr = device->GetId(&deviceId);
    if (FAILED(hr))
    {
        printf("Unable to get device %d id: %x\n", DeviceIndex, hr);
        return NULL;
    }

    IPropertyStore *propertyStore;
    hr = device->OpenPropertyStore(STGM_READ, &propertyStore);
    SafeRelease(&device);
    if (FAILED(hr))
    {
        printf("Unable to open device %d property store: %x\n", DeviceIndex, hr);
        return NULL;
    }

    PROPVARIANT friendlyName;
    PropVariantInit(&friendlyName);
    hr = propertyStore->GetValue(PKEY_Device_FriendlyName, &friendlyName);
    SafeRelease(&propertyStore);

    if (FAILED(hr))
    {
        printf("Unable to retrieve friendly name for device %d : %x\n", DeviceIndex, hr);
        return NULL;
    }

    wchar_t deviceName[128];
    hr = StringCbPrintf(deviceName, sizeof(deviceName), L"%s (%s)", friendlyName.vt != VT_LPWSTR ? L"Unknown" : friendlyName.pwszVal, deviceId);
    if (FAILED(hr))
    {
        printf("Unable to format friendly name for device %d : %x\n", DeviceIndex, hr);
        return NULL;
    }

    PropVariantClear(&friendlyName);
    CoTaskMemFree(deviceId);

    wchar_t *returnValue = _wcsdup(deviceName);
    if (returnValue == NULL)
    {
        printf("Unable to allocate buffer for return\n");
        return NULL;
    }
    return returnValue;
}
bool PickDevice(IMMDevice **DeviceToUse, bool *IsDefaultDevice, ERole *DefaultDeviceRole)
{
    HRESULT hr;
    bool retValue = true;
    IMMDeviceEnumerator *deviceEnumerator = NULL;
    IMMDeviceCollection *deviceCollection = NULL;

    *IsDefaultDevice = false;   // Assume we're not using the default device.

    hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&deviceEnumerator));
    if (FAILED(hr))
    {
        printf("Unable to instantiate device enumerator: %x\n", hr);
        retValue = false;
        goto Exit;
    }

    IMMDevice *device = NULL;

    //
    //  First off, if none of the console switches was specified, use the console device.
    //
    if (!UseConsoleDevice && !UseCommunicationsDevice && !UseMultimediaDevice && OutputEndpoint == NULL)
    {
        //
        //  The user didn't specify an output device, prompt the user for a device and use that.
        //
        hr = deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &deviceCollection);
        if (FAILED(hr))
        {
            printf("Unable to retrieve device collection: %x\n", hr);
            retValue = false;
            goto Exit;
        }

      //  printf("Select an output device:\n");
      //  printf("    0:  Default Console Device\n");
      //  printf("    1:  Default Communications Device\n");
      //  printf("    2:  Default Multimedia Device\n");
        UINT deviceCount;
        hr = deviceCollection->GetCount(&deviceCount);
        if (FAILED(hr))
        {
            printf("Unable to get device collection length: %x\n", hr);
            retValue = false;
            goto Exit;
        }
        for (UINT i = 0 ; i < deviceCount ; i += 1)
        {
            LPWSTR deviceName;

            deviceName = GetDeviceName(deviceCollection, i);
            if (deviceName == NULL)
            {
                retValue = false;
                goto Exit;
            }
            printf("    %d:  %S\n", i + 3, deviceName);
            free(deviceName);
        }
        wchar_t choice[10];
       // _getws_s(choice);   // Note: Using the safe CRT version of _getws.

        long deviceIndex;
        wchar_t *endPointer;

        deviceIndex = 0;//= wcstoul(choice, &endPointer, 0);
        if (deviceIndex == 0 && endPointer == choice)
        {
            printf("unrecognized device index: %S\n", choice);
            retValue = false;
            goto Exit;
        }
        switch (deviceIndex)
        {
        case 0:
            UseConsoleDevice = 1;
            break;
        case 1:
            UseCommunicationsDevice = 1;
            break;
        case 2:
            UseMultimediaDevice = 1;
            break;
        default:
            hr = deviceCollection->Item(deviceIndex - 3, &device);
            if (FAILED(hr))
            {
                printf("Unable to retrieve device %d: %x\n", deviceIndex - 3, hr);
                retValue = false;
                goto Exit;
            }
            break;
        }
    } 
    else if (OutputEndpoint != NULL)
    {
        hr = deviceEnumerator->GetDevice(OutputEndpoint, &device);
        if (FAILED(hr))
        {
            printf("Unable to get endpoint for endpoint %S: %x\n", OutputEndpoint, hr);
            retValue = false;
            goto Exit;
        }
    }

    if (device == NULL)
    {
        ERole deviceRole = eConsole;    // Assume we're using the console role.
        if (UseConsoleDevice)
        {
            deviceRole = eConsole;
        }
        else if (UseCommunicationsDevice)
        {
            deviceRole = eCommunications;
        }
        else if (UseMultimediaDevice)
        {
            deviceRole = eMultimedia;
        }
        hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, deviceRole, &device);
        if (FAILED(hr))
        {
            printf("Unable to get default device for role %d: %x\n", deviceRole, hr);
            retValue = false;
            goto Exit;
        }
        *IsDefaultDevice = true;
        *DefaultDeviceRole = deviceRole;
    }

    *DeviceToUse = device;
    retValue = true;
Exit:
    SafeRelease(&deviceCollection);
    SafeRelease(&deviceEnumerator);
	return retValue;
}


 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
 {
	 
	int result = 0;

	bool isDefaultDevice;
   
    IMMDevice *device = NULL;
    
    ERole role;

    HRESULT hr;

    IMMDeviceEnumerator *deviceEnumerator = NULL;
	

	hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if (FAILED(hr))
    {
        printf("Unable to initialize COM: %x\n", hr);
        result = hr;
    }
	    
	if (!PickDevice(&device, &isDefaultDevice, &role))
    {
		printf("no pickdevice \n");
        result = -1;
    }

   
	
   	
    hr = device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&endpointVolume));
    
	if (FAILED(hr))
    {
        printf("Unable to activate endpoint volume on output device: %x\n", hr);
        result = -1;
		printf("1 if ");
        goto Exit;
		
    }//Apartir daqui começa a escolher as funções para 

		
		
		printf(" 7");
        BOOL currentMute;
		printf(" 8");
        hr = endpointVolume->GetMute(&currentMute);
		printf(" 9");
        if (FAILED(hr))
        {
			printf(" 10");
            printf("Unable to retrieve current mute state: %x\n", hr);
			printf(" 11");
            result = -1;
			printf(" 12");
           // goto Exit;
        }

        //
        //  Since we're not reacting to volume changes, we don't care about the event context.
        //
		printf(" 13");
        hr = endpointVolume->SetMute(currentMute ? FALSE : TRUE, NULL);
       printf(" 14");



	UINT currentStep, stepCount;
    hr = endpointVolume->GetVolumeStepInfo(&currentStep, &stepCount);
    if (FAILED(hr))
    {
        printf("Unable to get current volume step: %x\n", hr);
        result = -1;
		printf(" 2 if ");
        goto Exit;

    }

    float currentVolume;
    hr = endpointVolume->GetMasterVolumeLevelScalar(&currentVolume);
    if (FAILED(hr))
    {
        printf("Unable to get current volume step: %x\n", hr);
        result = -1;
		printf(" 3 if ");
        goto Exit;
    }

   
    hr = endpointVolume->GetMute(&currentMute);
    if (FAILED(hr))
    {
        printf("Unable to get current volume step: %x\n", hr);
        result = -1;
		printf(" 4 if ");
        goto Exit;
    }
	
    printf("Current master volume: %f.   Step %d of step range 0-%d.\nEndpoint Mute: %S\n", currentVolume, currentStep, stepCount, currentMute ? L"Muted" : L"Unmuted");
	
Exit:
	return 0;
}

JNIEXPORT void JNICALL Java_VolumeJNI_volumeUp
(JNIEnv *, jobject){
	HRESULT hr;
        hr = endpointVolume->VolumeStepUp(NULL);
        if (FAILED(hr))
        {
            printf("Unable to increase volume: %x\n", hr);
            result = -1;
            //goto Exit;
        }
        if (hr == S_FALSE)
        {
            printf("Volume is already at the maximum\n");
        }
  
}

JNIEXPORT void JNICALL Java_VolumeJNI_volumeDown
(JNIEnv *, jobject){
HRESULT hr;
 
        //
        //  Since we're not reacting to volume changes, we don't care about the event context.
        //
        hr = endpointVolume->VolumeStepDown(NULL);
        if (FAILED(hr))
        {
            printf("Unable to decrease volume: %x\n", hr);
            result = -1;
           // goto Exit;
        }
        if (hr == S_FALSE)
        {
            printf("Volume is already at the minimum\n");
        }
    


}

JNIEXPORT void JNICALL Java_VolumeJNI_toggleMute
(JNIEnv *, jobject){
	
		printf(" 6");
		HRESULT hr;
		printf(" 7");
        BOOL currentMute;
		printf(" 8");
        hr = endpointVolume->GetMute(&currentMute);
		printf(" 9");
        if (FAILED(hr))
        {
			printf(" 10");
            printf("Unable to retrieve current mute state: %x\n", hr);
			printf(" 11");
            result = -1;
			printf(" 12");
           // goto Exit;
        }

        //
        //  Since we're not reacting to volume changes, we don't care about the event context.
        //
		printf(" 13");
        hr = endpointVolume->SetMute(currentMute ? FALSE : TRUE, NULL);
       printf(" 14");
		
}

ERRO:

3:  Alto-falantes (SoundMAX Integrated Digital High Definition Audio) ({0.0.0.00000000}.{78b90aea-7be4-4276-ac0e-7700c8fda986})
 7 8 9 13 14Current master volume: 0.520000.   Step 26 of step range 0-51.
Endpoint Mute: Unmuted
ERRROOO /n 7 8 9 13 14Current master volume: 0.520000.   Step 26 of step range 0-51.
Endpoint Mute: Muted
ERRROOO /njava.lang.UnsatisfiedLinkError: C:\Users\0810850\Desktop\dlls\VolumeJNI.dll: Uma rotina de inicialização da biblioteca de vínculo dinâmico (DLL) falhou
	at java.lang.ClassLoader$NativeLibrary.load(Native Method)
	at java.lang.ClassLoader.loadLibrary0(Unknown Source)
	at java.lang.ClassLoader.loadLibrary(Unknown Source)
	at java.lang.Runtime.loadLibrary0(Unknown Source)
	at java.lang.System.loadLibrary(Unknown Source)
	at VolumeJNI.<clinit>(VolumeJNI.java:8)

Como nao e possivel debuggar a dll coloquei varios printf para saber onde o codigo quebrava. alguem Podeira me ajudar??

5 Respostas

MarcosOLIVEIRA

Quando chamo o loadLibrary ele chama a main da minha dll, ate ai blz isso ta certo mas ele quebra justamente quando a main da DLL retorna. Como faço se preciso instancia valores quando vou usa minha dll??? alguem???

B

Dica: não use DLLMain. Se possível, crie mais um método estático na sua classe JNI que você tenha de chamar obrigatoriamente.

Se não me engano, DLLMain é uma coisa que pode dar problemas com DLLs JNI. (Você pode declarar uma DLLMain que não faça nada).

Outra coisa: acho que não é bom usar printf - se não me engano, usar funções da biblioteca-padrão do C pode dar alguns problemas de conflito com a biblioteca-padrão do C usada pela própria JVM. No seu caso, use OutputDebugString e wsprintf. O problema, obviamente, é que OutputDebugString não joga na saída padrão e sim em um lugar que só dá para observer usando um programa como o WinDbg ou o DebugView.

http://msdn.microsoft.com/en-us/library/aa363362(v=vs.85).aspx

MarcosOLIVEIRA

Foi isso mesmo deu certo!!!

Tirei a DLLmain e coloquei um metodo iniciar que chamo sempre antes de chamar minha rotinas e pronto funcionou beleza!

Obrigado bezier

MarcosOLIVEIRA

Cara agora estou com outro problema. Quando estava desenvolvendo a JNI para aumentar o volume criei um projeto a parte chamado “Teste”, agora estou tentando integrar minha dll ao meu projeto real mas esta dando um erro que resolvi facil no projeto anteirior

Exception in thread "main" java.lang.UnsatisfiedLinkError: br.com.tecnometal.mbi.jni.VolumeJNI.iniciar()V
	at br.com.tecnometal.mbi.jni.VolumeJNI.iniciar(Native Method)
	at br.com.tecnometal.mbi.jni.VolumeJNI.main(VolumeJNI.java:52)

Acho que pode ter algo a ver com o path e a organização dos pacotes da minha aplicação real. alguem sabe como resolver isso??

desde ja agradeço

MarcosOLIVEIRA

Resolvido!

os metodos na minha dll devem ter o caminho completo das classes java tipo:

JNIEXPORT void JNICALL Java_br_com_tecnometal_mbi_jni_VolumeJNI_iniciar
  (JNIEnv *, jobject);

diferente de como estava antes:

JNIEXPORT void JNICALL Java_VolumeJNI_iniciar
  (JNIEnv *, jobject);
Criado 4 de maio de 2011
Ultima resposta 12 de mai. de 2011
Respostas 5
Participantes 2