Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to get shutdown event in windows from java app with jni

0.00/5 (No votes)
15 Sep 2018 2  
get shutdown message in java application with jni

Introduction

In this article i try explain how to get shutdown event from java application with jni in windows os beacuse in many situation application need save essential data before shutdown computer. 

The JNI is designed to handle situations where you need to combine Java
applications with native code. As a two-way interface, the JNI can support two
types of native code: native libraries and native applications.
You can use the JNI to write native methods that allow Java applications tocall functions implemented in native libraries. Java applications call native methods in the same way that they call methods implemented in the Java programming language. Behind the scenes, however, native methods are implemented in another language and reside in native libraries.

Why we need to detect computer shutdown?

Computer shutdown detection is required to complete short, but very important actions, such as:

  • Saving all unsaved data
  • Notify distributed system components via network that the current component will be shut off
  • Add record about the shutdown into the log in order to better analyze the situation

For get shutdown event the application must listen to WM_ENDSESSION.Windows sends a WM_ENDSESSION message to all programs with a Window before shutdown.

GUI applications

GUI application receives information about target events via window messages. We’re interested in the following window messages: WM_QUERYENDSESSION and WM_POWERBROADCAST. The first message (as seen from the title) appears when the process of closing user session is initiated. Shutting computer off as well as restarting it also causes user session to end, thus messages about it are delivered via the same window message. From the second message we can get information about the suspend event. We can get different types of events from wParam and lParam, transferred together with the message. Here is the part of our handler of window messages:

simple program

For do this i create a helloworld code example in java and create c code and make helloworld.dll .

1-Create a java class that declares the native method. a native method invoke our function in dll from java code.

helloworld.java

 

package helloworld;

public class HelloWorld {

    /**
     * @param args the command line arguments
     */
    static{
        try{
           
        System.load("YOUR absoulte PATH/HelloWorld.dll");//PATH TO DLL
        }
        catch(Exception e){
          System.out.println("dll not load");  
        }
    }
    private native void print();
    private static void callback(){
        System.out.println("shutdown Event");
    }
    public static void main(String[] args) {
       new HelloWorld().print();
    }
    
}

2-compile the HelloWorld source file with javac, resulting in the class file HelloWorld.class.

3-Use javah -jni to generate a C header file

HelloWorld.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#ifndef HELLOWORLD_H
#define HELLOWORLD_H

#include <jni.h>
/* Header for class helloworld_HelloWorld */

#ifndef _Included_helloworld_HelloWorld
#define _Included_helloworld_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     helloworld_HelloWorld
 * Method:    print
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_print
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

#endif    // HELLOWORLD_H

 

4-Write the C implementation of the native method.

The function registerWndProc creates the hidden window.

The function WndProc handles received messages.

HelloWorld.cpp

#include "helloworld_HelloWorld.h"
#include <jni.h>
#include <stdio.h>
#include <windows.h>
#include <signal.h>
#include <wtsapi32.h>
#include<istream>

