Main Page
Cookbook/Overview ImageMeister the jcprops file Licensing Binary Installation & Configuration [ Win · Mac · Nix · OSX ] Changes Public API Source Code Main Page Java [ Common · Win · Mac · Nix ] Native Code [ Common · Win · Mac · Nix ] Manifest Native Code Overviews [ Common · Win · Mac · Nix · Strings ] Macros [ General · Native Macros ] Walkthroughs [ Java only · Java and native ] Building [ Win · Mac · Nix · OSX ] Distribution Issues |
Let's assume that we're running on Windows95 with the SunJDK. This will use the jcnfigSN.dll, and we'll assume that this DLL was compiled with the DO_SEH symbol defined (this indicates that each native method should be surrounded by a SEH frame.)
The sequence of routines which will be called are shown, followed by a description of each step.
public static Monitor getMainMonitor() { Monitor retMon = null; if ( delegate != null ) retMon = delegate.getMainMonitor(); if ( retMon == null ) retMon = new MonitorPlain(); return retMon; } |
If delegate isn't null, it calls the delegate to obtain the user's main monitor. If this return null, or if delegate is null it returns a 'plain' monitor object. This will be initialized using the built-in Java information, which is minimal, and consists only of the width and height of the main monitor.We'll assume that delegate is not null.
` public Monitor getMainMonitor() { return MonitorHelperMSVM.getMainMonitor(); } |
In the current case, the delegate is a 'FileRegistryMSVM' object, which just passes the call to a static method of the 'MonitorHelperMSVM' class.For a description of how the FileRegistryMSVM object was selected as the delegate, see the overview_init.html file.
static Monitor getMainMonitor() { int monitorData[], theErr; monitorData = new int[ AppUtilsMSVM.kMonitorInfoNumInts ]; theErr = AppUtilsMSVM.getMainMonitorInfo( monitorData ); if ( theErr != ErrCodes.kNoErr ) return null; return new MonitorMSVM( monitorData, 0, AppUtilsMSVM.kMonitorInfoNumInts ); } |
The 'MonitorHelperMSVM.getMainMonitor()' method creates an int array, and passes it to a native method. The native method will fill out this int array with information on the main monitor. For instance, the top of the main monitor will be placed at offset 0 of the int array, the left of the monitor at offset 1, etc. Which data is stored where is defined by the 'kOffs...' constants in the 'MonitorMSVM' class.Creation of the 'MonitorMSVM' object will be described below.
static int getMainMonitorInfo( int monitorInfo[] ) { return nativeGetMainMonitorInfo( monitorInfo ); } private static native int nativeGetMainMonitorInfo( int monitorInfo[] ); |
'MonitorHelperMSVM' calls 'AppUtilsMSVM.getMainMonitorInfo()' with an array of ints. This method is just a wrapper around the native method 'AppUtilsMSVM.nativeGetMainMonitorInfo()'.
SEH_EXP JINT SEH_FUNC( jconfig, AppUtilsMSVM, nativeGetMainMonitorInfo ), JINTARRAY pMonitorInfo ) { SEH_TRY { return CALL_INNER( nativeGetMainMonitorInfo )( INNER_PREFIX, pMonitorInfo ); } SEH_EXCEPT( _TXL( "SEH in nativeGetMainMonitorInfo\n" ) ) } |
Now, we're in native code. This is a stub routine, which installs an SEH frame, and calls the routine 'INNER_nativeGetMainMonitorInfo' (see below.) All native methods follow the same pattern.If we replace the SEH-related macros, this looks like:
JNIEXPORT JINT JNICALL Java_COM_tolstoy_jconfig_win_AppUtilsMSVM_nativeGetMainMonitorInfo( JNIEnv *pEnv, jclass pObj, JINTARRAY pMonitorInfo ) { __try { return INNER_nativeGetMainMonitorInfo( pEnv, pObj, pMonitorInfo ); } __except ( EXCEPTION_EXECUTE_HANDLER ) { Debugger::debug( __LINE__, _TXL( "SEH in nativeGetMainMonitorInfo\n" ) ); return kErrSEH; } } |
'JINT' and 'JINTARRAY' are native macros; see nativemacros.html for more information.
'JNIEXPORT' and 'JNICALL' are defined by JNI.
EXP JINT FUNC( jconfig, AppUtilsMSVM, nativeGetMainMonitorInfo ), JINTARRAY pMonitorInfo ) { long *monitorInfoP, theErr; BEGINTRY { CHECKSIZE( pMonitorInfo, SMonitors::kMonitorInfoNumInts ); monitorInfoP = LOCKINTARRAY( pMonitorInfo ); theErr = SMonitors::iGetMainMonitorInfo( monitorInfoP ); UNLOCKINTARRAY( pMonitorInfo, monitorInfoP ); } ENDTRY bail: return theErr; } |
This routine is called by the previous routine which installed the SEH frame. If we replace the macros in this routine, it looks like:
jint INNER_nativeGetMainMonitorInfo, JNIEnv *pEnv, jclass pObj, jintArray pMonitorInfo ) { long *monitorInfoP, theErr; try { { // this was the CHECKSIZE macro if ( ( (pMonitorInfo) == NULL ) || ( pEnv->GetArrayLength( (pMonitorInfo) ) < (SMonitors::kMonitorInfoNumInts) ) ) { theErr = kErrParamErr; goto bail; } } // this was the LOCKINTARRAY macro monitorInfoP = pEnv->GetIntArrayElements( (pMonitorInfo), 0 ); theErr = SMonitors::iGetMainMonitorInfo( monitorInfoP ); // this was the UNLOCKINTARRAY macro pEnv->ReleaseIntArrayElements( (pMonitorInfo), (monitorInfoP), 0 ); } catch ( const LPCTSTR msg ) { Debugger::debug( __LINE__, _TXL( "got exception" ), msg ); theErr = kException; } bail: return theErr; } |
First, this checks that the parameter is OK. Then, it looks the array of Java ints, and calls a static method in the SMonitors class. If an exception occurs, it prints it out. After returning from SMonitors, it unlocks the Java int array, and returns a error code.
long SMonitors::iGetMainMonitorInfo( long *monitorInfoP ) { HWND hDesk; HDC hDC; RECT rcWorkarea, rcBounds; long theErr, screenWidth, screenHeight, screenDepth; BOOL bRet; theErr = kErrNoErr; bRet = SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWorkarea, 0 ); if ( !bRet ) { theErr = kErrSystemParametersInfo; goto bail; } screenWidth = GetSystemMetrics( SM_CXSCREEN ); screenHeight = GetSystemMetrics( SM_CYSCREEN ); SetRect( &rcBounds, 0, 0, screenWidth, screenHeight ); hDesk = GetDesktopWindow(); hDC = GetDC( hDesk ); screenDepth = GetDeviceCaps( hDC, BITSPIXEL ); ReleaseDC( hDesk, hDC ); stuffMonitorInfo( &rcBounds, &rcWorkarea, screenDepth, TRUE, 0, monitorInfoP ); bail: return theErr; } |
This gets information on the user's main monitor, and then puts it into the appropriate locations of an int array.
MonitorMSVM( int data[], int dataOffset, int dataLen ) { int top, left, bot, right; top = data[ dataOffset + kOffsBoundsTop ]; left = data[ dataOffset + kOffsBoundsLeft ]; bot = data[ dataOffset + kOffsBoundsBottom ]; right = data[ dataOffset + kOffsBoundsRight ]; boundsRect = new Rectangle( left, top, right - left, bot - top ); top = data[ dataOffset + kOffsWorkareaTop ]; left = data[ dataOffset + kOffsWorkareaLeft ]; bot = data[ dataOffset + kOffsWorkareaBottom ]; right = data[ dataOffset + kOffsWorkareaRight ]; workareaRect = new Rectangle( left, top, right - left, bot - top ); depth = data[ dataOffset + kOffsDepth ]; refNum = data[ dataOffset + kOffsRefNum ]; if ( data[ dataOffset + kOffsIsMainMonitor ] != 0 ) bIsMainMonitor = true; else bIsMainMonitor = false; } |
After the native code returns, we're back in Java, in the MonitorHelperMSVM.getMainMonitor() method. If no error occured, we create a 'MonitorMSVM' object using the int array filled out by the native code. 'MonitorMSVM' implements the Monitor interface, and returns the information obtained, such as the Rectangle of the workarea.