| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef NtEventLogAppender_h |
| #define NtEventLogAppender_h |
| |
| #ifdef __GNUC__ |
| typedef long long __int64; |
| #endif |
| |
| #include "org_apache_log4j_Priority.h" |
| #include "org_apache_log4j_nt_NTEventLogAppender.h" |
| #include <windows.h> |
| #include <jni.h> |
| |
| |
| HINSTANCE gModule = 0; |
| |
| class EventSourceMap { |
| #if _WIN64 |
| enum { MAX_SOURCES = 256 }; |
| HANDLE* sources; |
| public: |
| EventSourceMap() { |
| sources = (HANDLE*) calloc(MAX_SOURCES, sizeof(*sources)); |
| } |
| |
| ~EventSourceMap() { |
| free(sources); |
| } |
| |
| jint createKey(HANDLE handle) { |
| if (handle != 0) { |
| // |
| // find first available null entry (excluding sources[0]) |
| // |
| for(int i = 1; i < MAX_SOURCES; i++) { |
| if (InterlockedCompareExchangePointer(sources + i, handle, 0) == 0) { |
| return i; |
| } |
| } |
| } |
| return 0; |
| } |
| |
| HANDLE getHandle(jint key) { |
| if (key >= 1 && key < MAX_SOURCES) { |
| return sources[key]; |
| } |
| return 0; |
| } |
| |
| HANDLE releaseHandle(jint key) { |
| if (key >= 1 && key < MAX_SOURCES) { |
| return InterlockedExchangePointer(sources + key, 0); |
| } |
| return 0; |
| } |
| #else |
| public: |
| EventSourceMap() { |
| } |
| |
| jint createKey(HANDLE handle) { |
| return (jint) handle; |
| } |
| |
| HANDLE getHandle(jint key) { |
| return (HANDLE) key; |
| } |
| |
| HANDLE releaseHandle(jint key) { |
| return (HANDLE) key; |
| } |
| #endif |
| } gEventSources; |
| |
| /* |
| * Convert log4j Priority to an EventLog category. Each category is |
| * backed by a message resource so that proper category names will |
| * be displayed in the NT Event Viewer. |
| */ |
| WORD getCategory(jint priority) { |
| WORD category = 1; |
| if (priority >= org_apache_log4j_Priority_DEBUG_INT) { |
| category = 2; |
| if (priority >= org_apache_log4j_Priority_INFO_INT) { |
| category = 3; |
| if (priority >= org_apache_log4j_Priority_WARN_INT) { |
| category = 4; |
| if (priority >= org_apache_log4j_Priority_ERROR_INT) { |
| category = 5; |
| if (priority >= org_apache_log4j_Priority_FATAL_INT) { |
| category = 6; |
| } |
| } |
| } |
| } |
| } |
| return category; |
| } |
| |
| /* |
| * Convert log4j Priority to an EventLog type. The log4j package |
| * supports 8 defined priorites, but the NT EventLog only knows |
| * 3 event types of interest to us: ERROR, WARNING, and INFO. |
| */ |
| WORD getType(jint priority) { |
| WORD type = EVENTLOG_SUCCESS; |
| if (priority >= org_apache_log4j_Priority_INFO_INT) { |
| type = EVENTLOG_INFORMATION_TYPE; |
| if (priority >= org_apache_log4j_Priority_WARN_INT) { |
| type = EVENTLOG_WARNING_TYPE; |
| if (priority >= org_apache_log4j_Priority_ERROR_INT) { |
| type = EVENTLOG_ERROR_TYPE; |
| } |
| } |
| } |
| return type; |
| } |
| |
| HKEY regGetKey(wchar_t *subkey, DWORD *disposition) { |
| HKEY hkey = 0; |
| RegCreateKeyExW(HKEY_LOCAL_MACHINE, subkey, 0, NULL, |
| REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, |
| &hkey, disposition); |
| return hkey; |
| } |
| |
| void regSetString(HKEY hkey, wchar_t *name, wchar_t *value) { |
| RegSetValueExW(hkey, name, 0, REG_EXPAND_SZ, |
| (LPBYTE)value, (wcslen(value) + 1) * sizeof(wchar_t)); |
| } |
| |
| void regSetDword(HKEY hkey, wchar_t *name, DWORD value) { |
| RegSetValueExW(hkey, name, 0, REG_DWORD, (LPBYTE)&value, sizeof(DWORD)); |
| } |
| |
| /* |
| * Add this source with appropriate configuration keys to the registry. |
| */ |
| void addRegistryInfo(wchar_t *source) { |
| const wchar_t *prefix = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\"; |
| DWORD disposition; |
| HKEY hkey = 0; |
| wchar_t subkey[256]; |
| |
| wcscpy(subkey, prefix); |
| wcscat(subkey, source); |
| hkey = regGetKey(subkey, &disposition); |
| if (disposition == REG_CREATED_NEW_KEY) { |
| HMODULE hmodule = gModule; |
| if (hmodule == NULL) { |
| hmodule = GetModuleHandleW(L"NTEventLogAppender.dll"); |
| } |
| if (hmodule != NULL) { |
| wchar_t modpath[_MAX_PATH]; |
| DWORD modlen = GetModuleFileNameW(hmodule, modpath, _MAX_PATH - 1); |
| if (modlen > 0) { |
| modpath[modlen] = 0; |
| regSetString(hkey, L"EventMessageFile", modpath); |
| regSetString(hkey, L"CategoryMessageFile", modpath); |
| } |
| } |
| regSetDword(hkey, L"TypesSupported", (DWORD)7); |
| regSetDword(hkey, L"CategoryCount", (DWORD) 6); |
| } |
| RegCloseKey(hkey); |
| return; |
| } |
| |
| /* |
| * Class: org.apache.log4j.nt.NTEventLogAppender |
| * Method: registerEventSource |
| * Signature: (Ljava/lang/String;Ljava/lang/String;)I |
| */ |
| JNIEXPORT jint JNICALL Java_org_apache_log4j_nt_NTEventLogAppender_registerEventSource( |
| JNIEnv *env, jobject java_this, jstring server, jstring source) { |
| |
| jchar *nserver = 0; |
| jchar *nsource = 0; |
| |
| if (server != 0) { |
| jsize serverLen = env->GetStringLength(server); |
| nserver = (jchar*) malloc((serverLen +1) * sizeof(jchar)); |
| env->GetStringRegion(server, 0, serverLen, nserver); |
| nserver[serverLen] = 0; |
| } |
| if (source != 0) { |
| jsize sourceLen = env->GetStringLength(source); |
| nsource = (jchar*) malloc((sourceLen +1) * sizeof(jchar)); |
| env->GetStringRegion(source, 0, sourceLen, nsource); |
| nsource[sourceLen] = 0; |
| } |
| addRegistryInfo((wchar_t*) nsource); |
| jint handle = gEventSources.createKey(RegisterEventSourceW( |
| (const wchar_t*) nserver, (const wchar_t*) nsource)); |
| free(nserver); |
| free(nsource); |
| return handle; |
| } |
| |
| /* |
| * Class: org_apache_log4j_nt_NTEventLogAppender |
| * Method: reportEvent |
| * Signature: (ILjava/lang/String;I)V |
| */ |
| JNIEXPORT void JNICALL Java_org_apache_log4j_nt_NTEventLogAppender_reportEvent( |
| JNIEnv *env, jobject java_this, jint jhandle, jstring jstr, jint priority) { |
| jboolean localHandle = JNI_FALSE; |
| HANDLE handle = gEventSources.getHandle(jhandle); |
| if (handle == 0) { |
| // Client didn't give us a handle so make a local one. |
| handle = RegisterEventSourceW(NULL, L"Log4j"); |
| localHandle = JNI_TRUE; |
| } |
| |
| // convert Java String to character array |
| jsize msgLen = env->GetStringLength(jstr); |
| jchar* msg = (jchar*) malloc((msgLen + 1) * sizeof(jchar)); |
| env->GetStringRegion(jstr, 0, msgLen, msg); |
| msg[msgLen] = 0; |
| |
| // This is the only message supported by the package. It is backed by |
| // a message resource which consists of just '%1' which is replaced |
| // by the string we just created. |
| const DWORD messageID = 0x1000; |
| ReportEventW(handle, getType(priority), |
| getCategory(priority), |
| messageID, NULL, 1, 0, (const wchar_t**) &msg, NULL); |
| |
| free((void *)msg); |
| if (localHandle == JNI_TRUE) { |
| // Created the handle here so free it here too. |
| DeregisterEventSource(handle); |
| } |
| return; |
| } |
| |
| /* |
| * Class: org_apache_log4j_nt_NTEventLogAppender |
| * Method: deregisterEventSource |
| * Signature: (I)V |
| */ |
| JNIEXPORT void JNICALL Java_org_apache_log4j_nt_NTEventLogAppender_deregisterEventSource( |
| JNIEnv *env, |
| jobject java_this, |
| jint handle) |
| { |
| |
| DeregisterEventSource(gEventSources.releaseHandle(handle)); |
| } |
| |
| |
| // |
| // Entry point which registers default event source (Log4j) |
| // when invoked using regsvr32 tool. |
| // |
| // |
| extern "C" { |
| __declspec(dllexport) HRESULT __stdcall DllRegisterServer(void) { |
| HRESULT hr = E_FAIL; |
| HMODULE hmodule = gModule; |
| if (hmodule == NULL) { |
| hmodule = GetModuleHandleW(L"NTEventLogAppender.dll"); |
| } |
| if (hmodule != NULL) { |
| wchar_t modpath[_MAX_PATH]; |
| DWORD modlen = GetModuleFileNameW(hmodule, modpath, _MAX_PATH - 1); |
| if (modlen > 0) { |
| modpath[modlen] = 0; |
| const wchar_t key[] = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\Log4j"; |
| DWORD disposition; |
| HKEY hkey = 0; |
| |
| LONG stat = RegCreateKeyExW(HKEY_LOCAL_MACHINE, key, 0, NULL, |
| REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, |
| &hkey, &disposition); |
| if (stat == ERROR_SUCCESS) { |
| stat = RegSetValueExW(hkey, L"EventMessageFile", 0, REG_EXPAND_SZ, |
| (LPBYTE) modpath, (wcslen(modpath) + 1) * sizeof(wchar_t)); |
| if(stat == ERROR_SUCCESS) { |
| stat = RegSetValueExW(hkey, L"CategoryMessageFile", 0, REG_EXPAND_SZ, |
| (LPBYTE) modpath, (wcslen(modpath) + 1) * sizeof(wchar_t)); |
| } |
| if(stat == ERROR_SUCCESS) { |
| DWORD value = 7; |
| stat = RegSetValueExW(hkey, L"TypesSupported", 0, REG_DWORD, (LPBYTE)&value, sizeof(DWORD)); |
| } |
| if(stat == ERROR_SUCCESS) { |
| DWORD value = 6; |
| stat = RegSetValueExW(hkey, L"CategoryCount", 0, REG_DWORD, (LPBYTE)&value, sizeof(DWORD)); |
| } |
| LONG closeStat = RegCloseKey(hkey); |
| if (stat == ERROR_SUCCESS && closeStat == ERROR_SUCCESS) { |
| hr = S_OK; |
| } |
| } |
| } |
| } |
| return hr; |
| } |
| |
| |
| // |
| // Entry point which unregisters default event source (Log4j) |
| // when invoked using regsvr32 tool with /u option. |
| // |
| // |
| __declspec(dllexport) HRESULT __stdcall DllUnregisterServer(void) { |
| LONG stat = RegDeleteKeyW(HKEY_LOCAL_MACHINE, |
| L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\Log4j"); |
| return (stat == ERROR_SUCCESS || stat == ERROR_FILE_NOT_FOUND) ? S_OK : E_FAIL; |
| } |
| |
| BOOL APIENTRY DllMain( HMODULE hModule, |
| DWORD ul_reason_for_call, |
| LPVOID lpReserved |
| ) |
| { |
| switch (ul_reason_for_call) |
| { |
| case DLL_PROCESS_ATTACH: |
| gModule = hModule; |
| break; |
| case DLL_PROCESS_DETACH: |
| gModule = 0; |
| break; |
| |
| case DLL_THREAD_ATTACH: |
| case DLL_THREAD_DETACH: |
| break; |
| } |
| return TRUE; |
| } |
| |
| } |
| #endif |