Microsoft SDK for Java

Pointers and Java

Java does not support a pointer data type. However, if you just need a pointer to a single data object, pass a one-element array. For other uses, store pointers in Java integers and, if needed, use those integers (which really are pointers) to access the data they need by using various methods of com.ms.dll.DllLib such as ptrToStruct and ptrToString.

Return Value Pointers

Microsoft® Win32® functions that have multiple return values typically handle them by having the caller pass a pointer to a variable to be updated. For example, the GetDiskFreeSpace function has the following prototype:

   BOOL GetDiskFreeSpace(LPCTSTR szRootPathName,
                         DWORD  *lpSectorsPerCluster,
                         DWORD  *lpBytesPerCluster,
                         DWORD  *lpFreeClusters,
                         DWORD  *lpClusters);

GetDiskFreeSpace is typically called as follows:

DWORD sectorsPerCluster, bytesPerCluster, freeClusters, clusters;
GetDiskFreeSpace(rootname, &sectorsPerCluster,
                 &bytesPerCluster, &freeClusters, &clusters);

In Java, this is a special case of passing scalar arrays where the array size is one element. The following example shows how to call the GetDiskFreeSpace function:

class ShowGetDiskFreeSpace
{
  public static void main(String args[])
  {
    int sectorsPerCluster[] = {0};
    int bytesPerCluster[] = {0};
    int freeClusters[] = {0};
    int clusters[] = {0};
    GetDiskFreeSpace("c:\\", sectorsPerCluster, bytesPerCluster,
                     freeClusters, clusters);
    System.out.println("sectors/cluster  = " + sectorsPerCluster[0]);
    System.out.println("bytes/cluster = " + bytesPerCluster[0]);
    System.out.println("free clusters = " + freeClusters[0]);
    System.out.println("clusters = " + clusters[0]);
  }

  /** @dll.import("KERNEL32") */
  private native static boolean GetDiskFreeSpace(String rootname,
                   int pSectorsPerCluster[], int pBytesPerCluster[],
                   int pFreeClusters[], int pClusters[]);
}

Raw Pointers

A pointer to an unknown or particularly difficult structure can be stored in a plain Java integer. This is the simplest (and most efficient) approach if your application needs only to store the pointer and not dereference it. Consider using this technique to store a pointer returned by a DLL function that allocates a memory block. You can use this technique to store a pointer returned by any DLL function. Using raw pointers eliminates many of the safety advantages of Java. An alternative approach should be used whenever possible. However, there are situations when you might choose to use raw pointers. The following sections detail the two ways to read and write data from raw pointers.

Casting to a Reference to an @dll.struct Class

Data can be read and written through a raw pointer by casting the raw pointer to an @dll.struct class reference. Then, you can read and write the data using normal field access syntax. For example, you need to access a raw pointer as a RECT. Use the system method DllLib.ptrToStruct as follows:

  /** @dll.struct() */
  class RECT {
    int left;
    int top;
    int right;
    int bottom;
  }

  import com.ms.dll.*;

  int  rawptr = ...;
  RECT rect = (RECT)DllLib.ptrToStruct(RECT.class, rawptr);
  rect.left = 0;
  rect.top = 0;
  rect.right = 10;
  rect.bottom = 10;

The ptrToStruct method wraps the raw pointer in a RECT instance. Unlike instances created by the new operator, this RECT instance will not attempt to free the raw pointer upon reclamation by the garbage collector. This is because the RECT object has no way of knowing how the pointer was allocated. In addition, because the native memory was already constructed at the time ptrToStruct was called, the RECT class constructor is not called.

Using the DllLib Copy Methods

Another method for reading and writing data through a raw pointer is to use the overloaded copy methods in DllLib. These methods copy data between Java arrays of various types and raw pointers. If you need to treat a raw pointer as a pointer to a String (LPTSTR), use one of the DllLib methods ptrToStringAnsi, ptrToStringUni, or ptrToString to parse the String and convert it into a java.lang.String object.

  import com.ms.dll.*;

  int rawptr = ...;
  String s = DllLib.ptrToStringAnsi(rawptr);

!WARNING   All Java objects are subject to movement in memory or reclamation by the garbage collector. Therefore, do not attempt to obtain a pointer to a Java array by calling a DLL function that does generic casting. The following example shows an incorrect way to obtain the pointer.

  // Do not do this!
  /** @dll.import("MYDLL") */
  private native static int Cast(int javaarray[]);


  // Inside MYDLL.DLL.  
  LPVOID Cast(LPVOID ptr)
  {
    // Do not do this!
    return ptr; // Comes in as a Java array; goes out as a Java int.
  }

The value of ptr is guaranteed to be valid for only the duration of the call to the Cast function. This is because VM implementations are allowed to implement passing of arrays by copying rather than pinning and because garbage collection may cause the physical location of the array to be different after the call to the Cast function returns.

© 1999 Microsoft Corporation. All rights reserved. Terms of use.