using namespace std;
JNIEnv *cur_env; /* pointer to native method interface */
bool sleep=false;
void registerWndProc();
BOOL WTSRegisterSessionNotification(HWND  hwnd,DWORD dwFlags);
JNIEXPORT void JNICALL Java_helloworld_HelloWorld_print
  (JNIEnv *env, jobject){
    cur_env = env; /* Creates window & enters message loop */
    registerWndProc();
}
void calljvm() {
    JavaVM *jvm;
    cur_env->GetJavaVM(&jvm);
    jint AttachCurrentThread = (*jvm).AttachCurrentThread((void **)(&cur_env),NULL);
    jclass cls=cur_env->FindClass("helloworld/HelloWorld");
    jmethodID mid=cur_env->GetStaticMethodID(cls,"callback","()V");      
    (*cur_env).CallStaticVoidMethod(cls, mid);
    (*jvm).DetachCurrentThread();
} 
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam,LPARAM lParam)
{
    
    switch(msg) {
        case WM_CREATE:
            WTSRegisterSessionNotification( hwnd, NOTIFY_FOR_ALL_SESSIONS ) ;
            break;
        case WM_POWERBROADCAST:
            if (wParam==PBT_APMSUSPEND){/*go to sleep and hibernate*/
                sleep=true;
                MessageBox(NULL, TEXT("sleep"),
           NULL, NULL);//messagebox for example
              calljvm(); //it function can replace with your code
            }
            if(wParam==PBT_APMRESUMESUSPEND){/*wake up*/ 
                MessageBox(NULL,TEXT("wake up"),
           NULL, NULL);//messagebox for example
               calljvm(); //it function can replace with your code
            }
            break;
        case WM_ENDSESSION:/*shut down and log off*/
           MessageBox(NULL,TEXT("shut down"),
           NULL, NULL);
             calljvm(); //it function can replace with your code
        break;    
        case WM_WTSSESSION_CHANGE:
            switch(wParam){
            case WTS_SESSION_LOCK:/*lock the pc*/
                if(sleep==false){
                MessageBox(NULL, TEXT("lock"),
           NULL, NULL);//messagebox for example
                 calljvm(); //it function can replace with your code
                }
            break;
            case WTS_SESSION_UNLOCK:/*unlock the pc*/
                if(sleep==false){
                MessageBox(NULL, TEXT("unlock"),
           NULL, NULL);//messagebox for example
                  calljvm(); //it function can replace with your code
                }
                //it function can replace with your code

                 sleep=false;
            break;
            case WTS_SESSION_LOGON:/*log in to pc*/
                MessageBox(NULL, TEXT("log in"),
           NULL, NULL);//messagebox for example
                calljvm();//it function can replace with your code
            break;
             case WTS_SESSION_LOGOFF :/*log out to pc*/
                MessageBox(NULL, TEXT("log in"),
           NULL, NULL);//messagebox for example
                calljvm();//it function can replace with your code
            break;
            }
            
        default:
        break;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
void registerWndProc() {
    HINSTANCE h2 = GetModuleHandle(NULL); 
    static char szAppName[] = "winhello";
    WNDCLASSEX wndclass;
    wndclass.cbSize = sizeof(wndclass);
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = h2;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = NULL;
    wndclass.lpszClassName = szAppName;
    wndclass.lpszMenuName = NULL; 
    /* Register a new window class with Windows */
    if (!RegisterClassEx(&wndclass)) {
        MessageBox(NULL, TEXT("Registering class failed!"), TEXT("Error!"), MB_ICONEXCLAMATION | MB_OK);
        return;
    } 
    /* Create a window based on our new class */
    HWND hwnd; 
    hwnd = CreateWindow(szAppName, "Hello, world!",
    WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT, CW_USEDEFAULT,
    CW_USEDEFAULT, CW_USEDEFAULT,
    NULL, NULL, h2, NULL); 
    /* CreateWindow failed? */
    if( !hwnd ) {
        MessageBox(NULL, TEXT("Window creation failed!"), TEXT("Error!"), MB_ICONEXCLAMATION | MB_OK);
        return;
    } 
    /* Show and update our window */
    ShowWindow(hwnd, 1); /* 0 = SW_HIDE */
    UpdateWindow(hwnd); 
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0) ) {
        TranslateMessage(&msg); /* for certain keyboard messages */
        DispatchMessage(&msg); /* send message to WndProc */
     }
} 

finaly compile HelloWorld.c and make dll.

note:

Beware that the JDK has a 32-bits and 64-bits version. The dll file must be compiled for the right architecture.

You must add wtsapi32.dll to java library project.

USEFUL RESOURCE:

The Java™ Native Interface Programmer’s Guide and Specification

https://www.itxplain.nl/blog/java-jni-wm_endsession-messages

https://www.apriorit.com/dev-blog/413-win-api-shutdown-events

 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here